diff --git a/.gitignore b/.gitignore index 2890113a..b4a52775 100644 --- a/.gitignore +++ b/.gitignore @@ -1,11 +1,3 @@ -/target/ -!.mvn/wrapper/maven-wrapper.jar -/logs -.svn - -### IntelliJ IDEA ### -.idea -*.iws +.idea/ +target/ *.iml -*.ipr -/out/ diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..8dada3ed --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md index bce1ee49..e9df21cd 100644 --- a/README.md +++ b/README.md @@ -1,36 +1,18 @@ -# 1. Java基础 - - - -# 2. 设计模式 - -[设计模式](https://github.com/ggb2312/JavaNotes/tree/master/design-pattern) - - - -# 3. springboot-integration-examples - -[springboot-integration-examples](https://github.com/ggb2312/JavaNotes/tree/master/springboot-integration-examples) - -基于最新的 SpringBoot2.0+ - -## 3.1 Idea新建一个SpringBoot项目 - - [Idea新建一个SpringBoot项目](https://www.cnblogs.com/gj-blog/p/10803591.html) - -## 3.2 springboot-oss(SpringBoot整合阿里云OSS文件上传、下载、查看、删除) - - [SpringBoot整合阿里云OSS文件上传、下载、查看、删除](https://www.cnblogs.com/gj-blog/p/10789544.html) - -## 3.3 springboot-aoplog(SpringBoot整合aop日志管理) - - [SpringBoot整合aop日志管理](https://www.cnblogs.com/gj-blog/p/10803600.html) - -## 3.4 springboot-wx(SpringBoot整合微信小程序登录) - - [SpringBoot整合微信小程序登录](https://www.cnblogs.com/gj-blog/p/10803607.html) - -## 3.5 springboot-mybatisplus(SpringBoot整合MybatisPlus) - -[SpringBoot整合MybatisPlus](https://www.cnblogs.com/gj-blog/p/10803593.html) +``` +├─algorithms 算法 +├─database 数据库 +├─distributed 分布式系统 +├─framework 一些常用类库 +├─java-advance 高级类库和jsr规范等 +├─java-basic Java基础 +├─lesson-code 一些课程代码 +├─mvc mvc框架 +├─orm orm框架 +├─spring-annotation spring注解驱动开发 +├─spring-batch +├─springboot-aop springaop使用以及aop应用 +│ +└─ + +``` diff --git a/algorithms/README.MD b/algorithms/README.MD new file mode 100644 index 00000000..23e4b53e --- /dev/null +++ b/algorithms/README.MD @@ -0,0 +1,55 @@ + + +``` +├─algorithm +│ +├─datastructure 数据结构与常见算法 +│ │ +│ ├─graph 图 +│ │ +│ ├─hashtab 哈希表 +│ │ +│ ├─linkedlist 链表 +│ │ +│ ├─queue 队列 +│ │ +│ ├─recursion 递归 +│ │ +│ ├─search 搜索 +│ │ +│ ├─sort 排序 +│ │ +│ ├─sparsematrix 矩阵 +│ │ +│ ├─stack 栈 +│ │ +│ └─tree 树 +│ +├─leetcode leetcode对应数据结构刷题代码 +│ │ +│ ├─array 数组 +│ │ +│ ├─linkedlist 链表 +│ │ +│ ├─hashtable 哈希表 +│ │ +│ ├─stackqueue 栈与队列 +│ │ +│ ├─recurionbacktracking 递归与回溯 +│ │ +│ ├─binarytree 二叉树 +│ │ +│ ├─dynamic 动态规划 +│ │ +│ ├─greedy 贪心 +│ │ +│ └─other 其他 +│ +├─offer +│ +├─thread +│ +└─interview +``` + + diff --git "a/algorithms/TempFilePath/leetcode/editor/cn/[4]\345\257\273\346\211\276\344\270\244\344\270\252\346\234\211\345\272\217\346\225\260\347\273\204\347\232\204\344\270\255\344\275\215\346\225\260.java" "b/algorithms/TempFilePath/leetcode/editor/cn/[4]\345\257\273\346\211\276\344\270\244\344\270\252\346\234\211\345\272\217\346\225\260\347\273\204\347\232\204\344\270\255\344\275\215\346\225\260.java" deleted file mode 100644 index a614bb36..00000000 --- "a/algorithms/TempFilePath/leetcode/editor/cn/[4]\345\257\273\346\211\276\344\270\244\344\270\252\346\234\211\345\272\217\346\225\260\347\273\204\347\232\204\344\270\255\344\275\215\346\225\260.java" +++ /dev/null @@ -1,32 +0,0 @@ -//给定两个大小为 m 和 n 的有序数组 nums1 和 nums2。 -// -// 请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。 -// -// 你可以假设 nums1 和 nums2 不会同时为空。 -// -// 示例 1: -// -// nums1 = [1, 3] -//nums2 = [2] -// -//则中位数是 2.0 -// -// -// 示例 2: -// -// nums1 = [1, 2] -//nums2 = [3, 4] -// -//则中位数是 (2 + 3)/2 = 2.5 -// -// Related Topics 数组 二分查找 分治算法 - - - -//leetcode submit region begin(Prohibit modification and deletion) -class Solution { - public double findMedianSortedArrays(int[] nums1, int[] nums2) { - - } -} -//leetcode submit region end(Prohibit modification and deletion) diff --git "a/algorithms/TempFilePath/leetcode/editor/cn/[]\345\217\252\345\207\272\347\216\260\344\270\200\346\254\241\347\232\204\346\225\260\345\255\227.java" "b/algorithms/TempFilePath/leetcode/editor/cn/[]\345\217\252\345\207\272\347\216\260\344\270\200\346\254\241\347\232\204\346\225\260\345\255\227.java" deleted file mode 100644 index 49cb8971..00000000 --- "a/algorithms/TempFilePath/leetcode/editor/cn/[]\345\217\252\345\207\272\347\216\260\344\270\200\346\254\241\347\232\204\346\225\260\345\255\227.java" +++ /dev/null @@ -1,27 +0,0 @@ -//给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。 -// -// 说明: -// -// 你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗? -// -// 示例 1: -// -// 输入: [2,2,1] -//输出: 1 -// -// -// 示例 2: -// -// 输入: [4,1,2,1,2] -//输出: 4 -// Related Topics 位运算 哈希表 - - - -//leetcode submit region begin(Prohibit modification and deletion) -class Solution { - public int singleNumber(int[] nums) { - - } -} -//leetcode submit region end(Prohibit modification and deletion) diff --git a/algorithms/TempFilePath/leetcode/editor/cn/all.json b/algorithms/TempFilePath/leetcode/editor/cn/all.json deleted file mode 100644 index 88e36f0f..00000000 --- a/algorithms/TempFilePath/leetcode/editor/cn/all.json +++ /dev/null @@ -1 +0,0 @@ -[{"formTitle":"[1]两数之和","frontendQuestionId":"1","leaf":true,"level":1,"nodeType":"def","questionId":"1","status":"ac","title":"两数之和","titleSlug":"two-sum"},{"formTitle":"[2]两数相加","frontendQuestionId":"2","leaf":true,"level":2,"nodeType":"def","questionId":"2","status":"","title":"两数相加","titleSlug":"add-two-numbers"},{"formTitle":"[3]无重复字符的最长子串","frontendQuestionId":"3","leaf":true,"level":2,"nodeType":"def","questionId":"3","status":"ac","title":"无重复字符的最长子串","titleSlug":"longest-substring-without-repeating-characters"},{"formTitle":"[4]寻找两个有序数组的中位数","frontendQuestionId":"4","leaf":true,"level":3,"nodeType":"def","questionId":"4","status":"","title":"寻找两个有序数组的中位数","titleSlug":"median-of-two-sorted-arrays"},{"formTitle":"[5]最长回文子串","frontendQuestionId":"5","leaf":true,"level":2,"nodeType":"def","questionId":"5","status":"","title":"最长回文子串","titleSlug":"longest-palindromic-substring"},{"formTitle":"[6]Z 字形变换","frontendQuestionId":"6","leaf":true,"level":2,"nodeType":"def","questionId":"6","status":"","title":"Z 字形变换","titleSlug":"zigzag-conversion"},{"formTitle":"[7]整数反转","frontendQuestionId":"7","leaf":true,"level":1,"nodeType":"def","questionId":"7","status":"notac","title":"整数反转","titleSlug":"reverse-integer"},{"formTitle":"[8]字符串转换整数 (atoi)","frontendQuestionId":"8","leaf":true,"level":2,"nodeType":"def","questionId":"8","status":"","title":"字符串转换整数 (atoi)","titleSlug":"string-to-integer-atoi"},{"formTitle":"[9]回文数","frontendQuestionId":"9","leaf":true,"level":1,"nodeType":"def","questionId":"9","status":"","title":"回文数","titleSlug":"palindrome-number"},{"formTitle":"[10]正则表达式匹配","frontendQuestionId":"10","leaf":true,"level":3,"nodeType":"def","questionId":"10","status":"","title":"正则表达式匹配","titleSlug":"regular-expression-matching"},{"formTitle":"[11]盛最多水的容器","frontendQuestionId":"11","leaf":true,"level":2,"nodeType":"def","questionId":"11","status":"ac","title":"盛最多水的容器","titleSlug":"container-with-most-water"},{"formTitle":"[12]整数转罗马数字","frontendQuestionId":"12","leaf":true,"level":2,"nodeType":"def","questionId":"12","status":"","title":"整数转罗马数字","titleSlug":"integer-to-roman"},{"formTitle":"[13]罗马数字转整数","frontendQuestionId":"13","leaf":true,"level":1,"nodeType":"def","questionId":"13","status":"","title":"罗马数字转整数","titleSlug":"roman-to-integer"},{"formTitle":"[14]最长公共前缀","frontendQuestionId":"14","leaf":true,"level":1,"nodeType":"def","questionId":"14","status":"","title":"最长公共前缀","titleSlug":"longest-common-prefix"},{"formTitle":"[15]三数之和","frontendQuestionId":"15","leaf":true,"level":2,"nodeType":"def","questionId":"15","status":"","title":"三数之和","titleSlug":"3sum"},{"formTitle":"[16]最接近的三数之和","frontendQuestionId":"16","leaf":true,"level":2,"nodeType":"def","questionId":"16","status":"","title":"最接近的三数之和","titleSlug":"3sum-closest"},{"formTitle":"[17]电话号码的字母组合","frontendQuestionId":"17","leaf":true,"level":2,"nodeType":"def","questionId":"17","status":"","title":"电话号码的字母组合","titleSlug":"letter-combinations-of-a-phone-number"},{"formTitle":"[18]四数之和","frontendQuestionId":"18","leaf":true,"level":2,"nodeType":"def","questionId":"18","status":"","title":"四数之和","titleSlug":"4sum"},{"formTitle":"[19]删除链表的倒数第N个节点","frontendQuestionId":"19","leaf":true,"level":2,"nodeType":"def","questionId":"19","status":"","title":"删除链表的倒数第N个节点","titleSlug":"remove-nth-node-from-end-of-list"},{"formTitle":"[20]有效的括号","frontendQuestionId":"20","leaf":true,"level":1,"nodeType":"def","questionId":"20","status":"","title":"有效的括号","titleSlug":"valid-parentheses"},{"formTitle":"[21]合并两个有序链表","frontendQuestionId":"21","leaf":true,"level":1,"nodeType":"def","questionId":"21","status":"","title":"合并两个有序链表","titleSlug":"merge-two-sorted-lists"},{"formTitle":"[22]括号生成","frontendQuestionId":"22","leaf":true,"level":2,"nodeType":"def","questionId":"22","status":"","title":"括号生成","titleSlug":"generate-parentheses"},{"formTitle":"[23]合并K个排序链表","frontendQuestionId":"23","leaf":true,"level":3,"nodeType":"def","questionId":"23","status":"","title":"合并K个排序链表","titleSlug":"merge-k-sorted-lists"},{"formTitle":"[24]两两交换链表中的节点","frontendQuestionId":"24","leaf":true,"level":2,"nodeType":"def","questionId":"24","status":"","title":"两两交换链表中的节点","titleSlug":"swap-nodes-in-pairs"},{"formTitle":"[25]K 个一组翻转链表","frontendQuestionId":"25","leaf":true,"level":3,"nodeType":"def","questionId":"25","status":"","title":"K 个一组翻转链表","titleSlug":"reverse-nodes-in-k-group"},{"formTitle":"[26]删除排序数组中的重复项","frontendQuestionId":"26","leaf":true,"level":1,"nodeType":"def","questionId":"26","status":"ac","title":"删除排序数组中的重复项","titleSlug":"remove-duplicates-from-sorted-array"},{"formTitle":"[27]移除元素","frontendQuestionId":"27","leaf":true,"level":1,"nodeType":"def","questionId":"27","status":"ac","title":"移除元素","titleSlug":"remove-element"},{"formTitle":"[28]实现 strStr()","frontendQuestionId":"28","leaf":true,"level":1,"nodeType":"def","questionId":"28","status":"","title":"实现 strStr()","titleSlug":"implement-strstr"},{"formTitle":"[29]两数相除","frontendQuestionId":"29","leaf":true,"level":2,"nodeType":"def","questionId":"29","status":"","title":"两数相除","titleSlug":"divide-two-integers"},{"formTitle":"[30]串联所有单词的子串","frontendQuestionId":"30","leaf":true,"level":3,"nodeType":"def","questionId":"30","status":"","title":"串联所有单词的子串","titleSlug":"substring-with-concatenation-of-all-words"},{"formTitle":"[31]下一个排列","frontendQuestionId":"31","leaf":true,"level":2,"nodeType":"def","questionId":"31","status":"","title":"下一个排列","titleSlug":"next-permutation"},{"formTitle":"[32]最长有效括号","frontendQuestionId":"32","leaf":true,"level":3,"nodeType":"def","questionId":"32","status":"","title":"最长有效括号","titleSlug":"longest-valid-parentheses"},{"formTitle":"[33]搜索旋转排序数组","frontendQuestionId":"33","leaf":true,"level":2,"nodeType":"def","questionId":"33","status":"","title":"搜索旋转排序数组","titleSlug":"search-in-rotated-sorted-array"},{"formTitle":"[34]在排序数组中查找元素的第一个和最后一个位置","frontendQuestionId":"34","leaf":true,"level":2,"nodeType":"def","questionId":"34","status":"","title":"在排序数组中查找元素的第一个和最后一个位置","titleSlug":"find-first-and-last-position-of-element-in-sorted-array"},{"formTitle":"[35]搜索插入位置","frontendQuestionId":"35","leaf":true,"level":1,"nodeType":"def","questionId":"35","status":"","title":"搜索插入位置","titleSlug":"search-insert-position"},{"formTitle":"[36]有效的数独","frontendQuestionId":"36","leaf":true,"level":2,"nodeType":"def","questionId":"36","status":"","title":"有效的数独","titleSlug":"valid-sudoku"},{"formTitle":"[37]解数独","frontendQuestionId":"37","leaf":true,"level":3,"nodeType":"def","questionId":"37","status":"","title":"解数独","titleSlug":"sudoku-solver"},{"formTitle":"[38]报数","frontendQuestionId":"38","leaf":true,"level":1,"nodeType":"def","questionId":"38","status":"","title":"报数","titleSlug":"count-and-say"},{"formTitle":"[39]组合总和","frontendQuestionId":"39","leaf":true,"level":2,"nodeType":"def","questionId":"39","status":"","title":"组合总和","titleSlug":"combination-sum"},{"formTitle":"[40]组合总和 II","frontendQuestionId":"40","leaf":true,"level":2,"nodeType":"def","questionId":"40","status":"","title":"组合总和 II","titleSlug":"combination-sum-ii"},{"formTitle":"[41]缺失的第一个正数","frontendQuestionId":"41","leaf":true,"level":3,"nodeType":"def","questionId":"41","status":"","title":"缺失的第一个正数","titleSlug":"first-missing-positive"},{"formTitle":"[42]接雨水","frontendQuestionId":"42","leaf":true,"level":3,"nodeType":"def","questionId":"42","status":"","title":"接雨水","titleSlug":"trapping-rain-water"},{"formTitle":"[43]字符串相乘","frontendQuestionId":"43","leaf":true,"level":2,"nodeType":"def","questionId":"43","status":"","title":"字符串相乘","titleSlug":"multiply-strings"},{"formTitle":"[44]通配符匹配","frontendQuestionId":"44","leaf":true,"level":3,"nodeType":"def","questionId":"44","status":"","title":"通配符匹配","titleSlug":"wildcard-matching"},{"formTitle":"[45]跳跃游戏 II","frontendQuestionId":"45","leaf":true,"level":3,"nodeType":"def","questionId":"45","status":"","title":"跳跃游戏 II","titleSlug":"jump-game-ii"},{"formTitle":"[46]全排列","frontendQuestionId":"46","leaf":true,"level":2,"nodeType":"def","questionId":"46","status":"","title":"全排列","titleSlug":"permutations"},{"formTitle":"[47]全排列 II","frontendQuestionId":"47","leaf":true,"level":2,"nodeType":"def","questionId":"47","status":"","title":"全排列 II","titleSlug":"permutations-ii"},{"formTitle":"[48]旋转图像","frontendQuestionId":"48","leaf":true,"level":2,"nodeType":"def","questionId":"48","status":"","title":"旋转图像","titleSlug":"rotate-image"},{"formTitle":"[49]字母异位词分组","frontendQuestionId":"49","leaf":true,"level":2,"nodeType":"def","questionId":"49","status":"","title":"字母异位词分组","titleSlug":"group-anagrams"},{"formTitle":"[50]Pow(x, n)","frontendQuestionId":"50","leaf":true,"level":2,"nodeType":"def","questionId":"50","status":"","title":"Pow(x, n)","titleSlug":"powx-n"},{"formTitle":"[51]N皇后","frontendQuestionId":"51","leaf":true,"level":3,"nodeType":"def","questionId":"51","status":"","title":"N皇后","titleSlug":"n-queens"},{"formTitle":"[52]N皇后 II","frontendQuestionId":"52","leaf":true,"level":3,"nodeType":"def","questionId":"52","status":"","title":"N皇后 II","titleSlug":"n-queens-ii"},{"formTitle":"[53]最大子序和","frontendQuestionId":"53","leaf":true,"level":1,"nodeType":"def","questionId":"53","status":"","title":"最大子序和","titleSlug":"maximum-subarray"},{"formTitle":"[54]螺旋矩阵","frontendQuestionId":"54","leaf":true,"level":2,"nodeType":"def","questionId":"54","status":"","title":"螺旋矩阵","titleSlug":"spiral-matrix"},{"formTitle":"[55]跳跃游戏","frontendQuestionId":"55","leaf":true,"level":2,"nodeType":"def","questionId":"55","status":"","title":"跳跃游戏","titleSlug":"jump-game"},{"formTitle":"[56]合并区间","frontendQuestionId":"56","leaf":true,"level":2,"nodeType":"def","questionId":"56","status":"","title":"合并区间","titleSlug":"merge-intervals"},{"formTitle":"[57]插入区间","frontendQuestionId":"57","leaf":true,"level":3,"nodeType":"def","questionId":"57","status":"","title":"插入区间","titleSlug":"insert-interval"},{"formTitle":"[58]最后一个单词的长度","frontendQuestionId":"58","leaf":true,"level":1,"nodeType":"def","questionId":"58","status":"","title":"最后一个单词的长度","titleSlug":"length-of-last-word"},{"formTitle":"[59]螺旋矩阵 II","frontendQuestionId":"59","leaf":true,"level":2,"nodeType":"def","questionId":"59","status":"","title":"螺旋矩阵 II","titleSlug":"spiral-matrix-ii"},{"formTitle":"[60]第k个排列","frontendQuestionId":"60","leaf":true,"level":2,"nodeType":"def","questionId":"60","status":"","title":"第k个排列","titleSlug":"permutation-sequence"},{"formTitle":"[61]旋转链表","frontendQuestionId":"61","leaf":true,"level":2,"nodeType":"def","questionId":"61","status":"","title":"旋转链表","titleSlug":"rotate-list"},{"formTitle":"[62]不同路径","frontendQuestionId":"62","leaf":true,"level":2,"nodeType":"def","questionId":"62","status":"","title":"不同路径","titleSlug":"unique-paths"},{"formTitle":"[63]不同路径 II","frontendQuestionId":"63","leaf":true,"level":2,"nodeType":"def","questionId":"63","status":"","title":"不同路径 II","titleSlug":"unique-paths-ii"},{"formTitle":"[64]最小路径和","frontendQuestionId":"64","leaf":true,"level":2,"nodeType":"def","questionId":"64","status":"","title":"最小路径和","titleSlug":"minimum-path-sum"},{"formTitle":"[65]有效数字","frontendQuestionId":"65","leaf":true,"level":3,"nodeType":"def","questionId":"65","status":"","title":"有效数字","titleSlug":"valid-number"},{"formTitle":"[66]加一","frontendQuestionId":"66","leaf":true,"level":1,"nodeType":"def","questionId":"66","status":"","title":"加一","titleSlug":"plus-one"},{"formTitle":"[67]二进制求和","frontendQuestionId":"67","leaf":true,"level":1,"nodeType":"def","questionId":"67","status":"","title":"二进制求和","titleSlug":"add-binary"},{"formTitle":"[68]文本左右对齐","frontendQuestionId":"68","leaf":true,"level":3,"nodeType":"def","questionId":"68","status":"","title":"文本左右对齐","titleSlug":"text-justification"},{"formTitle":"[69]x 的平方根","frontendQuestionId":"69","leaf":true,"level":1,"nodeType":"def","questionId":"69","status":"","title":"x 的平方根","titleSlug":"sqrtx"},{"formTitle":"[70]爬楼梯","frontendQuestionId":"70","leaf":true,"level":1,"nodeType":"def","questionId":"70","status":"","title":"爬楼梯","titleSlug":"climbing-stairs"},{"formTitle":"[71]简化路径","frontendQuestionId":"71","leaf":true,"level":2,"nodeType":"def","questionId":"71","status":"","title":"简化路径","titleSlug":"simplify-path"},{"formTitle":"[72]编辑距离","frontendQuestionId":"72","leaf":true,"level":3,"nodeType":"def","questionId":"72","status":"","title":"编辑距离","titleSlug":"edit-distance"},{"formTitle":"[73]矩阵置零","frontendQuestionId":"73","leaf":true,"level":2,"nodeType":"def","questionId":"73","status":"","title":"矩阵置零","titleSlug":"set-matrix-zeroes"},{"formTitle":"[74]搜索二维矩阵","frontendQuestionId":"74","leaf":true,"level":2,"nodeType":"def","questionId":"74","status":"","title":"搜索二维矩阵","titleSlug":"search-a-2d-matrix"},{"formTitle":"[75]颜色分类","frontendQuestionId":"75","leaf":true,"level":2,"nodeType":"def","questionId":"75","status":"ac","title":"颜色分类","titleSlug":"sort-colors"},{"formTitle":"[76]最小覆盖子串","frontendQuestionId":"76","leaf":true,"level":3,"nodeType":"def","questionId":"76","status":"ac","title":"最小覆盖子串","titleSlug":"minimum-window-substring"},{"formTitle":"[77]组合","frontendQuestionId":"77","leaf":true,"level":2,"nodeType":"def","questionId":"77","status":"","title":"组合","titleSlug":"combinations"},{"formTitle":"[78]子集","frontendQuestionId":"78","leaf":true,"level":2,"nodeType":"def","questionId":"78","status":"","title":"子集","titleSlug":"subsets"},{"formTitle":"[79]单词搜索","frontendQuestionId":"79","leaf":true,"level":2,"nodeType":"def","questionId":"79","status":"","title":"单词搜索","titleSlug":"word-search"},{"formTitle":"[80]删除排序数组中的重复项 II","frontendQuestionId":"80","leaf":true,"level":2,"nodeType":"def","questionId":"80","status":"","title":"删除排序数组中的重复项 II","titleSlug":"remove-duplicates-from-sorted-array-ii"},{"formTitle":"[81]搜索旋转排序数组 II","frontendQuestionId":"81","leaf":true,"level":2,"nodeType":"def","questionId":"81","status":"","title":"搜索旋转排序数组 II","titleSlug":"search-in-rotated-sorted-array-ii"},{"formTitle":"[82]删除排序链表中的重复元素 II","frontendQuestionId":"82","leaf":true,"level":2,"nodeType":"def","questionId":"82","status":"","title":"删除排序链表中的重复元素 II","titleSlug":"remove-duplicates-from-sorted-list-ii"},{"formTitle":"[83]删除排序链表中的重复元素","frontendQuestionId":"83","leaf":true,"level":1,"nodeType":"def","questionId":"83","status":"","title":"删除排序链表中的重复元素","titleSlug":"remove-duplicates-from-sorted-list"},{"formTitle":"[84]柱状图中最大的矩形","frontendQuestionId":"84","leaf":true,"level":3,"nodeType":"def","questionId":"84","status":"","title":"柱状图中最大的矩形","titleSlug":"largest-rectangle-in-histogram"},{"formTitle":"[85]最大矩形","frontendQuestionId":"85","leaf":true,"level":3,"nodeType":"def","questionId":"85","status":"","title":"最大矩形","titleSlug":"maximal-rectangle"},{"formTitle":"[86]分隔链表","frontendQuestionId":"86","leaf":true,"level":2,"nodeType":"def","questionId":"86","status":"","title":"分隔链表","titleSlug":"partition-list"},{"formTitle":"[87]扰乱字符串","frontendQuestionId":"87","leaf":true,"level":3,"nodeType":"def","questionId":"87","status":"","title":"扰乱字符串","titleSlug":"scramble-string"},{"formTitle":"[88]合并两个有序数组","frontendQuestionId":"88","leaf":true,"level":1,"nodeType":"def","questionId":"88","status":"ac","title":"合并两个有序数组","titleSlug":"merge-sorted-array"},{"formTitle":"[89]格雷编码","frontendQuestionId":"89","leaf":true,"level":2,"nodeType":"def","questionId":"89","status":"","title":"格雷编码","titleSlug":"gray-code"},{"formTitle":"[90]子集 II","frontendQuestionId":"90","leaf":true,"level":2,"nodeType":"def","questionId":"90","status":"","title":"子集 II","titleSlug":"subsets-ii"},{"formTitle":"[91]解码方法","frontendQuestionId":"91","leaf":true,"level":2,"nodeType":"def","questionId":"91","status":"","title":"解码方法","titleSlug":"decode-ways"},{"formTitle":"[92]反转链表 II","frontendQuestionId":"92","leaf":true,"level":2,"nodeType":"def","questionId":"92","status":"","title":"反转链表 II","titleSlug":"reverse-linked-list-ii"},{"formTitle":"[93]复原IP地址","frontendQuestionId":"93","leaf":true,"level":2,"nodeType":"def","questionId":"93","status":"","title":"复原IP地址","titleSlug":"restore-ip-addresses"},{"formTitle":"[94]二叉树的中序遍历","frontendQuestionId":"94","leaf":true,"level":2,"nodeType":"def","questionId":"94","status":"","title":"二叉树的中序遍历","titleSlug":"binary-tree-inorder-traversal"},{"formTitle":"[95]不同的二叉搜索树 II","frontendQuestionId":"95","leaf":true,"level":2,"nodeType":"def","questionId":"95","status":"","title":"不同的二叉搜索树 II","titleSlug":"unique-binary-search-trees-ii"},{"formTitle":"[96]不同的二叉搜索树","frontendQuestionId":"96","leaf":true,"level":2,"nodeType":"def","questionId":"96","status":"","title":"不同的二叉搜索树","titleSlug":"unique-binary-search-trees"},{"formTitle":"[97]交错字符串","frontendQuestionId":"97","leaf":true,"level":3,"nodeType":"def","questionId":"97","status":"","title":"交错字符串","titleSlug":"interleaving-string"},{"formTitle":"[98]验证二叉搜索树","frontendQuestionId":"98","leaf":true,"level":2,"nodeType":"def","questionId":"98","status":"","title":"验证二叉搜索树","titleSlug":"validate-binary-search-tree"},{"formTitle":"[99]恢复二叉搜索树","frontendQuestionId":"99","leaf":true,"level":3,"nodeType":"def","questionId":"99","status":"","title":"恢复二叉搜索树","titleSlug":"recover-binary-search-tree"},{"formTitle":"[100]相同的树","frontendQuestionId":"100","leaf":true,"level":1,"nodeType":"def","questionId":"100","status":"","title":"相同的树","titleSlug":"same-tree"},{"formTitle":"[101]对称二叉树","frontendQuestionId":"101","leaf":true,"level":1,"nodeType":"def","questionId":"101","status":"","title":"对称二叉树","titleSlug":"symmetric-tree"},{"formTitle":"[102]二叉树的层次遍历","frontendQuestionId":"102","leaf":true,"level":2,"nodeType":"def","questionId":"102","status":"","title":"二叉树的层次遍历","titleSlug":"binary-tree-level-order-traversal"},{"formTitle":"[103]二叉树的锯齿形层次遍历","frontendQuestionId":"103","leaf":true,"level":2,"nodeType":"def","questionId":"103","status":"","title":"二叉树的锯齿形层次遍历","titleSlug":"binary-tree-zigzag-level-order-traversal"},{"formTitle":"[104]二叉树的最大深度","frontendQuestionId":"104","leaf":true,"level":1,"nodeType":"def","questionId":"104","status":"","title":"二叉树的最大深度","titleSlug":"maximum-depth-of-binary-tree"},{"formTitle":"[105]从前序与中序遍历序列构造二叉树","frontendQuestionId":"105","leaf":true,"level":2,"nodeType":"def","questionId":"105","status":"","title":"从前序与中序遍历序列构造二叉树","titleSlug":"construct-binary-tree-from-preorder-and-inorder-traversal"},{"formTitle":"[106]从中序与后序遍历序列构造二叉树","frontendQuestionId":"106","leaf":true,"level":2,"nodeType":"def","questionId":"106","status":"","title":"从中序与后序遍历序列构造二叉树","titleSlug":"construct-binary-tree-from-inorder-and-postorder-traversal"},{"formTitle":"[107]二叉树的层次遍历 II","frontendQuestionId":"107","leaf":true,"level":1,"nodeType":"def","questionId":"107","status":"","title":"二叉树的层次遍历 II","titleSlug":"binary-tree-level-order-traversal-ii"},{"formTitle":"[108]将有序数组转换为二叉搜索树","frontendQuestionId":"108","leaf":true,"level":1,"nodeType":"def","questionId":"108","status":"","title":"将有序数组转换为二叉搜索树","titleSlug":"convert-sorted-array-to-binary-search-tree"},{"formTitle":"[109]有序链表转换二叉搜索树","frontendQuestionId":"109","leaf":true,"level":2,"nodeType":"def","questionId":"109","status":"","title":"有序链表转换二叉搜索树","titleSlug":"convert-sorted-list-to-binary-search-tree"},{"formTitle":"[110]平衡二叉树","frontendQuestionId":"110","leaf":true,"level":1,"nodeType":"def","questionId":"110","status":"","title":"平衡二叉树","titleSlug":"balanced-binary-tree"},{"formTitle":"[111]二叉树的最小深度","frontendQuestionId":"111","leaf":true,"level":1,"nodeType":"def","questionId":"111","status":"","title":"二叉树的最小深度","titleSlug":"minimum-depth-of-binary-tree"},{"formTitle":"[112]路径总和","frontendQuestionId":"112","leaf":true,"level":1,"nodeType":"def","questionId":"112","status":"","title":"路径总和","titleSlug":"path-sum"},{"formTitle":"[113]路径总和 II","frontendQuestionId":"113","leaf":true,"level":2,"nodeType":"def","questionId":"113","status":"","title":"路径总和 II","titleSlug":"path-sum-ii"},{"formTitle":"[114]二叉树展开为链表","frontendQuestionId":"114","leaf":true,"level":2,"nodeType":"def","questionId":"114","status":"","title":"二叉树展开为链表","titleSlug":"flatten-binary-tree-to-linked-list"},{"formTitle":"[115]不同的子序列","frontendQuestionId":"115","leaf":true,"level":3,"nodeType":"def","questionId":"115","status":"","title":"不同的子序列","titleSlug":"distinct-subsequences"},{"formTitle":"[116]填充每个节点的下一个右侧节点指针","frontendQuestionId":"116","leaf":true,"level":2,"nodeType":"def","questionId":"116","status":"","title":"填充每个节点的下一个右侧节点指针","titleSlug":"populating-next-right-pointers-in-each-node"},{"formTitle":"[117]填充每个节点的下一个右侧节点指针 II","frontendQuestionId":"117","leaf":true,"level":2,"nodeType":"def","questionId":"117","status":"","title":"填充每个节点的下一个右侧节点指针 II","titleSlug":"populating-next-right-pointers-in-each-node-ii"},{"formTitle":"[118]杨辉三角","frontendQuestionId":"118","leaf":true,"level":1,"nodeType":"def","questionId":"118","status":"","title":"杨辉三角","titleSlug":"pascals-triangle"},{"formTitle":"[119]杨辉三角 II","frontendQuestionId":"119","leaf":true,"level":1,"nodeType":"def","questionId":"119","status":"","title":"杨辉三角 II","titleSlug":"pascals-triangle-ii"},{"formTitle":"[120]三角形最小路径和","frontendQuestionId":"120","leaf":true,"level":2,"nodeType":"def","questionId":"120","status":"","title":"三角形最小路径和","titleSlug":"triangle"},{"formTitle":"[121]买卖股票的最佳时机","frontendQuestionId":"121","leaf":true,"level":1,"nodeType":"def","questionId":"121","status":"","title":"买卖股票的最佳时机","titleSlug":"best-time-to-buy-and-sell-stock"},{"formTitle":"[122]买卖股票的最佳时机 II","frontendQuestionId":"122","leaf":true,"level":1,"nodeType":"def","questionId":"122","status":"","title":"买卖股票的最佳时机 II","titleSlug":"best-time-to-buy-and-sell-stock-ii"},{"formTitle":"[123]买卖股票的最佳时机 III","frontendQuestionId":"123","leaf":true,"level":3,"nodeType":"def","questionId":"123","status":"","title":"买卖股票的最佳时机 III","titleSlug":"best-time-to-buy-and-sell-stock-iii"},{"formTitle":"[124]二叉树中的最大路径和","frontendQuestionId":"124","leaf":true,"level":3,"nodeType":"def","questionId":"124","status":"","title":"二叉树中的最大路径和","titleSlug":"binary-tree-maximum-path-sum"},{"formTitle":"[125]验证回文串","frontendQuestionId":"125","leaf":true,"level":1,"nodeType":"def","questionId":"125","status":"ac","title":"验证回文串","titleSlug":"valid-palindrome"},{"formTitle":"[126]单词接龙 II","frontendQuestionId":"126","leaf":true,"level":3,"nodeType":"def","questionId":"126","status":"","title":"单词接龙 II","titleSlug":"word-ladder-ii"},{"formTitle":"[127]单词接龙","frontendQuestionId":"127","leaf":true,"level":2,"nodeType":"def","questionId":"127","status":"","title":"单词接龙","titleSlug":"word-ladder"},{"formTitle":"[128]最长连续序列","frontendQuestionId":"128","leaf":true,"level":3,"nodeType":"def","questionId":"128","status":"","title":"最长连续序列","titleSlug":"longest-consecutive-sequence"},{"formTitle":"[129]求根到叶子节点数字之和","frontendQuestionId":"129","leaf":true,"level":2,"nodeType":"def","questionId":"129","status":"","title":"求根到叶子节点数字之和","titleSlug":"sum-root-to-leaf-numbers"},{"formTitle":"[130]被围绕的区域","frontendQuestionId":"130","leaf":true,"level":2,"nodeType":"def","questionId":"130","status":"","title":"被围绕的区域","titleSlug":"surrounded-regions"},{"formTitle":"[131]分割回文串","frontendQuestionId":"131","leaf":true,"level":2,"nodeType":"def","questionId":"131","status":"","title":"分割回文串","titleSlug":"palindrome-partitioning"},{"formTitle":"[132]分割回文串 II","frontendQuestionId":"132","leaf":true,"level":3,"nodeType":"def","questionId":"132","status":"","title":"分割回文串 II","titleSlug":"palindrome-partitioning-ii"},{"formTitle":"[133]克隆图","frontendQuestionId":"133","leaf":true,"level":2,"nodeType":"def","questionId":"133","status":"","title":"克隆图","titleSlug":"clone-graph"},{"formTitle":"[134]加油站","frontendQuestionId":"134","leaf":true,"level":2,"nodeType":"def","questionId":"134","status":"","title":"加油站","titleSlug":"gas-station"},{"formTitle":"[135]分发糖果","frontendQuestionId":"135","leaf":true,"level":3,"nodeType":"def","questionId":"135","status":"","title":"分发糖果","titleSlug":"candy"},{"formTitle":"[136]只出现一次的数字","frontendQuestionId":"136","leaf":true,"level":1,"nodeType":"def","questionId":"136","status":"","title":"只出现一次的数字","titleSlug":"single-number"},{"formTitle":"[137]只出现一次的数字 II","frontendQuestionId":"137","leaf":true,"level":2,"nodeType":"def","questionId":"137","status":"","title":"只出现一次的数字 II","titleSlug":"single-number-ii"},{"formTitle":"[138]复制带随机指针的链表","frontendQuestionId":"138","leaf":true,"level":2,"nodeType":"def","questionId":"138","status":"","title":"复制带随机指针的链表","titleSlug":"copy-list-with-random-pointer"},{"formTitle":"[139]单词拆分","frontendQuestionId":"139","leaf":true,"level":2,"nodeType":"def","questionId":"139","status":"","title":"单词拆分","titleSlug":"word-break"},{"formTitle":"[140]单词拆分 II","frontendQuestionId":"140","leaf":true,"level":3,"nodeType":"def","questionId":"140","status":"","title":"单词拆分 II","titleSlug":"word-break-ii"},{"formTitle":"[141]环形链表","frontendQuestionId":"141","leaf":true,"level":1,"nodeType":"def","questionId":"141","status":"","title":"环形链表","titleSlug":"linked-list-cycle"},{"formTitle":"[142]环形链表 II","frontendQuestionId":"142","leaf":true,"level":2,"nodeType":"def","questionId":"142","status":"","title":"环形链表 II","titleSlug":"linked-list-cycle-ii"},{"formTitle":"[143]重排链表","frontendQuestionId":"143","leaf":true,"level":2,"nodeType":"def","questionId":"143","status":"","title":"重排链表","titleSlug":"reorder-list"},{"formTitle":"[144]二叉树的前序遍历","frontendQuestionId":"144","leaf":true,"level":2,"nodeType":"def","questionId":"144","status":"","title":"二叉树的前序遍历","titleSlug":"binary-tree-preorder-traversal"},{"formTitle":"[145]二叉树的后序遍历","frontendQuestionId":"145","leaf":true,"level":3,"nodeType":"def","questionId":"145","status":"","title":"二叉树的后序遍历","titleSlug":"binary-tree-postorder-traversal"},{"formTitle":"[146]LRU缓存机制","frontendQuestionId":"146","leaf":true,"level":2,"nodeType":"def","questionId":"146","status":"ac","title":"LRU缓存机制","titleSlug":"lru-cache"},{"formTitle":"[147]对链表进行插入排序","frontendQuestionId":"147","leaf":true,"level":2,"nodeType":"def","questionId":"147","status":"","title":"对链表进行插入排序","titleSlug":"insertion-sort-list"},{"formTitle":"[148]排序链表","frontendQuestionId":"148","leaf":true,"level":2,"nodeType":"def","questionId":"148","status":"","title":"排序链表","titleSlug":"sort-list"},{"formTitle":"[149]直线上最多的点数","frontendQuestionId":"149","leaf":true,"level":3,"nodeType":"def","questionId":"149","status":"","title":"直线上最多的点数","titleSlug":"max-points-on-a-line"},{"formTitle":"[150]逆波兰表达式求值","frontendQuestionId":"150","leaf":true,"level":2,"nodeType":"def","questionId":"150","status":"","title":"逆波兰表达式求值","titleSlug":"evaluate-reverse-polish-notation"},{"formTitle":"[151]翻转字符串里的单词","frontendQuestionId":"151","leaf":true,"level":2,"nodeType":"def","questionId":"151","status":"","title":"翻转字符串里的单词","titleSlug":"reverse-words-in-a-string"},{"formTitle":"[152]乘积最大子序列","frontendQuestionId":"152","leaf":true,"level":2,"nodeType":"def","questionId":"152","status":"","title":"乘积最大子序列","titleSlug":"maximum-product-subarray"},{"formTitle":"[153]寻找旋转排序数组中的最小值","frontendQuestionId":"153","leaf":true,"level":2,"nodeType":"def","questionId":"153","status":"","title":"寻找旋转排序数组中的最小值","titleSlug":"find-minimum-in-rotated-sorted-array"},{"formTitle":"[154]寻找旋转排序数组中的最小值 II","frontendQuestionId":"154","leaf":true,"level":3,"nodeType":"def","questionId":"154","status":"","title":"寻找旋转排序数组中的最小值 II","titleSlug":"find-minimum-in-rotated-sorted-array-ii"},{"formTitle":"[155]最小栈","frontendQuestionId":"155","leaf":true,"level":1,"nodeType":"def","questionId":"155","status":"","title":"最小栈","titleSlug":"min-stack"},{"formTitle":"[156]上下翻转二叉树","frontendQuestionId":"156","leaf":true,"level":2,"nodeType":"def","questionId":"156","status":"lock","title":"上下翻转二叉树","titleSlug":"binary-tree-upside-down"},{"formTitle":"[157]用 Read4 读取 N 个字符","frontendQuestionId":"157","leaf":true,"level":1,"nodeType":"def","questionId":"157","status":"lock","title":"用 Read4 读取 N 个字符","titleSlug":"read-n-characters-given-read4"},{"formTitle":"[158]用 Read4 读取 N 个字符 II","frontendQuestionId":"158","leaf":true,"level":3,"nodeType":"def","questionId":"158","status":"lock","title":"用 Read4 读取 N 个字符 II","titleSlug":"read-n-characters-given-read4-ii-call-multiple-times"},{"formTitle":"[159]至多包含两个不同字符的最长子串","frontendQuestionId":"159","leaf":true,"level":3,"nodeType":"def","questionId":"159","status":"lock","title":"至多包含两个不同字符的最长子串","titleSlug":"longest-substring-with-at-most-two-distinct-characters"},{"formTitle":"[160]相交链表","frontendQuestionId":"160","leaf":true,"level":1,"nodeType":"def","questionId":"160","status":"","title":"相交链表","titleSlug":"intersection-of-two-linked-lists"},{"formTitle":"[161]相隔为 1 的编辑距离","frontendQuestionId":"161","leaf":true,"level":2,"nodeType":"def","questionId":"161","status":"lock","title":"相隔为 1 的编辑距离","titleSlug":"one-edit-distance"},{"formTitle":"[162]寻找峰值","frontendQuestionId":"162","leaf":true,"level":2,"nodeType":"def","questionId":"162","status":"","title":"寻找峰值","titleSlug":"find-peak-element"},{"formTitle":"[163]缺失的区间","frontendQuestionId":"163","leaf":true,"level":2,"nodeType":"def","questionId":"163","status":"lock","title":"缺失的区间","titleSlug":"missing-ranges"},{"formTitle":"[164]最大间距","frontendQuestionId":"164","leaf":true,"level":3,"nodeType":"def","questionId":"164","status":"","title":"最大间距","titleSlug":"maximum-gap"},{"formTitle":"[165]比较版本号","frontendQuestionId":"165","leaf":true,"level":2,"nodeType":"def","questionId":"165","status":"","title":"比较版本号","titleSlug":"compare-version-numbers"},{"formTitle":"[166]分数到小数","frontendQuestionId":"166","leaf":true,"level":2,"nodeType":"def","questionId":"166","status":"","title":"分数到小数","titleSlug":"fraction-to-recurring-decimal"},{"formTitle":"[167]两数之和 II - 输入有序数组","frontendQuestionId":"167","leaf":true,"level":1,"nodeType":"def","questionId":"167","status":"ac","title":"两数之和 II - 输入有序数组","titleSlug":"two-sum-ii-input-array-is-sorted"},{"formTitle":"[168]Excel表列名称","frontendQuestionId":"168","leaf":true,"level":1,"nodeType":"def","questionId":"168","status":"","title":"Excel表列名称","titleSlug":"excel-sheet-column-title"},{"formTitle":"[169]求众数","frontendQuestionId":"169","leaf":true,"level":1,"nodeType":"def","questionId":"169","status":"","title":"求众数","titleSlug":"majority-element"},{"formTitle":"[170]两数之和 III - 数据结构设计","frontendQuestionId":"170","leaf":true,"level":1,"nodeType":"def","questionId":"170","status":"lock","title":"两数之和 III - 数据结构设计","titleSlug":"two-sum-iii-data-structure-design"},{"formTitle":"[171]Excel表列序号","frontendQuestionId":"171","leaf":true,"level":1,"nodeType":"def","questionId":"171","status":"","title":"Excel表列序号","titleSlug":"excel-sheet-column-number"},{"formTitle":"[172]阶乘后的零","frontendQuestionId":"172","leaf":true,"level":1,"nodeType":"def","questionId":"172","status":"","title":"阶乘后的零","titleSlug":"factorial-trailing-zeroes"},{"formTitle":"[173]二叉搜索树迭代器","frontendQuestionId":"173","leaf":true,"level":2,"nodeType":"def","questionId":"173","status":"","title":"二叉搜索树迭代器","titleSlug":"binary-search-tree-iterator"},{"formTitle":"[174]地下城游戏","frontendQuestionId":"174","leaf":true,"level":3,"nodeType":"def","questionId":"174","status":"","title":"地下城游戏","titleSlug":"dungeon-game"},{"formTitle":"[175]组合两个表","frontendQuestionId":"175","leaf":true,"level":1,"nodeType":"def","questionId":"175","status":"","title":"组合两个表","titleSlug":"combine-two-tables"},{"formTitle":"[176]第二高的薪水","frontendQuestionId":"176","leaf":true,"level":1,"nodeType":"def","questionId":"176","status":"","title":"第二高的薪水","titleSlug":"second-highest-salary"},{"formTitle":"[177]第N高的薪水","frontendQuestionId":"177","leaf":true,"level":2,"nodeType":"def","questionId":"177","status":"","title":"第N高的薪水","titleSlug":"nth-highest-salary"},{"formTitle":"[178]分数排名","frontendQuestionId":"178","leaf":true,"level":2,"nodeType":"def","questionId":"178","status":"","title":"分数排名","titleSlug":"rank-scores"},{"formTitle":"[179]最大数","frontendQuestionId":"179","leaf":true,"level":2,"nodeType":"def","questionId":"179","status":"","title":"最大数","titleSlug":"largest-number"},{"formTitle":"[180]连续出现的数字","frontendQuestionId":"180","leaf":true,"level":2,"nodeType":"def","questionId":"180","status":"","title":"连续出现的数字","titleSlug":"consecutive-numbers"},{"formTitle":"[181]超过经理收入的员工","frontendQuestionId":"181","leaf":true,"level":1,"nodeType":"def","questionId":"181","status":"","title":"超过经理收入的员工","titleSlug":"employees-earning-more-than-their-managers"},{"formTitle":"[182]查找重复的电子邮箱","frontendQuestionId":"182","leaf":true,"level":1,"nodeType":"def","questionId":"182","status":"","title":"查找重复的电子邮箱","titleSlug":"duplicate-emails"},{"formTitle":"[183]从不订购的客户","frontendQuestionId":"183","leaf":true,"level":1,"nodeType":"def","questionId":"183","status":"","title":"从不订购的客户","titleSlug":"customers-who-never-order"},{"formTitle":"[184]部门工资最高的员工","frontendQuestionId":"184","leaf":true,"level":2,"nodeType":"def","questionId":"184","status":"","title":"部门工资最高的员工","titleSlug":"department-highest-salary"},{"formTitle":"[185]部门工资前三高的所有员工","frontendQuestionId":"185","leaf":true,"level":3,"nodeType":"def","questionId":"185","status":"","title":"部门工资前三高的所有员工","titleSlug":"department-top-three-salaries"},{"formTitle":"[186]翻转字符串里的单词 II","frontendQuestionId":"186","leaf":true,"level":2,"nodeType":"def","questionId":"186","status":"lock","title":"翻转字符串里的单词 II","titleSlug":"reverse-words-in-a-string-ii"},{"formTitle":"[187]重复的DNA序列","frontendQuestionId":"187","leaf":true,"level":2,"nodeType":"def","questionId":"187","status":"","title":"重复的DNA序列","titleSlug":"repeated-dna-sequences"},{"formTitle":"[188]买卖股票的最佳时机 IV","frontendQuestionId":"188","leaf":true,"level":3,"nodeType":"def","questionId":"188","status":"","title":"买卖股票的最佳时机 IV","titleSlug":"best-time-to-buy-and-sell-stock-iv"},{"formTitle":"[189]旋转数组","frontendQuestionId":"189","leaf":true,"level":1,"nodeType":"def","questionId":"189","status":"","title":"旋转数组","titleSlug":"rotate-array"},{"formTitle":"[190]颠倒二进制位","frontendQuestionId":"190","leaf":true,"level":1,"nodeType":"def","questionId":"190","status":"","title":"颠倒二进制位","titleSlug":"reverse-bits"},{"formTitle":"[191]位1的个数","frontendQuestionId":"191","leaf":true,"level":1,"nodeType":"def","questionId":"191","status":"","title":"位1的个数","titleSlug":"number-of-1-bits"},{"formTitle":"[192]统计词频","frontendQuestionId":"192","leaf":true,"level":2,"nodeType":"def","questionId":"192","status":"","title":"统计词频","titleSlug":"word-frequency"},{"formTitle":"[193]有效电话号码","frontendQuestionId":"193","leaf":true,"level":1,"nodeType":"def","questionId":"193","status":"","title":"有效电话号码","titleSlug":"valid-phone-numbers"},{"formTitle":"[194]转置文件","frontendQuestionId":"194","leaf":true,"level":2,"nodeType":"def","questionId":"194","status":"","title":"转置文件","titleSlug":"transpose-file"},{"formTitle":"[195]第十行","frontendQuestionId":"195","leaf":true,"level":1,"nodeType":"def","questionId":"195","status":"","title":"第十行","titleSlug":"tenth-line"},{"formTitle":"[196]删除重复的电子邮箱","frontendQuestionId":"196","leaf":true,"level":1,"nodeType":"def","questionId":"196","status":"","title":"删除重复的电子邮箱","titleSlug":"delete-duplicate-emails"},{"formTitle":"[197]上升的温度","frontendQuestionId":"197","leaf":true,"level":1,"nodeType":"def","questionId":"197","status":"","title":"上升的温度","titleSlug":"rising-temperature"},{"formTitle":"[198]打家劫舍","frontendQuestionId":"198","leaf":true,"level":1,"nodeType":"def","questionId":"198","status":"","title":"打家劫舍","titleSlug":"house-robber"},{"formTitle":"[199]二叉树的右视图","frontendQuestionId":"199","leaf":true,"level":2,"nodeType":"def","questionId":"199","status":"","title":"二叉树的右视图","titleSlug":"binary-tree-right-side-view"},{"formTitle":"[200]岛屿数量","frontendQuestionId":"200","leaf":true,"level":2,"nodeType":"def","questionId":"200","status":"","title":"岛屿数量","titleSlug":"number-of-islands"},{"formTitle":"[201]数字范围按位与","frontendQuestionId":"201","leaf":true,"level":2,"nodeType":"def","questionId":"201","status":"","title":"数字范围按位与","titleSlug":"bitwise-and-of-numbers-range"},{"formTitle":"[202]快乐数","frontendQuestionId":"202","leaf":true,"level":1,"nodeType":"def","questionId":"202","status":"ac","title":"快乐数","titleSlug":"happy-number"},{"formTitle":"[203]移除链表元素","frontendQuestionId":"203","leaf":true,"level":1,"nodeType":"def","questionId":"203","status":"","title":"移除链表元素","titleSlug":"remove-linked-list-elements"},{"formTitle":"[204]计数质数","frontendQuestionId":"204","leaf":true,"level":1,"nodeType":"def","questionId":"204","status":"","title":"计数质数","titleSlug":"count-primes"},{"formTitle":"[205]同构字符串","frontendQuestionId":"205","leaf":true,"level":1,"nodeType":"def","questionId":"205","status":"ac","title":"同构字符串","titleSlug":"isomorphic-strings"},{"formTitle":"[206]反转链表","frontendQuestionId":"206","leaf":true,"level":1,"nodeType":"def","questionId":"206","status":"","title":"反转链表","titleSlug":"reverse-linked-list"},{"formTitle":"[207]课程表","frontendQuestionId":"207","leaf":true,"level":2,"nodeType":"def","questionId":"207","status":"","title":"课程表","titleSlug":"course-schedule"},{"formTitle":"[208]实现 Trie (前缀树)","frontendQuestionId":"208","leaf":true,"level":2,"nodeType":"def","questionId":"208","status":"","title":"实现 Trie (前缀树)","titleSlug":"implement-trie-prefix-tree"},{"formTitle":"[209]长度最小的子数组","frontendQuestionId":"209","leaf":true,"level":2,"nodeType":"def","questionId":"209","status":"ac","title":"长度最小的子数组","titleSlug":"minimum-size-subarray-sum"},{"formTitle":"[210]课程表 II","frontendQuestionId":"210","leaf":true,"level":2,"nodeType":"def","questionId":"210","status":"","title":"课程表 II","titleSlug":"course-schedule-ii"},{"formTitle":"[211]添加与搜索单词 - 数据结构设计","frontendQuestionId":"211","leaf":true,"level":2,"nodeType":"def","questionId":"211","status":"","title":"添加与搜索单词 - 数据结构设计","titleSlug":"add-and-search-word-data-structure-design"},{"formTitle":"[212]单词搜索 II","frontendQuestionId":"212","leaf":true,"level":3,"nodeType":"def","questionId":"212","status":"","title":"单词搜索 II","titleSlug":"word-search-ii"},{"formTitle":"[213]打家劫舍 II","frontendQuestionId":"213","leaf":true,"level":2,"nodeType":"def","questionId":"213","status":"","title":"打家劫舍 II","titleSlug":"house-robber-ii"},{"formTitle":"[214]最短回文串","frontendQuestionId":"214","leaf":true,"level":3,"nodeType":"def","questionId":"214","status":"","title":"最短回文串","titleSlug":"shortest-palindrome"},{"formTitle":"[215]数组中的第K个最大元素","frontendQuestionId":"215","leaf":true,"level":2,"nodeType":"def","questionId":"215","status":"","title":"数组中的第K个最大元素","titleSlug":"kth-largest-element-in-an-array"},{"formTitle":"[216]组合总和 III","frontendQuestionId":"216","leaf":true,"level":2,"nodeType":"def","questionId":"216","status":"","title":"组合总和 III","titleSlug":"combination-sum-iii"},{"formTitle":"[217]存在重复元素","frontendQuestionId":"217","leaf":true,"level":1,"nodeType":"def","questionId":"217","status":"","title":"存在重复元素","titleSlug":"contains-duplicate"},{"formTitle":"[218]天际线问题","frontendQuestionId":"218","leaf":true,"level":3,"nodeType":"def","questionId":"218","status":"","title":"天际线问题","titleSlug":"the-skyline-problem"},{"formTitle":"[219]存在重复元素 II","frontendQuestionId":"219","leaf":true,"level":1,"nodeType":"def","questionId":"219","status":"","title":"存在重复元素 II","titleSlug":"contains-duplicate-ii"},{"formTitle":"[220]存在重复元素 III","frontendQuestionId":"220","leaf":true,"level":2,"nodeType":"def","questionId":"220","status":"","title":"存在重复元素 III","titleSlug":"contains-duplicate-iii"},{"formTitle":"[221]最大正方形","frontendQuestionId":"221","leaf":true,"level":2,"nodeType":"def","questionId":"221","status":"","title":"最大正方形","titleSlug":"maximal-square"},{"formTitle":"[222]完全二叉树的节点个数","frontendQuestionId":"222","leaf":true,"level":2,"nodeType":"def","questionId":"222","status":"","title":"完全二叉树的节点个数","titleSlug":"count-complete-tree-nodes"},{"formTitle":"[223]矩形面积","frontendQuestionId":"223","leaf":true,"level":2,"nodeType":"def","questionId":"223","status":"","title":"矩形面积","titleSlug":"rectangle-area"},{"formTitle":"[224]基本计算器","frontendQuestionId":"224","leaf":true,"level":3,"nodeType":"def","questionId":"224","status":"","title":"基本计算器","titleSlug":"basic-calculator"},{"formTitle":"[225]用队列实现栈","frontendQuestionId":"225","leaf":true,"level":1,"nodeType":"def","questionId":"225","status":"","title":"用队列实现栈","titleSlug":"implement-stack-using-queues"},{"formTitle":"[226]翻转二叉树","frontendQuestionId":"226","leaf":true,"level":1,"nodeType":"def","questionId":"226","status":"","title":"翻转二叉树","titleSlug":"invert-binary-tree"},{"formTitle":"[227]基本计算器 II","frontendQuestionId":"227","leaf":true,"level":2,"nodeType":"def","questionId":"227","status":"","title":"基本计算器 II","titleSlug":"basic-calculator-ii"},{"formTitle":"[228]汇总区间","frontendQuestionId":"228","leaf":true,"level":2,"nodeType":"def","questionId":"228","status":"","title":"汇总区间","titleSlug":"summary-ranges"},{"formTitle":"[229]求众数 II","frontendQuestionId":"229","leaf":true,"level":2,"nodeType":"def","questionId":"229","status":"","title":"求众数 II","titleSlug":"majority-element-ii"},{"formTitle":"[230]二叉搜索树中第K小的元素","frontendQuestionId":"230","leaf":true,"level":2,"nodeType":"def","questionId":"230","status":"","title":"二叉搜索树中第K小的元素","titleSlug":"kth-smallest-element-in-a-bst"},{"formTitle":"[231]2的幂","frontendQuestionId":"231","leaf":true,"level":1,"nodeType":"def","questionId":"231","status":"","title":"2的幂","titleSlug":"power-of-two"},{"formTitle":"[232]用栈实现队列","frontendQuestionId":"232","leaf":true,"level":1,"nodeType":"def","questionId":"232","status":"","title":"用栈实现队列","titleSlug":"implement-queue-using-stacks"},{"formTitle":"[233]数字 1 的个数","frontendQuestionId":"233","leaf":true,"level":3,"nodeType":"def","questionId":"233","status":"","title":"数字 1 的个数","titleSlug":"number-of-digit-one"},{"formTitle":"[234]回文链表","frontendQuestionId":"234","leaf":true,"level":1,"nodeType":"def","questionId":"234","status":"","title":"回文链表","titleSlug":"palindrome-linked-list"},{"formTitle":"[235]二叉搜索树的最近公共祖先","frontendQuestionId":"235","leaf":true,"level":1,"nodeType":"def","questionId":"235","status":"","title":"二叉搜索树的最近公共祖先","titleSlug":"lowest-common-ancestor-of-a-binary-search-tree"},{"formTitle":"[236]二叉树的最近公共祖先","frontendQuestionId":"236","leaf":true,"level":2,"nodeType":"def","questionId":"236","status":"","title":"二叉树的最近公共祖先","titleSlug":"lowest-common-ancestor-of-a-binary-tree"},{"formTitle":"[237]删除链表中的节点","frontendQuestionId":"237","leaf":true,"level":1,"nodeType":"def","questionId":"237","status":"","title":"删除链表中的节点","titleSlug":"delete-node-in-a-linked-list"},{"formTitle":"[238]除自身以外数组的乘积","frontendQuestionId":"238","leaf":true,"level":2,"nodeType":"def","questionId":"238","status":"","title":"除自身以外数组的乘积","titleSlug":"product-of-array-except-self"},{"formTitle":"[239]滑动窗口最大值","frontendQuestionId":"239","leaf":true,"level":3,"nodeType":"def","questionId":"239","status":"","title":"滑动窗口最大值","titleSlug":"sliding-window-maximum"},{"formTitle":"[240]搜索二维矩阵 II","frontendQuestionId":"240","leaf":true,"level":2,"nodeType":"def","questionId":"240","status":"","title":"搜索二维矩阵 II","titleSlug":"search-a-2d-matrix-ii"},{"formTitle":"[241]为运算表达式设计优先级","frontendQuestionId":"241","leaf":true,"level":2,"nodeType":"def","questionId":"241","status":"","title":"为运算表达式设计优先级","titleSlug":"different-ways-to-add-parentheses"},{"formTitle":"[242]有效的字母异位词","frontendQuestionId":"242","leaf":true,"level":1,"nodeType":"def","questionId":"242","status":"ac","title":"有效的字母异位词","titleSlug":"valid-anagram"},{"formTitle":"[243]最短单词距离","frontendQuestionId":"243","leaf":true,"level":1,"nodeType":"def","questionId":"243","status":"lock","title":"最短单词距离","titleSlug":"shortest-word-distance"},{"formTitle":"[244]最短单词距离 II","frontendQuestionId":"244","leaf":true,"level":2,"nodeType":"def","questionId":"244","status":"lock","title":"最短单词距离 II","titleSlug":"shortest-word-distance-ii"},{"formTitle":"[245]最短单词距离 III","frontendQuestionId":"245","leaf":true,"level":2,"nodeType":"def","questionId":"245","status":"lock","title":"最短单词距离 III","titleSlug":"shortest-word-distance-iii"},{"formTitle":"[246]中心对称数","frontendQuestionId":"246","leaf":true,"level":1,"nodeType":"def","questionId":"246","status":"lock","title":"中心对称数","titleSlug":"strobogrammatic-number"},{"formTitle":"[247]中心对称数 II","frontendQuestionId":"247","leaf":true,"level":2,"nodeType":"def","questionId":"247","status":"lock","title":"中心对称数 II","titleSlug":"strobogrammatic-number-ii"},{"formTitle":"[248]中心对称数 III","frontendQuestionId":"248","leaf":true,"level":3,"nodeType":"def","questionId":"248","status":"lock","title":"中心对称数 III","titleSlug":"strobogrammatic-number-iii"},{"formTitle":"[249]移位字符串分组","frontendQuestionId":"249","leaf":true,"level":2,"nodeType":"def","questionId":"249","status":"lock","title":"移位字符串分组","titleSlug":"group-shifted-strings"},{"formTitle":"[250]统计同值子树","frontendQuestionId":"250","leaf":true,"level":2,"nodeType":"def","questionId":"250","status":"lock","title":"统计同值子树","titleSlug":"count-univalue-subtrees"},{"formTitle":"[251]展开二维向量","frontendQuestionId":"251","leaf":true,"level":2,"nodeType":"def","questionId":"251","status":"lock","title":"展开二维向量","titleSlug":"flatten-2d-vector"},{"formTitle":"[252]会议室","frontendQuestionId":"252","leaf":true,"level":1,"nodeType":"def","questionId":"252","status":"lock","title":"会议室","titleSlug":"meeting-rooms"},{"formTitle":"[253]会议室 II","frontendQuestionId":"253","leaf":true,"level":2,"nodeType":"def","questionId":"253","status":"lock","title":"会议室 II","titleSlug":"meeting-rooms-ii"},{"formTitle":"[254]因子的组合","frontendQuestionId":"254","leaf":true,"level":2,"nodeType":"def","questionId":"254","status":"lock","title":"因子的组合","titleSlug":"factor-combinations"},{"formTitle":"[255]验证前序遍历序列二叉搜索树","frontendQuestionId":"255","leaf":true,"level":2,"nodeType":"def","questionId":"255","status":"lock","title":"验证前序遍历序列二叉搜索树","titleSlug":"verify-preorder-sequence-in-binary-search-tree"},{"formTitle":"[256]粉刷房子","frontendQuestionId":"256","leaf":true,"level":1,"nodeType":"def","questionId":"256","status":"lock","title":"粉刷房子","titleSlug":"paint-house"},{"formTitle":"[257]二叉树的所有路径","frontendQuestionId":"257","leaf":true,"level":1,"nodeType":"def","questionId":"257","status":"","title":"二叉树的所有路径","titleSlug":"binary-tree-paths"},{"formTitle":"[258]各位相加","frontendQuestionId":"258","leaf":true,"level":1,"nodeType":"def","questionId":"258","status":"","title":"各位相加","titleSlug":"add-digits"},{"formTitle":"[259]较小的三数之和","frontendQuestionId":"259","leaf":true,"level":2,"nodeType":"def","questionId":"259","status":"lock","title":"较小的三数之和","titleSlug":"3sum-smaller"},{"formTitle":"[260]只出现一次的数字 III","frontendQuestionId":"260","leaf":true,"level":2,"nodeType":"def","questionId":"260","status":"","title":"只出现一次的数字 III","titleSlug":"single-number-iii"},{"formTitle":"[261]以图判树","frontendQuestionId":"261","leaf":true,"level":2,"nodeType":"def","questionId":"261","status":"lock","title":"以图判树","titleSlug":"graph-valid-tree"},{"formTitle":"[262]行程和用户","frontendQuestionId":"262","leaf":true,"level":3,"nodeType":"def","questionId":"262","status":"","title":"行程和用户","titleSlug":"trips-and-users"},{"formTitle":"[263]丑数","frontendQuestionId":"263","leaf":true,"level":1,"nodeType":"def","questionId":"263","status":"","title":"丑数","titleSlug":"ugly-number"},{"formTitle":"[264]丑数 II","frontendQuestionId":"264","leaf":true,"level":2,"nodeType":"def","questionId":"264","status":"","title":"丑数 II","titleSlug":"ugly-number-ii"},{"formTitle":"[265]粉刷房子 II","frontendQuestionId":"265","leaf":true,"level":3,"nodeType":"def","questionId":"265","status":"lock","title":"粉刷房子 II","titleSlug":"paint-house-ii"},{"formTitle":"[266]回文排列","frontendQuestionId":"266","leaf":true,"level":1,"nodeType":"def","questionId":"266","status":"lock","title":"回文排列","titleSlug":"palindrome-permutation"},{"formTitle":"[267]回文排列 II","frontendQuestionId":"267","leaf":true,"level":2,"nodeType":"def","questionId":"267","status":"lock","title":"回文排列 II","titleSlug":"palindrome-permutation-ii"},{"formTitle":"[268]缺失数字","frontendQuestionId":"268","leaf":true,"level":1,"nodeType":"def","questionId":"268","status":"","title":"缺失数字","titleSlug":"missing-number"},{"formTitle":"[269]火星词典","frontendQuestionId":"269","leaf":true,"level":3,"nodeType":"def","questionId":"269","status":"lock","title":"火星词典","titleSlug":"alien-dictionary"},{"formTitle":"[270]最接近的二叉搜索树值","frontendQuestionId":"270","leaf":true,"level":1,"nodeType":"def","questionId":"270","status":"lock","title":"最接近的二叉搜索树值","titleSlug":"closest-binary-search-tree-value"},{"formTitle":"[271]字符串的编码与解码","frontendQuestionId":"271","leaf":true,"level":2,"nodeType":"def","questionId":"271","status":"lock","title":"字符串的编码与解码","titleSlug":"encode-and-decode-strings"},{"formTitle":"[272]最接近的二叉搜索树值 II","frontendQuestionId":"272","leaf":true,"level":3,"nodeType":"def","questionId":"272","status":"lock","title":"最接近的二叉搜索树值 II","titleSlug":"closest-binary-search-tree-value-ii"},{"formTitle":"[273]整数转换英文表示","frontendQuestionId":"273","leaf":true,"level":3,"nodeType":"def","questionId":"273","status":"","title":"整数转换英文表示","titleSlug":"integer-to-english-words"},{"formTitle":"[274]H指数","frontendQuestionId":"274","leaf":true,"level":2,"nodeType":"def","questionId":"274","status":"","title":"H指数","titleSlug":"h-index"},{"formTitle":"[275]H指数 II","frontendQuestionId":"275","leaf":true,"level":2,"nodeType":"def","questionId":"275","status":"","title":"H指数 II","titleSlug":"h-index-ii"},{"formTitle":"[276]栅栏涂色","frontendQuestionId":"276","leaf":true,"level":1,"nodeType":"def","questionId":"276","status":"lock","title":"栅栏涂色","titleSlug":"paint-fence"},{"formTitle":"[277]搜寻名人","frontendQuestionId":"277","leaf":true,"level":2,"nodeType":"def","questionId":"277","status":"lock","title":"搜寻名人","titleSlug":"find-the-celebrity"},{"formTitle":"[278]第一个错误的版本","frontendQuestionId":"278","leaf":true,"level":1,"nodeType":"def","questionId":"278","status":"","title":"第一个错误的版本","titleSlug":"first-bad-version"},{"formTitle":"[279]完全平方数","frontendQuestionId":"279","leaf":true,"level":2,"nodeType":"def","questionId":"279","status":"","title":"完全平方数","titleSlug":"perfect-squares"},{"formTitle":"[280]摆动排序","frontendQuestionId":"280","leaf":true,"level":2,"nodeType":"def","questionId":"280","status":"lock","title":"摆动排序","titleSlug":"wiggle-sort"},{"formTitle":"[281]锯齿迭代器","frontendQuestionId":"281","leaf":true,"level":2,"nodeType":"def","questionId":"281","status":"lock","title":"锯齿迭代器","titleSlug":"zigzag-iterator"},{"formTitle":"[282]给表达式添加运算符","frontendQuestionId":"282","leaf":true,"level":3,"nodeType":"def","questionId":"282","status":"","title":"给表达式添加运算符","titleSlug":"expression-add-operators"},{"formTitle":"[283]移动零","frontendQuestionId":"283","leaf":true,"level":1,"nodeType":"def","questionId":"283","status":"ac","title":"移动零","titleSlug":"move-zeroes"},{"formTitle":"[284]顶端迭代器","frontendQuestionId":"284","leaf":true,"level":2,"nodeType":"def","questionId":"284","status":"","title":"顶端迭代器","titleSlug":"peeking-iterator"},{"formTitle":"[285]二叉搜索树中的顺序后继","frontendQuestionId":"285","leaf":true,"level":2,"nodeType":"def","questionId":"285","status":"lock","title":"二叉搜索树中的顺序后继","titleSlug":"inorder-successor-in-bst"},{"formTitle":"[286]墙与门","frontendQuestionId":"286","leaf":true,"level":2,"nodeType":"def","questionId":"286","status":"lock","title":"墙与门","titleSlug":"walls-and-gates"},{"formTitle":"[287]寻找重复数","frontendQuestionId":"287","leaf":true,"level":2,"nodeType":"def","questionId":"287","status":"","title":"寻找重复数","titleSlug":"find-the-duplicate-number"},{"formTitle":"[288]单词的唯一缩写","frontendQuestionId":"288","leaf":true,"level":2,"nodeType":"def","questionId":"288","status":"lock","title":"单词的唯一缩写","titleSlug":"unique-word-abbreviation"},{"formTitle":"[289]生命游戏","frontendQuestionId":"289","leaf":true,"level":2,"nodeType":"def","questionId":"289","status":"","title":"生命游戏","titleSlug":"game-of-life"},{"formTitle":"[290]单词规律","frontendQuestionId":"290","leaf":true,"level":1,"nodeType":"def","questionId":"290","status":"ac","title":"单词规律","titleSlug":"word-pattern"},{"formTitle":"[291]单词规律 II","frontendQuestionId":"291","leaf":true,"level":3,"nodeType":"def","questionId":"291","status":"lock","title":"单词规律 II","titleSlug":"word-pattern-ii"},{"formTitle":"[292]Nim 游戏","frontendQuestionId":"292","leaf":true,"level":1,"nodeType":"def","questionId":"292","status":"","title":"Nim 游戏","titleSlug":"nim-game"},{"formTitle":"[293]翻转游戏","frontendQuestionId":"293","leaf":true,"level":1,"nodeType":"def","questionId":"293","status":"lock","title":"翻转游戏","titleSlug":"flip-game"},{"formTitle":"[294]翻转游戏 II","frontendQuestionId":"294","leaf":true,"level":2,"nodeType":"def","questionId":"294","status":"lock","title":"翻转游戏 II","titleSlug":"flip-game-ii"},{"formTitle":"[295]数据流的中位数","frontendQuestionId":"295","leaf":true,"level":3,"nodeType":"def","questionId":"295","status":"","title":"数据流的中位数","titleSlug":"find-median-from-data-stream"},{"formTitle":"[296]最佳的碰头地点","frontendQuestionId":"296","leaf":true,"level":3,"nodeType":"def","questionId":"296","status":"lock","title":"最佳的碰头地点","titleSlug":"best-meeting-point"},{"formTitle":"[297]二叉树的序列化与反序列化","frontendQuestionId":"297","leaf":true,"level":3,"nodeType":"def","questionId":"297","status":"","title":"二叉树的序列化与反序列化","titleSlug":"serialize-and-deserialize-binary-tree"},{"formTitle":"[298]二叉树最长连续序列","frontendQuestionId":"298","leaf":true,"level":2,"nodeType":"def","questionId":"298","status":"lock","title":"二叉树最长连续序列","titleSlug":"binary-tree-longest-consecutive-sequence"},{"formTitle":"[299]猜数字游戏","frontendQuestionId":"299","leaf":true,"level":1,"nodeType":"def","questionId":"299","status":"","title":"猜数字游戏","titleSlug":"bulls-and-cows"},{"formTitle":"[300]最长上升子序列","frontendQuestionId":"300","leaf":true,"level":2,"nodeType":"def","questionId":"300","status":"","title":"最长上升子序列","titleSlug":"longest-increasing-subsequence"},{"formTitle":"[301]删除无效的括号","frontendQuestionId":"301","leaf":true,"level":3,"nodeType":"def","questionId":"301","status":"","title":"删除无效的括号","titleSlug":"remove-invalid-parentheses"},{"formTitle":"[302]包含全部黑色像素的最小矩形","frontendQuestionId":"302","leaf":true,"level":3,"nodeType":"def","questionId":"302","status":"lock","title":"包含全部黑色像素的最小矩形","titleSlug":"smallest-rectangle-enclosing-black-pixels"},{"formTitle":"[303]区域和检索 - 数组不可变","frontendQuestionId":"303","leaf":true,"level":1,"nodeType":"def","questionId":"303","status":"","title":"区域和检索 - 数组不可变","titleSlug":"range-sum-query-immutable"},{"formTitle":"[304]二维区域和检索 - 矩阵不可变","frontendQuestionId":"304","leaf":true,"level":2,"nodeType":"def","questionId":"304","status":"","title":"二维区域和检索 - 矩阵不可变","titleSlug":"range-sum-query-2d-immutable"},{"formTitle":"[305]岛屿数量 II","frontendQuestionId":"305","leaf":true,"level":3,"nodeType":"def","questionId":"305","status":"lock","title":"岛屿数量 II","titleSlug":"number-of-islands-ii"},{"formTitle":"[306]累加数","frontendQuestionId":"306","leaf":true,"level":2,"nodeType":"def","questionId":"306","status":"","title":"累加数","titleSlug":"additive-number"},{"formTitle":"[307]区域和检索 - 数组可修改","frontendQuestionId":"307","leaf":true,"level":2,"nodeType":"def","questionId":"307","status":"","title":"区域和检索 - 数组可修改","titleSlug":"range-sum-query-mutable"},{"formTitle":"[308]二维区域和检索 - 可变","frontendQuestionId":"308","leaf":true,"level":3,"nodeType":"def","questionId":"308","status":"lock","title":"二维区域和检索 - 可变","titleSlug":"range-sum-query-2d-mutable"},{"formTitle":"[309]最佳买卖股票时机含冷冻期","frontendQuestionId":"309","leaf":true,"level":2,"nodeType":"def","questionId":"309","status":"","title":"最佳买卖股票时机含冷冻期","titleSlug":"best-time-to-buy-and-sell-stock-with-cooldown"},{"formTitle":"[310]最小高度树","frontendQuestionId":"310","leaf":true,"level":2,"nodeType":"def","questionId":"310","status":"","title":"最小高度树","titleSlug":"minimum-height-trees"},{"formTitle":"[311]稀疏矩阵的乘法","frontendQuestionId":"311","leaf":true,"level":2,"nodeType":"def","questionId":"311","status":"lock","title":"稀疏矩阵的乘法","titleSlug":"sparse-matrix-multiplication"},{"formTitle":"[312]戳气球","frontendQuestionId":"312","leaf":true,"level":3,"nodeType":"def","questionId":"312","status":"","title":"戳气球","titleSlug":"burst-balloons"},{"formTitle":"[313]超级丑数","frontendQuestionId":"313","leaf":true,"level":2,"nodeType":"def","questionId":"313","status":"","title":"超级丑数","titleSlug":"super-ugly-number"},{"formTitle":"[314]二叉树的垂直遍历","frontendQuestionId":"314","leaf":true,"level":2,"nodeType":"def","questionId":"314","status":"lock","title":"二叉树的垂直遍历","titleSlug":"binary-tree-vertical-order-traversal"},{"formTitle":"[315]计算右侧小于当前元素的个数","frontendQuestionId":"315","leaf":true,"level":3,"nodeType":"def","questionId":"315","status":"","title":"计算右侧小于当前元素的个数","titleSlug":"count-of-smaller-numbers-after-self"},{"formTitle":"[316]去除重复字母","frontendQuestionId":"316","leaf":true,"level":3,"nodeType":"def","questionId":"316","status":"","title":"去除重复字母","titleSlug":"remove-duplicate-letters"},{"formTitle":"[317]离建筑物最近的距离","frontendQuestionId":"317","leaf":true,"level":3,"nodeType":"def","questionId":"317","status":"lock","title":"离建筑物最近的距离","titleSlug":"shortest-distance-from-all-buildings"},{"formTitle":"[318]最大单词长度乘积","frontendQuestionId":"318","leaf":true,"level":2,"nodeType":"def","questionId":"318","status":"","title":"最大单词长度乘积","titleSlug":"maximum-product-of-word-lengths"},{"formTitle":"[319]灯泡开关","frontendQuestionId":"319","leaf":true,"level":2,"nodeType":"def","questionId":"319","status":"","title":"灯泡开关","titleSlug":"bulb-switcher"},{"formTitle":"[320]列举单词的全部缩写","frontendQuestionId":"320","leaf":true,"level":2,"nodeType":"def","questionId":"320","status":"lock","title":"列举单词的全部缩写","titleSlug":"generalized-abbreviation"},{"formTitle":"[321]拼接最大数","frontendQuestionId":"321","leaf":true,"level":3,"nodeType":"def","questionId":"321","status":"","title":"拼接最大数","titleSlug":"create-maximum-number"},{"formTitle":"[322]零钱兑换","frontendQuestionId":"322","leaf":true,"level":2,"nodeType":"def","questionId":"322","status":"","title":"零钱兑换","titleSlug":"coin-change"},{"formTitle":"[323]无向图中连通分量的数目","frontendQuestionId":"323","leaf":true,"level":2,"nodeType":"def","questionId":"323","status":"lock","title":"无向图中连通分量的数目","titleSlug":"number-of-connected-components-in-an-undirected-graph"},{"formTitle":"[324]摆动排序 II","frontendQuestionId":"324","leaf":true,"level":2,"nodeType":"def","questionId":"324","status":"","title":"摆动排序 II","titleSlug":"wiggle-sort-ii"},{"formTitle":"[325]和等于 k 的最长子数组长度","frontendQuestionId":"325","leaf":true,"level":2,"nodeType":"def","questionId":"325","status":"lock","title":"和等于 k 的最长子数组长度","titleSlug":"maximum-size-subarray-sum-equals-k"},{"formTitle":"[326]3的幂","frontendQuestionId":"326","leaf":true,"level":1,"nodeType":"def","questionId":"326","status":"","title":"3的幂","titleSlug":"power-of-three"},{"formTitle":"[327]区间和的个数","frontendQuestionId":"327","leaf":true,"level":3,"nodeType":"def","questionId":"327","status":"","title":"区间和的个数","titleSlug":"count-of-range-sum"},{"formTitle":"[328]奇偶链表","frontendQuestionId":"328","leaf":true,"level":2,"nodeType":"def","questionId":"328","status":"","title":"奇偶链表","titleSlug":"odd-even-linked-list"},{"formTitle":"[329]矩阵中的最长递增路径","frontendQuestionId":"329","leaf":true,"level":3,"nodeType":"def","questionId":"329","status":"","title":"矩阵中的最长递增路径","titleSlug":"longest-increasing-path-in-a-matrix"},{"formTitle":"[330]按要求补齐数组","frontendQuestionId":"330","leaf":true,"level":3,"nodeType":"def","questionId":"330","status":"","title":"按要求补齐数组","titleSlug":"patching-array"},{"formTitle":"[331]验证二叉树的前序序列化","frontendQuestionId":"331","leaf":true,"level":2,"nodeType":"def","questionId":"331","status":"","title":"验证二叉树的前序序列化","titleSlug":"verify-preorder-serialization-of-a-binary-tree"},{"formTitle":"[332]重新安排行程","frontendQuestionId":"332","leaf":true,"level":2,"nodeType":"def","questionId":"332","status":"","title":"重新安排行程","titleSlug":"reconstruct-itinerary"},{"formTitle":"[333]最大 BST 子树","frontendQuestionId":"333","leaf":true,"level":2,"nodeType":"def","questionId":"333","status":"lock","title":"最大 BST 子树","titleSlug":"largest-bst-subtree"},{"formTitle":"[334]递增的三元子序列","frontendQuestionId":"334","leaf":true,"level":2,"nodeType":"def","questionId":"334","status":"","title":"递增的三元子序列","titleSlug":"increasing-triplet-subsequence"},{"formTitle":"[335]路径交叉","frontendQuestionId":"335","leaf":true,"level":3,"nodeType":"def","questionId":"335","status":"","title":"路径交叉","titleSlug":"self-crossing"},{"formTitle":"[336]回文对","frontendQuestionId":"336","leaf":true,"level":3,"nodeType":"def","questionId":"336","status":"","title":"回文对","titleSlug":"palindrome-pairs"},{"formTitle":"[337]打家劫舍 III","frontendQuestionId":"337","leaf":true,"level":2,"nodeType":"def","questionId":"337","status":"","title":"打家劫舍 III","titleSlug":"house-robber-iii"},{"formTitle":"[338]比特位计数","frontendQuestionId":"338","leaf":true,"level":2,"nodeType":"def","questionId":"338","status":"","title":"比特位计数","titleSlug":"counting-bits"},{"formTitle":"[339]嵌套列表权重和","frontendQuestionId":"339","leaf":true,"level":1,"nodeType":"def","questionId":"339","status":"lock","title":"嵌套列表权重和","titleSlug":"nested-list-weight-sum"},{"formTitle":"[340]至多包含 K 个不同字符的最长子串","frontendQuestionId":"340","leaf":true,"level":3,"nodeType":"def","questionId":"340","status":"lock","title":"至多包含 K 个不同字符的最长子串","titleSlug":"longest-substring-with-at-most-k-distinct-characters"},{"formTitle":"[341]扁平化嵌套列表迭代器","frontendQuestionId":"341","leaf":true,"level":2,"nodeType":"def","questionId":"341","status":"","title":"扁平化嵌套列表迭代器","titleSlug":"flatten-nested-list-iterator"},{"formTitle":"[342]4的幂","frontendQuestionId":"342","leaf":true,"level":1,"nodeType":"def","questionId":"342","status":"","title":"4的幂","titleSlug":"power-of-four"},{"formTitle":"[343]整数拆分","frontendQuestionId":"343","leaf":true,"level":2,"nodeType":"def","questionId":"343","status":"","title":"整数拆分","titleSlug":"integer-break"},{"formTitle":"[344]反转字符串","frontendQuestionId":"344","leaf":true,"level":1,"nodeType":"def","questionId":"344","status":"ac","title":"反转字符串","titleSlug":"reverse-string"},{"formTitle":"[345]反转字符串中的元音字母","frontendQuestionId":"345","leaf":true,"level":1,"nodeType":"def","questionId":"345","status":"ac","title":"反转字符串中的元音字母","titleSlug":"reverse-vowels-of-a-string"},{"formTitle":"[346]数据流中的移动平均值","frontendQuestionId":"346","leaf":true,"level":1,"nodeType":"def","questionId":"346","status":"lock","title":"数据流中的移动平均值","titleSlug":"moving-average-from-data-stream"},{"formTitle":"[347]前 K 个高频元素","frontendQuestionId":"347","leaf":true,"level":2,"nodeType":"def","questionId":"347","status":"","title":"前 K 个高频元素","titleSlug":"top-k-frequent-elements"},{"formTitle":"[348]判定井字棋胜负","frontendQuestionId":"348","leaf":true,"level":2,"nodeType":"def","questionId":"348","status":"lock","title":"判定井字棋胜负","titleSlug":"design-tic-tac-toe"},{"formTitle":"[349]两个数组的交集","frontendQuestionId":"349","leaf":true,"level":1,"nodeType":"def","questionId":"349","status":"ac","title":"两个数组的交集","titleSlug":"intersection-of-two-arrays"},{"formTitle":"[350]两个数组的交集 II","frontendQuestionId":"350","leaf":true,"level":1,"nodeType":"def","questionId":"350","status":"ac","title":"两个数组的交集 II","titleSlug":"intersection-of-two-arrays-ii"},{"formTitle":"[351]安卓系统手势解锁","frontendQuestionId":"351","leaf":true,"level":2,"nodeType":"def","questionId":"351","status":"lock","title":"安卓系统手势解锁","titleSlug":"android-unlock-patterns"},{"formTitle":"[352]将数据流变为多个不相交区间","frontendQuestionId":"352","leaf":true,"level":3,"nodeType":"def","questionId":"352","status":"","title":"将数据流变为多个不相交区间","titleSlug":"data-stream-as-disjoint-intervals"},{"formTitle":"[353]贪吃蛇","frontendQuestionId":"353","leaf":true,"level":2,"nodeType":"def","questionId":"353","status":"lock","title":"贪吃蛇","titleSlug":"design-snake-game"},{"formTitle":"[354]俄罗斯套娃信封问题","frontendQuestionId":"354","leaf":true,"level":3,"nodeType":"def","questionId":"354","status":"","title":"俄罗斯套娃信封问题","titleSlug":"russian-doll-envelopes"},{"formTitle":"[355]设计推特","frontendQuestionId":"355","leaf":true,"level":2,"nodeType":"def","questionId":"355","status":"","title":"设计推特","titleSlug":"design-twitter"},{"formTitle":"[356]直线镜像","frontendQuestionId":"356","leaf":true,"level":2,"nodeType":"def","questionId":"356","status":"lock","title":"直线镜像","titleSlug":"line-reflection"},{"formTitle":"[357]计算各个位数不同的数字个数","frontendQuestionId":"357","leaf":true,"level":2,"nodeType":"def","questionId":"357","status":"","title":"计算各个位数不同的数字个数","titleSlug":"count-numbers-with-unique-digits"},{"formTitle":"[358]K 距离间隔重排字符串","frontendQuestionId":"358","leaf":true,"level":3,"nodeType":"def","questionId":"358","status":"lock","title":"K 距离间隔重排字符串","titleSlug":"rearrange-string-k-distance-apart"},{"formTitle":"[359]日志速率限制器","frontendQuestionId":"359","leaf":true,"level":1,"nodeType":"def","questionId":"359","status":"lock","title":"日志速率限制器","titleSlug":"logger-rate-limiter"},{"formTitle":"[360]有序转化数组","frontendQuestionId":"360","leaf":true,"level":2,"nodeType":"def","questionId":"360","status":"lock","title":"有序转化数组","titleSlug":"sort-transformed-array"},{"formTitle":"[361]轰炸敌人","frontendQuestionId":"361","leaf":true,"level":2,"nodeType":"def","questionId":"361","status":"lock","title":"轰炸敌人","titleSlug":"bomb-enemy"},{"formTitle":"[362]敲击计数器","frontendQuestionId":"362","leaf":true,"level":2,"nodeType":"def","questionId":"362","status":"lock","title":"敲击计数器","titleSlug":"design-hit-counter"},{"formTitle":"[363]矩形区域不超过 K 的最大数值和","frontendQuestionId":"363","leaf":true,"level":3,"nodeType":"def","questionId":"363","status":"","title":"矩形区域不超过 K 的最大数值和","titleSlug":"max-sum-of-rectangle-no-larger-than-k"},{"formTitle":"[364]加权嵌套序列和 II","frontendQuestionId":"364","leaf":true,"level":2,"nodeType":"def","questionId":"364","status":"lock","title":"加权嵌套序列和 II","titleSlug":"nested-list-weight-sum-ii"},{"formTitle":"[365]水壶问题","frontendQuestionId":"365","leaf":true,"level":2,"nodeType":"def","questionId":"365","status":"","title":"水壶问题","titleSlug":"water-and-jug-problem"},{"formTitle":"[366]寻找完全二叉树的叶子节点","frontendQuestionId":"366","leaf":true,"level":2,"nodeType":"def","questionId":"366","status":"lock","title":"寻找完全二叉树的叶子节点","titleSlug":"find-leaves-of-binary-tree"},{"formTitle":"[367]有效的完全平方数","frontendQuestionId":"367","leaf":true,"level":1,"nodeType":"def","questionId":"367","status":"","title":"有效的完全平方数","titleSlug":"valid-perfect-square"},{"formTitle":"[368]最大整除子集","frontendQuestionId":"368","leaf":true,"level":2,"nodeType":"def","questionId":"368","status":"","title":"最大整除子集","titleSlug":"largest-divisible-subset"},{"formTitle":"[369]给单链表加一","frontendQuestionId":"369","leaf":true,"level":2,"nodeType":"def","questionId":"369","status":"lock","title":"给单链表加一","titleSlug":"plus-one-linked-list"},{"formTitle":"[370]区间加法","frontendQuestionId":"370","leaf":true,"level":2,"nodeType":"def","questionId":"370","status":"lock","title":"区间加法","titleSlug":"range-addition"},{"formTitle":"[371]两整数之和","frontendQuestionId":"371","leaf":true,"level":1,"nodeType":"def","questionId":"371","status":"","title":"两整数之和","titleSlug":"sum-of-two-integers"},{"formTitle":"[372]超级次方","frontendQuestionId":"372","leaf":true,"level":2,"nodeType":"def","questionId":"372","status":"","title":"超级次方","titleSlug":"super-pow"},{"formTitle":"[373]查找和最小的K对数字","frontendQuestionId":"373","leaf":true,"level":2,"nodeType":"def","questionId":"373","status":"","title":"查找和最小的K对数字","titleSlug":"find-k-pairs-with-smallest-sums"},{"formTitle":"[374]猜数字大小","frontendQuestionId":"374","leaf":true,"level":1,"nodeType":"def","questionId":"374","status":"","title":"猜数字大小","titleSlug":"guess-number-higher-or-lower"},{"formTitle":"[375]猜数字大小 II","frontendQuestionId":"375","leaf":true,"level":2,"nodeType":"def","questionId":"375","status":"","title":"猜数字大小 II","titleSlug":"guess-number-higher-or-lower-ii"},{"formTitle":"[376]摆动序列","frontendQuestionId":"376","leaf":true,"level":2,"nodeType":"def","questionId":"376","status":"","title":"摆动序列","titleSlug":"wiggle-subsequence"},{"formTitle":"[377]组合总和 Ⅳ","frontendQuestionId":"377","leaf":true,"level":2,"nodeType":"def","questionId":"377","status":"","title":"组合总和 Ⅳ","titleSlug":"combination-sum-iv"},{"formTitle":"[378]有序矩阵中第K小的元素","frontendQuestionId":"378","leaf":true,"level":2,"nodeType":"def","questionId":"378","status":"","title":"有序矩阵中第K小的元素","titleSlug":"kth-smallest-element-in-a-sorted-matrix"},{"formTitle":"[379]电话目录管理系统","frontendQuestionId":"379","leaf":true,"level":2,"nodeType":"def","questionId":"379","status":"lock","title":"电话目录管理系统","titleSlug":"design-phone-directory"},{"formTitle":"[380]常数时间插入、删除和获取随机元素","frontendQuestionId":"380","leaf":true,"level":2,"nodeType":"def","questionId":"380","status":"","title":"常数时间插入、删除和获取随机元素","titleSlug":"insert-delete-getrandom-o1"},{"formTitle":"[381]O(1) 时间插入、删除和获取随机元素 - 允许重复","frontendQuestionId":"381","leaf":true,"level":3,"nodeType":"def","questionId":"381","status":"","title":"O(1) 时间插入、删除和获取随机元素 - 允许重复","titleSlug":"insert-delete-getrandom-o1-duplicates-allowed"},{"formTitle":"[382]链表随机节点","frontendQuestionId":"382","leaf":true,"level":2,"nodeType":"def","questionId":"382","status":"","title":"链表随机节点","titleSlug":"linked-list-random-node"},{"formTitle":"[383]赎金信","frontendQuestionId":"383","leaf":true,"level":1,"nodeType":"def","questionId":"383","status":"","title":"赎金信","titleSlug":"ransom-note"},{"formTitle":"[384]打乱数组","frontendQuestionId":"384","leaf":true,"level":2,"nodeType":"def","questionId":"384","status":"","title":"打乱数组","titleSlug":"shuffle-an-array"},{"formTitle":"[385]迷你语法分析器","frontendQuestionId":"385","leaf":true,"level":2,"nodeType":"def","questionId":"385","status":"","title":"迷你语法分析器","titleSlug":"mini-parser"},{"formTitle":"[386]字典序排数","frontendQuestionId":"386","leaf":true,"level":2,"nodeType":"def","questionId":"386","status":"","title":"字典序排数","titleSlug":"lexicographical-numbers"},{"formTitle":"[387]字符串中的第一个唯一字符","frontendQuestionId":"387","leaf":true,"level":1,"nodeType":"def","questionId":"387","status":"","title":"字符串中的第一个唯一字符","titleSlug":"first-unique-character-in-a-string"},{"formTitle":"[388]文件的最长绝对路径","frontendQuestionId":"388","leaf":true,"level":2,"nodeType":"def","questionId":"388","status":"","title":"文件的最长绝对路径","titleSlug":"longest-absolute-file-path"},{"formTitle":"[389]找不同","frontendQuestionId":"389","leaf":true,"level":1,"nodeType":"def","questionId":"389","status":"","title":"找不同","titleSlug":"find-the-difference"},{"formTitle":"[390]消除游戏","frontendQuestionId":"390","leaf":true,"level":2,"nodeType":"def","questionId":"390","status":"","title":"消除游戏","titleSlug":"elimination-game"},{"formTitle":"[391]完美矩形","frontendQuestionId":"391","leaf":true,"level":3,"nodeType":"def","questionId":"391","status":"","title":"完美矩形","titleSlug":"perfect-rectangle"},{"formTitle":"[392]判断子序列","frontendQuestionId":"392","leaf":true,"level":1,"nodeType":"def","questionId":"392","status":"","title":"判断子序列","titleSlug":"is-subsequence"},{"formTitle":"[393]UTF-8 编码验证","frontendQuestionId":"393","leaf":true,"level":2,"nodeType":"def","questionId":"393","status":"","title":"UTF-8 编码验证","titleSlug":"utf-8-validation"},{"formTitle":"[394]字符串解码","frontendQuestionId":"394","leaf":true,"level":2,"nodeType":"def","questionId":"394","status":"","title":"字符串解码","titleSlug":"decode-string"},{"formTitle":"[395]至少有K个重复字符的最长子串","frontendQuestionId":"395","leaf":true,"level":2,"nodeType":"def","questionId":"395","status":"","title":"至少有K个重复字符的最长子串","titleSlug":"longest-substring-with-at-least-k-repeating-characters"},{"formTitle":"[396]旋转函数","frontendQuestionId":"396","leaf":true,"level":2,"nodeType":"def","questionId":"396","status":"","title":"旋转函数","titleSlug":"rotate-function"},{"formTitle":"[397]整数替换","frontendQuestionId":"397","leaf":true,"level":2,"nodeType":"def","questionId":"397","status":"","title":"整数替换","titleSlug":"integer-replacement"},{"formTitle":"[398]随机数索引","frontendQuestionId":"398","leaf":true,"level":2,"nodeType":"def","questionId":"398","status":"","title":"随机数索引","titleSlug":"random-pick-index"},{"formTitle":"[399]除法求值","frontendQuestionId":"399","leaf":true,"level":2,"nodeType":"def","questionId":"399","status":"","title":"除法求值","titleSlug":"evaluate-division"},{"formTitle":"[400]第N个数字","frontendQuestionId":"400","leaf":true,"level":2,"nodeType":"def","questionId":"400","status":"","title":"第N个数字","titleSlug":"nth-digit"},{"formTitle":"[401]二进制手表","frontendQuestionId":"401","leaf":true,"level":1,"nodeType":"def","questionId":"401","status":"","title":"二进制手表","titleSlug":"binary-watch"},{"formTitle":"[402]移掉K位数字","frontendQuestionId":"402","leaf":true,"level":2,"nodeType":"def","questionId":"402","status":"","title":"移掉K位数字","titleSlug":"remove-k-digits"},{"formTitle":"[403]青蛙过河","frontendQuestionId":"403","leaf":true,"level":3,"nodeType":"def","questionId":"403","status":"","title":"青蛙过河","titleSlug":"frog-jump"},{"formTitle":"[404]左叶子之和","frontendQuestionId":"404","leaf":true,"level":1,"nodeType":"def","questionId":"404","status":"","title":"左叶子之和","titleSlug":"sum-of-left-leaves"},{"formTitle":"[405]数字转换为十六进制数","frontendQuestionId":"405","leaf":true,"level":1,"nodeType":"def","questionId":"405","status":"","title":"数字转换为十六进制数","titleSlug":"convert-a-number-to-hexadecimal"},{"formTitle":"[406]根据身高重建队列","frontendQuestionId":"406","leaf":true,"level":2,"nodeType":"def","questionId":"406","status":"","title":"根据身高重建队列","titleSlug":"queue-reconstruction-by-height"},{"formTitle":"[407]接雨水 II","frontendQuestionId":"407","leaf":true,"level":3,"nodeType":"def","questionId":"407","status":"","title":"接雨水 II","titleSlug":"trapping-rain-water-ii"},{"formTitle":"[408]有效单词缩写","frontendQuestionId":"408","leaf":true,"level":1,"nodeType":"def","questionId":"408","status":"lock","title":"有效单词缩写","titleSlug":"valid-word-abbreviation"},{"formTitle":"[409]最长回文串","frontendQuestionId":"409","leaf":true,"level":1,"nodeType":"def","questionId":"409","status":"","title":"最长回文串","titleSlug":"longest-palindrome"},{"formTitle":"[410]分割数组的最大值","frontendQuestionId":"410","leaf":true,"level":3,"nodeType":"def","questionId":"410","status":"","title":"分割数组的最大值","titleSlug":"split-array-largest-sum"},{"formTitle":"[411]最短特异单词缩写","frontendQuestionId":"411","leaf":true,"level":3,"nodeType":"def","questionId":"411","status":"lock","title":"最短特异单词缩写","titleSlug":"minimum-unique-word-abbreviation"},{"formTitle":"[412]Fizz Buzz","frontendQuestionId":"412","leaf":true,"level":1,"nodeType":"def","questionId":"412","status":"","title":"Fizz Buzz","titleSlug":"fizz-buzz"},{"formTitle":"[413]等差数列划分","frontendQuestionId":"413","leaf":true,"level":2,"nodeType":"def","questionId":"413","status":"","title":"等差数列划分","titleSlug":"arithmetic-slices"},{"formTitle":"[414]第三大的数","frontendQuestionId":"414","leaf":true,"level":1,"nodeType":"def","questionId":"414","status":"","title":"第三大的数","titleSlug":"third-maximum-number"},{"formTitle":"[415]字符串相加","frontendQuestionId":"415","leaf":true,"level":1,"nodeType":"def","questionId":"415","status":"","title":"字符串相加","titleSlug":"add-strings"},{"formTitle":"[416]分割等和子集","frontendQuestionId":"416","leaf":true,"level":2,"nodeType":"def","questionId":"416","status":"","title":"分割等和子集","titleSlug":"partition-equal-subset-sum"},{"formTitle":"[417]太平洋大西洋水流问题","frontendQuestionId":"417","leaf":true,"level":2,"nodeType":"def","questionId":"417","status":"","title":"太平洋大西洋水流问题","titleSlug":"pacific-atlantic-water-flow"},{"formTitle":"[418]屏幕可显示句子的数量","frontendQuestionId":"418","leaf":true,"level":2,"nodeType":"def","questionId":"418","status":"lock","title":"屏幕可显示句子的数量","titleSlug":"sentence-screen-fitting"},{"formTitle":"[419]甲板上的战舰","frontendQuestionId":"419","leaf":true,"level":2,"nodeType":"def","questionId":"419","status":"","title":"甲板上的战舰","titleSlug":"battleships-in-a-board"},{"formTitle":"[420]强密码检验器","frontendQuestionId":"420","leaf":true,"level":3,"nodeType":"def","questionId":"420","status":"","title":"强密码检验器","titleSlug":"strong-password-checker"},{"formTitle":"[421]数组中两个数的最大异或值","frontendQuestionId":"421","leaf":true,"level":2,"nodeType":"def","questionId":"421","status":"","title":"数组中两个数的最大异或值","titleSlug":"maximum-xor-of-two-numbers-in-an-array"},{"formTitle":"[422]有效的单词方块","frontendQuestionId":"422","leaf":true,"level":1,"nodeType":"def","questionId":"422","status":"lock","title":"有效的单词方块","titleSlug":"valid-word-square"},{"formTitle":"[423]从英文中重建数字","frontendQuestionId":"423","leaf":true,"level":2,"nodeType":"def","questionId":"423","status":"","title":"从英文中重建数字","titleSlug":"reconstruct-original-digits-from-english"},{"formTitle":"[424]替换后的最长重复字符","frontendQuestionId":"424","leaf":true,"level":2,"nodeType":"def","questionId":"424","status":"","title":"替换后的最长重复字符","titleSlug":"longest-repeating-character-replacement"},{"formTitle":"[425]单词方块","frontendQuestionId":"425","leaf":true,"level":3,"nodeType":"def","questionId":"425","status":"lock","title":"单词方块","titleSlug":"word-squares"},{"formTitle":"[426]将二叉搜索树转化为排序的双向链表","frontendQuestionId":"426","leaf":true,"level":2,"nodeType":"def","questionId":"758","status":"lock","title":"将二叉搜索树转化为排序的双向链表","titleSlug":"convert-binary-search-tree-to-sorted-doubly-linked-list"},{"formTitle":"[427]建立四叉树","frontendQuestionId":"427","leaf":true,"level":2,"nodeType":"def","questionId":"772","status":"","title":"建立四叉树","titleSlug":"construct-quad-tree"},{"formTitle":"[428]序列化和反序列化 N 叉树","frontendQuestionId":"428","leaf":true,"level":3,"nodeType":"def","questionId":"765","status":"lock","title":"序列化和反序列化 N 叉树","titleSlug":"serialize-and-deserialize-n-ary-tree"},{"formTitle":"[429]N叉树的层序遍历","frontendQuestionId":"429","leaf":true,"level":1,"nodeType":"def","questionId":"764","status":"","title":"N叉树的层序遍历","titleSlug":"n-ary-tree-level-order-traversal"},{"formTitle":"[430]扁平化多级双向链表","frontendQuestionId":"430","leaf":true,"level":2,"nodeType":"def","questionId":"766","status":"","title":"扁平化多级双向链表","titleSlug":"flatten-a-multilevel-doubly-linked-list"},{"formTitle":"[431]将 N 叉树编码为二叉树","frontendQuestionId":"431","leaf":true,"level":3,"nodeType":"def","questionId":"771","status":"lock","title":"将 N 叉树编码为二叉树","titleSlug":"encode-n-ary-tree-to-binary-tree"},{"formTitle":"[432]全 O(1) 的数据结构","frontendQuestionId":"432","leaf":true,"level":3,"nodeType":"def","questionId":"432","status":"","title":"全 O(1) 的数据结构","titleSlug":"all-oone-data-structure"},{"formTitle":"[433]最小基因变化","frontendQuestionId":"433","leaf":true,"level":2,"nodeType":"def","questionId":"433","status":"","title":"最小基因变化","titleSlug":"minimum-genetic-mutation"},{"formTitle":"[434]字符串中的单词数","frontendQuestionId":"434","leaf":true,"level":1,"nodeType":"def","questionId":"434","status":"","title":"字符串中的单词数","titleSlug":"number-of-segments-in-a-string"},{"formTitle":"[435]无重叠区间","frontendQuestionId":"435","leaf":true,"level":2,"nodeType":"def","questionId":"435","status":"","title":"无重叠区间","titleSlug":"non-overlapping-intervals"},{"formTitle":"[436]寻找右区间","frontendQuestionId":"436","leaf":true,"level":2,"nodeType":"def","questionId":"436","status":"","title":"寻找右区间","titleSlug":"find-right-interval"},{"formTitle":"[437]路径总和 III","frontendQuestionId":"437","leaf":true,"level":1,"nodeType":"def","questionId":"437","status":"","title":"路径总和 III","titleSlug":"path-sum-iii"},{"formTitle":"[438]找到字符串中所有字母异位词","frontendQuestionId":"438","leaf":true,"level":2,"nodeType":"def","questionId":"438","status":"ac","title":"找到字符串中所有字母异位词","titleSlug":"find-all-anagrams-in-a-string"},{"formTitle":"[439]三元表达式解析器","frontendQuestionId":"439","leaf":true,"level":2,"nodeType":"def","questionId":"439","status":"lock","title":"三元表达式解析器","titleSlug":"ternary-expression-parser"},{"formTitle":"[440]字典序的第K小数字","frontendQuestionId":"440","leaf":true,"level":3,"nodeType":"def","questionId":"440","status":"","title":"字典序的第K小数字","titleSlug":"k-th-smallest-in-lexicographical-order"},{"formTitle":"[441]排列硬币","frontendQuestionId":"441","leaf":true,"level":1,"nodeType":"def","questionId":"441","status":"","title":"排列硬币","titleSlug":"arranging-coins"},{"formTitle":"[442]数组中重复的数据","frontendQuestionId":"442","leaf":true,"level":2,"nodeType":"def","questionId":"442","status":"","title":"数组中重复的数据","titleSlug":"find-all-duplicates-in-an-array"},{"formTitle":"[443]压缩字符串","frontendQuestionId":"443","leaf":true,"level":1,"nodeType":"def","questionId":"443","status":"","title":"压缩字符串","titleSlug":"string-compression"},{"formTitle":"[444]序列重建","frontendQuestionId":"444","leaf":true,"level":2,"nodeType":"def","questionId":"444","status":"lock","title":"序列重建","titleSlug":"sequence-reconstruction"},{"formTitle":"[445]两数相加 II","frontendQuestionId":"445","leaf":true,"level":2,"nodeType":"def","questionId":"445","status":"","title":"两数相加 II","titleSlug":"add-two-numbers-ii"},{"formTitle":"[446]等差数列划分 II - 子序列","frontendQuestionId":"446","leaf":true,"level":3,"nodeType":"def","questionId":"446","status":"","title":"等差数列划分 II - 子序列","titleSlug":"arithmetic-slices-ii-subsequence"},{"formTitle":"[447]回旋镖的数量","frontendQuestionId":"447","leaf":true,"level":1,"nodeType":"def","questionId":"447","status":"","title":"回旋镖的数量","titleSlug":"number-of-boomerangs"},{"formTitle":"[448]找到所有数组中消失的数字","frontendQuestionId":"448","leaf":true,"level":1,"nodeType":"def","questionId":"448","status":"","title":"找到所有数组中消失的数字","titleSlug":"find-all-numbers-disappeared-in-an-array"},{"formTitle":"[449]序列化和反序列化二叉搜索树","frontendQuestionId":"449","leaf":true,"level":2,"nodeType":"def","questionId":"449","status":"","title":"序列化和反序列化二叉搜索树","titleSlug":"serialize-and-deserialize-bst"},{"formTitle":"[450]删除二叉搜索树中的节点","frontendQuestionId":"450","leaf":true,"level":2,"nodeType":"def","questionId":"450","status":"","title":"删除二叉搜索树中的节点","titleSlug":"delete-node-in-a-bst"},{"formTitle":"[451]根据字符出现频率排序","frontendQuestionId":"451","leaf":true,"level":2,"nodeType":"def","questionId":"451","status":"ac","title":"根据字符出现频率排序","titleSlug":"sort-characters-by-frequency"},{"formTitle":"[452]用最少数量的箭引爆气球","frontendQuestionId":"452","leaf":true,"level":2,"nodeType":"def","questionId":"452","status":"","title":"用最少数量的箭引爆气球","titleSlug":"minimum-number-of-arrows-to-burst-balloons"},{"formTitle":"[453]最小移动次数使数组元素相等","frontendQuestionId":"453","leaf":true,"level":1,"nodeType":"def","questionId":"453","status":"","title":"最小移动次数使数组元素相等","titleSlug":"minimum-moves-to-equal-array-elements"},{"formTitle":"[454]四数相加 II","frontendQuestionId":"454","leaf":true,"level":2,"nodeType":"def","questionId":"454","status":"","title":"四数相加 II","titleSlug":"4sum-ii"},{"formTitle":"[455]分发饼干","frontendQuestionId":"455","leaf":true,"level":1,"nodeType":"def","questionId":"455","status":"","title":"分发饼干","titleSlug":"assign-cookies"},{"formTitle":"[456]132模式","frontendQuestionId":"456","leaf":true,"level":2,"nodeType":"def","questionId":"456","status":"","title":"132模式","titleSlug":"132-pattern"},{"formTitle":"[457]环形数组循环","frontendQuestionId":"457","leaf":true,"level":2,"nodeType":"def","questionId":"457","status":"","title":"环形数组循环","titleSlug":"circular-array-loop"},{"formTitle":"[458]可怜的小猪","frontendQuestionId":"458","leaf":true,"level":3,"nodeType":"def","questionId":"458","status":"","title":"可怜的小猪","titleSlug":"poor-pigs"},{"formTitle":"[459]重复的子字符串","frontendQuestionId":"459","leaf":true,"level":1,"nodeType":"def","questionId":"459","status":"","title":"重复的子字符串","titleSlug":"repeated-substring-pattern"},{"formTitle":"[460]LFU缓存","frontendQuestionId":"460","leaf":true,"level":3,"nodeType":"def","questionId":"460","status":"","title":"LFU缓存","titleSlug":"lfu-cache"},{"formTitle":"[461]汉明距离","frontendQuestionId":"461","leaf":true,"level":1,"nodeType":"def","questionId":"461","status":"","title":"汉明距离","titleSlug":"hamming-distance"},{"formTitle":"[462]最少移动次数使数组元素相等 II","frontendQuestionId":"462","leaf":true,"level":2,"nodeType":"def","questionId":"462","status":"","title":"最少移动次数使数组元素相等 II","titleSlug":"minimum-moves-to-equal-array-elements-ii"},{"formTitle":"[463]岛屿的周长","frontendQuestionId":"463","leaf":true,"level":1,"nodeType":"def","questionId":"463","status":"","title":"岛屿的周长","titleSlug":"island-perimeter"},{"formTitle":"[464]我能赢吗","frontendQuestionId":"464","leaf":true,"level":2,"nodeType":"def","questionId":"464","status":"","title":"我能赢吗","titleSlug":"can-i-win"},{"formTitle":"[465]最优账单平衡","frontendQuestionId":"465","leaf":true,"level":3,"nodeType":"def","questionId":"465","status":"lock","title":"最优账单平衡","titleSlug":"optimal-account-balancing"},{"formTitle":"[466]统计重复个数","frontendQuestionId":"466","leaf":true,"level":3,"nodeType":"def","questionId":"466","status":"","title":"统计重复个数","titleSlug":"count-the-repetitions"},{"formTitle":"[467]环绕字符串中唯一的子字符串","frontendQuestionId":"467","leaf":true,"level":2,"nodeType":"def","questionId":"467","status":"","title":"环绕字符串中唯一的子字符串","titleSlug":"unique-substrings-in-wraparound-string"},{"formTitle":"[468]验证IP地址","frontendQuestionId":"468","leaf":true,"level":2,"nodeType":"def","questionId":"468","status":"","title":"验证IP地址","titleSlug":"validate-ip-address"},{"formTitle":"[469]凸多边形","frontendQuestionId":"469","leaf":true,"level":2,"nodeType":"def","questionId":"469","status":"lock","title":"凸多边形","titleSlug":"convex-polygon"},{"formTitle":"[470]用 Rand7() 实现 Rand10()","frontendQuestionId":"470","leaf":true,"level":2,"nodeType":"def","questionId":"903","status":"","title":"用 Rand7() 实现 Rand10()","titleSlug":"implement-rand10-using-rand7"},{"formTitle":"[471]编码最短长度的字符串","frontendQuestionId":"471","leaf":true,"level":3,"nodeType":"def","questionId":"471","status":"lock","title":"编码最短长度的字符串","titleSlug":"encode-string-with-shortest-length"},{"formTitle":"[472]连接词","frontendQuestionId":"472","leaf":true,"level":3,"nodeType":"def","questionId":"472","status":"","title":"连接词","titleSlug":"concatenated-words"},{"formTitle":"[473]火柴拼正方形","frontendQuestionId":"473","leaf":true,"level":2,"nodeType":"def","questionId":"473","status":"","title":"火柴拼正方形","titleSlug":"matchsticks-to-square"},{"formTitle":"[474]一和零","frontendQuestionId":"474","leaf":true,"level":2,"nodeType":"def","questionId":"474","status":"","title":"一和零","titleSlug":"ones-and-zeroes"},{"formTitle":"[475]供暖器","frontendQuestionId":"475","leaf":true,"level":1,"nodeType":"def","questionId":"475","status":"","title":"供暖器","titleSlug":"heaters"},{"formTitle":"[476]数字的补数","frontendQuestionId":"476","leaf":true,"level":1,"nodeType":"def","questionId":"476","status":"","title":"数字的补数","titleSlug":"number-complement"},{"formTitle":"[477]汉明距离总和","frontendQuestionId":"477","leaf":true,"level":2,"nodeType":"def","questionId":"477","status":"","title":"汉明距离总和","titleSlug":"total-hamming-distance"},{"formTitle":"[478]在圆内随机生成点","frontendQuestionId":"478","leaf":true,"level":2,"nodeType":"def","questionId":"915","status":"","title":"在圆内随机生成点","titleSlug":"generate-random-point-in-a-circle"},{"formTitle":"[479]最大回文数乘积","frontendQuestionId":"479","leaf":true,"level":3,"nodeType":"def","questionId":"479","status":"","title":"最大回文数乘积","titleSlug":"largest-palindrome-product"},{"formTitle":"[480]滑动窗口中位数","frontendQuestionId":"480","leaf":true,"level":3,"nodeType":"def","questionId":"480","status":"","title":"滑动窗口中位数","titleSlug":"sliding-window-median"},{"formTitle":"[481]神奇字符串","frontendQuestionId":"481","leaf":true,"level":2,"nodeType":"def","questionId":"481","status":"","title":"神奇字符串","titleSlug":"magical-string"},{"formTitle":"[482]密钥格式化","frontendQuestionId":"482","leaf":true,"level":1,"nodeType":"def","questionId":"482","status":"","title":"密钥格式化","titleSlug":"license-key-formatting"},{"formTitle":"[483]最小好进制","frontendQuestionId":"483","leaf":true,"level":3,"nodeType":"def","questionId":"483","status":"","title":"最小好进制","titleSlug":"smallest-good-base"},{"formTitle":"[484]寻找排列","frontendQuestionId":"484","leaf":true,"level":2,"nodeType":"def","questionId":"484","status":"lock","title":"寻找排列","titleSlug":"find-permutation"},{"formTitle":"[485]最大连续1的个数","frontendQuestionId":"485","leaf":true,"level":1,"nodeType":"def","questionId":"485","status":"","title":"最大连续1的个数","titleSlug":"max-consecutive-ones"},{"formTitle":"[486]预测赢家","frontendQuestionId":"486","leaf":true,"level":2,"nodeType":"def","questionId":"486","status":"","title":"预测赢家","titleSlug":"predict-the-winner"},{"formTitle":"[487]最大连续1的个数 II","frontendQuestionId":"487","leaf":true,"level":2,"nodeType":"def","questionId":"487","status":"lock","title":"最大连续1的个数 II","titleSlug":"max-consecutive-ones-ii"},{"formTitle":"[488]祖玛游戏","frontendQuestionId":"488","leaf":true,"level":3,"nodeType":"def","questionId":"488","status":"","title":"祖玛游戏","titleSlug":"zuma-game"},{"formTitle":"[489]扫地机器人","frontendQuestionId":"489","leaf":true,"level":3,"nodeType":"def","questionId":"865","status":"lock","title":"扫地机器人","titleSlug":"robot-room-cleaner"},{"formTitle":"[490]迷宫","frontendQuestionId":"490","leaf":true,"level":2,"nodeType":"def","questionId":"490","status":"lock","title":"迷宫","titleSlug":"the-maze"},{"formTitle":"[491]递增子序列","frontendQuestionId":"491","leaf":true,"level":2,"nodeType":"def","questionId":"491","status":"","title":"递增子序列","titleSlug":"increasing-subsequences"},{"formTitle":"[492]构造矩形","frontendQuestionId":"492","leaf":true,"level":1,"nodeType":"def","questionId":"492","status":"","title":"构造矩形","titleSlug":"construct-the-rectangle"},{"formTitle":"[493]翻转对","frontendQuestionId":"493","leaf":true,"level":3,"nodeType":"def","questionId":"493","status":"","title":"翻转对","titleSlug":"reverse-pairs"},{"formTitle":"[494]目标和","frontendQuestionId":"494","leaf":true,"level":2,"nodeType":"def","questionId":"494","status":"","title":"目标和","titleSlug":"target-sum"},{"formTitle":"[495]提莫攻击","frontendQuestionId":"495","leaf":true,"level":2,"nodeType":"def","questionId":"495","status":"","title":"提莫攻击","titleSlug":"teemo-attacking"},{"formTitle":"[496]下一个更大元素 I","frontendQuestionId":"496","leaf":true,"level":1,"nodeType":"def","questionId":"496","status":"","title":"下一个更大元素 I","titleSlug":"next-greater-element-i"},{"formTitle":"[497]非重叠矩形中的随机点","frontendQuestionId":"497","leaf":true,"level":2,"nodeType":"def","questionId":"914","status":"","title":"非重叠矩形中的随机点","titleSlug":"random-point-in-non-overlapping-rectangles"},{"formTitle":"[498]对角线遍历","frontendQuestionId":"498","leaf":true,"level":2,"nodeType":"def","questionId":"498","status":"","title":"对角线遍历","titleSlug":"diagonal-traverse"},{"formTitle":"[499]迷宫 III","frontendQuestionId":"499","leaf":true,"level":3,"nodeType":"def","questionId":"499","status":"lock","title":"迷宫 III","titleSlug":"the-maze-iii"},{"formTitle":"[500]键盘行","frontendQuestionId":"500","leaf":true,"level":1,"nodeType":"def","questionId":"500","status":"","title":"键盘行","titleSlug":"keyboard-row"},{"formTitle":"[501]二叉搜索树中的众数","frontendQuestionId":"501","leaf":true,"level":1,"nodeType":"def","questionId":"501","status":"","title":"二叉搜索树中的众数","titleSlug":"find-mode-in-binary-search-tree"},{"formTitle":"[502]IPO","frontendQuestionId":"502","leaf":true,"level":3,"nodeType":"def","questionId":"502","status":"","title":"IPO","titleSlug":"ipo"},{"formTitle":"[503]下一个更大元素 II","frontendQuestionId":"503","leaf":true,"level":2,"nodeType":"def","questionId":"503","status":"","title":"下一个更大元素 II","titleSlug":"next-greater-element-ii"},{"formTitle":"[504]七进制数","frontendQuestionId":"504","leaf":true,"level":1,"nodeType":"def","questionId":"504","status":"","title":"七进制数","titleSlug":"base-7"},{"formTitle":"[505]迷宫 II","frontendQuestionId":"505","leaf":true,"level":2,"nodeType":"def","questionId":"505","status":"lock","title":"迷宫 II","titleSlug":"the-maze-ii"},{"formTitle":"[506]相对名次","frontendQuestionId":"506","leaf":true,"level":1,"nodeType":"def","questionId":"506","status":"","title":"相对名次","titleSlug":"relative-ranks"},{"formTitle":"[507]完美数","frontendQuestionId":"507","leaf":true,"level":1,"nodeType":"def","questionId":"507","status":"","title":"完美数","titleSlug":"perfect-number"},{"formTitle":"[508]出现次数最多的子树元素和","frontendQuestionId":"508","leaf":true,"level":2,"nodeType":"def","questionId":"508","status":"","title":"出现次数最多的子树元素和","titleSlug":"most-frequent-subtree-sum"},{"formTitle":"[509]斐波那契数","frontendQuestionId":"509","leaf":true,"level":1,"nodeType":"def","questionId":"1013","status":"ac","title":"斐波那契数","titleSlug":"fibonacci-number"},{"formTitle":"[510]二叉搜索树中的中序后继 II","frontendQuestionId":"510","leaf":true,"level":2,"nodeType":"def","questionId":"509","status":"lock","title":"二叉搜索树中的中序后继 II","titleSlug":"inorder-successor-in-bst-ii"},{"formTitle":"[511]游戏玩法分析 I","frontendQuestionId":"511","leaf":true,"level":1,"nodeType":"def","questionId":"1179","status":"lock","title":"游戏玩法分析 I","titleSlug":"game-play-analysis-i"},{"formTitle":"[512]游戏玩法分析 II","frontendQuestionId":"512","leaf":true,"level":1,"nodeType":"def","questionId":"1180","status":"lock","title":"游戏玩法分析 II","titleSlug":"game-play-analysis-ii"},{"formTitle":"[513]找树左下角的值","frontendQuestionId":"513","leaf":true,"level":2,"nodeType":"def","questionId":"513","status":"","title":"找树左下角的值","titleSlug":"find-bottom-left-tree-value"},{"formTitle":"[514]自由之路","frontendQuestionId":"514","leaf":true,"level":3,"nodeType":"def","questionId":"514","status":"","title":"自由之路","titleSlug":"freedom-trail"},{"formTitle":"[515]在每个树行中找最大值","frontendQuestionId":"515","leaf":true,"level":2,"nodeType":"def","questionId":"515","status":"","title":"在每个树行中找最大值","titleSlug":"find-largest-value-in-each-tree-row"},{"formTitle":"[516]最长回文子序列","frontendQuestionId":"516","leaf":true,"level":2,"nodeType":"def","questionId":"516","status":"","title":"最长回文子序列","titleSlug":"longest-palindromic-subsequence"},{"formTitle":"[517]超级洗衣机","frontendQuestionId":"517","leaf":true,"level":3,"nodeType":"def","questionId":"517","status":"","title":"超级洗衣机","titleSlug":"super-washing-machines"},{"formTitle":"[518]零钱兑换 II","frontendQuestionId":"518","leaf":true,"level":2,"nodeType":"def","questionId":"518","status":"","title":"零钱兑换 II","titleSlug":"coin-change-2"},{"formTitle":"[519]随机翻转矩阵","frontendQuestionId":"519","leaf":true,"level":2,"nodeType":"def","questionId":"913","status":"","title":"随机翻转矩阵","titleSlug":"random-flip-matrix"},{"formTitle":"[520]检测大写字母","frontendQuestionId":"520","leaf":true,"level":1,"nodeType":"def","questionId":"520","status":"","title":"检测大写字母","titleSlug":"detect-capital"},{"formTitle":"[521]最长特殊序列 Ⅰ","frontendQuestionId":"521","leaf":true,"level":1,"nodeType":"def","questionId":"521","status":"","title":"最长特殊序列 Ⅰ","titleSlug":"longest-uncommon-subsequence-i"},{"formTitle":"[522]最长特殊序列 II","frontendQuestionId":"522","leaf":true,"level":2,"nodeType":"def","questionId":"522","status":"","title":"最长特殊序列 II","titleSlug":"longest-uncommon-subsequence-ii"},{"formTitle":"[523]连续的子数组和","frontendQuestionId":"523","leaf":true,"level":2,"nodeType":"def","questionId":"523","status":"","title":"连续的子数组和","titleSlug":"continuous-subarray-sum"},{"formTitle":"[524]通过删除字母匹配到字典里最长单词","frontendQuestionId":"524","leaf":true,"level":2,"nodeType":"def","questionId":"524","status":"","title":"通过删除字母匹配到字典里最长单词","titleSlug":"longest-word-in-dictionary-through-deleting"},{"formTitle":"[525]连续数组","frontendQuestionId":"525","leaf":true,"level":2,"nodeType":"def","questionId":"525","status":"","title":"连续数组","titleSlug":"contiguous-array"},{"formTitle":"[526]优美的排列","frontendQuestionId":"526","leaf":true,"level":2,"nodeType":"def","questionId":"526","status":"","title":"优美的排列","titleSlug":"beautiful-arrangement"},{"formTitle":"[527]单词缩写","frontendQuestionId":"527","leaf":true,"level":3,"nodeType":"def","questionId":"527","status":"lock","title":"单词缩写","titleSlug":"word-abbreviation"},{"formTitle":"[528]按权重随机选择","frontendQuestionId":"528","leaf":true,"level":2,"nodeType":"def","questionId":"912","status":"","title":"按权重随机选择","titleSlug":"random-pick-with-weight"},{"formTitle":"[529]扫雷游戏","frontendQuestionId":"529","leaf":true,"level":2,"nodeType":"def","questionId":"529","status":"","title":"扫雷游戏","titleSlug":"minesweeper"},{"formTitle":"[530]二叉搜索树的最小绝对差","frontendQuestionId":"530","leaf":true,"level":1,"nodeType":"def","questionId":"530","status":"","title":"二叉搜索树的最小绝对差","titleSlug":"minimum-absolute-difference-in-bst"},{"formTitle":"[531]孤独像素 I","frontendQuestionId":"531","leaf":true,"level":2,"nodeType":"def","questionId":"531","status":"lock","title":"孤独像素 I","titleSlug":"lonely-pixel-i"},{"formTitle":"[532]数组中的K-diff数对","frontendQuestionId":"532","leaf":true,"level":1,"nodeType":"def","questionId":"532","status":"","title":"数组中的K-diff数对","titleSlug":"k-diff-pairs-in-an-array"},{"formTitle":"[533]孤独像素 II","frontendQuestionId":"533","leaf":true,"level":2,"nodeType":"def","questionId":"533","status":"lock","title":"孤独像素 II","titleSlug":"lonely-pixel-ii"},{"formTitle":"[534]游戏玩法分析 III","frontendQuestionId":"534","leaf":true,"level":2,"nodeType":"def","questionId":"1181","status":"lock","title":"游戏玩法分析 III","titleSlug":"game-play-analysis-iii"},{"formTitle":"[535]TinyURL 的加密与解密","frontendQuestionId":"535","leaf":true,"level":2,"nodeType":"def","questionId":"535","status":"","title":"TinyURL 的加密与解密","titleSlug":"encode-and-decode-tinyurl"},{"formTitle":"[536]从字符串生成二叉树","frontendQuestionId":"536","leaf":true,"level":2,"nodeType":"def","questionId":"536","status":"lock","title":"从字符串生成二叉树","titleSlug":"construct-binary-tree-from-string"},{"formTitle":"[537]复数乘法","frontendQuestionId":"537","leaf":true,"level":2,"nodeType":"def","questionId":"537","status":"","title":"复数乘法","titleSlug":"complex-number-multiplication"},{"formTitle":"[538]把二叉搜索树转换为累加树","frontendQuestionId":"538","leaf":true,"level":1,"nodeType":"def","questionId":"538","status":"","title":"把二叉搜索树转换为累加树","titleSlug":"convert-bst-to-greater-tree"},{"formTitle":"[539]最小时间差","frontendQuestionId":"539","leaf":true,"level":2,"nodeType":"def","questionId":"539","status":"","title":"最小时间差","titleSlug":"minimum-time-difference"},{"formTitle":"[540]有序数组中的单一元素","frontendQuestionId":"540","leaf":true,"level":2,"nodeType":"def","questionId":"540","status":"","title":"有序数组中的单一元素","titleSlug":"single-element-in-a-sorted-array"},{"formTitle":"[541]反转字符串 II","frontendQuestionId":"541","leaf":true,"level":1,"nodeType":"def","questionId":"541","status":"","title":"反转字符串 II","titleSlug":"reverse-string-ii"},{"formTitle":"[542]01 矩阵","frontendQuestionId":"542","leaf":true,"level":2,"nodeType":"def","questionId":"542","status":"","title":"01 矩阵","titleSlug":"01-matrix"},{"formTitle":"[543]二叉树的直径","frontendQuestionId":"543","leaf":true,"level":1,"nodeType":"def","questionId":"543","status":"","title":"二叉树的直径","titleSlug":"diameter-of-binary-tree"},{"formTitle":"[544]输出比赛匹配对","frontendQuestionId":"544","leaf":true,"level":2,"nodeType":"def","questionId":"544","status":"lock","title":"输出比赛匹配对","titleSlug":"output-contest-matches"},{"formTitle":"[545]二叉树的边界","frontendQuestionId":"545","leaf":true,"level":2,"nodeType":"def","questionId":"545","status":"lock","title":"二叉树的边界","titleSlug":"boundary-of-binary-tree"},{"formTitle":"[546]移除盒子","frontendQuestionId":"546","leaf":true,"level":3,"nodeType":"def","questionId":"546","status":"","title":"移除盒子","titleSlug":"remove-boxes"},{"formTitle":"[547]朋友圈","frontendQuestionId":"547","leaf":true,"level":2,"nodeType":"def","questionId":"547","status":"","title":"朋友圈","titleSlug":"friend-circles"},{"formTitle":"[548]将数组分割成和相等的子数组","frontendQuestionId":"548","leaf":true,"level":2,"nodeType":"def","questionId":"548","status":"lock","title":"将数组分割成和相等的子数组","titleSlug":"split-array-with-equal-sum"},{"formTitle":"[549]二叉树中最长的连续序列","frontendQuestionId":"549","leaf":true,"level":2,"nodeType":"def","questionId":"549","status":"lock","title":"二叉树中最长的连续序列","titleSlug":"binary-tree-longest-consecutive-sequence-ii"},{"formTitle":"[550]游戏玩法分析 IV","frontendQuestionId":"550","leaf":true,"level":2,"nodeType":"def","questionId":"1182","status":"lock","title":"游戏玩法分析 IV","titleSlug":"game-play-analysis-iv"},{"formTitle":"[551]学生出勤记录 I","frontendQuestionId":"551","leaf":true,"level":1,"nodeType":"def","questionId":"551","status":"","title":"学生出勤记录 I","titleSlug":"student-attendance-record-i"},{"formTitle":"[552]学生出勤记录 II","frontendQuestionId":"552","leaf":true,"level":3,"nodeType":"def","questionId":"552","status":"","title":"学生出勤记录 II","titleSlug":"student-attendance-record-ii"},{"formTitle":"[553]最优除法","frontendQuestionId":"553","leaf":true,"level":2,"nodeType":"def","questionId":"553","status":"","title":"最优除法","titleSlug":"optimal-division"},{"formTitle":"[554]砖墙","frontendQuestionId":"554","leaf":true,"level":2,"nodeType":"def","questionId":"554","status":"","title":"砖墙","titleSlug":"brick-wall"},{"formTitle":"[555]分割连接字符串","frontendQuestionId":"555","leaf":true,"level":2,"nodeType":"def","questionId":"555","status":"lock","title":"分割连接字符串","titleSlug":"split-concatenated-strings"},{"formTitle":"[556]下一个更大元素 III","frontendQuestionId":"556","leaf":true,"level":2,"nodeType":"def","questionId":"556","status":"","title":"下一个更大元素 III","titleSlug":"next-greater-element-iii"},{"formTitle":"[557]反转字符串中的单词 III","frontendQuestionId":"557","leaf":true,"level":1,"nodeType":"def","questionId":"557","status":"","title":"反转字符串中的单词 III","titleSlug":"reverse-words-in-a-string-iii"},{"formTitle":"[558]四叉树交集","frontendQuestionId":"558","leaf":true,"level":1,"nodeType":"def","questionId":"773","status":"","title":"四叉树交集","titleSlug":"quad-tree-intersection"},{"formTitle":"[559]N叉树的最大深度","frontendQuestionId":"559","leaf":true,"level":1,"nodeType":"def","questionId":"774","status":"","title":"N叉树的最大深度","titleSlug":"maximum-depth-of-n-ary-tree"},{"formTitle":"[560]和为K的子数组","frontendQuestionId":"560","leaf":true,"level":2,"nodeType":"def","questionId":"560","status":"","title":"和为K的子数组","titleSlug":"subarray-sum-equals-k"},{"formTitle":"[561]数组拆分 I","frontendQuestionId":"561","leaf":true,"level":1,"nodeType":"def","questionId":"561","status":"","title":"数组拆分 I","titleSlug":"array-partition-i"},{"formTitle":"[562]矩阵中最长的连续1线段","frontendQuestionId":"562","leaf":true,"level":2,"nodeType":"def","questionId":"562","status":"lock","title":"矩阵中最长的连续1线段","titleSlug":"longest-line-of-consecutive-one-in-matrix"},{"formTitle":"[563]二叉树的坡度","frontendQuestionId":"563","leaf":true,"level":1,"nodeType":"def","questionId":"563","status":"","title":"二叉树的坡度","titleSlug":"binary-tree-tilt"},{"formTitle":"[564]寻找最近的回文数","frontendQuestionId":"564","leaf":true,"level":3,"nodeType":"def","questionId":"564","status":"","title":"寻找最近的回文数","titleSlug":"find-the-closest-palindrome"},{"formTitle":"[565]数组嵌套","frontendQuestionId":"565","leaf":true,"level":2,"nodeType":"def","questionId":"565","status":"","title":"数组嵌套","titleSlug":"array-nesting"},{"formTitle":"[566]重塑矩阵","frontendQuestionId":"566","leaf":true,"level":1,"nodeType":"def","questionId":"566","status":"","title":"重塑矩阵","titleSlug":"reshape-the-matrix"},{"formTitle":"[567]字符串的排列","frontendQuestionId":"567","leaf":true,"level":2,"nodeType":"def","questionId":"567","status":"","title":"字符串的排列","titleSlug":"permutation-in-string"},{"formTitle":"[568]最大休假天数","frontendQuestionId":"568","leaf":true,"level":3,"nodeType":"def","questionId":"568","status":"lock","title":"最大休假天数","titleSlug":"maximum-vacation-days"},{"formTitle":"[569]员工薪水中位数","frontendQuestionId":"569","leaf":true,"level":3,"nodeType":"def","questionId":"569","status":"lock","title":"员工薪水中位数","titleSlug":"median-employee-salary"},{"formTitle":"[570]至少有5名直接下属的经理","frontendQuestionId":"570","leaf":true,"level":2,"nodeType":"def","questionId":"570","status":"lock","title":"至少有5名直接下属的经理","titleSlug":"managers-with-at-least-5-direct-reports"},{"formTitle":"[571]给定数字的频率查询中位数","frontendQuestionId":"571","leaf":true,"level":3,"nodeType":"def","questionId":"571","status":"lock","title":"给定数字的频率查询中位数","titleSlug":"find-median-given-frequency-of-numbers"},{"formTitle":"[572]另一个树的子树","frontendQuestionId":"572","leaf":true,"level":1,"nodeType":"def","questionId":"572","status":"","title":"另一个树的子树","titleSlug":"subtree-of-another-tree"},{"formTitle":"[573]松鼠模拟","frontendQuestionId":"573","leaf":true,"level":2,"nodeType":"def","questionId":"573","status":"lock","title":"松鼠模拟","titleSlug":"squirrel-simulation"},{"formTitle":"[574]当选者","frontendQuestionId":"574","leaf":true,"level":2,"nodeType":"def","questionId":"574","status":"lock","title":"当选者","titleSlug":"winning-candidate"},{"formTitle":"[575]分糖果","frontendQuestionId":"575","leaf":true,"level":1,"nodeType":"def","questionId":"575","status":"","title":"分糖果","titleSlug":"distribute-candies"},{"formTitle":"[576]出界的路径数","frontendQuestionId":"576","leaf":true,"level":2,"nodeType":"def","questionId":"576","status":"","title":"出界的路径数","titleSlug":"out-of-boundary-paths"},{"formTitle":"[577]员工奖金","frontendQuestionId":"577","leaf":true,"level":1,"nodeType":"def","questionId":"577","status":"lock","title":"员工奖金","titleSlug":"employee-bonus"},{"formTitle":"[578]查询回答率最高的问题","frontendQuestionId":"578","leaf":true,"level":2,"nodeType":"def","questionId":"578","status":"lock","title":"查询回答率最高的问题","titleSlug":"get-highest-answer-rate-question"},{"formTitle":"[579]查询员工的累计薪水","frontendQuestionId":"579","leaf":true,"level":3,"nodeType":"def","questionId":"579","status":"lock","title":"查询员工的累计薪水","titleSlug":"find-cumulative-salary-of-an-employee"},{"formTitle":"[580]统计各专业学生人数","frontendQuestionId":"580","leaf":true,"level":2,"nodeType":"def","questionId":"580","status":"lock","title":"统计各专业学生人数","titleSlug":"count-student-number-in-departments"},{"formTitle":"[581]最短无序连续子数组","frontendQuestionId":"581","leaf":true,"level":1,"nodeType":"def","questionId":"581","status":"","title":"最短无序连续子数组","titleSlug":"shortest-unsorted-continuous-subarray"},{"formTitle":"[582]杀死进程","frontendQuestionId":"582","leaf":true,"level":2,"nodeType":"def","questionId":"582","status":"lock","title":"杀死进程","titleSlug":"kill-process"},{"formTitle":"[583]两个字符串的删除操作","frontendQuestionId":"583","leaf":true,"level":2,"nodeType":"def","questionId":"583","status":"","title":"两个字符串的删除操作","titleSlug":"delete-operation-for-two-strings"},{"formTitle":"[584]寻找用户推荐人","frontendQuestionId":"584","leaf":true,"level":1,"nodeType":"def","questionId":"584","status":"lock","title":"寻找用户推荐人","titleSlug":"find-customer-referee"},{"formTitle":"[585]2016年的投资","frontendQuestionId":"585","leaf":true,"level":2,"nodeType":"def","questionId":"585","status":"lock","title":"2016年的投资","titleSlug":"investments-in-2016"},{"formTitle":"[586]订单最多的客户","frontendQuestionId":"586","leaf":true,"level":1,"nodeType":"def","questionId":"586","status":"lock","title":"订单最多的客户","titleSlug":"customer-placing-the-largest-number-of-orders"},{"formTitle":"[587]安装栅栏","frontendQuestionId":"587","leaf":true,"level":3,"nodeType":"def","questionId":"587","status":"","title":"安装栅栏","titleSlug":"erect-the-fence"},{"formTitle":"[588]设计内存文件系统","frontendQuestionId":"588","leaf":true,"level":3,"nodeType":"def","questionId":"588","status":"lock","title":"设计内存文件系统","titleSlug":"design-in-memory-file-system"},{"formTitle":"[589]N叉树的前序遍历","frontendQuestionId":"589","leaf":true,"level":1,"nodeType":"def","questionId":"775","status":"","title":"N叉树的前序遍历","titleSlug":"n-ary-tree-preorder-traversal"},{"formTitle":"[590]N叉树的后序遍历","frontendQuestionId":"590","leaf":true,"level":1,"nodeType":"def","questionId":"776","status":"","title":"N叉树的后序遍历","titleSlug":"n-ary-tree-postorder-traversal"},{"formTitle":"[591]标签验证器","frontendQuestionId":"591","leaf":true,"level":3,"nodeType":"def","questionId":"591","status":"","title":"标签验证器","titleSlug":"tag-validator"},{"formTitle":"[592]分数加减运算","frontendQuestionId":"592","leaf":true,"level":2,"nodeType":"def","questionId":"592","status":"","title":"分数加减运算","titleSlug":"fraction-addition-and-subtraction"},{"formTitle":"[593]有效的正方形","frontendQuestionId":"593","leaf":true,"level":2,"nodeType":"def","questionId":"593","status":"","title":"有效的正方形","titleSlug":"valid-square"},{"formTitle":"[594]最长和谐子序列","frontendQuestionId":"594","leaf":true,"level":1,"nodeType":"def","questionId":"594","status":"","title":"最长和谐子序列","titleSlug":"longest-harmonious-subsequence"},{"formTitle":"[595]大的国家","frontendQuestionId":"595","leaf":true,"level":1,"nodeType":"def","questionId":"595","status":"","title":"大的国家","titleSlug":"big-countries"},{"formTitle":"[596]超过5名学生的课","frontendQuestionId":"596","leaf":true,"level":1,"nodeType":"def","questionId":"596","status":"","title":"超过5名学生的课","titleSlug":"classes-more-than-5-students"},{"formTitle":"[597]好友申请 I :总体通过率","frontendQuestionId":"597","leaf":true,"level":1,"nodeType":"def","questionId":"597","status":"lock","title":"好友申请 I :总体通过率","titleSlug":"friend-requests-i-overall-acceptance-rate"},{"formTitle":"[598]范围求和 II","frontendQuestionId":"598","leaf":true,"level":1,"nodeType":"def","questionId":"598","status":"","title":"范围求和 II","titleSlug":"range-addition-ii"},{"formTitle":"[599]两个列表的最小索引总和","frontendQuestionId":"599","leaf":true,"level":1,"nodeType":"def","questionId":"599","status":"","title":"两个列表的最小索引总和","titleSlug":"minimum-index-sum-of-two-lists"},{"formTitle":"[600]不含连续1的非负整数","frontendQuestionId":"600","leaf":true,"level":3,"nodeType":"def","questionId":"600","status":"","title":"不含连续1的非负整数","titleSlug":"non-negative-integers-without-consecutive-ones"},{"formTitle":"[601]体育馆的人流量","frontendQuestionId":"601","leaf":true,"level":3,"nodeType":"def","questionId":"601","status":"","title":"体育馆的人流量","titleSlug":"human-traffic-of-stadium"},{"formTitle":"[602]好友申请 II :谁有最多的好友","frontendQuestionId":"602","leaf":true,"level":2,"nodeType":"def","questionId":"602","status":"lock","title":"好友申请 II :谁有最多的好友","titleSlug":"friend-requests-ii-who-has-the-most-friends"},{"formTitle":"[603]连续空余座位","frontendQuestionId":"603","leaf":true,"level":1,"nodeType":"def","questionId":"603","status":"lock","title":"连续空余座位","titleSlug":"consecutive-available-seats"},{"formTitle":"[604]迭代压缩字符串","frontendQuestionId":"604","leaf":true,"level":1,"nodeType":"def","questionId":"604","status":"lock","title":"迭代压缩字符串","titleSlug":"design-compressed-string-iterator"},{"formTitle":"[605]种花问题","frontendQuestionId":"605","leaf":true,"level":1,"nodeType":"def","questionId":"605","status":"","title":"种花问题","titleSlug":"can-place-flowers"},{"formTitle":"[606]根据二叉树创建字符串","frontendQuestionId":"606","leaf":true,"level":1,"nodeType":"def","questionId":"606","status":"","title":"根据二叉树创建字符串","titleSlug":"construct-string-from-binary-tree"},{"formTitle":"[607]销售员","frontendQuestionId":"607","leaf":true,"level":1,"nodeType":"def","questionId":"607","status":"lock","title":"销售员","titleSlug":"sales-person"},{"formTitle":"[608]树节点","frontendQuestionId":"608","leaf":true,"level":2,"nodeType":"def","questionId":"608","status":"lock","title":"树节点","titleSlug":"tree-node"},{"formTitle":"[609]在系统中查找重复文件","frontendQuestionId":"609","leaf":true,"level":2,"nodeType":"def","questionId":"609","status":"","title":"在系统中查找重复文件","titleSlug":"find-duplicate-file-in-system"},{"formTitle":"[610]判断三角形","frontendQuestionId":"610","leaf":true,"level":1,"nodeType":"def","questionId":"610","status":"lock","title":"判断三角形","titleSlug":"triangle-judgement"},{"formTitle":"[611]有效三角形的个数","frontendQuestionId":"611","leaf":true,"level":2,"nodeType":"def","questionId":"611","status":"","title":"有效三角形的个数","titleSlug":"valid-triangle-number"},{"formTitle":"[612]平面上的最近距离","frontendQuestionId":"612","leaf":true,"level":2,"nodeType":"def","questionId":"612","status":"lock","title":"平面上的最近距离","titleSlug":"shortest-distance-in-a-plane"},{"formTitle":"[613]直线上的最近距离","frontendQuestionId":"613","leaf":true,"level":1,"nodeType":"def","questionId":"613","status":"lock","title":"直线上的最近距离","titleSlug":"shortest-distance-in-a-line"},{"formTitle":"[614]二级关注者","frontendQuestionId":"614","leaf":true,"level":2,"nodeType":"def","questionId":"614","status":"lock","title":"二级关注者","titleSlug":"second-degree-follower"},{"formTitle":"[615]平均工资:部门与公司比较","frontendQuestionId":"615","leaf":true,"level":3,"nodeType":"def","questionId":"615","status":"lock","title":"平均工资:部门与公司比较","titleSlug":"average-salary-departments-vs-company"},{"formTitle":"[616]给字符串添加加粗标签","frontendQuestionId":"616","leaf":true,"level":2,"nodeType":"def","questionId":"616","status":"lock","title":"给字符串添加加粗标签","titleSlug":"add-bold-tag-in-string"},{"formTitle":"[617]合并二叉树","frontendQuestionId":"617","leaf":true,"level":1,"nodeType":"def","questionId":"617","status":"","title":"合并二叉树","titleSlug":"merge-two-binary-trees"},{"formTitle":"[618]学生地理信息报告","frontendQuestionId":"618","leaf":true,"level":3,"nodeType":"def","questionId":"618","status":"lock","title":"学生地理信息报告","titleSlug":"students-report-by-geography"},{"formTitle":"[619]只出现一次的最大数字","frontendQuestionId":"619","leaf":true,"level":1,"nodeType":"def","questionId":"619","status":"lock","title":"只出现一次的最大数字","titleSlug":"biggest-single-number"},{"formTitle":"[620]有趣的电影","frontendQuestionId":"620","leaf":true,"level":1,"nodeType":"def","questionId":"620","status":"","title":"有趣的电影","titleSlug":"not-boring-movies"},{"formTitle":"[621]任务调度器","frontendQuestionId":"621","leaf":true,"level":2,"nodeType":"def","questionId":"621","status":"","title":"任务调度器","titleSlug":"task-scheduler"},{"formTitle":"[622]设计循环队列","frontendQuestionId":"622","leaf":true,"level":2,"nodeType":"def","questionId":"860","status":"","title":"设计循环队列","titleSlug":"design-circular-queue"},{"formTitle":"[623]在二叉树中增加一行","frontendQuestionId":"623","leaf":true,"level":2,"nodeType":"def","questionId":"623","status":"","title":"在二叉树中增加一行","titleSlug":"add-one-row-to-tree"},{"formTitle":"[624]数组列表中的最大距离","frontendQuestionId":"624","leaf":true,"level":1,"nodeType":"def","questionId":"624","status":"lock","title":"数组列表中的最大距离","titleSlug":"maximum-distance-in-arrays"},{"formTitle":"[625]最小因式分解","frontendQuestionId":"625","leaf":true,"level":2,"nodeType":"def","questionId":"625","status":"lock","title":"最小因式分解","titleSlug":"minimum-factorization"},{"formTitle":"[626]换座位","frontendQuestionId":"626","leaf":true,"level":2,"nodeType":"def","questionId":"626","status":"","title":"换座位","titleSlug":"exchange-seats"},{"formTitle":"[627]交换工资","frontendQuestionId":"627","leaf":true,"level":1,"nodeType":"def","questionId":"627","status":"","title":"交换工资","titleSlug":"swap-salary"},{"formTitle":"[628]三个数的最大乘积","frontendQuestionId":"628","leaf":true,"level":1,"nodeType":"def","questionId":"628","status":"","title":"三个数的最大乘积","titleSlug":"maximum-product-of-three-numbers"},{"formTitle":"[629]K个逆序对数组","frontendQuestionId":"629","leaf":true,"level":3,"nodeType":"def","questionId":"629","status":"","title":"K个逆序对数组","titleSlug":"k-inverse-pairs-array"},{"formTitle":"[630]课程表 III","frontendQuestionId":"630","leaf":true,"level":3,"nodeType":"def","questionId":"630","status":"","title":"课程表 III","titleSlug":"course-schedule-iii"},{"formTitle":"[631]设计 Excel 求和公式","frontendQuestionId":"631","leaf":true,"level":3,"nodeType":"def","questionId":"631","status":"lock","title":"设计 Excel 求和公式","titleSlug":"design-excel-sum-formula"},{"formTitle":"[632]最小区间","frontendQuestionId":"632","leaf":true,"level":3,"nodeType":"def","questionId":"632","status":"","title":"最小区间","titleSlug":"smallest-range-covering-elements-from-k-lists"},{"formTitle":"[633]平方数之和","frontendQuestionId":"633","leaf":true,"level":1,"nodeType":"def","questionId":"633","status":"","title":"平方数之和","titleSlug":"sum-of-square-numbers"},{"formTitle":"[634]寻找数组的错位排列","frontendQuestionId":"634","leaf":true,"level":2,"nodeType":"def","questionId":"634","status":"lock","title":"寻找数组的错位排列","titleSlug":"find-the-derangement-of-an-array"},{"formTitle":"[635]设计日志存储系统","frontendQuestionId":"635","leaf":true,"level":2,"nodeType":"def","questionId":"635","status":"lock","title":"设计日志存储系统","titleSlug":"design-log-storage-system"},{"formTitle":"[636]函数的独占时间","frontendQuestionId":"636","leaf":true,"level":2,"nodeType":"def","questionId":"636","status":"","title":"函数的独占时间","titleSlug":"exclusive-time-of-functions"},{"formTitle":"[637]二叉树的层平均值","frontendQuestionId":"637","leaf":true,"level":1,"nodeType":"def","questionId":"637","status":"","title":"二叉树的层平均值","titleSlug":"average-of-levels-in-binary-tree"},{"formTitle":"[638]大礼包","frontendQuestionId":"638","leaf":true,"level":2,"nodeType":"def","questionId":"638","status":"","title":"大礼包","titleSlug":"shopping-offers"},{"formTitle":"[639]解码方法 2","frontendQuestionId":"639","leaf":true,"level":3,"nodeType":"def","questionId":"639","status":"","title":"解码方法 2","titleSlug":"decode-ways-ii"},{"formTitle":"[640]求解方程","frontendQuestionId":"640","leaf":true,"level":2,"nodeType":"def","questionId":"640","status":"","title":"求解方程","titleSlug":"solve-the-equation"},{"formTitle":"[641]设计循环双端队列","frontendQuestionId":"641","leaf":true,"level":2,"nodeType":"def","questionId":"859","status":"","title":"设计循环双端队列","titleSlug":"design-circular-deque"},{"formTitle":"[642]设计搜索自动补全系统","frontendQuestionId":"642","leaf":true,"level":3,"nodeType":"def","questionId":"642","status":"lock","title":"设计搜索自动补全系统","titleSlug":"design-search-autocomplete-system"},{"formTitle":"[643]子数组最大平均数 I","frontendQuestionId":"643","leaf":true,"level":1,"nodeType":"def","questionId":"643","status":"","title":"子数组最大平均数 I","titleSlug":"maximum-average-subarray-i"},{"formTitle":"[644]最大平均子段和 II","frontendQuestionId":"644","leaf":true,"level":3,"nodeType":"def","questionId":"644","status":"lock","title":"最大平均子段和 II","titleSlug":"maximum-average-subarray-ii"},{"formTitle":"[645]错误的集合","frontendQuestionId":"645","leaf":true,"level":1,"nodeType":"def","questionId":"645","status":"","title":"错误的集合","titleSlug":"set-mismatch"},{"formTitle":"[646]最长数对链","frontendQuestionId":"646","leaf":true,"level":2,"nodeType":"def","questionId":"646","status":"","title":"最长数对链","titleSlug":"maximum-length-of-pair-chain"},{"formTitle":"[647]回文子串","frontendQuestionId":"647","leaf":true,"level":2,"nodeType":"def","questionId":"647","status":"","title":"回文子串","titleSlug":"palindromic-substrings"},{"formTitle":"[648]单词替换","frontendQuestionId":"648","leaf":true,"level":2,"nodeType":"def","questionId":"648","status":"","title":"单词替换","titleSlug":"replace-words"},{"formTitle":"[649]Dota2 参议院","frontendQuestionId":"649","leaf":true,"level":2,"nodeType":"def","questionId":"649","status":"","title":"Dota2 参议院","titleSlug":"dota2-senate"},{"formTitle":"[650]只有两个键的键盘","frontendQuestionId":"650","leaf":true,"level":2,"nodeType":"def","questionId":"650","status":"","title":"只有两个键的键盘","titleSlug":"2-keys-keyboard"},{"formTitle":"[651]4键键盘","frontendQuestionId":"651","leaf":true,"level":2,"nodeType":"def","questionId":"651","status":"lock","title":"4键键盘","titleSlug":"4-keys-keyboard"},{"formTitle":"[652]寻找重复的子树","frontendQuestionId":"652","leaf":true,"level":2,"nodeType":"def","questionId":"652","status":"","title":"寻找重复的子树","titleSlug":"find-duplicate-subtrees"},{"formTitle":"[653]两数之和 IV - 输入 BST","frontendQuestionId":"653","leaf":true,"level":1,"nodeType":"def","questionId":"653","status":"","title":"两数之和 IV - 输入 BST","titleSlug":"two-sum-iv-input-is-a-bst"},{"formTitle":"[654]最大二叉树","frontendQuestionId":"654","leaf":true,"level":2,"nodeType":"def","questionId":"654","status":"","title":"最大二叉树","titleSlug":"maximum-binary-tree"},{"formTitle":"[655]输出二叉树","frontendQuestionId":"655","leaf":true,"level":2,"nodeType":"def","questionId":"655","status":"","title":"输出二叉树","titleSlug":"print-binary-tree"},{"formTitle":"[656]金币路径","frontendQuestionId":"656","leaf":true,"level":3,"nodeType":"def","questionId":"656","status":"lock","title":"金币路径","titleSlug":"coin-path"},{"formTitle":"[657]机器人能否返回原点","frontendQuestionId":"657","leaf":true,"level":1,"nodeType":"def","questionId":"657","status":"","title":"机器人能否返回原点","titleSlug":"robot-return-to-origin"},{"formTitle":"[658]找到 K 个最接近的元素","frontendQuestionId":"658","leaf":true,"level":2,"nodeType":"def","questionId":"658","status":"","title":"找到 K 个最接近的元素","titleSlug":"find-k-closest-elements"},{"formTitle":"[659]分割数组为连续子序列","frontendQuestionId":"659","leaf":true,"level":2,"nodeType":"def","questionId":"659","status":"","title":"分割数组为连续子序列","titleSlug":"split-array-into-consecutive-subsequences"},{"formTitle":"[660]移除 9","frontendQuestionId":"660","leaf":true,"level":3,"nodeType":"def","questionId":"660","status":"lock","title":"移除 9","titleSlug":"remove-9"},{"formTitle":"[661]图片平滑器","frontendQuestionId":"661","leaf":true,"level":1,"nodeType":"def","questionId":"661","status":"","title":"图片平滑器","titleSlug":"image-smoother"},{"formTitle":"[662]二叉树最大宽度","frontendQuestionId":"662","leaf":true,"level":2,"nodeType":"def","questionId":"662","status":"","title":"二叉树最大宽度","titleSlug":"maximum-width-of-binary-tree"},{"formTitle":"[663]均匀树划分","frontendQuestionId":"663","leaf":true,"level":2,"nodeType":"def","questionId":"663","status":"lock","title":"均匀树划分","titleSlug":"equal-tree-partition"},{"formTitle":"[664]奇怪的打印机","frontendQuestionId":"664","leaf":true,"level":3,"nodeType":"def","questionId":"664","status":"","title":"奇怪的打印机","titleSlug":"strange-printer"},{"formTitle":"[665]非递减数列","frontendQuestionId":"665","leaf":true,"level":1,"nodeType":"def","questionId":"665","status":"","title":"非递减数列","titleSlug":"non-decreasing-array"},{"formTitle":"[666]路径和 IV","frontendQuestionId":"666","leaf":true,"level":2,"nodeType":"def","questionId":"666","status":"lock","title":"路径和 IV","titleSlug":"path-sum-iv"},{"formTitle":"[667]优美的排列 II","frontendQuestionId":"667","leaf":true,"level":2,"nodeType":"def","questionId":"667","status":"","title":"优美的排列 II","titleSlug":"beautiful-arrangement-ii"},{"formTitle":"[668]乘法表中第k小的数","frontendQuestionId":"668","leaf":true,"level":3,"nodeType":"def","questionId":"668","status":"","title":"乘法表中第k小的数","titleSlug":"kth-smallest-number-in-multiplication-table"},{"formTitle":"[669]修剪二叉搜索树","frontendQuestionId":"669","leaf":true,"level":1,"nodeType":"def","questionId":"669","status":"","title":"修剪二叉搜索树","titleSlug":"trim-a-binary-search-tree"},{"formTitle":"[670]最大交换","frontendQuestionId":"670","leaf":true,"level":2,"nodeType":"def","questionId":"670","status":"","title":"最大交换","titleSlug":"maximum-swap"},{"formTitle":"[671]二叉树中第二小的节点","frontendQuestionId":"671","leaf":true,"level":1,"nodeType":"def","questionId":"671","status":"","title":"二叉树中第二小的节点","titleSlug":"second-minimum-node-in-a-binary-tree"},{"formTitle":"[672]灯泡开关 Ⅱ","frontendQuestionId":"672","leaf":true,"level":2,"nodeType":"def","questionId":"672","status":"","title":"灯泡开关 Ⅱ","titleSlug":"bulb-switcher-ii"},{"formTitle":"[673]最长递增子序列的个数","frontendQuestionId":"673","leaf":true,"level":2,"nodeType":"def","questionId":"673","status":"","title":"最长递增子序列的个数","titleSlug":"number-of-longest-increasing-subsequence"},{"formTitle":"[674]最长连续递增序列","frontendQuestionId":"674","leaf":true,"level":1,"nodeType":"def","questionId":"674","status":"","title":"最长连续递增序列","titleSlug":"longest-continuous-increasing-subsequence"},{"formTitle":"[675]为高尔夫比赛砍树","frontendQuestionId":"675","leaf":true,"level":3,"nodeType":"def","questionId":"675","status":"","title":"为高尔夫比赛砍树","titleSlug":"cut-off-trees-for-golf-event"},{"formTitle":"[676]实现一个魔法字典","frontendQuestionId":"676","leaf":true,"level":2,"nodeType":"def","questionId":"676","status":"","title":"实现一个魔法字典","titleSlug":"implement-magic-dictionary"},{"formTitle":"[677]键值映射","frontendQuestionId":"677","leaf":true,"level":2,"nodeType":"def","questionId":"677","status":"","title":"键值映射","titleSlug":"map-sum-pairs"},{"formTitle":"[678]有效的括号字符串","frontendQuestionId":"678","leaf":true,"level":2,"nodeType":"def","questionId":"678","status":"","title":"有效的括号字符串","titleSlug":"valid-parenthesis-string"},{"formTitle":"[679]24 点游戏","frontendQuestionId":"679","leaf":true,"level":3,"nodeType":"def","questionId":"679","status":"","title":"24 点游戏","titleSlug":"24-game"},{"formTitle":"[680]验证回文字符串 Ⅱ","frontendQuestionId":"680","leaf":true,"level":1,"nodeType":"def","questionId":"680","status":"","title":"验证回文字符串 Ⅱ","titleSlug":"valid-palindrome-ii"},{"formTitle":"[681]最近时刻","frontendQuestionId":"681","leaf":true,"level":2,"nodeType":"def","questionId":"681","status":"lock","title":"最近时刻","titleSlug":"next-closest-time"},{"formTitle":"[682]棒球比赛","frontendQuestionId":"682","leaf":true,"level":1,"nodeType":"def","questionId":"682","status":"","title":"棒球比赛","titleSlug":"baseball-game"},{"formTitle":"[683]K 个空花盆","frontendQuestionId":"683","leaf":true,"level":3,"nodeType":"def","questionId":"683","status":"lock","title":"K 个空花盆","titleSlug":"k-empty-slots"},{"formTitle":"[684]冗余连接","frontendQuestionId":"684","leaf":true,"level":2,"nodeType":"def","questionId":"684","status":"","title":"冗余连接","titleSlug":"redundant-connection"},{"formTitle":"[685]冗余连接 II","frontendQuestionId":"685","leaf":true,"level":3,"nodeType":"def","questionId":"685","status":"","title":"冗余连接 II","titleSlug":"redundant-connection-ii"},{"formTitle":"[686]重复叠加字符串匹配","frontendQuestionId":"686","leaf":true,"level":1,"nodeType":"def","questionId":"686","status":"","title":"重复叠加字符串匹配","titleSlug":"repeated-string-match"},{"formTitle":"[687]最长同值路径","frontendQuestionId":"687","leaf":true,"level":1,"nodeType":"def","questionId":"687","status":"","title":"最长同值路径","titleSlug":"longest-univalue-path"},{"formTitle":"[688]“马”在棋盘上的概率","frontendQuestionId":"688","leaf":true,"level":2,"nodeType":"def","questionId":"688","status":"","title":"“马”在棋盘上的概率","titleSlug":"knight-probability-in-chessboard"},{"formTitle":"[689]三个无重叠子数组的最大和","frontendQuestionId":"689","leaf":true,"level":3,"nodeType":"def","questionId":"689","status":"","title":"三个无重叠子数组的最大和","titleSlug":"maximum-sum-of-3-non-overlapping-subarrays"},{"formTitle":"[690]员工的重要性","frontendQuestionId":"690","leaf":true,"level":1,"nodeType":"def","questionId":"690","status":"","title":"员工的重要性","titleSlug":"employee-importance"},{"formTitle":"[691]贴纸拼词","frontendQuestionId":"691","leaf":true,"level":3,"nodeType":"def","questionId":"691","status":"","title":"贴纸拼词","titleSlug":"stickers-to-spell-word"},{"formTitle":"[692]前K个高频单词","frontendQuestionId":"692","leaf":true,"level":2,"nodeType":"def","questionId":"692","status":"","title":"前K个高频单词","titleSlug":"top-k-frequent-words"},{"formTitle":"[693]交替位二进制数","frontendQuestionId":"693","leaf":true,"level":1,"nodeType":"def","questionId":"693","status":"","title":"交替位二进制数","titleSlug":"binary-number-with-alternating-bits"},{"formTitle":"[694]不同岛屿的数量","frontendQuestionId":"694","leaf":true,"level":2,"nodeType":"def","questionId":"694","status":"lock","title":"不同岛屿的数量","titleSlug":"number-of-distinct-islands"},{"formTitle":"[695]岛屿的最大面积","frontendQuestionId":"695","leaf":true,"level":2,"nodeType":"def","questionId":"695","status":"","title":"岛屿的最大面积","titleSlug":"max-area-of-island"},{"formTitle":"[696]计数二进制子串","frontendQuestionId":"696","leaf":true,"level":1,"nodeType":"def","questionId":"696","status":"","title":"计数二进制子串","titleSlug":"count-binary-substrings"},{"formTitle":"[697]数组的度","frontendQuestionId":"697","leaf":true,"level":1,"nodeType":"def","questionId":"697","status":"","title":"数组的度","titleSlug":"degree-of-an-array"},{"formTitle":"[698]划分为k个相等的子集","frontendQuestionId":"698","leaf":true,"level":2,"nodeType":"def","questionId":"698","status":"","title":"划分为k个相等的子集","titleSlug":"partition-to-k-equal-sum-subsets"},{"formTitle":"[699]掉落的方块","frontendQuestionId":"699","leaf":true,"level":3,"nodeType":"def","questionId":"699","status":"","title":"掉落的方块","titleSlug":"falling-squares"},{"formTitle":"[700]二叉搜索树中的搜索","frontendQuestionId":"700","leaf":true,"level":1,"nodeType":"def","questionId":"783","status":"","title":"二叉搜索树中的搜索","titleSlug":"search-in-a-binary-search-tree"},{"formTitle":"[701]二叉搜索树中的插入操作","frontendQuestionId":"701","leaf":true,"level":2,"nodeType":"def","questionId":"784","status":"","title":"二叉搜索树中的插入操作","titleSlug":"insert-into-a-binary-search-tree"},{"formTitle":"[702]搜索长度未知的有序数组","frontendQuestionId":"702","leaf":true,"level":2,"nodeType":"def","questionId":"786","status":"lock","title":"搜索长度未知的有序数组","titleSlug":"search-in-a-sorted-array-of-unknown-size"},{"formTitle":"[703]数据流中的第K大元素","frontendQuestionId":"703","leaf":true,"level":1,"nodeType":"def","questionId":"789","status":"","title":"数据流中的第K大元素","titleSlug":"kth-largest-element-in-a-stream"},{"formTitle":"[704]二分查找","frontendQuestionId":"704","leaf":true,"level":1,"nodeType":"def","questionId":"792","status":"","title":"二分查找","titleSlug":"binary-search"},{"formTitle":"[705]设计哈希集合","frontendQuestionId":"705","leaf":true,"level":1,"nodeType":"def","questionId":"816","status":"","title":"设计哈希集合","titleSlug":"design-hashset"},{"formTitle":"[706]设计哈希映射","frontendQuestionId":"706","leaf":true,"level":1,"nodeType":"def","questionId":"817","status":"","title":"设计哈希映射","titleSlug":"design-hashmap"},{"formTitle":"[707]设计链表","frontendQuestionId":"707","leaf":true,"level":2,"nodeType":"def","questionId":"838","status":"","title":"设计链表","titleSlug":"design-linked-list"},{"formTitle":"[708]循环有序列表的插入","frontendQuestionId":"708","leaf":true,"level":2,"nodeType":"def","questionId":"850","status":"lock","title":"循环有序列表的插入","titleSlug":"insert-into-a-cyclic-sorted-list"},{"formTitle":"[709]转换成小写字母","frontendQuestionId":"709","leaf":true,"level":1,"nodeType":"def","questionId":"742","status":"","title":"转换成小写字母","titleSlug":"to-lower-case"},{"formTitle":"[710]黑名单中的随机数","frontendQuestionId":"710","leaf":true,"level":3,"nodeType":"def","questionId":"894","status":"","title":"黑名单中的随机数","titleSlug":"random-pick-with-blacklist"},{"formTitle":"[711]不同岛屿的数量 II","frontendQuestionId":"711","leaf":true,"level":3,"nodeType":"def","questionId":"711","status":"lock","title":"不同岛屿的数量 II","titleSlug":"number-of-distinct-islands-ii"},{"formTitle":"[712]两个字符串的最小ASCII删除和","frontendQuestionId":"712","leaf":true,"level":2,"nodeType":"def","questionId":"712","status":"","title":"两个字符串的最小ASCII删除和","titleSlug":"minimum-ascii-delete-sum-for-two-strings"},{"formTitle":"[713]乘积小于K的子数组","frontendQuestionId":"713","leaf":true,"level":2,"nodeType":"def","questionId":"713","status":"","title":"乘积小于K的子数组","titleSlug":"subarray-product-less-than-k"},{"formTitle":"[714]买卖股票的最佳时机含手续费","frontendQuestionId":"714","leaf":true,"level":2,"nodeType":"def","questionId":"714","status":"","title":"买卖股票的最佳时机含手续费","titleSlug":"best-time-to-buy-and-sell-stock-with-transaction-fee"},{"formTitle":"[715]Range 模块","frontendQuestionId":"715","leaf":true,"level":3,"nodeType":"def","questionId":"715","status":"","title":"Range 模块","titleSlug":"range-module"},{"formTitle":"[716]最大栈","frontendQuestionId":"716","leaf":true,"level":1,"nodeType":"def","questionId":"716","status":"lock","title":"最大栈","titleSlug":"max-stack"},{"formTitle":"[717]1比特与2比特字符","frontendQuestionId":"717","leaf":true,"level":1,"nodeType":"def","questionId":"717","status":"","title":"1比特与2比特字符","titleSlug":"1-bit-and-2-bit-characters"},{"formTitle":"[718]最长重复子数组","frontendQuestionId":"718","leaf":true,"level":2,"nodeType":"def","questionId":"718","status":"","title":"最长重复子数组","titleSlug":"maximum-length-of-repeated-subarray"},{"formTitle":"[719]找出第 k 小的距离对","frontendQuestionId":"719","leaf":true,"level":3,"nodeType":"def","questionId":"719","status":"","title":"找出第 k 小的距离对","titleSlug":"find-k-th-smallest-pair-distance"},{"formTitle":"[720]词典中最长的单词","frontendQuestionId":"720","leaf":true,"level":1,"nodeType":"def","questionId":"720","status":"","title":"词典中最长的单词","titleSlug":"longest-word-in-dictionary"},{"formTitle":"[721]账户合并","frontendQuestionId":"721","leaf":true,"level":2,"nodeType":"def","questionId":"721","status":"","title":"账户合并","titleSlug":"accounts-merge"},{"formTitle":"[722]删除注释","frontendQuestionId":"722","leaf":true,"level":2,"nodeType":"def","questionId":"722","status":"","title":"删除注释","titleSlug":"remove-comments"},{"formTitle":"[723]粉碎糖果","frontendQuestionId":"723","leaf":true,"level":2,"nodeType":"def","questionId":"723","status":"lock","title":"粉碎糖果","titleSlug":"candy-crush"},{"formTitle":"[724]寻找数组的中心索引","frontendQuestionId":"724","leaf":true,"level":1,"nodeType":"def","questionId":"724","status":"","title":"寻找数组的中心索引","titleSlug":"find-pivot-index"},{"formTitle":"[725]分隔链表","frontendQuestionId":"725","leaf":true,"level":2,"nodeType":"def","questionId":"725","status":"","title":"分隔链表","titleSlug":"split-linked-list-in-parts"},{"formTitle":"[726]原子的数量","frontendQuestionId":"726","leaf":true,"level":3,"nodeType":"def","questionId":"726","status":"","title":"原子的数量","titleSlug":"number-of-atoms"},{"formTitle":"[727]最小窗口子序列","frontendQuestionId":"727","leaf":true,"level":3,"nodeType":"def","questionId":"727","status":"lock","title":"最小窗口子序列","titleSlug":"minimum-window-subsequence"},{"formTitle":"[728]自除数","frontendQuestionId":"728","leaf":true,"level":1,"nodeType":"def","questionId":"728","status":"","title":"自除数","titleSlug":"self-dividing-numbers"},{"formTitle":"[729]我的日程安排表 I","frontendQuestionId":"729","leaf":true,"level":2,"nodeType":"def","questionId":"729","status":"","title":"我的日程安排表 I","titleSlug":"my-calendar-i"},{"formTitle":"[730]统计不同回文子字符串","frontendQuestionId":"730","leaf":true,"level":3,"nodeType":"def","questionId":"730","status":"","title":"统计不同回文子字符串","titleSlug":"count-different-palindromic-subsequences"},{"formTitle":"[731]我的日程安排表 II","frontendQuestionId":"731","leaf":true,"level":2,"nodeType":"def","questionId":"731","status":"","title":"我的日程安排表 II","titleSlug":"my-calendar-ii"},{"formTitle":"[732]我的日程安排表 III","frontendQuestionId":"732","leaf":true,"level":3,"nodeType":"def","questionId":"732","status":"","title":"我的日程安排表 III","titleSlug":"my-calendar-iii"},{"formTitle":"[733]图像渲染","frontendQuestionId":"733","leaf":true,"level":1,"nodeType":"def","questionId":"733","status":"","title":"图像渲染","titleSlug":"flood-fill"},{"formTitle":"[734]句子相似性","frontendQuestionId":"734","leaf":true,"level":1,"nodeType":"def","questionId":"734","status":"lock","title":"句子相似性","titleSlug":"sentence-similarity"},{"formTitle":"[735]行星碰撞","frontendQuestionId":"735","leaf":true,"level":2,"nodeType":"def","questionId":"735","status":"","title":"行星碰撞","titleSlug":"asteroid-collision"},{"formTitle":"[736]Lisp 语法解析","frontendQuestionId":"736","leaf":true,"level":3,"nodeType":"def","questionId":"736","status":"","title":"Lisp 语法解析","titleSlug":"parse-lisp-expression"},{"formTitle":"[737]句子相似性 II","frontendQuestionId":"737","leaf":true,"level":2,"nodeType":"def","questionId":"737","status":"lock","title":"句子相似性 II","titleSlug":"sentence-similarity-ii"},{"formTitle":"[738]单调递增的数字","frontendQuestionId":"738","leaf":true,"level":2,"nodeType":"def","questionId":"738","status":"","title":"单调递增的数字","titleSlug":"monotone-increasing-digits"},{"formTitle":"[739]每日温度","frontendQuestionId":"739","leaf":true,"level":2,"nodeType":"def","questionId":"739","status":"","title":"每日温度","titleSlug":"daily-temperatures"},{"formTitle":"[740]删除与获得点数","frontendQuestionId":"740","leaf":true,"level":2,"nodeType":"def","questionId":"740","status":"","title":"删除与获得点数","titleSlug":"delete-and-earn"},{"formTitle":"[741]摘樱桃","frontendQuestionId":"741","leaf":true,"level":3,"nodeType":"def","questionId":"741","status":"","title":"摘樱桃","titleSlug":"cherry-pickup"},{"formTitle":"[742]二叉树最近的叶节点","frontendQuestionId":"742","leaf":true,"level":2,"nodeType":"def","questionId":"743","status":"lock","title":"二叉树最近的叶节点","titleSlug":"closest-leaf-in-a-binary-tree"},{"formTitle":"[743]网络延迟时间","frontendQuestionId":"743","leaf":true,"level":2,"nodeType":"def","questionId":"744","status":"","title":"网络延迟时间","titleSlug":"network-delay-time"},{"formTitle":"[744]寻找比目标字母大的最小字母","frontendQuestionId":"744","leaf":true,"level":1,"nodeType":"def","questionId":"745","status":"","title":"寻找比目标字母大的最小字母","titleSlug":"find-smallest-letter-greater-than-target"},{"formTitle":"[745]前缀和后缀搜索","frontendQuestionId":"745","leaf":true,"level":3,"nodeType":"def","questionId":"746","status":"","title":"前缀和后缀搜索","titleSlug":"prefix-and-suffix-search"},{"formTitle":"[746]使用最小花费爬楼梯","frontendQuestionId":"746","leaf":true,"level":1,"nodeType":"def","questionId":"747","status":"","title":"使用最小花费爬楼梯","titleSlug":"min-cost-climbing-stairs"},{"formTitle":"[747]至少是其他数字两倍的最大数","frontendQuestionId":"747","leaf":true,"level":1,"nodeType":"def","questionId":"748","status":"","title":"至少是其他数字两倍的最大数","titleSlug":"largest-number-at-least-twice-of-others"},{"formTitle":"[748]最短完整词","frontendQuestionId":"748","leaf":true,"level":1,"nodeType":"def","questionId":"749","status":"","title":"最短完整词","titleSlug":"shortest-completing-word"},{"formTitle":"[749]隔离病毒","frontendQuestionId":"749","leaf":true,"level":3,"nodeType":"def","questionId":"750","status":"","title":"隔离病毒","titleSlug":"contain-virus"},{"formTitle":"[750]角矩形的数量","frontendQuestionId":"750","leaf":true,"level":2,"nodeType":"def","questionId":"751","status":"lock","title":"角矩形的数量","titleSlug":"number-of-corner-rectangles"},{"formTitle":"[751]IP 到 CIDR","frontendQuestionId":"751","leaf":true,"level":1,"nodeType":"def","questionId":"752","status":"lock","title":"IP 到 CIDR","titleSlug":"ip-to-cidr"},{"formTitle":"[752]打开转盘锁","frontendQuestionId":"752","leaf":true,"level":2,"nodeType":"def","questionId":"753","status":"","title":"打开转盘锁","titleSlug":"open-the-lock"},{"formTitle":"[753]破解保险箱","frontendQuestionId":"753","leaf":true,"level":3,"nodeType":"def","questionId":"754","status":"","title":"破解保险箱","titleSlug":"cracking-the-safe"},{"formTitle":"[754]到达终点数字","frontendQuestionId":"754","leaf":true,"level":1,"nodeType":"def","questionId":"755","status":"","title":"到达终点数字","titleSlug":"reach-a-number"},{"formTitle":"[755]倒水","frontendQuestionId":"755","leaf":true,"level":2,"nodeType":"def","questionId":"756","status":"lock","title":"倒水","titleSlug":"pour-water"},{"formTitle":"[756]金字塔转换矩阵","frontendQuestionId":"756","leaf":true,"level":2,"nodeType":"def","questionId":"757","status":"","title":"金字塔转换矩阵","titleSlug":"pyramid-transition-matrix"},{"formTitle":"[757] 设置交集大小至少为2","frontendQuestionId":"757","leaf":true,"level":3,"nodeType":"def","questionId":"759","status":"","title":" 设置交集大小至少为2","titleSlug":"set-intersection-size-at-least-two"},{"formTitle":"[758]字符串中的加粗单词","frontendQuestionId":"758","leaf":true,"level":1,"nodeType":"def","questionId":"760","status":"lock","title":"字符串中的加粗单词","titleSlug":"bold-words-in-string"},{"formTitle":"[759]员工空闲时间","frontendQuestionId":"759","leaf":true,"level":3,"nodeType":"def","questionId":"761","status":"lock","title":"员工空闲时间","titleSlug":"employee-free-time"},{"formTitle":"[760]找出变位映射","frontendQuestionId":"760","leaf":true,"level":1,"nodeType":"def","questionId":"762","status":"lock","title":"找出变位映射","titleSlug":"find-anagram-mappings"},{"formTitle":"[761]特殊的二进制序列","frontendQuestionId":"761","leaf":true,"level":3,"nodeType":"def","questionId":"763","status":"","title":"特殊的二进制序列","titleSlug":"special-binary-string"},{"formTitle":"[762]二进制表示中质数个计算置位","frontendQuestionId":"762","leaf":true,"level":1,"nodeType":"def","questionId":"767","status":"","title":"二进制表示中质数个计算置位","titleSlug":"prime-number-of-set-bits-in-binary-representation"},{"formTitle":"[763]划分字母区间","frontendQuestionId":"763","leaf":true,"level":2,"nodeType":"def","questionId":"768","status":"","title":"划分字母区间","titleSlug":"partition-labels"},{"formTitle":"[764]最大加号标志","frontendQuestionId":"764","leaf":true,"level":2,"nodeType":"def","questionId":"769","status":"","title":"最大加号标志","titleSlug":"largest-plus-sign"},{"formTitle":"[765]情侣牵手","frontendQuestionId":"765","leaf":true,"level":3,"nodeType":"def","questionId":"770","status":"","title":"情侣牵手","titleSlug":"couples-holding-hands"},{"formTitle":"[766]托普利茨矩阵","frontendQuestionId":"766","leaf":true,"level":1,"nodeType":"def","questionId":"777","status":"","title":"托普利茨矩阵","titleSlug":"toeplitz-matrix"},{"formTitle":"[767]重构字符串","frontendQuestionId":"767","leaf":true,"level":2,"nodeType":"def","questionId":"778","status":"","title":"重构字符串","titleSlug":"reorganize-string"},{"formTitle":"[768]最多能完成排序的块 II","frontendQuestionId":"768","leaf":true,"level":3,"nodeType":"def","questionId":"779","status":"","title":"最多能完成排序的块 II","titleSlug":"max-chunks-to-make-sorted-ii"},{"formTitle":"[769]最多能完成排序的块","frontendQuestionId":"769","leaf":true,"level":2,"nodeType":"def","questionId":"780","status":"","title":"最多能完成排序的块","titleSlug":"max-chunks-to-make-sorted"},{"formTitle":"[770]基本计算器 IV","frontendQuestionId":"770","leaf":true,"level":3,"nodeType":"def","questionId":"781","status":"","title":"基本计算器 IV","titleSlug":"basic-calculator-iv"},{"formTitle":"[771]宝石与石头","frontendQuestionId":"771","leaf":true,"level":1,"nodeType":"def","questionId":"782","status":"","title":"宝石与石头","titleSlug":"jewels-and-stones"},{"formTitle":"[772]基本计算器 III","frontendQuestionId":"772","leaf":true,"level":3,"nodeType":"def","questionId":"785","status":"lock","title":"基本计算器 III","titleSlug":"basic-calculator-iii"},{"formTitle":"[773]滑动谜题","frontendQuestionId":"773","leaf":true,"level":3,"nodeType":"def","questionId":"787","status":"","title":"滑动谜题","titleSlug":"sliding-puzzle"},{"formTitle":"[774]最小化去加油站的最大距离","frontendQuestionId":"774","leaf":true,"level":3,"nodeType":"def","questionId":"788","status":"lock","title":"最小化去加油站的最大距离","titleSlug":"minimize-max-distance-to-gas-station"},{"formTitle":"[775]全局倒置与局部倒置","frontendQuestionId":"775","leaf":true,"level":2,"nodeType":"def","questionId":"790","status":"","title":"全局倒置与局部倒置","titleSlug":"global-and-local-inversions"},{"formTitle":"[776]拆分二叉搜索树","frontendQuestionId":"776","leaf":true,"level":2,"nodeType":"def","questionId":"791","status":"lock","title":"拆分二叉搜索树","titleSlug":"split-bst"},{"formTitle":"[777]在LR字符串中交换相邻字符","frontendQuestionId":"777","leaf":true,"level":2,"nodeType":"def","questionId":"793","status":"","title":"在LR字符串中交换相邻字符","titleSlug":"swap-adjacent-in-lr-string"},{"formTitle":"[778]水位上升的泳池中游泳","frontendQuestionId":"778","leaf":true,"level":3,"nodeType":"def","questionId":"794","status":"","title":"水位上升的泳池中游泳","titleSlug":"swim-in-rising-water"},{"formTitle":"[779]第K个语法符号","frontendQuestionId":"779","leaf":true,"level":2,"nodeType":"def","questionId":"795","status":"","title":"第K个语法符号","titleSlug":"k-th-symbol-in-grammar"},{"formTitle":"[780]到达终点","frontendQuestionId":"780","leaf":true,"level":3,"nodeType":"def","questionId":"796","status":"","title":"到达终点","titleSlug":"reaching-points"},{"formTitle":"[781]森林中的兔子","frontendQuestionId":"781","leaf":true,"level":2,"nodeType":"def","questionId":"797","status":"","title":"森林中的兔子","titleSlug":"rabbits-in-forest"},{"formTitle":"[782]变为棋盘","frontendQuestionId":"782","leaf":true,"level":3,"nodeType":"def","questionId":"798","status":"","title":"变为棋盘","titleSlug":"transform-to-chessboard"},{"formTitle":"[783]二叉搜索树结点最小距离","frontendQuestionId":"783","leaf":true,"level":1,"nodeType":"def","questionId":"799","status":"","title":"二叉搜索树结点最小距离","titleSlug":"minimum-distance-between-bst-nodes"},{"formTitle":"[784]字母大小写全排列","frontendQuestionId":"784","leaf":true,"level":1,"nodeType":"def","questionId":"800","status":"","title":"字母大小写全排列","titleSlug":"letter-case-permutation"},{"formTitle":"[785]判断二分图","frontendQuestionId":"785","leaf":true,"level":2,"nodeType":"def","questionId":"801","status":"","title":"判断二分图","titleSlug":"is-graph-bipartite"},{"formTitle":"[786]第 K 个最小的素数分数","frontendQuestionId":"786","leaf":true,"level":3,"nodeType":"def","questionId":"802","status":"","title":"第 K 个最小的素数分数","titleSlug":"k-th-smallest-prime-fraction"},{"formTitle":"[787]K 站中转内最便宜的航班","frontendQuestionId":"787","leaf":true,"level":2,"nodeType":"def","questionId":"803","status":"","title":"K 站中转内最便宜的航班","titleSlug":"cheapest-flights-within-k-stops"},{"formTitle":"[788]旋转数字","frontendQuestionId":"788","leaf":true,"level":1,"nodeType":"def","questionId":"804","status":"","title":"旋转数字","titleSlug":"rotated-digits"},{"formTitle":"[789]逃脱阻碍者","frontendQuestionId":"789","leaf":true,"level":2,"nodeType":"def","questionId":"805","status":"","title":"逃脱阻碍者","titleSlug":"escape-the-ghosts"},{"formTitle":"[790]多米诺和托米诺平铺","frontendQuestionId":"790","leaf":true,"level":2,"nodeType":"def","questionId":"806","status":"","title":"多米诺和托米诺平铺","titleSlug":"domino-and-tromino-tiling"},{"formTitle":"[791]自定义字符串排序","frontendQuestionId":"791","leaf":true,"level":2,"nodeType":"def","questionId":"807","status":"","title":"自定义字符串排序","titleSlug":"custom-sort-string"},{"formTitle":"[792]匹配子序列的单词数","frontendQuestionId":"792","leaf":true,"level":2,"nodeType":"def","questionId":"808","status":"","title":"匹配子序列的单词数","titleSlug":"number-of-matching-subsequences"},{"formTitle":"[793]阶乘函数后K个零","frontendQuestionId":"793","leaf":true,"level":3,"nodeType":"def","questionId":"809","status":"","title":"阶乘函数后K个零","titleSlug":"preimage-size-of-factorial-zeroes-function"},{"formTitle":"[794]有效的井字游戏","frontendQuestionId":"794","leaf":true,"level":2,"nodeType":"def","questionId":"810","status":"","title":"有效的井字游戏","titleSlug":"valid-tic-tac-toe-state"},{"formTitle":"[795]区间子数组个数","frontendQuestionId":"795","leaf":true,"level":2,"nodeType":"def","questionId":"811","status":"","title":"区间子数组个数","titleSlug":"number-of-subarrays-with-bounded-maximum"},{"formTitle":"[796]旋转字符串","frontendQuestionId":"796","leaf":true,"level":1,"nodeType":"def","questionId":"812","status":"","title":"旋转字符串","titleSlug":"rotate-string"},{"formTitle":"[797]所有可能的路径","frontendQuestionId":"797","leaf":true,"level":2,"nodeType":"def","questionId":"813","status":"","title":"所有可能的路径","titleSlug":"all-paths-from-source-to-target"},{"formTitle":"[798]得分最高的最小轮调","frontendQuestionId":"798","leaf":true,"level":3,"nodeType":"def","questionId":"814","status":"","title":"得分最高的最小轮调","titleSlug":"smallest-rotation-with-highest-score"},{"formTitle":"[799]香槟塔","frontendQuestionId":"799","leaf":true,"level":2,"nodeType":"def","questionId":"815","status":"","title":"香槟塔","titleSlug":"champagne-tower"},{"formTitle":"[800]相似 RGB 颜色","frontendQuestionId":"800","leaf":true,"level":1,"nodeType":"def","questionId":"818","status":"lock","title":"相似 RGB 颜色","titleSlug":"similar-rgb-color"},{"formTitle":"[801]使序列递增的最小交换次数","frontendQuestionId":"801","leaf":true,"level":2,"nodeType":"def","questionId":"819","status":"","title":"使序列递增的最小交换次数","titleSlug":"minimum-swaps-to-make-sequences-increasing"},{"formTitle":"[802]找到最终的安全状态","frontendQuestionId":"802","leaf":true,"level":2,"nodeType":"def","questionId":"820","status":"","title":"找到最终的安全状态","titleSlug":"find-eventual-safe-states"},{"formTitle":"[803]打砖块","frontendQuestionId":"803","leaf":true,"level":3,"nodeType":"def","questionId":"821","status":"","title":"打砖块","titleSlug":"bricks-falling-when-hit"},{"formTitle":"[804]唯一摩尔斯密码词","frontendQuestionId":"804","leaf":true,"level":1,"nodeType":"def","questionId":"822","status":"","title":"唯一摩尔斯密码词","titleSlug":"unique-morse-code-words"},{"formTitle":"[805]数组的均值分割","frontendQuestionId":"805","leaf":true,"level":3,"nodeType":"def","questionId":"823","status":"","title":"数组的均值分割","titleSlug":"split-array-with-same-average"},{"formTitle":"[806]写字符串需要的行数","frontendQuestionId":"806","leaf":true,"level":1,"nodeType":"def","questionId":"824","status":"","title":"写字符串需要的行数","titleSlug":"number-of-lines-to-write-string"},{"formTitle":"[807]保持城市天际线","frontendQuestionId":"807","leaf":true,"level":2,"nodeType":"def","questionId":"825","status":"","title":"保持城市天际线","titleSlug":"max-increase-to-keep-city-skyline"},{"formTitle":"[808]分汤","frontendQuestionId":"808","leaf":true,"level":2,"nodeType":"def","questionId":"826","status":"","title":"分汤","titleSlug":"soup-servings"},{"formTitle":"[809]情感丰富的文字","frontendQuestionId":"809","leaf":true,"level":2,"nodeType":"def","questionId":"827","status":"","title":"情感丰富的文字","titleSlug":"expressive-words"},{"formTitle":"[810]黑板异或游戏","frontendQuestionId":"810","leaf":true,"level":3,"nodeType":"def","questionId":"828","status":"","title":"黑板异或游戏","titleSlug":"chalkboard-xor-game"},{"formTitle":"[811]子域名访问计数","frontendQuestionId":"811","leaf":true,"level":1,"nodeType":"def","questionId":"829","status":"","title":"子域名访问计数","titleSlug":"subdomain-visit-count"},{"formTitle":"[812]最大三角形面积","frontendQuestionId":"812","leaf":true,"level":1,"nodeType":"def","questionId":"830","status":"","title":"最大三角形面积","titleSlug":"largest-triangle-area"},{"formTitle":"[813]最大平均值和的分组","frontendQuestionId":"813","leaf":true,"level":2,"nodeType":"def","questionId":"831","status":"","title":"最大平均值和的分组","titleSlug":"largest-sum-of-averages"},{"formTitle":"[814]二叉树剪枝","frontendQuestionId":"814","leaf":true,"level":2,"nodeType":"def","questionId":"832","status":"","title":"二叉树剪枝","titleSlug":"binary-tree-pruning"},{"formTitle":"[815]公交路线","frontendQuestionId":"815","leaf":true,"level":3,"nodeType":"def","questionId":"833","status":"","title":"公交路线","titleSlug":"bus-routes"},{"formTitle":"[816]模糊坐标","frontendQuestionId":"816","leaf":true,"level":2,"nodeType":"def","questionId":"834","status":"","title":"模糊坐标","titleSlug":"ambiguous-coordinates"},{"formTitle":"[817]链表组件","frontendQuestionId":"817","leaf":true,"level":2,"nodeType":"def","questionId":"835","status":"","title":"链表组件","titleSlug":"linked-list-components"},{"formTitle":"[818]赛车","frontendQuestionId":"818","leaf":true,"level":3,"nodeType":"def","questionId":"836","status":"","title":"赛车","titleSlug":"race-car"},{"formTitle":"[819]最常见的单词","frontendQuestionId":"819","leaf":true,"level":1,"nodeType":"def","questionId":"837","status":"","title":"最常见的单词","titleSlug":"most-common-word"},{"formTitle":"[820]单词的压缩编码","frontendQuestionId":"820","leaf":true,"level":2,"nodeType":"def","questionId":"839","status":"","title":"单词的压缩编码","titleSlug":"short-encoding-of-words"},{"formTitle":"[821]字符的最短距离","frontendQuestionId":"821","leaf":true,"level":1,"nodeType":"def","questionId":"841","status":"","title":"字符的最短距离","titleSlug":"shortest-distance-to-a-character"},{"formTitle":"[822]翻转卡片游戏","frontendQuestionId":"822","leaf":true,"level":2,"nodeType":"def","questionId":"842","status":"","title":"翻转卡片游戏","titleSlug":"card-flipping-game"},{"formTitle":"[823]带因子的二叉树","frontendQuestionId":"823","leaf":true,"level":2,"nodeType":"def","questionId":"843","status":"","title":"带因子的二叉树","titleSlug":"binary-trees-with-factors"},{"formTitle":"[824]山羊拉丁文","frontendQuestionId":"824","leaf":true,"level":1,"nodeType":"def","questionId":"851","status":"","title":"山羊拉丁文","titleSlug":"goat-latin"},{"formTitle":"[825]适龄的朋友","frontendQuestionId":"825","leaf":true,"level":2,"nodeType":"def","questionId":"852","status":"","title":"适龄的朋友","titleSlug":"friends-of-appropriate-ages"},{"formTitle":"[826]安排工作以达到最大收益","frontendQuestionId":"826","leaf":true,"level":2,"nodeType":"def","questionId":"853","status":"","title":"安排工作以达到最大收益","titleSlug":"most-profit-assigning-work"},{"formTitle":"[827]最大人工岛","frontendQuestionId":"827","leaf":true,"level":3,"nodeType":"def","questionId":"854","status":"","title":"最大人工岛","titleSlug":"making-a-large-island"},{"formTitle":"[828]独特字符串","frontendQuestionId":"828","leaf":true,"level":3,"nodeType":"def","questionId":"855","status":"","title":"独特字符串","titleSlug":"unique-letter-string"},{"formTitle":"[829]连续整数求和","frontendQuestionId":"829","leaf":true,"level":3,"nodeType":"def","questionId":"856","status":"","title":"连续整数求和","titleSlug":"consecutive-numbers-sum"},{"formTitle":"[830]较大分组的位置","frontendQuestionId":"830","leaf":true,"level":1,"nodeType":"def","questionId":"857","status":"","title":"较大分组的位置","titleSlug":"positions-of-large-groups"},{"formTitle":"[831]隐藏个人信息","frontendQuestionId":"831","leaf":true,"level":2,"nodeType":"def","questionId":"858","status":"","title":"隐藏个人信息","titleSlug":"masking-personal-information"},{"formTitle":"[832]翻转图像","frontendQuestionId":"832","leaf":true,"level":1,"nodeType":"def","questionId":"861","status":"","title":"翻转图像","titleSlug":"flipping-an-image"},{"formTitle":"[833]字符串中的查找与替换","frontendQuestionId":"833","leaf":true,"level":2,"nodeType":"def","questionId":"862","status":"","title":"字符串中的查找与替换","titleSlug":"find-and-replace-in-string"},{"formTitle":"[834]树中距离之和","frontendQuestionId":"834","leaf":true,"level":3,"nodeType":"def","questionId":"863","status":"","title":"树中距离之和","titleSlug":"sum-of-distances-in-tree"},{"formTitle":"[835]图像重叠","frontendQuestionId":"835","leaf":true,"level":2,"nodeType":"def","questionId":"864","status":"","title":"图像重叠","titleSlug":"image-overlap"},{"formTitle":"[836]矩形重叠","frontendQuestionId":"836","leaf":true,"level":1,"nodeType":"def","questionId":"866","status":"","title":"矩形重叠","titleSlug":"rectangle-overlap"},{"formTitle":"[837]新21点","frontendQuestionId":"837","leaf":true,"level":2,"nodeType":"def","questionId":"867","status":"","title":"新21点","titleSlug":"new-21-game"},{"formTitle":"[838]推多米诺","frontendQuestionId":"838","leaf":true,"level":2,"nodeType":"def","questionId":"868","status":"","title":"推多米诺","titleSlug":"push-dominoes"},{"formTitle":"[839]相似字符串组","frontendQuestionId":"839","leaf":true,"level":3,"nodeType":"def","questionId":"869","status":"","title":"相似字符串组","titleSlug":"similar-string-groups"},{"formTitle":"[840]矩阵中的幻方","frontendQuestionId":"840","leaf":true,"level":1,"nodeType":"def","questionId":"870","status":"","title":"矩阵中的幻方","titleSlug":"magic-squares-in-grid"},{"formTitle":"[841]钥匙和房间","frontendQuestionId":"841","leaf":true,"level":2,"nodeType":"def","questionId":"871","status":"","title":"钥匙和房间","titleSlug":"keys-and-rooms"},{"formTitle":"[842]将数组拆分成斐波那契序列","frontendQuestionId":"842","leaf":true,"level":2,"nodeType":"def","questionId":"872","status":"","title":"将数组拆分成斐波那契序列","titleSlug":"split-array-into-fibonacci-sequence"},{"formTitle":"[843]猜猜这个单词","frontendQuestionId":"843","leaf":true,"level":3,"nodeType":"def","questionId":"873","status":"","title":"猜猜这个单词","titleSlug":"guess-the-word"},{"formTitle":"[844]比较含退格的字符串","frontendQuestionId":"844","leaf":true,"level":1,"nodeType":"def","questionId":"874","status":"","title":"比较含退格的字符串","titleSlug":"backspace-string-compare"},{"formTitle":"[845]数组中的最长山脉","frontendQuestionId":"845","leaf":true,"level":2,"nodeType":"def","questionId":"875","status":"","title":"数组中的最长山脉","titleSlug":"longest-mountain-in-array"},{"formTitle":"[846]一手顺子","frontendQuestionId":"846","leaf":true,"level":2,"nodeType":"def","questionId":"876","status":"","title":"一手顺子","titleSlug":"hand-of-straights"},{"formTitle":"[847]访问所有节点的最短路径","frontendQuestionId":"847","leaf":true,"level":3,"nodeType":"def","questionId":"877","status":"","title":"访问所有节点的最短路径","titleSlug":"shortest-path-visiting-all-nodes"},{"formTitle":"[848]字母移位","frontendQuestionId":"848","leaf":true,"level":2,"nodeType":"def","questionId":"878","status":"","title":"字母移位","titleSlug":"shifting-letters"},{"formTitle":"[849]到最近的人的最大距离","frontendQuestionId":"849","leaf":true,"level":1,"nodeType":"def","questionId":"879","status":"","title":"到最近的人的最大距离","titleSlug":"maximize-distance-to-closest-person"},{"formTitle":"[850]矩形面积 II","frontendQuestionId":"850","leaf":true,"level":3,"nodeType":"def","questionId":"880","status":"","title":"矩形面积 II","titleSlug":"rectangle-area-ii"},{"formTitle":"[851]喧闹和富有","frontendQuestionId":"851","leaf":true,"level":2,"nodeType":"def","questionId":"881","status":"","title":"喧闹和富有","titleSlug":"loud-and-rich"},{"formTitle":"[852]山脉数组的峰顶索引","frontendQuestionId":"852","leaf":true,"level":1,"nodeType":"def","questionId":"882","status":"","title":"山脉数组的峰顶索引","titleSlug":"peak-index-in-a-mountain-array"},{"formTitle":"[853]车队","frontendQuestionId":"853","leaf":true,"level":2,"nodeType":"def","questionId":"883","status":"","title":"车队","titleSlug":"car-fleet"},{"formTitle":"[854]相似度为 K 的字符串","frontendQuestionId":"854","leaf":true,"level":3,"nodeType":"def","questionId":"884","status":"","title":"相似度为 K 的字符串","titleSlug":"k-similar-strings"},{"formTitle":"[855]考场就座","frontendQuestionId":"855","leaf":true,"level":2,"nodeType":"def","questionId":"885","status":"","title":"考场就座","titleSlug":"exam-room"},{"formTitle":"[856]括号的分数","frontendQuestionId":"856","leaf":true,"level":2,"nodeType":"def","questionId":"886","status":"","title":"括号的分数","titleSlug":"score-of-parentheses"},{"formTitle":"[857]雇佣 K 名工人的最低成本","frontendQuestionId":"857","leaf":true,"level":3,"nodeType":"def","questionId":"887","status":"","title":"雇佣 K 名工人的最低成本","titleSlug":"minimum-cost-to-hire-k-workers"},{"formTitle":"[858]镜面反射","frontendQuestionId":"858","leaf":true,"level":2,"nodeType":"def","questionId":"888","status":"","title":"镜面反射","titleSlug":"mirror-reflection"},{"formTitle":"[859]亲密字符串","frontendQuestionId":"859","leaf":true,"level":1,"nodeType":"def","questionId":"889","status":"","title":"亲密字符串","titleSlug":"buddy-strings"},{"formTitle":"[860]柠檬水找零","frontendQuestionId":"860","leaf":true,"level":1,"nodeType":"def","questionId":"890","status":"","title":"柠檬水找零","titleSlug":"lemonade-change"},{"formTitle":"[861]翻转矩阵后的得分","frontendQuestionId":"861","leaf":true,"level":2,"nodeType":"def","questionId":"891","status":"","title":"翻转矩阵后的得分","titleSlug":"score-after-flipping-matrix"},{"formTitle":"[862]和至少为 K 的最短子数组","frontendQuestionId":"862","leaf":true,"level":3,"nodeType":"def","questionId":"892","status":"","title":"和至少为 K 的最短子数组","titleSlug":"shortest-subarray-with-sum-at-least-k"},{"formTitle":"[863]二叉树中所有距离为 K 的结点","frontendQuestionId":"863","leaf":true,"level":2,"nodeType":"def","questionId":"893","status":"","title":"二叉树中所有距离为 K 的结点","titleSlug":"all-nodes-distance-k-in-binary-tree"},{"formTitle":"[864]获取所有钥匙的最短路径","frontendQuestionId":"864","leaf":true,"level":3,"nodeType":"def","questionId":"895","status":"","title":"获取所有钥匙的最短路径","titleSlug":"shortest-path-to-get-all-keys"},{"formTitle":"[865]具有所有最深结点的最小子树","frontendQuestionId":"865","leaf":true,"level":2,"nodeType":"def","questionId":"896","status":"","title":"具有所有最深结点的最小子树","titleSlug":"smallest-subtree-with-all-the-deepest-nodes"},{"formTitle":"[866]回文素数","frontendQuestionId":"866","leaf":true,"level":2,"nodeType":"def","questionId":"897","status":"","title":"回文素数","titleSlug":"prime-palindrome"},{"formTitle":"[867]转置矩阵","frontendQuestionId":"867","leaf":true,"level":1,"nodeType":"def","questionId":"898","status":"","title":"转置矩阵","titleSlug":"transpose-matrix"},{"formTitle":"[868]二进制间距","frontendQuestionId":"868","leaf":true,"level":1,"nodeType":"def","questionId":"899","status":"","title":"二进制间距","titleSlug":"binary-gap"},{"formTitle":"[869]重新排序得到 2 的幂","frontendQuestionId":"869","leaf":true,"level":2,"nodeType":"def","questionId":"900","status":"","title":"重新排序得到 2 的幂","titleSlug":"reordered-power-of-2"},{"formTitle":"[870]优势洗牌","frontendQuestionId":"870","leaf":true,"level":2,"nodeType":"def","questionId":"901","status":"","title":"优势洗牌","titleSlug":"advantage-shuffle"},{"formTitle":"[871]最低加油次数","frontendQuestionId":"871","leaf":true,"level":3,"nodeType":"def","questionId":"902","status":"","title":"最低加油次数","titleSlug":"minimum-number-of-refueling-stops"},{"formTitle":"[872]叶子相似的树","frontendQuestionId":"872","leaf":true,"level":1,"nodeType":"def","questionId":"904","status":"","title":"叶子相似的树","titleSlug":"leaf-similar-trees"},{"formTitle":"[873]最长的斐波那契子序列的长度","frontendQuestionId":"873","leaf":true,"level":2,"nodeType":"def","questionId":"905","status":"","title":"最长的斐波那契子序列的长度","titleSlug":"length-of-longest-fibonacci-subsequence"},{"formTitle":"[874]模拟行走机器人","frontendQuestionId":"874","leaf":true,"level":1,"nodeType":"def","questionId":"906","status":"","title":"模拟行走机器人","titleSlug":"walking-robot-simulation"},{"formTitle":"[875]爱吃香蕉的珂珂","frontendQuestionId":"875","leaf":true,"level":2,"nodeType":"def","questionId":"907","status":"","title":"爱吃香蕉的珂珂","titleSlug":"koko-eating-bananas"},{"formTitle":"[876]链表的中间结点","frontendQuestionId":"876","leaf":true,"level":1,"nodeType":"def","questionId":"908","status":"","title":"链表的中间结点","titleSlug":"middle-of-the-linked-list"},{"formTitle":"[877]石子游戏","frontendQuestionId":"877","leaf":true,"level":2,"nodeType":"def","questionId":"909","status":"","title":"石子游戏","titleSlug":"stone-game"},{"formTitle":"[878]第 N 个神奇数字","frontendQuestionId":"878","leaf":true,"level":3,"nodeType":"def","questionId":"910","status":"","title":"第 N 个神奇数字","titleSlug":"nth-magical-number"},{"formTitle":"[879]盈利计划","frontendQuestionId":"879","leaf":true,"level":3,"nodeType":"def","questionId":"911","status":"","title":"盈利计划","titleSlug":"profitable-schemes"},{"formTitle":"[880]索引处的解码字符串","frontendQuestionId":"880","leaf":true,"level":2,"nodeType":"def","questionId":"916","status":"","title":"索引处的解码字符串","titleSlug":"decoded-string-at-index"},{"formTitle":"[881]救生艇","frontendQuestionId":"881","leaf":true,"level":2,"nodeType":"def","questionId":"917","status":"","title":"救生艇","titleSlug":"boats-to-save-people"},{"formTitle":"[882]细分图中的可到达结点","frontendQuestionId":"882","leaf":true,"level":3,"nodeType":"def","questionId":"918","status":"","title":"细分图中的可到达结点","titleSlug":"reachable-nodes-in-subdivided-graph"},{"formTitle":"[883]三维形体投影面积","frontendQuestionId":"883","leaf":true,"level":1,"nodeType":"def","questionId":"919","status":"","title":"三维形体投影面积","titleSlug":"projection-area-of-3d-shapes"},{"formTitle":"[884]两句话中的不常见单词","frontendQuestionId":"884","leaf":true,"level":1,"nodeType":"def","questionId":"920","status":"","title":"两句话中的不常见单词","titleSlug":"uncommon-words-from-two-sentences"},{"formTitle":"[885]螺旋矩阵 III","frontendQuestionId":"885","leaf":true,"level":2,"nodeType":"def","questionId":"921","status":"","title":"螺旋矩阵 III","titleSlug":"spiral-matrix-iii"},{"formTitle":"[886]可能的二分法","frontendQuestionId":"886","leaf":true,"level":2,"nodeType":"def","questionId":"922","status":"","title":"可能的二分法","titleSlug":"possible-bipartition"},{"formTitle":"[887]鸡蛋掉落","frontendQuestionId":"887","leaf":true,"level":3,"nodeType":"def","questionId":"923","status":"","title":"鸡蛋掉落","titleSlug":"super-egg-drop"},{"formTitle":"[888]公平的糖果交换","frontendQuestionId":"888","leaf":true,"level":1,"nodeType":"def","questionId":"924","status":"","title":"公平的糖果交换","titleSlug":"fair-candy-swap"},{"formTitle":"[889]根据前序和后序遍历构造二叉树","frontendQuestionId":"889","leaf":true,"level":2,"nodeType":"def","questionId":"925","status":"","title":"根据前序和后序遍历构造二叉树","titleSlug":"construct-binary-tree-from-preorder-and-postorder-traversal"},{"formTitle":"[890]查找和替换模式","frontendQuestionId":"890","leaf":true,"level":2,"nodeType":"def","questionId":"926","status":"","title":"查找和替换模式","titleSlug":"find-and-replace-pattern"},{"formTitle":"[891]子序列宽度之和","frontendQuestionId":"891","leaf":true,"level":3,"nodeType":"def","questionId":"927","status":"","title":"子序列宽度之和","titleSlug":"sum-of-subsequence-widths"},{"formTitle":"[892]三维形体的表面积","frontendQuestionId":"892","leaf":true,"level":1,"nodeType":"def","questionId":"928","status":"","title":"三维形体的表面积","titleSlug":"surface-area-of-3d-shapes"},{"formTitle":"[893]特殊等价字符串组","frontendQuestionId":"893","leaf":true,"level":1,"nodeType":"def","questionId":"929","status":"","title":"特殊等价字符串组","titleSlug":"groups-of-special-equivalent-strings"},{"formTitle":"[894]所有可能的满二叉树","frontendQuestionId":"894","leaf":true,"level":2,"nodeType":"def","questionId":"930","status":"","title":"所有可能的满二叉树","titleSlug":"all-possible-full-binary-trees"},{"formTitle":"[895]最大频率栈","frontendQuestionId":"895","leaf":true,"level":3,"nodeType":"def","questionId":"931","status":"","title":"最大频率栈","titleSlug":"maximum-frequency-stack"},{"formTitle":"[896]单调数列","frontendQuestionId":"896","leaf":true,"level":1,"nodeType":"def","questionId":"932","status":"","title":"单调数列","titleSlug":"monotonic-array"},{"formTitle":"[897]递增顺序查找树","frontendQuestionId":"897","leaf":true,"level":1,"nodeType":"def","questionId":"933","status":"","title":"递增顺序查找树","titleSlug":"increasing-order-search-tree"},{"formTitle":"[898]子数组按位或操作","frontendQuestionId":"898","leaf":true,"level":2,"nodeType":"def","questionId":"934","status":"","title":"子数组按位或操作","titleSlug":"bitwise-ors-of-subarrays"},{"formTitle":"[899]有序队列","frontendQuestionId":"899","leaf":true,"level":3,"nodeType":"def","questionId":"935","status":"","title":"有序队列","titleSlug":"orderly-queue"},{"formTitle":"[900]RLE 迭代器","frontendQuestionId":"900","leaf":true,"level":2,"nodeType":"def","questionId":"936","status":"","title":"RLE 迭代器","titleSlug":"rle-iterator"},{"formTitle":"[901]股票价格跨度","frontendQuestionId":"901","leaf":true,"level":2,"nodeType":"def","questionId":"937","status":"","title":"股票价格跨度","titleSlug":"online-stock-span"},{"formTitle":"[902]最大为 N 的数字组合","frontendQuestionId":"902","leaf":true,"level":3,"nodeType":"def","questionId":"938","status":"","title":"最大为 N 的数字组合","titleSlug":"numbers-at-most-n-given-digit-set"},{"formTitle":"[903]DI 序列的有效排列","frontendQuestionId":"903","leaf":true,"level":3,"nodeType":"def","questionId":"939","status":"","title":"DI 序列的有效排列","titleSlug":"valid-permutations-for-di-sequence"},{"formTitle":"[904]水果成篮","frontendQuestionId":"904","leaf":true,"level":2,"nodeType":"def","questionId":"940","status":"","title":"水果成篮","titleSlug":"fruit-into-baskets"},{"formTitle":"[905]按奇偶排序数组","frontendQuestionId":"905","leaf":true,"level":1,"nodeType":"def","questionId":"941","status":"","title":"按奇偶排序数组","titleSlug":"sort-array-by-parity"},{"formTitle":"[906]超级回文数","frontendQuestionId":"906","leaf":true,"level":3,"nodeType":"def","questionId":"942","status":"","title":"超级回文数","titleSlug":"super-palindromes"},{"formTitle":"[907]子数组的最小值之和","frontendQuestionId":"907","leaf":true,"level":2,"nodeType":"def","questionId":"943","status":"","title":"子数组的最小值之和","titleSlug":"sum-of-subarray-minimums"},{"formTitle":"[908]最小差值 I","frontendQuestionId":"908","leaf":true,"level":1,"nodeType":"def","questionId":"944","status":"","title":"最小差值 I","titleSlug":"smallest-range-i"},{"formTitle":"[909]蛇梯棋","frontendQuestionId":"909","leaf":true,"level":2,"nodeType":"def","questionId":"945","status":"","title":"蛇梯棋","titleSlug":"snakes-and-ladders"},{"formTitle":"[910]最小差值 II","frontendQuestionId":"910","leaf":true,"level":2,"nodeType":"def","questionId":"946","status":"","title":"最小差值 II","titleSlug":"smallest-range-ii"},{"formTitle":"[911]在线选举","frontendQuestionId":"911","leaf":true,"level":2,"nodeType":"def","questionId":"947","status":"","title":"在线选举","titleSlug":"online-election"},{"formTitle":"[912]排序数组","frontendQuestionId":"912","leaf":true,"level":2,"nodeType":"def","questionId":"948","status":"","title":"排序数组","titleSlug":"sort-an-array"},{"formTitle":"[913]猫和老鼠","frontendQuestionId":"913","leaf":true,"level":3,"nodeType":"def","questionId":"949","status":"","title":"猫和老鼠","titleSlug":"cat-and-mouse"},{"formTitle":"[914]卡牌分组","frontendQuestionId":"914","leaf":true,"level":1,"nodeType":"def","questionId":"950","status":"","title":"卡牌分组","titleSlug":"x-of-a-kind-in-a-deck-of-cards"},{"formTitle":"[915]分割数组","frontendQuestionId":"915","leaf":true,"level":2,"nodeType":"def","questionId":"951","status":"","title":"分割数组","titleSlug":"partition-array-into-disjoint-intervals"},{"formTitle":"[916]单词子集","frontendQuestionId":"916","leaf":true,"level":2,"nodeType":"def","questionId":"952","status":"","title":"单词子集","titleSlug":"word-subsets"},{"formTitle":"[917]仅仅反转字母","frontendQuestionId":"917","leaf":true,"level":1,"nodeType":"def","questionId":"953","status":"","title":"仅仅反转字母","titleSlug":"reverse-only-letters"},{"formTitle":"[918]环形子数组的最大和","frontendQuestionId":"918","leaf":true,"level":2,"nodeType":"def","questionId":"954","status":"","title":"环形子数组的最大和","titleSlug":"maximum-sum-circular-subarray"},{"formTitle":"[919]完全二叉树插入器","frontendQuestionId":"919","leaf":true,"level":2,"nodeType":"def","questionId":"955","status":"","title":"完全二叉树插入器","titleSlug":"complete-binary-tree-inserter"},{"formTitle":"[920]播放列表的数量","frontendQuestionId":"920","leaf":true,"level":3,"nodeType":"def","questionId":"956","status":"","title":"播放列表的数量","titleSlug":"number-of-music-playlists"},{"formTitle":"[921]使括号有效的最少添加","frontendQuestionId":"921","leaf":true,"level":2,"nodeType":"def","questionId":"957","status":"","title":"使括号有效的最少添加","titleSlug":"minimum-add-to-make-parentheses-valid"},{"formTitle":"[922]按奇偶排序数组 II","frontendQuestionId":"922","leaf":true,"level":1,"nodeType":"def","questionId":"958","status":"","title":"按奇偶排序数组 II","titleSlug":"sort-array-by-parity-ii"},{"formTitle":"[923]三数之和的多种可能","frontendQuestionId":"923","leaf":true,"level":2,"nodeType":"def","questionId":"959","status":"","title":"三数之和的多种可能","titleSlug":"3sum-with-multiplicity"},{"formTitle":"[924]尽量减少恶意软件的传播","frontendQuestionId":"924","leaf":true,"level":3,"nodeType":"def","questionId":"960","status":"","title":"尽量减少恶意软件的传播","titleSlug":"minimize-malware-spread"},{"formTitle":"[925]长按键入","frontendQuestionId":"925","leaf":true,"level":1,"nodeType":"def","questionId":"961","status":"","title":"长按键入","titleSlug":"long-pressed-name"},{"formTitle":"[926]将字符串翻转到单调递增","frontendQuestionId":"926","leaf":true,"level":2,"nodeType":"def","questionId":"962","status":"","title":"将字符串翻转到单调递增","titleSlug":"flip-string-to-monotone-increasing"},{"formTitle":"[927]三等分","frontendQuestionId":"927","leaf":true,"level":3,"nodeType":"def","questionId":"963","status":"","title":"三等分","titleSlug":"three-equal-parts"},{"formTitle":"[928]尽量减少恶意软件的传播 II","frontendQuestionId":"928","leaf":true,"level":3,"nodeType":"def","questionId":"964","status":"","title":"尽量减少恶意软件的传播 II","titleSlug":"minimize-malware-spread-ii"},{"formTitle":"[929]独特的电子邮件地址","frontendQuestionId":"929","leaf":true,"level":1,"nodeType":"def","questionId":"965","status":"","title":"独特的电子邮件地址","titleSlug":"unique-email-addresses"},{"formTitle":"[930]和相同的二元子数组","frontendQuestionId":"930","leaf":true,"level":2,"nodeType":"def","questionId":"966","status":"","title":"和相同的二元子数组","titleSlug":"binary-subarrays-with-sum"},{"formTitle":"[931]下降路径最小和","frontendQuestionId":"931","leaf":true,"level":2,"nodeType":"def","questionId":"967","status":"","title":"下降路径最小和","titleSlug":"minimum-falling-path-sum"},{"formTitle":"[932]漂亮数组","frontendQuestionId":"932","leaf":true,"level":2,"nodeType":"def","questionId":"968","status":"","title":"漂亮数组","titleSlug":"beautiful-array"},{"formTitle":"[933]最近的请求次数","frontendQuestionId":"933","leaf":true,"level":1,"nodeType":"def","questionId":"969","status":"","title":"最近的请求次数","titleSlug":"number-of-recent-calls"},{"formTitle":"[934]最短的桥","frontendQuestionId":"934","leaf":true,"level":2,"nodeType":"def","questionId":"971","status":"","title":"最短的桥","titleSlug":"shortest-bridge"},{"formTitle":"[935]骑士拨号器","frontendQuestionId":"935","leaf":true,"level":2,"nodeType":"def","questionId":"972","status":"","title":"骑士拨号器","titleSlug":"knight-dialer"},{"formTitle":"[936]戳印序列","frontendQuestionId":"936","leaf":true,"level":3,"nodeType":"def","questionId":"973","status":"","title":"戳印序列","titleSlug":"stamping-the-sequence"},{"formTitle":"[937]重新排列日志文件","frontendQuestionId":"937","leaf":true,"level":1,"nodeType":"def","questionId":"974","status":"","title":"重新排列日志文件","titleSlug":"reorder-data-in-log-files"},{"formTitle":"[938]二叉搜索树的范围和","frontendQuestionId":"938","leaf":true,"level":1,"nodeType":"def","questionId":"975","status":"","title":"二叉搜索树的范围和","titleSlug":"range-sum-of-bst"},{"formTitle":"[939]最小面积矩形","frontendQuestionId":"939","leaf":true,"level":2,"nodeType":"def","questionId":"976","status":"","title":"最小面积矩形","titleSlug":"minimum-area-rectangle"},{"formTitle":"[940]不同的子序列 II","frontendQuestionId":"940","leaf":true,"level":3,"nodeType":"def","questionId":"977","status":"","title":"不同的子序列 II","titleSlug":"distinct-subsequences-ii"},{"formTitle":"[941]有效的山脉数组","frontendQuestionId":"941","leaf":true,"level":1,"nodeType":"def","questionId":"978","status":"","title":"有效的山脉数组","titleSlug":"valid-mountain-array"},{"formTitle":"[942]增减字符串匹配","frontendQuestionId":"942","leaf":true,"level":1,"nodeType":"def","questionId":"979","status":"","title":"增减字符串匹配","titleSlug":"di-string-match"},{"formTitle":"[943]最短超级串","frontendQuestionId":"943","leaf":true,"level":3,"nodeType":"def","questionId":"980","status":"","title":"最短超级串","titleSlug":"find-the-shortest-superstring"},{"formTitle":"[944]删列造序","frontendQuestionId":"944","leaf":true,"level":1,"nodeType":"def","questionId":"981","status":"","title":"删列造序","titleSlug":"delete-columns-to-make-sorted"},{"formTitle":"[945]使数组唯一的最小增量","frontendQuestionId":"945","leaf":true,"level":2,"nodeType":"def","questionId":"982","status":"","title":"使数组唯一的最小增量","titleSlug":"minimum-increment-to-make-array-unique"},{"formTitle":"[946]验证栈序列","frontendQuestionId":"946","leaf":true,"level":2,"nodeType":"def","questionId":"983","status":"","title":"验证栈序列","titleSlug":"validate-stack-sequences"},{"formTitle":"[947]移除最多的同行或同列石头","frontendQuestionId":"947","leaf":true,"level":2,"nodeType":"def","questionId":"984","status":"","title":"移除最多的同行或同列石头","titleSlug":"most-stones-removed-with-same-row-or-column"},{"formTitle":"[948]令牌放置","frontendQuestionId":"948","leaf":true,"level":2,"nodeType":"def","questionId":"985","status":"","title":"令牌放置","titleSlug":"bag-of-tokens"},{"formTitle":"[949]给定数字能组成的最大时间","frontendQuestionId":"949","leaf":true,"level":1,"nodeType":"def","questionId":"986","status":"","title":"给定数字能组成的最大时间","titleSlug":"largest-time-for-given-digits"},{"formTitle":"[950]按递增顺序显示卡牌","frontendQuestionId":"950","leaf":true,"level":2,"nodeType":"def","questionId":"987","status":"","title":"按递增顺序显示卡牌","titleSlug":"reveal-cards-in-increasing-order"},{"formTitle":"[951]翻转等价二叉树","frontendQuestionId":"951","leaf":true,"level":2,"nodeType":"def","questionId":"988","status":"","title":"翻转等价二叉树","titleSlug":"flip-equivalent-binary-trees"},{"formTitle":"[952]按公因数计算最大组件大小","frontendQuestionId":"952","leaf":true,"level":3,"nodeType":"def","questionId":"989","status":"","title":"按公因数计算最大组件大小","titleSlug":"largest-component-size-by-common-factor"},{"formTitle":"[953]验证外星语词典","frontendQuestionId":"953","leaf":true,"level":1,"nodeType":"def","questionId":"990","status":"","title":"验证外星语词典","titleSlug":"verifying-an-alien-dictionary"},{"formTitle":"[954]二倍数对数组","frontendQuestionId":"954","leaf":true,"level":2,"nodeType":"def","questionId":"991","status":"","title":"二倍数对数组","titleSlug":"array-of-doubled-pairs"},{"formTitle":"[955]删列造序 II","frontendQuestionId":"955","leaf":true,"level":2,"nodeType":"def","questionId":"992","status":"","title":"删列造序 II","titleSlug":"delete-columns-to-make-sorted-ii"},{"formTitle":"[956]最高的广告牌","frontendQuestionId":"956","leaf":true,"level":3,"nodeType":"def","questionId":"993","status":"","title":"最高的广告牌","titleSlug":"tallest-billboard"},{"formTitle":"[957]N 天后的牢房","frontendQuestionId":"957","leaf":true,"level":2,"nodeType":"def","questionId":"994","status":"","title":"N 天后的牢房","titleSlug":"prison-cells-after-n-days"},{"formTitle":"[958]二叉树的完全性检验","frontendQuestionId":"958","leaf":true,"level":2,"nodeType":"def","questionId":"998","status":"","title":"二叉树的完全性检验","titleSlug":"check-completeness-of-a-binary-tree"},{"formTitle":"[959]由斜杠划分区域","frontendQuestionId":"959","leaf":true,"level":2,"nodeType":"def","questionId":"999","status":"","title":"由斜杠划分区域","titleSlug":"regions-cut-by-slashes"},{"formTitle":"[960]删列造序 III","frontendQuestionId":"960","leaf":true,"level":3,"nodeType":"def","questionId":"1000","status":"","title":"删列造序 III","titleSlug":"delete-columns-to-make-sorted-iii"},{"formTitle":"[961]重复 N 次的元素","frontendQuestionId":"961","leaf":true,"level":1,"nodeType":"def","questionId":"1001","status":"","title":"重复 N 次的元素","titleSlug":"n-repeated-element-in-size-2n-array"},{"formTitle":"[962]最大宽度坡","frontendQuestionId":"962","leaf":true,"level":2,"nodeType":"def","questionId":"1002","status":"","title":"最大宽度坡","titleSlug":"maximum-width-ramp"},{"formTitle":"[963]最小面积矩形 II","frontendQuestionId":"963","leaf":true,"level":2,"nodeType":"def","questionId":"1003","status":"","title":"最小面积矩形 II","titleSlug":"minimum-area-rectangle-ii"},{"formTitle":"[964]表示数字的最少运算符","frontendQuestionId":"964","leaf":true,"level":3,"nodeType":"def","questionId":"1004","status":"","title":"表示数字的最少运算符","titleSlug":"least-operators-to-express-number"},{"formTitle":"[965]单值二叉树","frontendQuestionId":"965","leaf":true,"level":1,"nodeType":"def","questionId":"1005","status":"","title":"单值二叉树","titleSlug":"univalued-binary-tree"},{"formTitle":"[966]元音拼写检查器","frontendQuestionId":"966","leaf":true,"level":2,"nodeType":"def","questionId":"1006","status":"","title":"元音拼写检查器","titleSlug":"vowel-spellchecker"},{"formTitle":"[967]连续差相同的数字","frontendQuestionId":"967","leaf":true,"level":2,"nodeType":"def","questionId":"1007","status":"","title":"连续差相同的数字","titleSlug":"numbers-with-same-consecutive-differences"},{"formTitle":"[968]监控二叉树","frontendQuestionId":"968","leaf":true,"level":3,"nodeType":"def","questionId":"1008","status":"","title":"监控二叉树","titleSlug":"binary-tree-cameras"},{"formTitle":"[969]煎饼排序","frontendQuestionId":"969","leaf":true,"level":2,"nodeType":"def","questionId":"1009","status":"","title":"煎饼排序","titleSlug":"pancake-sorting"},{"formTitle":"[970]强整数","frontendQuestionId":"970","leaf":true,"level":1,"nodeType":"def","questionId":"1010","status":"","title":"强整数","titleSlug":"powerful-integers"},{"formTitle":"[971]翻转二叉树以匹配先序遍历","frontendQuestionId":"971","leaf":true,"level":2,"nodeType":"def","questionId":"1011","status":"","title":"翻转二叉树以匹配先序遍历","titleSlug":"flip-binary-tree-to-match-preorder-traversal"},{"formTitle":"[972]相等的有理数","frontendQuestionId":"972","leaf":true,"level":3,"nodeType":"def","questionId":"1012","status":"","title":"相等的有理数","titleSlug":"equal-rational-numbers"},{"formTitle":"[973]最接近原点的 K 个点","frontendQuestionId":"973","leaf":true,"level":2,"nodeType":"def","questionId":"1014","status":"","title":"最接近原点的 K 个点","titleSlug":"k-closest-points-to-origin"},{"formTitle":"[974]和可被 K 整除的子数组","frontendQuestionId":"974","leaf":true,"level":2,"nodeType":"def","questionId":"1016","status":"","title":"和可被 K 整除的子数组","titleSlug":"subarray-sums-divisible-by-k"},{"formTitle":"[975]奇偶跳","frontendQuestionId":"975","leaf":true,"level":3,"nodeType":"def","questionId":"1017","status":"","title":"奇偶跳","titleSlug":"odd-even-jump"},{"formTitle":"[976]三角形的最大周长","frontendQuestionId":"976","leaf":true,"level":1,"nodeType":"def","questionId":"1018","status":"","title":"三角形的最大周长","titleSlug":"largest-perimeter-triangle"},{"formTitle":"[977]有序数组的平方","frontendQuestionId":"977","leaf":true,"level":1,"nodeType":"def","questionId":"1019","status":"","title":"有序数组的平方","titleSlug":"squares-of-a-sorted-array"},{"formTitle":"[978]最长湍流子数组","frontendQuestionId":"978","leaf":true,"level":2,"nodeType":"def","questionId":"1020","status":"","title":"最长湍流子数组","titleSlug":"longest-turbulent-subarray"},{"formTitle":"[979]在二叉树中分配硬币","frontendQuestionId":"979","leaf":true,"level":2,"nodeType":"def","questionId":"1021","status":"","title":"在二叉树中分配硬币","titleSlug":"distribute-coins-in-binary-tree"},{"formTitle":"[980]不同路径 III","frontendQuestionId":"980","leaf":true,"level":3,"nodeType":"def","questionId":"1022","status":"","title":"不同路径 III","titleSlug":"unique-paths-iii"},{"formTitle":"[981]基于时间的键值存储","frontendQuestionId":"981","leaf":true,"level":2,"nodeType":"def","questionId":"1023","status":"","title":"基于时间的键值存储","titleSlug":"time-based-key-value-store"},{"formTitle":"[982]按位与为零的三元组","frontendQuestionId":"982","leaf":true,"level":3,"nodeType":"def","questionId":"1024","status":"","title":"按位与为零的三元组","titleSlug":"triples-with-bitwise-and-equal-to-zero"},{"formTitle":"[983]最低票价","frontendQuestionId":"983","leaf":true,"level":2,"nodeType":"def","questionId":"1025","status":"","title":"最低票价","titleSlug":"minimum-cost-for-tickets"},{"formTitle":"[984]不含 AAA 或 BBB 的字符串","frontendQuestionId":"984","leaf":true,"level":2,"nodeType":"def","questionId":"1026","status":"","title":"不含 AAA 或 BBB 的字符串","titleSlug":"string-without-aaa-or-bbb"},{"formTitle":"[985]查询后的偶数和","frontendQuestionId":"985","leaf":true,"level":1,"nodeType":"def","questionId":"1027","status":"","title":"查询后的偶数和","titleSlug":"sum-of-even-numbers-after-queries"},{"formTitle":"[986]区间列表的交集","frontendQuestionId":"986","leaf":true,"level":2,"nodeType":"def","questionId":"1028","status":"","title":"区间列表的交集","titleSlug":"interval-list-intersections"},{"formTitle":"[987]二叉树的垂序遍历","frontendQuestionId":"987","leaf":true,"level":2,"nodeType":"def","questionId":"1029","status":"","title":"二叉树的垂序遍历","titleSlug":"vertical-order-traversal-of-a-binary-tree"},{"formTitle":"[988]从叶结点开始的最小字符串","frontendQuestionId":"988","leaf":true,"level":2,"nodeType":"def","questionId":"1030","status":"","title":"从叶结点开始的最小字符串","titleSlug":"smallest-string-starting-from-leaf"},{"formTitle":"[989]数组形式的整数加法","frontendQuestionId":"989","leaf":true,"level":1,"nodeType":"def","questionId":"1031","status":"","title":"数组形式的整数加法","titleSlug":"add-to-array-form-of-integer"},{"formTitle":"[990]等式方程的可满足性","frontendQuestionId":"990","leaf":true,"level":2,"nodeType":"def","questionId":"1032","status":"","title":"等式方程的可满足性","titleSlug":"satisfiability-of-equality-equations"},{"formTitle":"[991]坏了的计算器","frontendQuestionId":"991","leaf":true,"level":2,"nodeType":"def","questionId":"1033","status":"","title":"坏了的计算器","titleSlug":"broken-calculator"},{"formTitle":"[992]K 个不同整数的子数组","frontendQuestionId":"992","leaf":true,"level":3,"nodeType":"def","questionId":"1034","status":"","title":"K 个不同整数的子数组","titleSlug":"subarrays-with-k-different-integers"},{"formTitle":"[993]二叉树的堂兄弟节点","frontendQuestionId":"993","leaf":true,"level":1,"nodeType":"def","questionId":"1035","status":"","title":"二叉树的堂兄弟节点","titleSlug":"cousins-in-binary-tree"},{"formTitle":"[994]腐烂的橘子","frontendQuestionId":"994","leaf":true,"level":1,"nodeType":"def","questionId":"1036","status":"","title":"腐烂的橘子","titleSlug":"rotting-oranges"},{"formTitle":"[995]K 连续位的最小翻转次数","frontendQuestionId":"995","leaf":true,"level":3,"nodeType":"def","questionId":"1037","status":"","title":"K 连续位的最小翻转次数","titleSlug":"minimum-number-of-k-consecutive-bit-flips"},{"formTitle":"[996]正方形数组的数目","frontendQuestionId":"996","leaf":true,"level":3,"nodeType":"def","questionId":"1038","status":"","title":"正方形数组的数目","titleSlug":"number-of-squareful-arrays"},{"formTitle":"[997]找到小镇的法官","frontendQuestionId":"997","leaf":true,"level":1,"nodeType":"def","questionId":"1039","status":"","title":"找到小镇的法官","titleSlug":"find-the-town-judge"},{"formTitle":"[998]最大二叉树 II","frontendQuestionId":"998","leaf":true,"level":2,"nodeType":"def","questionId":"1040","status":"","title":"最大二叉树 II","titleSlug":"maximum-binary-tree-ii"},{"formTitle":"[999]车的可用捕获量","frontendQuestionId":"999","leaf":true,"level":1,"nodeType":"def","questionId":"1041","status":"","title":"车的可用捕获量","titleSlug":"available-captures-for-rook"},{"formTitle":"[1000]合并石头的最低成本","frontendQuestionId":"1000","leaf":true,"level":3,"nodeType":"def","questionId":"1042","status":"","title":"合并石头的最低成本","titleSlug":"minimum-cost-to-merge-stones"},{"formTitle":"[1001]网格照明","frontendQuestionId":"1001","leaf":true,"level":3,"nodeType":"def","questionId":"1043","status":"","title":"网格照明","titleSlug":"grid-illumination"},{"formTitle":"[1002]查找常用字符","frontendQuestionId":"1002","leaf":true,"level":1,"nodeType":"def","questionId":"1044","status":"","title":"查找常用字符","titleSlug":"find-common-characters"},{"formTitle":"[1003]检查替换后的词是否有效","frontendQuestionId":"1003","leaf":true,"level":2,"nodeType":"def","questionId":"1045","status":"","title":"检查替换后的词是否有效","titleSlug":"check-if-word-is-valid-after-substitutions"},{"formTitle":"[1004]最大连续1的个数 III","frontendQuestionId":"1004","leaf":true,"level":2,"nodeType":"def","questionId":"1046","status":"","title":"最大连续1的个数 III","titleSlug":"max-consecutive-ones-iii"},{"formTitle":"[1005]K 次取反后最大化的数组和","frontendQuestionId":"1005","leaf":true,"level":1,"nodeType":"def","questionId":"1047","status":"","title":"K 次取反后最大化的数组和","titleSlug":"maximize-sum-of-array-after-k-negations"},{"formTitle":"[1006]笨阶乘","frontendQuestionId":"1006","leaf":true,"level":2,"nodeType":"def","questionId":"1048","status":"","title":"笨阶乘","titleSlug":"clumsy-factorial"},{"formTitle":"[1007]行相等的最少多米诺旋转","frontendQuestionId":"1007","leaf":true,"level":2,"nodeType":"def","questionId":"1049","status":"","title":"行相等的最少多米诺旋转","titleSlug":"minimum-domino-rotations-for-equal-row"},{"formTitle":"[1008]先序遍历构造二叉树","frontendQuestionId":"1008","leaf":true,"level":2,"nodeType":"def","questionId":"1050","status":"","title":"先序遍历构造二叉树","titleSlug":"construct-binary-search-tree-from-preorder-traversal"},{"formTitle":"[1009]十进制整数的反码","frontendQuestionId":"1009","leaf":true,"level":1,"nodeType":"def","questionId":"1054","status":"","title":"十进制整数的反码","titleSlug":"complement-of-base-10-integer"},{"formTitle":"[1010]总持续时间可被 60 整除的歌曲","frontendQuestionId":"1010","leaf":true,"level":1,"nodeType":"def","questionId":"1055","status":"","title":"总持续时间可被 60 整除的歌曲","titleSlug":"pairs-of-songs-with-total-durations-divisible-by-60"},{"formTitle":"[1011]在 D 天内送达包裹的能力","frontendQuestionId":"1011","leaf":true,"level":2,"nodeType":"def","questionId":"1056","status":"","title":"在 D 天内送达包裹的能力","titleSlug":"capacity-to-ship-packages-within-d-days"},{"formTitle":"[1012]至少有 1 位重复的数字","frontendQuestionId":"1012","leaf":true,"level":3,"nodeType":"def","questionId":"1057","status":"","title":"至少有 1 位重复的数字","titleSlug":"numbers-with-repeated-digits"},{"formTitle":"[1013]将数组分成和相等的三个部分","frontendQuestionId":"1013","leaf":true,"level":1,"nodeType":"def","questionId":"1062","status":"","title":"将数组分成和相等的三个部分","titleSlug":"partition-array-into-three-parts-with-equal-sum"},{"formTitle":"[1014]最佳观光组合","frontendQuestionId":"1014","leaf":true,"level":2,"nodeType":"def","questionId":"1063","status":"","title":"最佳观光组合","titleSlug":"best-sightseeing-pair"},{"formTitle":"[1015]可被 K 整除的最小整数","frontendQuestionId":"1015","leaf":true,"level":2,"nodeType":"def","questionId":"1064","status":"","title":"可被 K 整除的最小整数","titleSlug":"smallest-integer-divisible-by-k"},{"formTitle":"[1016]子串能表示从 1 到 N 数字的二进制串","frontendQuestionId":"1016","leaf":true,"level":2,"nodeType":"def","questionId":"1065","status":"","title":"子串能表示从 1 到 N 数字的二进制串","titleSlug":"binary-string-with-substrings-representing-1-to-n"},{"formTitle":"[1017]负二进制转换","frontendQuestionId":"1017","leaf":true,"level":2,"nodeType":"def","questionId":"1070","status":"","title":"负二进制转换","titleSlug":"convert-to-base-2"},{"formTitle":"[1018]可被 5 整除的二进制前缀","frontendQuestionId":"1018","leaf":true,"level":1,"nodeType":"def","questionId":"1071","status":"","title":"可被 5 整除的二进制前缀","titleSlug":"binary-prefix-divisible-by-5"},{"formTitle":"[1019]链表中的下一个更大节点","frontendQuestionId":"1019","leaf":true,"level":2,"nodeType":"def","questionId":"1072","status":"","title":"链表中的下一个更大节点","titleSlug":"next-greater-node-in-linked-list"},{"formTitle":"[1020]飞地的数量","frontendQuestionId":"1020","leaf":true,"level":2,"nodeType":"def","questionId":"1073","status":"","title":"飞地的数量","titleSlug":"number-of-enclaves"},{"formTitle":"[1021]删除最外层的括号","frontendQuestionId":"1021","leaf":true,"level":1,"nodeType":"def","questionId":"1078","status":"","title":"删除最外层的括号","titleSlug":"remove-outermost-parentheses"},{"formTitle":"[1022]从根到叶的二进制数之和","frontendQuestionId":"1022","leaf":true,"level":1,"nodeType":"def","questionId":"1079","status":"","title":"从根到叶的二进制数之和","titleSlug":"sum-of-root-to-leaf-binary-numbers"},{"formTitle":"[1023]驼峰式匹配","frontendQuestionId":"1023","leaf":true,"level":2,"nodeType":"def","questionId":"1080","status":"","title":"驼峰式匹配","titleSlug":"camelcase-matching"},{"formTitle":"[1024]视频拼接","frontendQuestionId":"1024","leaf":true,"level":2,"nodeType":"def","questionId":"1081","status":"","title":"视频拼接","titleSlug":"video-stitching"},{"formTitle":"[1025]除数博弈","frontendQuestionId":"1025","leaf":true,"level":1,"nodeType":"def","questionId":"1086","status":"","title":"除数博弈","titleSlug":"divisor-game"},{"formTitle":"[1026]节点与其祖先之间的最大差值","frontendQuestionId":"1026","leaf":true,"level":2,"nodeType":"def","questionId":"1092","status":"","title":"节点与其祖先之间的最大差值","titleSlug":"maximum-difference-between-node-and-ancestor"},{"formTitle":"[1027]最长等差数列","frontendQuestionId":"1027","leaf":true,"level":2,"nodeType":"def","questionId":"1087","status":"","title":"最长等差数列","titleSlug":"longest-arithmetic-sequence"},{"formTitle":"[1028]从先序遍历还原二叉树","frontendQuestionId":"1028","leaf":true,"level":3,"nodeType":"def","questionId":"1093","status":"","title":"从先序遍历还原二叉树","titleSlug":"recover-a-tree-from-preorder-traversal"},{"formTitle":"[1029]两地调度","frontendQuestionId":"1029","leaf":true,"level":1,"nodeType":"def","questionId":"1095","status":"","title":"两地调度","titleSlug":"two-city-scheduling"},{"formTitle":"[1030]距离顺序排列矩阵单元格","frontendQuestionId":"1030","leaf":true,"level":1,"nodeType":"def","questionId":"1094","status":"","title":"距离顺序排列矩阵单元格","titleSlug":"matrix-cells-in-distance-order"},{"formTitle":"[1031]两个非重叠子数组的最大和","frontendQuestionId":"1031","leaf":true,"level":2,"nodeType":"def","questionId":"1096","status":"","title":"两个非重叠子数组的最大和","titleSlug":"maximum-sum-of-two-non-overlapping-subarrays"},{"formTitle":"[1032]字符流","frontendQuestionId":"1032","leaf":true,"level":3,"nodeType":"def","questionId":"1097","status":"","title":"字符流","titleSlug":"stream-of-characters"},{"formTitle":"[1033]移动石子直到连续","frontendQuestionId":"1033","leaf":true,"level":1,"nodeType":"def","questionId":"1103","status":"","title":"移动石子直到连续","titleSlug":"moving-stones-until-consecutive"},{"formTitle":"[1034]边框着色","frontendQuestionId":"1034","leaf":true,"level":2,"nodeType":"def","questionId":"1104","status":"","title":"边框着色","titleSlug":"coloring-a-border"},{"formTitle":"[1035]不相交的线","frontendQuestionId":"1035","leaf":true,"level":2,"nodeType":"def","questionId":"1105","status":"","title":"不相交的线","titleSlug":"uncrossed-lines"},{"formTitle":"[1036]逃离大迷宫","frontendQuestionId":"1036","leaf":true,"level":3,"nodeType":"def","questionId":"1106","status":"","title":"逃离大迷宫","titleSlug":"escape-a-large-maze"},{"formTitle":"[1037]有效的回旋镖","frontendQuestionId":"1037","leaf":true,"level":1,"nodeType":"def","questionId":"1115","status":"","title":"有效的回旋镖","titleSlug":"valid-boomerang"},{"formTitle":"[1038]从二叉搜索树到更大和树","frontendQuestionId":"1038","leaf":true,"level":2,"nodeType":"def","questionId":"1114","status":"","title":"从二叉搜索树到更大和树","titleSlug":"binary-search-tree-to-greater-sum-tree"},{"formTitle":"[1039]多边形三角剖分的最低得分","frontendQuestionId":"1039","leaf":true,"level":2,"nodeType":"def","questionId":"1111","status":"","title":"多边形三角剖分的最低得分","titleSlug":"minimum-score-triangulation-of-polygon"},{"formTitle":"[1040]移动石子直到连续 II","frontendQuestionId":"1040","leaf":true,"level":2,"nodeType":"def","questionId":"1113","status":"","title":"移动石子直到连续 II","titleSlug":"moving-stones-until-consecutive-ii"},{"formTitle":"[1041]困于环中的机器人","frontendQuestionId":"1041","leaf":true,"level":2,"nodeType":"def","questionId":"1119","status":"","title":"困于环中的机器人","titleSlug":"robot-bounded-in-circle"},{"formTitle":"[1042]不邻接植花","frontendQuestionId":"1042","leaf":true,"level":1,"nodeType":"def","questionId":"1120","status":"","title":"不邻接植花","titleSlug":"flower-planting-with-no-adjacent"},{"formTitle":"[1043]分隔数组以得到最大和","frontendQuestionId":"1043","leaf":true,"level":2,"nodeType":"def","questionId":"1121","status":"","title":"分隔数组以得到最大和","titleSlug":"partition-array-for-maximum-sum"},{"formTitle":"[1044]最长重复子串","frontendQuestionId":"1044","leaf":true,"level":3,"nodeType":"def","questionId":"1122","status":"","title":"最长重复子串","titleSlug":"longest-duplicate-substring"},{"formTitle":"[1045]买下所有产品的客户","frontendQuestionId":"1045","leaf":true,"level":2,"nodeType":"def","questionId":"1135","status":"lock","title":"买下所有产品的客户","titleSlug":"customers-who-bought-all-products"},{"formTitle":"[1046]最后一块石头的重量","frontendQuestionId":"1046","leaf":true,"level":1,"nodeType":"def","questionId":"1127","status":"","title":"最后一块石头的重量","titleSlug":"last-stone-weight"},{"formTitle":"[1047]删除字符串中的所有相邻重复项","frontendQuestionId":"1047","leaf":true,"level":1,"nodeType":"def","questionId":"1128","status":"","title":"删除字符串中的所有相邻重复项","titleSlug":"remove-all-adjacent-duplicates-in-string"},{"formTitle":"[1048]最长字符串链","frontendQuestionId":"1048","leaf":true,"level":2,"nodeType":"def","questionId":"1129","status":"","title":"最长字符串链","titleSlug":"longest-string-chain"},{"formTitle":"[1049]最后一块石头的重量 II","frontendQuestionId":"1049","leaf":true,"level":2,"nodeType":"def","questionId":"1130","status":"","title":"最后一块石头的重量 II","titleSlug":"last-stone-weight-ii"},{"formTitle":"[1050]合作过至少三次的演员和导演","frontendQuestionId":"1050","leaf":true,"level":1,"nodeType":"def","questionId":"1136","status":"lock","title":"合作过至少三次的演员和导演","titleSlug":"actors-and-directors-who-cooperated-at-least-three-times"},{"formTitle":"[1051]高度检查器","frontendQuestionId":"1051","leaf":true,"level":1,"nodeType":"def","questionId":"1137","status":"","title":"高度检查器","titleSlug":"height-checker"},{"formTitle":"[1052]爱生气的书店老板","frontendQuestionId":"1052","leaf":true,"level":2,"nodeType":"def","questionId":"1138","status":"","title":"爱生气的书店老板","titleSlug":"grumpy-bookstore-owner"},{"formTitle":"[1053]交换一次的先前排列","frontendQuestionId":"1053","leaf":true,"level":2,"nodeType":"def","questionId":"1139","status":"","title":"交换一次的先前排列","titleSlug":"previous-permutation-with-one-swap"},{"formTitle":"[1054]距离相等的条形码","frontendQuestionId":"1054","leaf":true,"level":2,"nodeType":"def","questionId":"1140","status":"","title":"距离相等的条形码","titleSlug":"distant-barcodes"},{"formTitle":"[1055]形成字符串的最短路径","frontendQuestionId":"1055","leaf":true,"level":2,"nodeType":"def","questionId":"1051","status":"lock","title":"形成字符串的最短路径","titleSlug":"shortest-way-to-form-string"},{"formTitle":"[1056]易混淆数","frontendQuestionId":"1056","leaf":true,"level":1,"nodeType":"def","questionId":"1069","status":"lock","title":"易混淆数","titleSlug":"confusing-number"},{"formTitle":"[1057]校园自行车分配","frontendQuestionId":"1057","leaf":true,"level":2,"nodeType":"def","questionId":"1052","status":"lock","title":"校园自行车分配","titleSlug":"campus-bikes"},{"formTitle":"[1058]最小化舍入误差以满足目标","frontendQuestionId":"1058","leaf":true,"level":2,"nodeType":"def","questionId":"1053","status":"lock","title":"最小化舍入误差以满足目标","titleSlug":"minimize-rounding-error-to-meet-target"},{"formTitle":"[1059]从始点到终点的所有路径","frontendQuestionId":"1059","leaf":true,"level":2,"nodeType":"def","questionId":"511","status":"lock","title":"从始点到终点的所有路径","titleSlug":"all-paths-from-source-lead-to-destination"},{"formTitle":"[1060]有序数组中的缺失元素","frontendQuestionId":"1060","leaf":true,"level":2,"nodeType":"def","questionId":"1059","status":"lock","title":"有序数组中的缺失元素","titleSlug":"missing-element-in-sorted-array"},{"formTitle":"[1061]按字典序排列最小的等效字符串","frontendQuestionId":"1061","leaf":true,"level":2,"nodeType":"def","questionId":"1058","status":"lock","title":"按字典序排列最小的等效字符串","titleSlug":"lexicographically-smallest-equivalent-string"},{"formTitle":"[1062]最长重复子串","frontendQuestionId":"1062","leaf":true,"level":2,"nodeType":"def","questionId":"1060","status":"lock","title":"最长重复子串","titleSlug":"longest-repeating-substring"},{"formTitle":"[1063]有效子数组的数目","frontendQuestionId":"1063","leaf":true,"level":3,"nodeType":"def","questionId":"1061","status":"lock","title":"有效子数组的数目","titleSlug":"number-of-valid-subarrays"},{"formTitle":"[1064]不动点","frontendQuestionId":"1064","leaf":true,"level":1,"nodeType":"def","questionId":"1066","status":"lock","title":"不动点","titleSlug":"fixed-point"},{"formTitle":"[1065]字符串的索引对","frontendQuestionId":"1065","leaf":true,"level":1,"nodeType":"def","questionId":"1075","status":"lock","title":"字符串的索引对","titleSlug":"index-pairs-of-a-string"},{"formTitle":"[1066]校园自行车分配 II","frontendQuestionId":"1066","leaf":true,"level":2,"nodeType":"def","questionId":"1067","status":"lock","title":"校园自行车分配 II","titleSlug":"campus-bikes-ii"},{"formTitle":"[1067]范围内的数字计数","frontendQuestionId":"1067","leaf":true,"level":3,"nodeType":"def","questionId":"1068","status":"lock","title":"范围内的数字计数","titleSlug":"digit-count-in-range"},{"formTitle":"[1068]产品销售分析 I","frontendQuestionId":"1068","leaf":true,"level":1,"nodeType":"def","questionId":"1153","status":"lock","title":"产品销售分析 I","titleSlug":"product-sales-analysis-i"},{"formTitle":"[1069]产品销售分析 II","frontendQuestionId":"1069","leaf":true,"level":1,"nodeType":"def","questionId":"1154","status":"lock","title":"产品销售分析 II","titleSlug":"product-sales-analysis-ii"},{"formTitle":"[1070]产品销售分析 III","frontendQuestionId":"1070","leaf":true,"level":2,"nodeType":"def","questionId":"1155","status":"lock","title":"产品销售分析 III","titleSlug":"product-sales-analysis-iii"},{"formTitle":"[1071]字符串的最大公因子","frontendQuestionId":"1071","leaf":true,"level":1,"nodeType":"def","questionId":"1146","status":"","title":"字符串的最大公因子","titleSlug":"greatest-common-divisor-of-strings"},{"formTitle":"[1072]按列翻转得到最大值等行数","frontendQuestionId":"1072","leaf":true,"level":2,"nodeType":"def","questionId":"1147","status":"","title":"按列翻转得到最大值等行数","titleSlug":"flip-columns-for-maximum-number-of-equal-rows"},{"formTitle":"[1073]负二进制数相加","frontendQuestionId":"1073","leaf":true,"level":2,"nodeType":"def","questionId":"1148","status":"","title":"负二进制数相加","titleSlug":"adding-two-negabinary-numbers"},{"formTitle":"[1074]元素和为目标值的子矩阵数量","frontendQuestionId":"1074","leaf":true,"level":3,"nodeType":"def","questionId":"1145","status":"","title":"元素和为目标值的子矩阵数量","titleSlug":"number-of-submatrices-that-sum-to-target"},{"formTitle":"[1075]项目员工 I","frontendQuestionId":"1075","leaf":true,"level":1,"nodeType":"def","questionId":"1161","status":"lock","title":"项目员工 I","titleSlug":"project-employees-i"},{"formTitle":"[1076]项目员工II","frontendQuestionId":"1076","leaf":true,"level":1,"nodeType":"def","questionId":"1162","status":"lock","title":"项目员工II","titleSlug":"project-employees-ii"},{"formTitle":"[1077]项目员工 III","frontendQuestionId":"1077","leaf":true,"level":2,"nodeType":"def","questionId":"1163","status":"lock","title":"项目员工 III","titleSlug":"project-employees-iii"},{"formTitle":"[1078]Bigram 分词","frontendQuestionId":"1078","leaf":true,"level":1,"nodeType":"def","questionId":"1156","status":"","title":"Bigram 分词","titleSlug":"occurrences-after-bigram"},{"formTitle":"[1079]活字印刷","frontendQuestionId":"1079","leaf":true,"level":2,"nodeType":"def","questionId":"1160","status":"","title":"活字印刷","titleSlug":"letter-tile-possibilities"},{"formTitle":"[1080]根到叶路径上的不足节点","frontendQuestionId":"1080","leaf":true,"level":2,"nodeType":"def","questionId":"1157","status":"","title":"根到叶路径上的不足节点","titleSlug":"insufficient-nodes-in-root-to-leaf-paths"},{"formTitle":"[1081]不同字符的最小子序列","frontendQuestionId":"1081","leaf":true,"level":2,"nodeType":"def","questionId":"1159","status":"","title":"不同字符的最小子序列","titleSlug":"smallest-subsequence-of-distinct-characters"},{"formTitle":"[1082]销售分析 I ","frontendQuestionId":"1082","leaf":true,"level":1,"nodeType":"def","questionId":"1172","status":"lock","title":"销售分析 I ","titleSlug":"sales-analysis-i"},{"formTitle":"[1083]销售分析 II","frontendQuestionId":"1083","leaf":true,"level":1,"nodeType":"def","questionId":"1173","status":"lock","title":"销售分析 II","titleSlug":"sales-analysis-ii"},{"formTitle":"[1084]销售分析III","frontendQuestionId":"1084","leaf":true,"level":1,"nodeType":"def","questionId":"1174","status":"lock","title":"销售分析III","titleSlug":"sales-analysis-iii"},{"formTitle":"[1085]最小元素各数位之和","frontendQuestionId":"1085","leaf":true,"level":1,"nodeType":"def","questionId":"1082","status":"lock","title":"最小元素各数位之和","titleSlug":"sum-of-digits-in-the-minimum-number"},{"formTitle":"[1086]前五科的均分","frontendQuestionId":"1086","leaf":true,"level":1,"nodeType":"def","questionId":"1074","status":"lock","title":"前五科的均分","titleSlug":"high-five"},{"formTitle":"[1087]字母切换","frontendQuestionId":"1087","leaf":true,"level":2,"nodeType":"def","questionId":"1076","status":"lock","title":"字母切换","titleSlug":"brace-expansion"},{"formTitle":"[1088]易混淆数 II","frontendQuestionId":"1088","leaf":true,"level":3,"nodeType":"def","questionId":"1077","status":"lock","title":"易混淆数 II","titleSlug":"confusing-number-ii"},{"formTitle":"[1089]复写零","frontendQuestionId":"1089","leaf":true,"level":1,"nodeType":"def","questionId":"1168","status":"","title":"复写零","titleSlug":"duplicate-zeros"},{"formTitle":"[1090]受标签影响的最大值","frontendQuestionId":"1090","leaf":true,"level":2,"nodeType":"def","questionId":"1169","status":"","title":"受标签影响的最大值","titleSlug":"largest-values-from-labels"},{"formTitle":"[1091]二进制矩阵中的最短路径","frontendQuestionId":"1091","leaf":true,"level":2,"nodeType":"def","questionId":"1171","status":"","title":"二进制矩阵中的最短路径","titleSlug":"shortest-path-in-binary-matrix"},{"formTitle":"[1092]最短公共超序列","frontendQuestionId":"1092","leaf":true,"level":3,"nodeType":"def","questionId":"1170","status":"","title":"最短公共超序列","titleSlug":"shortest-common-supersequence"},{"formTitle":"[1093]大样本统计","frontendQuestionId":"1093","leaf":true,"level":2,"nodeType":"def","questionId":"1183","status":"","title":"大样本统计","titleSlug":"statistics-from-a-large-sample"},{"formTitle":"[1094]拼车","frontendQuestionId":"1094","leaf":true,"level":2,"nodeType":"def","questionId":"1184","status":"","title":"拼车","titleSlug":"car-pooling"},{"formTitle":"[1095]山脉数组中查找目标值","frontendQuestionId":"1095","leaf":true,"level":3,"nodeType":"def","questionId":"1185","status":"","title":"山脉数组中查找目标值","titleSlug":"find-in-mountain-array"},{"formTitle":"[1096]花括号展开 II","frontendQuestionId":"1096","leaf":true,"level":3,"nodeType":"def","questionId":"1188","status":"","title":"花括号展开 II","titleSlug":"brace-expansion-ii"},{"formTitle":"[1097]游戏玩法分析 V","frontendQuestionId":"1097","leaf":true,"level":3,"nodeType":"def","questionId":"1193","status":"lock","title":"游戏玩法分析 V","titleSlug":"game-play-analysis-v"},{"formTitle":"[1098]小众书籍","frontendQuestionId":"1098","leaf":true,"level":2,"nodeType":"def","questionId":"1198","status":"lock","title":"小众书籍","titleSlug":"unpopular-books"},{"formTitle":"[1099]小于 K 的两数之和","frontendQuestionId":"1099","leaf":true,"level":1,"nodeType":"def","questionId":"1083","status":"lock","title":"小于 K 的两数之和","titleSlug":"two-sum-less-than-k"},{"formTitle":"[1100]长度为 K 的无重复字符子串","frontendQuestionId":"1100","leaf":true,"level":2,"nodeType":"def","questionId":"1084","status":"lock","title":"长度为 K 的无重复字符子串","titleSlug":"find-k-length-substrings-with-no-repeated-characters"},{"formTitle":"[1101]彼此熟识的最早时间","frontendQuestionId":"1101","leaf":true,"level":2,"nodeType":"def","questionId":"1085","status":"lock","title":"彼此熟识的最早时间","titleSlug":"the-earliest-moment-when-everyone-become-friends"},{"formTitle":"[1102]得分最高的路径","frontendQuestionId":"1102","leaf":true,"level":2,"nodeType":"def","questionId":"1099","status":"lock","title":"得分最高的路径","titleSlug":"path-with-maximum-minimum-value"},{"formTitle":"[1103]分糖果 II","frontendQuestionId":"1103","leaf":true,"level":1,"nodeType":"def","questionId":"1195","status":"","title":"分糖果 II","titleSlug":"distribute-candies-to-people"},{"formTitle":"[1104]二叉树寻路","frontendQuestionId":"1104","leaf":true,"level":2,"nodeType":"def","questionId":"1194","status":"","title":"二叉树寻路","titleSlug":"path-in-zigzag-labelled-binary-tree"},{"formTitle":"[1105]填充书架","frontendQuestionId":"1105","leaf":true,"level":2,"nodeType":"def","questionId":"1196","status":"","title":"填充书架","titleSlug":"filling-bookcase-shelves"},{"formTitle":"[1106]解析布尔表达式","frontendQuestionId":"1106","leaf":true,"level":3,"nodeType":"def","questionId":"1197","status":"","title":"解析布尔表达式","titleSlug":"parsing-a-boolean-expression"},{"formTitle":"[1107]每日新用户统计","frontendQuestionId":"1107","leaf":true,"level":2,"nodeType":"def","questionId":"1204","status":"lock","title":"每日新用户统计","titleSlug":"new-users-daily-count"},{"formTitle":"[1108]IP 地址无效化","frontendQuestionId":"1108","leaf":true,"level":1,"nodeType":"def","questionId":"1205","status":"","title":"IP 地址无效化","titleSlug":"defanging-an-ip-address"},{"formTitle":"[1109]航班预订统计","frontendQuestionId":"1109","leaf":true,"level":2,"nodeType":"def","questionId":"1206","status":"","title":"航班预订统计","titleSlug":"corporate-flight-bookings"},{"formTitle":"[1110]删点成林","frontendQuestionId":"1110","leaf":true,"level":2,"nodeType":"def","questionId":"1207","status":"","title":"删点成林","titleSlug":"delete-nodes-and-return-forest"},{"formTitle":"[1111]有效括号的嵌套深度","frontendQuestionId":"1111","leaf":true,"level":2,"nodeType":"def","questionId":"1208","status":"","title":"有效括号的嵌套深度","titleSlug":"maximum-nesting-depth-of-two-valid-parentheses-strings"},{"formTitle":"[1112]Highest Grade For Each Student","frontendQuestionId":"1112","leaf":true,"level":2,"nodeType":"def","questionId":"1214","status":"lock","title":"Highest Grade For Each Student","titleSlug":"highest-grade-for-each-student"},{"formTitle":"[1113]Reported Posts","frontendQuestionId":"1113","leaf":true,"level":1,"nodeType":"def","questionId":"1215","status":"lock","title":"Reported Posts","titleSlug":"reported-posts"},{"formTitle":"[1114]按序打印","frontendQuestionId":"1114","leaf":true,"level":1,"nodeType":"def","questionId":"1203","status":"","title":"按序打印","titleSlug":"print-in-order"},{"formTitle":"[1115]交替打印FooBar","frontendQuestionId":"1115","leaf":true,"level":2,"nodeType":"def","questionId":"1187","status":"","title":"交替打印FooBar","titleSlug":"print-foobar-alternately"},{"formTitle":"[1116]打印零与奇偶数","frontendQuestionId":"1116","leaf":true,"level":2,"nodeType":"def","questionId":"1216","status":"","title":"打印零与奇偶数","titleSlug":"print-zero-even-odd"},{"formTitle":"[1117]H2O 生成","frontendQuestionId":"1117","leaf":true,"level":2,"nodeType":"def","questionId":"1186","status":"","title":"H2O 生成","titleSlug":"building-h2o"},{"formTitle":"[1118]一月有多少天","frontendQuestionId":"1118","leaf":true,"level":1,"nodeType":"def","questionId":"1088","status":"lock","title":"一月有多少天","titleSlug":"number-of-days-in-a-month"},{"formTitle":"[1119]删去字符串中的元音","frontendQuestionId":"1119","leaf":true,"level":1,"nodeType":"def","questionId":"1089","status":"lock","title":"删去字符串中的元音","titleSlug":"remove-vowels-from-a-string"},{"formTitle":"[1120]子树的最大平均值","frontendQuestionId":"1120","leaf":true,"level":2,"nodeType":"def","questionId":"1091","status":"lock","title":"子树的最大平均值","titleSlug":"maximum-average-subtree"},{"formTitle":"[1121]将数组分成几个递增序列","frontendQuestionId":"1121","leaf":true,"level":3,"nodeType":"def","questionId":"1118","status":"lock","title":"将数组分成几个递增序列","titleSlug":"divide-array-into-increasing-sequences"},{"formTitle":"[1122]数组的相对排序","frontendQuestionId":"1122","leaf":true,"level":1,"nodeType":"def","questionId":"1217","status":"","title":"数组的相对排序","titleSlug":"relative-sort-array"},{"formTitle":"[1123]最深叶节点的最近公共祖先","frontendQuestionId":"1123","leaf":true,"level":2,"nodeType":"def","questionId":"1218","status":"","title":"最深叶节点的最近公共祖先","titleSlug":"lowest-common-ancestor-of-deepest-leaves"},{"formTitle":"[1124]表现良好的最长时间段","frontendQuestionId":"1124","leaf":true,"level":2,"nodeType":"def","questionId":"1219","status":"","title":"表现良好的最长时间段","titleSlug":"longest-well-performing-interval"},{"formTitle":"[1125]最小的必要团队","frontendQuestionId":"1125","leaf":true,"level":3,"nodeType":"def","questionId":"1220","status":"","title":"最小的必要团队","titleSlug":"smallest-sufficient-team"},{"formTitle":"[1126]Active Businesses","frontendQuestionId":"1126","leaf":true,"level":2,"nodeType":"def","questionId":"1225","status":"lock","title":"Active Businesses","titleSlug":"active-businesses"},{"formTitle":"[1127]User Purchase Platform","frontendQuestionId":"1127","leaf":true,"level":3,"nodeType":"def","questionId":"1226","status":"lock","title":"User Purchase Platform","titleSlug":"user-purchase-platform"},{"formTitle":"[1128]等价多米诺骨牌对的数量","frontendQuestionId":"1128","leaf":true,"level":1,"nodeType":"def","questionId":"1227","status":"","title":"等价多米诺骨牌对的数量","titleSlug":"number-of-equivalent-domino-pairs"},{"formTitle":"[1129]颜色交替的最短路径","frontendQuestionId":"1129","leaf":true,"level":2,"nodeType":"def","questionId":"1229","status":"","title":"颜色交替的最短路径","titleSlug":"shortest-path-with-alternating-colors"},{"formTitle":"[1130]叶值的最小代价生成树","frontendQuestionId":"1130","leaf":true,"level":2,"nodeType":"def","questionId":"1228","status":"","title":"叶值的最小代价生成树","titleSlug":"minimum-cost-tree-from-leaf-values"},{"formTitle":"[1131]绝对值表达式的最大值","frontendQuestionId":"1131","leaf":true,"level":2,"nodeType":"def","questionId":"1230","status":"","title":"绝对值表达式的最大值","titleSlug":"maximum-of-absolute-value-expression"},{"formTitle":"[1132]Reported Posts II","frontendQuestionId":"1132","leaf":true,"level":2,"nodeType":"def","questionId":"1237","status":"lock","title":"Reported Posts II","titleSlug":"reported-posts-ii"},{"formTitle":"[1133]最大唯一数","frontendQuestionId":"1133","leaf":true,"level":1,"nodeType":"def","questionId":"1098","status":"lock","title":"最大唯一数","titleSlug":"largest-unique-number"},{"formTitle":"[1134]阿姆斯特朗数","frontendQuestionId":"1134","leaf":true,"level":1,"nodeType":"def","questionId":"1090","status":"lock","title":"阿姆斯特朗数","titleSlug":"armstrong-number"},{"formTitle":"[1135]最低成本联通所有城市","frontendQuestionId":"1135","leaf":true,"level":2,"nodeType":"def","questionId":"1100","status":"lock","title":"最低成本联通所有城市","titleSlug":"connecting-cities-with-minimum-cost"},{"formTitle":"[1136]平行课程","frontendQuestionId":"1136","leaf":true,"level":3,"nodeType":"def","questionId":"1101","status":"lock","title":"平行课程","titleSlug":"parallel-courses"},{"formTitle":"[1137]第 N 个泰波那契数","frontendQuestionId":"1137","leaf":true,"level":1,"nodeType":"def","questionId":"1236","status":"","title":"第 N 个泰波那契数","titleSlug":"n-th-tribonacci-number"},{"formTitle":"[1138]字母板上的路径","frontendQuestionId":"1138","leaf":true,"level":2,"nodeType":"def","questionId":"1238","status":"","title":"字母板上的路径","titleSlug":"alphabet-board-path"},{"formTitle":"[1139]最大的以 1 为边界的正方形","frontendQuestionId":"1139","leaf":true,"level":2,"nodeType":"def","questionId":"1239","status":"","title":"最大的以 1 为边界的正方形","titleSlug":"largest-1-bordered-square"},{"formTitle":"[1140]石子游戏 II","frontendQuestionId":"1140","leaf":true,"level":2,"nodeType":"def","questionId":"1240","status":"","title":"石子游戏 II","titleSlug":"stone-game-ii"},{"formTitle":"[1141]User Activity for the Past 30 Days I","frontendQuestionId":"1141","leaf":true,"level":1,"nodeType":"def","questionId":"1245","status":"lock","title":"User Activity for the Past 30 Days I","titleSlug":"user-activity-for-the-past-30-days-i"},{"formTitle":"[1142]User Activity for the Past 30 Days II","frontendQuestionId":"1142","leaf":true,"level":1,"nodeType":"def","questionId":"1246","status":"lock","title":"User Activity for the Past 30 Days II","titleSlug":"user-activity-for-the-past-30-days-ii"},{"formTitle":"[1143]最长公共子序列","frontendQuestionId":"1143","leaf":true,"level":2,"nodeType":"def","questionId":"1250","status":"","title":"最长公共子序列","titleSlug":"longest-common-subsequence"},{"formTitle":"[1144]递减元素使数组呈锯齿状","frontendQuestionId":"1144","leaf":true,"level":2,"nodeType":"def","questionId":"1247","status":"","title":"递减元素使数组呈锯齿状","titleSlug":"decrease-elements-to-make-array-zigzag"},{"formTitle":"[1145]二叉树着色游戏","frontendQuestionId":"1145","leaf":true,"level":2,"nodeType":"def","questionId":"1248","status":"","title":"二叉树着色游戏","titleSlug":"binary-tree-coloring-game"},{"formTitle":"[1146]快照数组","frontendQuestionId":"1146","leaf":true,"level":2,"nodeType":"def","questionId":"1249","status":"","title":"快照数组","titleSlug":"snapshot-array"},{"formTitle":"[1147]段式回文","frontendQuestionId":"1147","leaf":true,"level":3,"nodeType":"def","questionId":"1251","status":"","title":"段式回文","titleSlug":"longest-chunked-palindrome-decomposition"},{"formTitle":"[1148]Article Views I","frontendQuestionId":"1148","leaf":true,"level":1,"nodeType":"def","questionId":"1258","status":"lock","title":"Article Views I","titleSlug":"article-views-i"},{"formTitle":"[1149]Article Views II","frontendQuestionId":"1149","leaf":true,"level":2,"nodeType":"def","questionId":"1259","status":"lock","title":"Article Views II","titleSlug":"article-views-ii"},{"formTitle":"[1150]检查一个数是否在数组中占绝大多数","frontendQuestionId":"1150","leaf":true,"level":1,"nodeType":"def","questionId":"1102","status":"lock","title":"检查一个数是否在数组中占绝大多数","titleSlug":"check-if-a-number-is-majority-element-in-a-sorted-array"},{"formTitle":"[1151]最少交换次数来组合所有的 1","frontendQuestionId":"1151","leaf":true,"level":2,"nodeType":"def","questionId":"1107","status":"lock","title":"最少交换次数来组合所有的 1","titleSlug":"minimum-swaps-to-group-all-1s-together"},{"formTitle":"[1152]用户网站访问行为分析","frontendQuestionId":"1152","leaf":true,"level":2,"nodeType":"def","questionId":"1108","status":"lock","title":"用户网站访问行为分析","titleSlug":"analyze-user-website-visit-pattern"},{"formTitle":"[1153]字符串转化","frontendQuestionId":"1153","leaf":true,"level":3,"nodeType":"def","questionId":"1124","status":"lock","title":"字符串转化","titleSlug":"string-transforms-into-another-string"},{"formTitle":"[1154]一年中的第几天","frontendQuestionId":"1154","leaf":true,"level":1,"nodeType":"def","questionId":"1260","status":"","title":"一年中的第几天","titleSlug":"day-of-the-year"},{"formTitle":"[1155]掷骰子的N种方法","frontendQuestionId":"1155","leaf":true,"level":2,"nodeType":"def","questionId":"1263","status":"","title":"掷骰子的N种方法","titleSlug":"number-of-dice-rolls-with-target-sum"},{"formTitle":"[1156]单字符重复子串的最大长度","frontendQuestionId":"1156","leaf":true,"level":2,"nodeType":"def","questionId":"1261","status":"","title":"单字符重复子串的最大长度","titleSlug":"swap-for-longest-repeated-character-substring"},{"formTitle":"[1157]子数组中占绝大多数的元素","frontendQuestionId":"1157","leaf":true,"level":3,"nodeType":"def","questionId":"1262","status":"","title":"子数组中占绝大多数的元素","titleSlug":"online-majority-element-in-subarray"},{"formTitle":"[1158]Market Analysis I","frontendQuestionId":"1158","leaf":true,"level":2,"nodeType":"def","questionId":"1268","status":"lock","title":"Market Analysis I","titleSlug":"market-analysis-i"},{"formTitle":"[1159]Market Analysis II","frontendQuestionId":"1159","leaf":true,"level":3,"nodeType":"def","questionId":"1269","status":"lock","title":"Market Analysis II","titleSlug":"market-analysis-ii"},{"formTitle":"[1160]拼写单词","frontendQuestionId":"1160","leaf":true,"level":1,"nodeType":"def","questionId":"1112","status":"","title":"拼写单词","titleSlug":"find-words-that-can-be-formed-by-characters"},{"formTitle":"[1161]最大层内元素和","frontendQuestionId":"1161","leaf":true,"level":2,"nodeType":"def","questionId":"1116","status":"","title":"最大层内元素和","titleSlug":"maximum-level-sum-of-a-binary-tree"},{"formTitle":"[1162]地图分析","frontendQuestionId":"1162","leaf":true,"level":2,"nodeType":"def","questionId":"1117","status":"","title":"地图分析","titleSlug":"as-far-from-land-as-possible"},{"formTitle":"[1163]按字典序排在最后的子串","frontendQuestionId":"1163","leaf":true,"level":3,"nodeType":"def","questionId":"1133","status":"","title":"按字典序排在最后的子串","titleSlug":"last-substring-in-lexicographical-order"},{"formTitle":"[1164]Product Price at a Given Date","frontendQuestionId":"1164","leaf":true,"level":2,"nodeType":"def","questionId":"1278","status":"lock","title":"Product Price at a Given Date","titleSlug":"product-price-at-a-given-date"},{"formTitle":"[1165]单行键盘","frontendQuestionId":"1165","leaf":true,"level":1,"nodeType":"def","questionId":"1123","status":"lock","title":"单行键盘","titleSlug":"single-row-keyboard"},{"formTitle":"[1166]设计文件系统","frontendQuestionId":"1166","leaf":true,"level":2,"nodeType":"def","questionId":"1125","status":"lock","title":"设计文件系统","titleSlug":"design-file-system"},{"formTitle":"[1167]连接棒材的最低费用","frontendQuestionId":"1167","leaf":true,"level":2,"nodeType":"def","questionId":"1126","status":"lock","title":"连接棒材的最低费用","titleSlug":"minimum-cost-to-connect-sticks"},{"formTitle":"[1168]水资源分配优化","frontendQuestionId":"1168","leaf":true,"level":3,"nodeType":"def","questionId":"1144","status":"lock","title":"水资源分配优化","titleSlug":"optimize-water-distribution-in-a-village"},{"formTitle":"[1169]查询无效交易","frontendQuestionId":"1169","leaf":true,"level":2,"nodeType":"def","questionId":"1272","status":"","title":"查询无效交易","titleSlug":"invalid-transactions"},{"formTitle":"[1170]比较字符串最小字母出现频次","frontendQuestionId":"1170","leaf":true,"level":1,"nodeType":"def","questionId":"1273","status":"","title":"比较字符串最小字母出现频次","titleSlug":"compare-strings-by-frequency-of-the-smallest-character"},{"formTitle":"[1171]从链表中删去总和值为零的连续节点","frontendQuestionId":"1171","leaf":true,"level":2,"nodeType":"def","questionId":"1267","status":"","title":"从链表中删去总和值为零的连续节点","titleSlug":"remove-zero-sum-consecutive-nodes-from-linked-list"},{"formTitle":"[1172]餐盘栈","frontendQuestionId":"1172","leaf":true,"level":3,"nodeType":"def","questionId":"1270","status":"","title":"餐盘栈","titleSlug":"dinner-plate-stacks"},{"formTitle":"[1173]Immediate Food Delivery I","frontendQuestionId":"1173","leaf":true,"level":1,"nodeType":"def","questionId":"1291","status":"lock","title":"Immediate Food Delivery I","titleSlug":"immediate-food-delivery-i"},{"formTitle":"[1174]Immediate Food Delivery II","frontendQuestionId":"1174","leaf":true,"level":2,"nodeType":"def","questionId":"1292","status":"lock","title":"Immediate Food Delivery II","titleSlug":"immediate-food-delivery-ii"},{"formTitle":"[1175]质数排列","frontendQuestionId":"1175","leaf":true,"level":1,"nodeType":"def","questionId":"1279","status":"","title":"质数排列","titleSlug":"prime-arrangements"},{"formTitle":"[1176]健身计划评估","frontendQuestionId":"1176","leaf":true,"level":1,"nodeType":"def","questionId":"1280","status":"lock","title":"健身计划评估","titleSlug":"diet-plan-performance"},{"formTitle":"[1177]构建回文串检测","frontendQuestionId":"1177","leaf":true,"level":2,"nodeType":"def","questionId":"1281","status":"","title":"构建回文串检测","titleSlug":"can-make-palindrome-from-substring"},{"formTitle":"[1178]猜字谜","frontendQuestionId":"1178","leaf":true,"level":3,"nodeType":"def","questionId":"1282","status":"","title":"猜字谜","titleSlug":"number-of-valid-words-for-each-puzzle"},{"formTitle":"[1179]重新格式化部门表","frontendQuestionId":"1179","leaf":true,"level":1,"nodeType":"def","questionId":"1301","status":"","title":"重新格式化部门表","titleSlug":"reformat-department-table"},{"formTitle":"[1180]统计只含单一字母的子串","frontendQuestionId":"1180","leaf":true,"level":1,"nodeType":"def","questionId":"1131","status":"lock","title":"统计只含单一字母的子串","titleSlug":"count-substrings-with-only-one-distinct-letter"},{"formTitle":"[1181]前后拼接","frontendQuestionId":"1181","leaf":true,"level":2,"nodeType":"def","questionId":"1132","status":"lock","title":"前后拼接","titleSlug":"before-and-after-puzzle"},{"formTitle":"[1182]与目标颜色间的最短距离","frontendQuestionId":"1182","leaf":true,"level":2,"nodeType":"def","questionId":"1134","status":"lock","title":"与目标颜色间的最短距离","titleSlug":"shortest-distance-to-target-color"},{"formTitle":"[1183]矩阵中 1 的最大数量","frontendQuestionId":"1183","leaf":true,"level":3,"nodeType":"def","questionId":"1152","status":"lock","title":"矩阵中 1 的最大数量","titleSlug":"maximum-number-of-ones"},{"formTitle":"[1184]公交站间的距离","frontendQuestionId":"1184","leaf":true,"level":1,"nodeType":"def","questionId":"1287","status":"","title":"公交站间的距离","titleSlug":"distance-between-bus-stops"},{"formTitle":"[1185]一周中的第几天","frontendQuestionId":"1185","leaf":true,"level":1,"nodeType":"def","questionId":"1289","status":"","title":"一周中的第几天","titleSlug":"day-of-the-week"},{"formTitle":"[1186]删除一次得到子数组最大和","frontendQuestionId":"1186","leaf":true,"level":2,"nodeType":"def","questionId":"1288","status":"","title":"删除一次得到子数组最大和","titleSlug":"maximum-subarray-sum-with-one-deletion"},{"formTitle":"[1187]使数组严格递增","frontendQuestionId":"1187","leaf":true,"level":3,"nodeType":"def","questionId":"1290","status":"","title":"使数组严格递增","titleSlug":"make-array-strictly-increasing"},{"formTitle":"[1188]设计有限阻塞队列","frontendQuestionId":"1188","leaf":true,"level":2,"nodeType":"def","questionId":"1209","status":"lock","title":"设计有限阻塞队列","titleSlug":"design-bounded-blocking-queue"},{"formTitle":"[1189]“气球” 的最大数量","frontendQuestionId":"1189","leaf":true,"level":1,"nodeType":"def","questionId":"1297","status":"","title":"“气球” 的最大数量","titleSlug":"maximum-number-of-balloons"},{"formTitle":"[1190]反转每对括号间的子串","frontendQuestionId":"1190","leaf":true,"level":2,"nodeType":"def","questionId":"1298","status":"","title":"反转每对括号间的子串","titleSlug":"reverse-substrings-between-each-pair-of-parentheses"},{"formTitle":"[1191]K 次串联后最大子数组之和","frontendQuestionId":"1191","leaf":true,"level":2,"nodeType":"def","questionId":"1299","status":"","title":"K 次串联后最大子数组之和","titleSlug":"k-concatenation-maximum-sum"},{"formTitle":"[1192]查找集群内的「关键连接」","frontendQuestionId":"1192","leaf":true,"level":3,"nodeType":"def","questionId":"1300","status":"","title":"查找集群内的「关键连接」","titleSlug":"critical-connections-in-a-network"},{"formTitle":"[1193]每月交易 I","frontendQuestionId":"1193","leaf":true,"level":2,"nodeType":"def","questionId":"1317","status":"lock","title":"每月交易 I","titleSlug":"monthly-transactions-i"},{"formTitle":"[1194]锦标赛优胜者","frontendQuestionId":"1194","leaf":true,"level":3,"nodeType":"def","questionId":"1318","status":"lock","title":"锦标赛优胜者","titleSlug":"tournament-winners"},{"formTitle":"[1195]交替打印字符串","frontendQuestionId":"1195","leaf":true,"level":2,"nodeType":"def","questionId":"1316","status":"","title":"交替打印字符串","titleSlug":"fizz-buzz-multithreaded"},{"formTitle":"[1196]最多可以买到的苹果数量","frontendQuestionId":"1196","leaf":true,"level":1,"nodeType":"def","questionId":"1141","status":"lock","title":"最多可以买到的苹果数量","titleSlug":"how-many-apples-can-you-put-into-the-basket"},{"formTitle":"[1197]进击的骑士","frontendQuestionId":"1197","leaf":true,"level":2,"nodeType":"def","questionId":"1142","status":"lock","title":"进击的骑士","titleSlug":"minimum-knight-moves"},{"formTitle":"[1198]找出所有行中最小公共元素","frontendQuestionId":"1198","leaf":true,"level":2,"nodeType":"def","questionId":"1143","status":"lock","title":"找出所有行中最小公共元素","titleSlug":"find-smallest-common-element-in-all-rows"},{"formTitle":"[1199]建造街区的最短时间","frontendQuestionId":"1199","leaf":true,"level":3,"nodeType":"def","questionId":"1167","status":"lock","title":"建造街区的最短时间","titleSlug":"minimum-time-to-build-blocks"},{"formTitle":"[1200]最小绝对差","frontendQuestionId":"1200","leaf":true,"level":1,"nodeType":"def","questionId":"1306","status":"","title":"最小绝对差","titleSlug":"minimum-absolute-difference"},{"formTitle":"[1201]丑数 III","frontendQuestionId":"1201","leaf":true,"level":2,"nodeType":"def","questionId":"1307","status":"","title":"丑数 III","titleSlug":"ugly-number-iii"},{"formTitle":"[1202]交换字符串中的元素","frontendQuestionId":"1202","leaf":true,"level":2,"nodeType":"def","questionId":"1308","status":"","title":"交换字符串中的元素","titleSlug":"smallest-string-with-swaps"},{"formTitle":"[1203]项目管理","frontendQuestionId":"1203","leaf":true,"level":3,"nodeType":"def","questionId":"1309","status":"","title":"项目管理","titleSlug":"sort-items-by-groups-respecting-dependencies"},{"formTitle":"[1204]Last Person to Fit in the Elevator","frontendQuestionId":"1204","leaf":true,"level":2,"nodeType":"def","questionId":"1327","status":"lock","title":"Last Person to Fit in the Elevator","titleSlug":"last-person-to-fit-in-the-elevator"},{"formTitle":"[1205]每月交易II","frontendQuestionId":"1205","leaf":true,"level":2,"nodeType":"def","questionId":"1328","status":"lock","title":"每月交易II","titleSlug":"monthly-transactions-ii"},{"formTitle":"[1206]设计跳表","frontendQuestionId":"1206","leaf":true,"level":3,"nodeType":"def","questionId":"1337","status":"","title":"设计跳表","titleSlug":"design-skiplist"},{"formTitle":"[1207]独一无二的出现次数","frontendQuestionId":"1207","leaf":true,"level":1,"nodeType":"def","questionId":"1319","status":"","title":"独一无二的出现次数","titleSlug":"unique-number-of-occurrences"},{"formTitle":"[1208]尽可能使字符串相等","frontendQuestionId":"1208","leaf":true,"level":2,"nodeType":"def","questionId":"1321","status":"","title":"尽可能使字符串相等","titleSlug":"get-equal-substrings-within-budget"},{"formTitle":"[1209]删除字符串中的所有相邻重复项 II","frontendQuestionId":"1209","leaf":true,"level":2,"nodeType":"def","questionId":"1320","status":"","title":"删除字符串中的所有相邻重复项 II","titleSlug":"remove-all-adjacent-duplicates-in-string-ii"},{"formTitle":"[1210]穿过迷宫的最少移动次数","frontendQuestionId":"1210","leaf":true,"level":3,"nodeType":"def","questionId":"1322","status":"","title":"穿过迷宫的最少移动次数","titleSlug":"minimum-moves-to-reach-target-with-rotations"},{"formTitle":"[1211]Queries Quality and Percentage","frontendQuestionId":"1211","leaf":true,"level":1,"nodeType":"def","questionId":"1338","status":"lock","title":"Queries Quality and Percentage","titleSlug":"queries-quality-and-percentage"},{"formTitle":"[1212]Team Scores in Football Tournament","frontendQuestionId":"1212","leaf":true,"level":2,"nodeType":"def","questionId":"1339","status":"lock","title":"Team Scores in Football Tournament","titleSlug":"team-scores-in-football-tournament"},{"formTitle":"[1213]三个有序数组的交集","frontendQuestionId":"1213","leaf":true,"level":1,"nodeType":"def","questionId":"1149","status":"lock","title":"三个有序数组的交集","titleSlug":"intersection-of-three-sorted-arrays"},{"formTitle":"[1214]查找两棵二叉搜索树之和","frontendQuestionId":"1214","leaf":true,"level":2,"nodeType":"def","questionId":"1150","status":"lock","title":"查找两棵二叉搜索树之和","titleSlug":"two-sum-bsts"},{"formTitle":"[1215]步进数","frontendQuestionId":"1215","leaf":true,"level":2,"nodeType":"def","questionId":"1151","status":"lock","title":"步进数","titleSlug":"stepping-numbers"},{"formTitle":"[1216]验证回文字符串 III","frontendQuestionId":"1216","leaf":true,"level":3,"nodeType":"def","questionId":"1178","status":"lock","title":"验证回文字符串 III","titleSlug":"valid-palindrome-iii"},{"formTitle":"[1217]玩筹码","frontendQuestionId":"1217","leaf":true,"level":1,"nodeType":"def","questionId":"1329","status":"","title":"玩筹码","titleSlug":"play-with-chips"},{"formTitle":"[1218]最长定差子序列","frontendQuestionId":"1218","leaf":true,"level":2,"nodeType":"def","questionId":"1330","status":"","title":"最长定差子序列","titleSlug":"longest-arithmetic-subsequence-of-given-difference"},{"formTitle":"[1219]黄金矿工","frontendQuestionId":"1219","leaf":true,"level":2,"nodeType":"def","questionId":"1331","status":"","title":"黄金矿工","titleSlug":"path-with-maximum-gold"},{"formTitle":"[1220]统计元音字母序列的数目","frontendQuestionId":"1220","leaf":true,"level":3,"nodeType":"def","questionId":"1332","status":"","title":"统计元音字母序列的数目","titleSlug":"count-vowels-permutation"},{"formTitle":"[1221]分割平衡字符串","frontendQuestionId":"1221","leaf":true,"level":1,"nodeType":"def","questionId":"1341","status":"","title":"分割平衡字符串","titleSlug":"split-a-string-in-balanced-strings"},{"formTitle":"[1222]可以攻击国王的皇后","frontendQuestionId":"1222","leaf":true,"level":2,"nodeType":"def","questionId":"1342","status":"","title":"可以攻击国王的皇后","titleSlug":"queens-that-can-attack-the-king"},{"formTitle":"[1223]掷骰子模拟","frontendQuestionId":"1223","leaf":true,"level":2,"nodeType":"def","questionId":"1343","status":"","title":"掷骰子模拟","titleSlug":"dice-roll-simulation"},{"formTitle":"[1224]最大相等频率","frontendQuestionId":"1224","leaf":true,"level":3,"nodeType":"def","questionId":"1344","status":"","title":"最大相等频率","titleSlug":"maximum-equal-frequency"},{"formTitle":"[1225]Report Contiguous Dates","frontendQuestionId":"1225","leaf":true,"level":3,"nodeType":"def","questionId":"1357","status":"","title":"Report Contiguous Dates","titleSlug":"report-contiguous-dates"},{"formTitle":"[1226]The Dining Philosophers","frontendQuestionId":"1226","leaf":true,"level":2,"nodeType":"def","questionId":"1340","status":"","title":"The Dining Philosophers","titleSlug":"the-dining-philosophers"},{"formTitle":"[1228]等差数列中缺失的数字","frontendQuestionId":"1228","leaf":true,"level":1,"nodeType":"def","questionId":"1164","status":"lock","title":"等差数列中缺失的数字","titleSlug":"missing-number-in-arithmetic-progression"},{"formTitle":"[1229]安排会议日程","frontendQuestionId":"1229","leaf":true,"level":2,"nodeType":"def","questionId":"1165","status":"lock","title":"安排会议日程","titleSlug":"meeting-scheduler"},{"formTitle":"[1230]抛掷硬币","frontendQuestionId":"1230","leaf":true,"level":2,"nodeType":"def","questionId":"1166","status":"lock","title":"抛掷硬币","titleSlug":"toss-strange-coins"},{"formTitle":"[1231]分享巧克力","frontendQuestionId":"1231","leaf":true,"level":3,"nodeType":"def","questionId":"1192","status":"lock","title":"分享巧克力","titleSlug":"divide-chocolate"},{"formTitle":"[1232]缀点成线","frontendQuestionId":"1232","leaf":true,"level":1,"nodeType":"def","questionId":"1349","status":"","title":"缀点成线","titleSlug":"check-if-it-is-a-straight-line"},{"formTitle":"[1233]删除子文件夹","frontendQuestionId":"1233","leaf":true,"level":2,"nodeType":"def","questionId":"1350","status":"","title":"删除子文件夹","titleSlug":"remove-sub-folders-from-the-filesystem"},{"formTitle":"[1234]替换子串得到平衡字符串","frontendQuestionId":"1234","leaf":true,"level":2,"nodeType":"def","questionId":"1351","status":"","title":"替换子串得到平衡字符串","titleSlug":"replace-the-substring-for-balanced-string"},{"formTitle":"[1235]规划兼职工作","frontendQuestionId":"1235","leaf":true,"level":3,"nodeType":"def","questionId":"1352","status":"","title":"规划兼职工作","titleSlug":"maximum-profit-in-job-scheduling"},{"formTitle":"[1236]Web Crawler","frontendQuestionId":"1236","leaf":true,"level":2,"nodeType":"def","questionId":"1271","status":"lock","title":"Web Crawler","titleSlug":"web-crawler"},{"formTitle":"[LCP 1]猜数字","frontendQuestionId":"LCP 1","leaf":true,"level":1,"nodeType":"def","questionId":"100107","status":"","title":"猜数字","titleSlug":"guess-numbers"},{"formTitle":"[LCP 2]分式化简","frontendQuestionId":"LCP 2","leaf":true,"level":1,"nodeType":"def","questionId":"100092","status":"","title":"分式化简","titleSlug":"deep-dark-fraction"},{"formTitle":"[LCP 3]机器人大冒险","frontendQuestionId":"LCP 3","leaf":true,"level":2,"nodeType":"def","questionId":"100096","status":"","title":"机器人大冒险","titleSlug":"programmable-robot"},{"formTitle":"[LCP 4]覆盖","frontendQuestionId":"LCP 4","leaf":true,"level":3,"nodeType":"def","questionId":"100093","status":"","title":"覆盖","titleSlug":"broken-board-dominoes"},{"formTitle":"[LCP 5]发 LeetCoin","frontendQuestionId":"LCP 5","leaf":true,"level":3,"nodeType":"def","questionId":"100094","status":"","title":"发 LeetCoin","titleSlug":"coin-bonus"}] \ No newline at end of file diff --git a/algorithms/TempFilePath/leetcode/editor/cn/translation.json b/algorithms/TempFilePath/leetcode/editor/cn/translation.json deleted file mode 100644 index f0574163..00000000 --- a/algorithms/TempFilePath/leetcode/editor/cn/translation.json +++ /dev/null @@ -1 +0,0 @@ -{"data":{"translations":[{"title":"\u4e24\u6570\u4e4b\u548c","question":{"questionId":"1","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e24\u6570\u76f8\u52a0","question":{"questionId":"2","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u65e0\u91cd\u590d\u5b57\u7b26\u7684\u6700\u957f\u5b50\u4e32","question":{"questionId":"3","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5bfb\u627e\u4e24\u4e2a\u6709\u5e8f\u6570\u7ec4\u7684\u4e2d\u4f4d\u6570","question":{"questionId":"4","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u957f\u56de\u6587\u5b50\u4e32","question":{"questionId":"5","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5408\u5e76\u4e24\u4e2a\u6709\u5e8f\u94fe\u8868","question":{"questionId":"21","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u53cd\u8f6c\u5b57\u7b26\u4e32","question":{"questionId":"344","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5220\u9664\u6392\u5e8f\u6570\u7ec4\u4e2d\u7684\u91cd\u590d\u9879","question":{"questionId":"26","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6768\u8f89\u4e09\u89d2 II","question":{"questionId":"119","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6574\u6570\u53cd\u8f6c","question":{"questionId":"7","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u540e\u4e00\u4e2a\u5355\u8bcd\u7684\u957f\u5ea6","question":{"questionId":"58","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u8fdb\u5236\u6c42\u548c","question":{"questionId":"67","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7f57\u9a6c\u6570\u5b57\u8f6c\u6574\u6570","question":{"questionId":"13","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6b63\u5219\u8868\u8fbe\u5f0f\u5339\u914d","question":{"questionId":"10","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u722c\u697c\u68af","question":{"questionId":"70","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u56de\u6587\u6570","question":{"questionId":"9","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u957f\u516c\u5171\u524d\u7f00","question":{"questionId":"14","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6253\u5bb6\u52ab\u820d","question":{"questionId":"198","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6574\u6570\u8f6c\u7f57\u9a6c\u6570\u5b57","question":{"questionId":"12","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"Z \u5b57\u5f62\u53d8\u6362","question":{"questionId":"6","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"N\u7687\u540e","question":{"questionId":"51","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u79fb\u9664\u5143\u7d20","question":{"questionId":"27","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7ec4\u5408\u4e24\u4e2a\u8868","question":{"questionId":"175","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6709\u6548\u7684\u5b8c\u5168\u5e73\u65b9\u6570","question":{"questionId":"367","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u56db\u6570\u4e4b\u548c","question":{"questionId":"18","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5c0f\u65f6\u95f4\u5dee","question":{"questionId":"539","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u65cb\u8f6c\u56fe\u50cf","question":{"questionId":"48","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"Pow(x, n)","question":{"questionId":"50","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"x \u7684\u5e73\u65b9\u6839","question":{"questionId":"69","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e09\u6570\u4e4b\u548c","question":{"questionId":"15","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u63a5\u8fd1\u7684\u4e09\u6570\u4e4b\u548c","question":{"questionId":"16","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6709\u6548\u7684\u6570\u72ec","question":{"questionId":"36","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7ec4\u5408\u603b\u548c II","question":{"questionId":"40","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b57\u7b26\u4e32\u8f6c\u6362\u6574\u6570 (atoi)","question":{"questionId":"8","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u641c\u7d22\u63d2\u5165\u4f4d\u7f6e","question":{"questionId":"35","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7535\u8bdd\u53f7\u7801\u7684\u5b57\u6bcd\u7ec4\u5408","question":{"questionId":"17","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u62ec\u53f7\u751f\u6210","question":{"questionId":"22","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6709\u6548\u7684\u62ec\u53f7","question":{"questionId":"20","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5220\u9664\u94fe\u8868\u7684\u5012\u6570\u7b2cN\u4e2a\u8282\u70b9","question":{"questionId":"19","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6709\u6548\u7535\u8bdd\u53f7\u7801","question":{"questionId":"193","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b50\u6570\u7ec4\u6700\u5927\u5e73\u5747\u6570 I","question":{"questionId":"643","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7b2c\u5341\u884c","question":{"questionId":"195","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6709\u6548\u7684\u6b63\u65b9\u5f62","question":{"questionId":"593","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5220\u9664\u6392\u5e8f\u94fe\u8868\u4e2d\u7684\u91cd\u590d\u5143\u7d20","question":{"questionId":"83","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7edf\u8ba1\u8bcd\u9891","question":{"questionId":"192","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e24\u6570\u76f8\u9664","question":{"questionId":"29","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b9e\u73b0 strStr()","question":{"questionId":"28","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8f6c\u7f6e\u6587\u4ef6","question":{"questionId":"194","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"N\u7687\u540e II","question":{"questionId":"52","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5212\u5206\u4e3ak\u4e2a\u76f8\u7b49\u7684\u5b50\u96c6","question":{"questionId":"698","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5728\u6bcf\u4e2a\u6811\u884c\u4e2d\u627e\u6700\u5927\u503c","question":{"questionId":"515","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6c47\u603b\u533a\u95f4","question":{"questionId":"228","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u627e\u6811\u5de6\u4e0b\u89d2\u7684\u503c","question":{"questionId":"513","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u76db\u6700\u591a\u6c34\u7684\u5bb9\u5668","question":{"questionId":"11","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u53ea\u51fa\u73b0\u4e00\u6b21\u7684\u6570\u5b57","question":{"questionId":"136","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5168\u6392\u5217","question":{"questionId":"46","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5408\u5e76K\u4e2a\u6392\u5e8f\u94fe\u8868","question":{"questionId":"23","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7b2cK\u4e2a\u8bed\u6cd5\u7b26\u53f7","question":{"questionId":"795","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e24\u4e24\u4ea4\u6362\u94fe\u8868\u4e2d\u7684\u8282\u70b9","question":{"questionId":"24","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b57\u7b26\u4e32\u76f8\u4e58","question":{"questionId":"43","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8df3\u8dc3\u6e38\u620f","question":{"questionId":"55","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5728\u6392\u5e8f\u6570\u7ec4\u4e2d\u67e5\u627e\u5143\u7d20\u7684\u7b2c\u4e00\u4e2a\u548c\u6700\u540e\u4e00\u4e2a\u4f4d\u7f6e","question":{"questionId":"34","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b57\u6bcd\u5f02\u4f4d\u8bcd\u5206\u7ec4","question":{"questionId":"49","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9a8c\u8bc1\u56de\u6587\u4e32","question":{"questionId":"125","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b57\u7b26\u4e32\u7684\u6392\u5217","question":{"questionId":"567","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5e73\u65b9\u6570\u4e4b\u548c","question":{"questionId":"633","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e11\u6570","question":{"questionId":"263","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e11\u6570 II","question":{"questionId":"264","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b8c\u7f8e\u6570","question":{"questionId":"507","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5408\u5e76\u533a\u95f4","question":{"questionId":"56","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5e73\u8861\u4e8c\u53c9\u6811","question":{"questionId":"110","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u6811\u7684\u6700\u5927\u6df1\u5ea6","question":{"questionId":"104","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5feb\u4e50\u6570","question":{"questionId":"202","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u53cd\u8f6c\u94fe\u8868","question":{"questionId":"206","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u56de\u6587\u94fe\u8868","question":{"questionId":"234","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5404\u4f4d\u76f8\u52a0","question":{"questionId":"258","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7f3a\u5931\u6570\u5b57","question":{"questionId":"268","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7b2c\u4e00\u4e2a\u9519\u8bef\u7684\u7248\u672c","question":{"questionId":"278","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u79fb\u52a8\u96f6","question":{"questionId":"283","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u731c\u6570\u5b57\u5927\u5c0f","question":{"questionId":"374","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b57\u7b26\u4e32\u4e2d\u7684\u7b2c\u4e00\u4e2a\u552f\u4e00\u5b57\u7b26","question":{"questionId":"387","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u8fdb\u5236\u624b\u8868","question":{"questionId":"401","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7b2c\u4e8c\u9ad8\u7684\u85aa\u6c34","question":{"questionId":"176","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e32\u8054\u6240\u6709\u5355\u8bcd\u7684\u5b50\u4e32","question":{"questionId":"30","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8d85\u8fc7\u7ecf\u7406\u6536\u5165\u7684\u5458\u5de5","question":{"questionId":"181","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u90e8\u95e8\u5de5\u8d44\u524d\u4e09\u9ad8\u7684\u6240\u6709\u5458\u5de5","question":{"questionId":"185","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7ec4\u5408\u603b\u548c","question":{"questionId":"39","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u901a\u914d\u7b26\u5339\u914d","question":{"questionId":"44","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u62a5\u6570","question":{"questionId":"38","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u641c\u7d22\u65cb\u8f6c\u6392\u5e8f\u6570\u7ec4","question":{"questionId":"33","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u957f\u6709\u6548\u62ec\u53f7","question":{"questionId":"32","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u89e3\u6570\u72ec","question":{"questionId":"37","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7f3a\u5931\u7684\u7b2c\u4e00\u4e2a\u6b63\u6570","question":{"questionId":"41","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u63a5\u96e8\u6c34","question":{"questionId":"42","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5927\u5b50\u5e8f\u548c","question":{"questionId":"53","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e0b\u4e00\u4e2a\u6392\u5217","question":{"questionId":"31","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u87ba\u65cb\u77e9\u9635","question":{"questionId":"54","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e70\u5356\u80a1\u7968\u7684\u6700\u4f73\u65f6\u673a","question":{"questionId":"121","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e70\u5356\u80a1\u7968\u7684\u6700\u4f73\u65f6\u673a II","question":{"questionId":"122","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u627e\u4e0d\u540c","question":{"questionId":"389","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5de6\u53f6\u5b50\u4e4b\u548c","question":{"questionId":"404","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2\u7684\u5e42","question":{"questionId":"231","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"K \u4e2a\u4e00\u7ec4\u7ffb\u8f6c\u94fe\u8868","question":{"questionId":"25","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e24\u6574\u6570\u4e4b\u548c","question":{"questionId":"371","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5bf9\u79f0\u4e8c\u53c9\u6811","question":{"questionId":"101","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"Fizz Buzz","question":{"questionId":"412","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5408\u5e76\u4e24\u4e2a\u6709\u5e8f\u6570\u7ec4","question":{"questionId":"88","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7b2cN\u9ad8\u7684\u85aa\u6c34","question":{"questionId":"177","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u76f8\u540c\u7684\u6811","question":{"questionId":"100","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u73af\u5f62\u94fe\u8868","question":{"questionId":"141","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8df3\u8dc3\u6e38\u620f II","question":{"questionId":"45","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u52a0\u4e00","question":{"questionId":"66","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u53cd\u8f6c\u94fe\u8868 II","question":{"questionId":"92","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u76f8\u4ea4\u94fe\u8868","question":{"questionId":"160","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e24\u6570\u4e4b\u548c II - \u8f93\u5165\u6709\u5e8f\u6570\u7ec4","question":{"questionId":"167","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6c42\u4f17\u6570","question":{"questionId":"169","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u6811\u7684\u5c42\u5e73\u5747\u503c","question":{"questionId":"637","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6768\u8f89\u4e09\u89d2","question":{"questionId":"118","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u53cd\u8f6c\u5b57\u7b26\u4e32 II","question":{"questionId":"541","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5c06\u6709\u5e8f\u6570\u7ec4\u8f6c\u6362\u4e3a\u4e8c\u53c9\u641c\u7d22\u6811","question":{"questionId":"108","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u952e\u76d8\u884c","question":{"questionId":"500","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6709\u6548\u7684\u62ec\u53f7\u5b57\u7b26\u4e32","question":{"questionId":"678","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u673a\u5668\u4eba\u80fd\u5426\u8fd4\u56de\u539f\u70b9","question":{"questionId":"657","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b57\u7b26\u4e32\u76f8\u52a0","question":{"questionId":"415","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6839\u636e\u4e8c\u53c9\u6811\u521b\u5efa\u5b57\u7b26\u4e32","question":{"questionId":"606","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"Excel\u8868\u5217\u5e8f\u53f7","question":{"questionId":"171","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"Excel\u8868\u5217\u540d\u79f0","question":{"questionId":"168","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u87ba\u65cb\u77e9\u9635 II","question":{"questionId":"59","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7b2ck\u4e2a\u6392\u5217","question":{"questionId":"60","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u63d2\u5165\u533a\u95f4","question":{"questionId":"57","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4ea4\u9519\u5b57\u7b26\u4e32","question":{"questionId":"97","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u65cb\u8f6c\u94fe\u8868","question":{"questionId":"61","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e0d\u540c\u8def\u5f84","question":{"questionId":"62","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e0d\u540c\u8def\u5f84 II","question":{"questionId":"63","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6709\u6548\u6570\u5b57","question":{"questionId":"65","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5c0f\u8def\u5f84\u548c","question":{"questionId":"64","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7b80\u5316\u8def\u5f84","question":{"questionId":"71","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7f16\u8f91\u8ddd\u79bb","question":{"questionId":"72","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8ba1\u6570\u8d28\u6570","question":{"questionId":"204","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u77e9\u9635\u7f6e\u96f6","question":{"questionId":"73","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u73af\u5f62\u94fe\u8868 II","question":{"questionId":"142","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5c0f\u6808","question":{"questionId":"155","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u540c\u6784\u5b57\u7b26\u4e32","question":{"questionId":"205","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5206\u9694\u94fe\u8868","question":{"questionId":"86","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5168\u6392\u5217 II","question":{"questionId":"47","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b50\u96c6","question":{"questionId":"78","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b50\u96c6 II","question":{"questionId":"90","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6233\u6c14\u7403","question":{"questionId":"312","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u62fc\u63a5\u6700\u5927\u6570","question":{"questionId":"321","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u524dK\u4e2a\u9ad8\u9891\u5355\u8bcd","question":{"questionId":"692","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8d26\u6237\u5408\u5e76","question":{"questionId":"721","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b58\u5728\u91cd\u590d\u5143\u7d20","question":{"questionId":"217","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b58\u5728\u91cd\u590d\u5143\u7d20 II","question":{"questionId":"219","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b58\u5728\u91cd\u590d\u5143\u7d20 III","question":{"questionId":"220","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u6811\u7684\u6700\u5c0f\u6df1\u5ea6","question":{"questionId":"111","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7ec4\u5408","question":{"questionId":"77","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5355\u8bcd\u641c\u7d22","question":{"questionId":"79","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u641c\u7d22\u65cb\u8f6c\u6392\u5e8f\u6570\u7ec4 II","question":{"questionId":"81","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u683c\u96f7\u7f16\u7801","question":{"questionId":"89","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u590d\u539fIP\u5730\u5740","question":{"questionId":"93","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e24\u4e2a\u6570\u7ec4\u7684\u4ea4\u96c6 II","question":{"questionId":"350","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u6811\u7684\u4e2d\u5e8f\u904d\u5386","question":{"questionId":"94","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u53cd\u8f6c\u5b57\u7b26\u4e32\u4e2d\u7684\u5355\u8bcd III","question":{"questionId":"557","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e0d\u540c\u7684\u4e8c\u53c9\u641c\u7d22\u6811 II","question":{"questionId":"95","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e0d\u540c\u7684\u4e8c\u53c9\u641c\u7d22\u6811","question":{"questionId":"96","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9a8c\u8bc1\u4e8c\u53c9\u641c\u7d22\u6811","question":{"questionId":"98","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6062\u590d\u4e8c\u53c9\u641c\u7d22\u6811","question":{"questionId":"99","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u6811\u7684\u952f\u9f7f\u5f62\u5c42\u6b21\u904d\u5386","question":{"questionId":"103","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u6811\u7684\u5c42\u6b21\u904d\u5386","question":{"questionId":"102","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8def\u5f84\u603b\u548c","question":{"questionId":"112","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u6811\u7684\u5c42\u6b21\u904d\u5386 II","question":{"questionId":"107","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5927\u8fde\u7eed1\u7684\u4e2a\u6570","question":{"questionId":"485","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e09\u4e2a\u6570\u7684\u6700\u5927\u4e58\u79ef","question":{"questionId":"628","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u89e3\u7801\u65b9\u6cd5","question":{"questionId":"91","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6570\u5b57\u8f6c\u6362\u4e3a\u5341\u516d\u8fdb\u5236\u6570","question":{"questionId":"405","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6362\u5ea7\u4f4d","question":{"questionId":"626","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u67e5\u627e\u91cd\u590d\u7684\u7535\u5b50\u90ae\u7bb1","question":{"questionId":"182","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6709\u6548\u7684\u5b57\u6bcd\u5f02\u4f4d\u8bcd","question":{"questionId":"242","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9a8c\u8bc1\u56de\u6587\u5b57\u7b26\u4e32 \u2161","question":{"questionId":"680","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4ece\u4e0d\u8ba2\u8d2d\u7684\u5ba2\u6237","question":{"questionId":"183","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u79fb\u9664\u94fe\u8868\u5143\u7d20","question":{"questionId":"203","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u98a0\u5012\u4e8c\u8fdb\u5236\u4f4d","question":{"questionId":"190","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u6811\u7684\u53f3\u89c6\u56fe","question":{"questionId":"199","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u641c\u7d22\u4e8c\u7ef4\u77e9\u9635","question":{"questionId":"74","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u989c\u8272\u5206\u7c7b","question":{"questionId":"75","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8def\u5f84\u603b\u548c II","question":{"questionId":"113","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u53ea\u51fa\u73b0\u4e00\u6b21\u7684\u6570\u5b57 II","question":{"questionId":"137","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e0d\u540c\u7684\u5b50\u5e8f\u5217","question":{"questionId":"115","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"LRU\u7f13\u5b58\u673a\u5236","question":{"questionId":"146","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4f4d1\u7684\u4e2a\u6570","question":{"questionId":"191","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6587\u672c\u5de6\u53f3\u5bf9\u9f50","question":{"questionId":"68","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5c0f\u8986\u76d6\u5b50\u4e32","question":{"questionId":"76","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"Nim \u6e38\u620f","question":{"questionId":"292","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e09\u89d2\u5f62\u6700\u5c0f\u8def\u5f84\u548c","question":{"questionId":"120","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5206\u6570\u6392\u540d","question":{"questionId":"178","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5927\u77e9\u5f62","question":{"questionId":"85","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5220\u9664\u6392\u5e8f\u6570\u7ec4\u4e2d\u7684\u91cd\u590d\u9879 II","question":{"questionId":"80","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5220\u9664\u6392\u5e8f\u94fe\u8868\u4e2d\u7684\u91cd\u590d\u5143\u7d20 II","question":{"questionId":"82","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u67f1\u72b6\u56fe\u4e2d\u6700\u5927\u7684\u77e9\u5f62","question":{"questionId":"84","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6709\u5e8f\u94fe\u8868\u8f6c\u6362\u4e8c\u53c9\u641c\u7d22\u6811","question":{"questionId":"109","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u6811\u5c55\u5f00\u4e3a\u94fe\u8868","question":{"questionId":"114","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u586b\u5145\u6bcf\u4e2a\u8282\u70b9\u7684\u4e0b\u4e00\u4e2a\u53f3\u4fa7\u8282\u70b9\u6307\u9488","question":{"questionId":"116","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e24\u6570\u4e4b\u548c IV - \u8f93\u5165 BST","question":{"questionId":"653","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6574\u6570\u8f6c\u6362\u82f1\u6587\u8868\u793a","question":{"questionId":"273","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5206\u53d1\u7cd6\u679c","question":{"questionId":"135","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4ece\u524d\u5e8f\u4e0e\u4e2d\u5e8f\u904d\u5386\u5e8f\u5217\u6784\u9020\u4e8c\u53c9\u6811","question":{"questionId":"105","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4ece\u4e2d\u5e8f\u4e0e\u540e\u5e8f\u904d\u5386\u5e8f\u5217\u6784\u9020\u4e8c\u53c9\u6811","question":{"questionId":"106","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u90e8\u95e8\u5de5\u8d44\u6700\u9ad8\u7684\u5458\u5de5","question":{"questionId":"184","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e70\u5356\u80a1\u7968\u7684\u6700\u4f73\u65f6\u673a III","question":{"questionId":"123","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u6811\u4e2d\u7684\u6700\u5927\u8def\u5f84\u548c","question":{"questionId":"124","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5355\u8bcd\u63a5\u9f99","question":{"questionId":"127","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5355\u8bcd\u63a5\u9f99 II","question":{"questionId":"126","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u957f\u8fde\u7eed\u5e8f\u5217","question":{"questionId":"128","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u88ab\u56f4\u7ed5\u7684\u533a\u57df","question":{"questionId":"130","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5206\u5272\u56de\u6587\u4e32","question":{"questionId":"131","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5206\u5272\u56de\u6587\u4e32 II","question":{"questionId":"132","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u514b\u9686\u56fe","question":{"questionId":"133","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6270\u4e71\u5b57\u7b26\u4e32","question":{"questionId":"87","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u586b\u5145\u6bcf\u4e2a\u8282\u70b9\u7684\u4e0b\u4e00\u4e2a\u53f3\u4fa7\u8282\u70b9\u6307\u9488 II","question":{"questionId":"117","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u52a0\u6cb9\u7ad9","question":{"questionId":"134","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u590d\u5236\u5e26\u968f\u673a\u6307\u9488\u7684\u94fe\u8868","question":{"questionId":"138","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5355\u8bcd\u62c6\u5206","question":{"questionId":"139","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5355\u8bcd\u62c6\u5206 II","question":{"questionId":"140","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u91cd\u6392\u94fe\u8868","question":{"questionId":"143","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u6811\u7684\u524d\u5e8f\u904d\u5386","question":{"questionId":"144","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u6811\u7684\u540e\u5e8f\u904d\u5386","question":{"questionId":"145","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5bf9\u94fe\u8868\u8fdb\u884c\u63d2\u5165\u6392\u5e8f","question":{"questionId":"147","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6392\u5e8f\u94fe\u8868","question":{"questionId":"148","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u76f4\u7ebf\u4e0a\u6700\u591a\u7684\u70b9\u6570","question":{"questionId":"149","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9006\u6ce2\u5170\u8868\u8fbe\u5f0f\u6c42\u503c","question":{"questionId":"150","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u57fa\u672c\u8ba1\u7b97\u5668","question":{"questionId":"224","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6709\u8da3\u7684\u7535\u5f71","question":{"questionId":"620","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5927\u95f4\u8ddd","question":{"questionId":"164","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8fde\u7eed\u51fa\u73b0\u7684\u6570\u5b57","question":{"questionId":"180","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4ea4\u6362\u5de5\u8d44","question":{"questionId":"627","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6c42\u6839\u5230\u53f6\u5b50\u8282\u70b9\u6570\u5b57\u4e4b\u548c","question":{"questionId":"129","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7ffb\u8f6c\u5b57\u7b26\u4e32\u91cc\u7684\u5355\u8bcd","question":{"questionId":"151","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e58\u79ef\u6700\u5927\u5b50\u5e8f\u5217","question":{"questionId":"152","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5bfb\u627e\u65cb\u8f6c\u6392\u5e8f\u6570\u7ec4\u4e2d\u7684\u6700\u5c0f\u503c","question":{"questionId":"153","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5bfb\u627e\u65cb\u8f6c\u6392\u5e8f\u6570\u7ec4\u4e2d\u7684\u6700\u5c0f\u503c II","question":{"questionId":"154","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5bfb\u627e\u5cf0\u503c","question":{"questionId":"162","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6bd4\u8f83\u7248\u672c\u53f7","question":{"questionId":"165","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5206\u6570\u5230\u5c0f\u6570","question":{"questionId":"166","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5220\u9664\u91cd\u590d\u7684\u7535\u5b50\u90ae\u7bb1","question":{"questionId":"196","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5927\u7684\u56fd\u5bb6","question":{"questionId":"595","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8d85\u8fc75\u540d\u5b66\u751f\u7684\u8bfe","question":{"questionId":"596","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e0a\u5347\u7684\u6e29\u5ea6","question":{"questionId":"197","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4f53\u80b2\u9986\u7684\u4eba\u6d41\u91cf","question":{"questionId":"601","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u884c\u7a0b\u548c\u7528\u6237","question":{"questionId":"262","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u63d0\u83ab\u653b\u51fb","question":{"questionId":"495","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7ec4\u5408\u603b\u548c III","question":{"questionId":"216","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u81f3\u5c11\u662f\u5176\u4ed6\u6570\u5b57\u4e24\u500d\u7684\u6700\u5927\u6570","question":{"questionId":"748","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7ed9\u8868\u8fbe\u5f0f\u6dfb\u52a0\u8fd0\u7b97\u7b26","question":{"questionId":"282","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6570\u7ec4\u62c6\u5206 I","question":{"questionId":"561","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u641c\u7d22\u6811\u8fed\u4ee3\u5668","question":{"questionId":"173","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5927\u6570","question":{"questionId":"179","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u533a\u57df\u548c\u68c0\u7d22 - \u6570\u7ec4\u4e0d\u53ef\u53d8","question":{"questionId":"303","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u53bb\u9664\u91cd\u590d\u5b57\u6bcd","question":{"questionId":"316","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u56de\u6587\u5bf9","question":{"questionId":"336","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u627e\u51fa\u7b2c k \u5c0f\u7684\u8ddd\u79bb\u5bf9","question":{"questionId":"719","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u201c\u9a6c\u201d\u5728\u68cb\u76d8\u4e0a\u7684\u6982\u7387","question":{"questionId":"688","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5c9b\u5c7f\u6570\u91cf","question":{"questionId":"200","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9636\u4e58\u540e\u7684\u96f6","question":{"questionId":"172","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5730\u4e0b\u57ce\u6e38\u620f","question":{"questionId":"174","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u91cd\u590d\u7684DNA\u5e8f\u5217","question":{"questionId":"187","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e70\u5356\u80a1\u7968\u7684\u6700\u4f73\u65f6\u673a IV","question":{"questionId":"188","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8bfe\u7a0b\u8868","question":{"questionId":"207","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u65cb\u8f6c\u6570\u7ec4","question":{"questionId":"189","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u56db\u6570\u76f8\u52a0 II","question":{"questionId":"454","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u6811\u7684\u6240\u6709\u8def\u5f84","question":{"questionId":"257","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6570\u5b57\u8303\u56f4\u6309\u4f4d\u4e0e","question":{"questionId":"201","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b9e\u73b0 Trie (\u524d\u7f00\u6811)","question":{"questionId":"208","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u957f\u5ea6\u6700\u5c0f\u7684\u5b50\u6570\u7ec4","question":{"questionId":"209","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"3\u7684\u5e42","question":{"questionId":"326","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6c49\u660e\u8ddd\u79bb","question":{"questionId":"461","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5927\u6b63\u65b9\u5f62","question":{"questionId":"221","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6bcf\u65e5\u6e29\u5ea6","question":{"questionId":"739","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u81ea\u9664\u6570","question":{"questionId":"728","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u96f6\u94b1\u5151\u6362 II","question":{"questionId":"518","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8bfe\u7a0b\u8868 II","question":{"questionId":"210","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6dfb\u52a0\u4e0e\u641c\u7d22\u5355\u8bcd - \u6570\u636e\u7ed3\u6784\u8bbe\u8ba1","question":{"questionId":"211","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5355\u8bcd\u641c\u7d22 II","question":{"questionId":"212","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6253\u5bb6\u52ab\u820d II","question":{"questionId":"213","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u77ed\u56de\u6587\u4e32","question":{"questionId":"214","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6570\u7ec4\u4e2d\u7684\u7b2cK\u4e2a\u6700\u5927\u5143\u7d20","question":{"questionId":"215","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5929\u9645\u7ebf\u95ee\u9898","question":{"questionId":"218","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5408\u5e76\u4e8c\u53c9\u6811","question":{"questionId":"617","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u68c0\u6d4b\u5927\u5199\u5b57\u6bcd","question":{"questionId":"520","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5c11\u79fb\u52a8\u6b21\u6570\u4f7f\u6570\u7ec4\u5143\u7d20\u76f8\u7b49 II","question":{"questionId":"462","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u91cd\u6784\u5b57\u7b26\u4e32","question":{"questionId":"778","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e58\u6cd5\u8868\u4e2d\u7b2ck\u5c0f\u7684\u6570","question":{"questionId":"668","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"1\u6bd4\u7279\u4e0e2\u6bd4\u7279\u5b57\u7b26","question":{"questionId":"717","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5197\u4f59\u8fde\u63a5","question":{"questionId":"684","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b8c\u5168\u4e8c\u53c9\u6811\u7684\u8282\u70b9\u4e2a\u6570","question":{"questionId":"222","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5197\u4f59\u8fde\u63a5 II","question":{"questionId":"685","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7b2c\u4e09\u5927\u7684\u6570","question":{"questionId":"414","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b57\u7b26\u4e32\u4e2d\u7684\u5355\u8bcd\u6570","question":{"questionId":"434","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5927\u4e8c\u53c9\u6811","question":{"questionId":"654","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9012\u589e\u7684\u4e09\u5143\u5b50\u5e8f\u5217","question":{"questionId":"334","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7528\u6808\u5b9e\u73b0\u961f\u5217","question":{"questionId":"232","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u6811\u7684\u5761\u5ea6","question":{"questionId":"563","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e03\u8fdb\u5236\u6570","question":{"questionId":"504","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u957f\u8fde\u7eed\u9012\u589e\u5e8f\u5217","question":{"questionId":"674","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5355\u8bcd\u89c4\u5f8b","question":{"questionId":"290","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5bfb\u627e\u91cd\u590d\u6570","question":{"questionId":"287","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e24\u4e2a\u6570\u7ec4\u7684\u4ea4\u96c6","question":{"questionId":"349","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6c34\u58f6\u95ee\u9898","question":{"questionId":"365","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8d4e\u91d1\u4fe1","question":{"questionId":"383","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u96f6\u94b1\u5151\u6362","question":{"questionId":"322","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6570\u636e\u6d41\u7684\u4e2d\u4f4d\u6570","question":{"questionId":"295","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8ba1\u7b97\u53f3\u4fa7\u5c0f\u4e8e\u5f53\u524d\u5143\u7d20\u7684\u4e2a\u6570","question":{"questionId":"315","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u68d2\u7403\u6bd4\u8d5b","question":{"questionId":"682","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6392\u5217\u786c\u5e01","question":{"questionId":"441","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6709\u5e8f\u6570\u7ec4\u4e2d\u7684\u5355\u4e00\u5143\u7d20","question":{"questionId":"540","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8ba1\u6570\u4e8c\u8fdb\u5236\u5b50\u4e32","question":{"questionId":"696","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u538b\u7f29\u5b57\u7b26\u4e32","question":{"questionId":"443","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u6811\u7684\u76f4\u5f84","question":{"questionId":"543","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u53cd\u8f6c\u5b57\u7b26\u4e32\u4e2d\u7684\u5143\u97f3\u5b57\u6bcd","question":{"questionId":"345","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5220\u9664\u94fe\u8868\u4e2d\u7684\u8282\u70b9","question":{"questionId":"237","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7b2cN\u4e2a\u6570\u5b57","question":{"questionId":"400","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u533a\u95f4\u5b50\u6570\u7ec4\u4e2a\u6570","question":{"questionId":"811","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8bcd\u5178\u4e2d\u6700\u957f\u7684\u5355\u8bcd","question":{"questionId":"720","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7528\u6700\u5c11\u6570\u91cf\u7684\u7bad\u5f15\u7206\u6c14\u7403","question":{"questionId":"452","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5220\u9664\u6ce8\u91ca","question":{"questionId":"722","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b66\u751f\u51fa\u52e4\u8bb0\u5f55 I","question":{"questionId":"551","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u957f\u548c\u8c10\u5b50\u5e8f\u5217","question":{"questionId":"594","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u65cb\u8f6c\u5b57\u7b26\u4e32","question":{"questionId":"812","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b57\u6bcd\u5927\u5c0f\u5199\u5168\u6392\u5217","question":{"questionId":"800","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u641c\u7d22\u6811\u7ed3\u70b9\u6700\u5c0f\u8ddd\u79bb","question":{"questionId":"799","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u91cd\u5851\u77e9\u9635","question":{"questionId":"566","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u53ea\u51fa\u73b0\u4e00\u6b21\u7684\u6570\u5b57 III","question":{"questionId":"260","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6bd4\u7279\u4f4d\u8ba1\u6570","question":{"questionId":"338","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6253\u5bb6\u52ab\u820d III","question":{"questionId":"337","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7ffb\u8f6c\u4e8c\u53c9\u6811","question":{"questionId":"226","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6258\u666e\u5229\u8328\u77e9\u9635","question":{"questionId":"777","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u957f\u540c\u503c\u8def\u5f84","question":{"questionId":"687","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u53ef\u601c\u7684\u5c0f\u732a","question":{"questionId":"458","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"H\u6307\u6570","question":{"questionId":"274","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"H\u6307\u6570 II","question":{"questionId":"275","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4ea4\u66ff\u4f4d\u4e8c\u8fdb\u5236\u6570","question":{"questionId":"693","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b9d\u77f3\u4e0e\u77f3\u5934","question":{"questionId":"782","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b8c\u5168\u5e73\u65b9\u6570","question":{"questionId":"279","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4f7f\u7528\u6700\u5c0f\u82b1\u8d39\u722c\u697c\u68af","question":{"questionId":"747","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5355\u8bcd\u66ff\u6362","question":{"questionId":"648","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u641c\u7d22\u6811\u7684\u6700\u8fd1\u516c\u5171\u7956\u5148","question":{"questionId":"235","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6570\u7ec4\u7684\u5747\u503c\u5206\u5272","question":{"questionId":"823","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6570\u5b57 1 \u7684\u4e2a\u6570","question":{"questionId":"233","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u957f\u4e0a\u5347\u5b50\u5e8f\u5217","question":{"questionId":"300","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5927\u6574\u9664\u5b50\u96c6","question":{"questionId":"368","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b9e\u73b0\u4e00\u4e2a\u9b54\u6cd5\u5b57\u5178","question":{"questionId":"676","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u552f\u4e00\u6469\u5c14\u65af\u5bc6\u7801\u8bcd","question":{"questionId":"822","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5199\u5b57\u7b26\u4e32\u9700\u8981\u7684\u884c\u6570","question":{"questionId":"824","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5206\u5272\u6570\u7ec4\u7684\u6700\u5927\u503c","question":{"questionId":"410","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u628a\u4e8c\u53c9\u641c\u7d22\u6811\u8f6c\u6362\u4e3a\u7d2f\u52a0\u6811","question":{"questionId":"538","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e24\u4e2a\u5217\u8868\u7684\u6700\u5c0f\u7d22\u5f15\u603b\u548c","question":{"questionId":"599","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u65cb\u8f6c\u6570\u5b57","question":{"questionId":"804","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8def\u5f84\u4ea4\u53c9","question":{"questionId":"335","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u641c\u7d22\u4e8c\u7ef4\u77e9\u9635 II","question":{"questionId":"240","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5206\u53d1\u997c\u5e72","question":{"questionId":"455","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5927\u4ea4\u6362","question":{"questionId":"670","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b8c\u7f8e\u77e9\u5f62","question":{"questionId":"391","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u77e9\u5f62\u9762\u79ef","question":{"questionId":"223","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u63a5\u96e8\u6c34 II","question":{"questionId":"407","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u548c\u4e3aK\u7684\u5b50\u6570\u7ec4","question":{"questionId":"560","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"4\u7684\u5e42","question":{"questionId":"342","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u975e\u9012\u51cf\u6570\u5217","question":{"questionId":"665","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u57fa\u672c\u8ba1\u7b97\u5668 II","question":{"questionId":"227","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u89e3\u7801\u65b9\u6cd5 2","question":{"questionId":"639","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u6811\u7684\u5e8f\u5217\u5316\u4e0e\u53cd\u5e8f\u5217\u5316","question":{"questionId":"297","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u627e\u5230\u6240\u6709\u6570\u7ec4\u4e2d\u6d88\u5931\u7684\u6570\u5b57","question":{"questionId":"448","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u77ed\u65e0\u5e8f\u8fde\u7eed\u5b50\u6570\u7ec4","question":{"questionId":"581","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8bbe\u8ba1\u63a8\u7279","question":{"questionId":"355","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u56fe\u7247\u5e73\u6ed1\u5668","question":{"questionId":"661","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5c9b\u5c7f\u7684\u6700\u5927\u9762\u79ef","question":{"questionId":"695","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4fee\u526a\u4e8c\u53c9\u641c\u7d22\u6811","question":{"questionId":"669","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u79fb\u6389K\u4f4d\u6570\u5b57","question":{"questionId":"402","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6253\u7816\u5757","question":{"questionId":"821","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u706f\u6ce1\u5f00\u5173","question":{"questionId":"319","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6c42\u4f17\u6570 II","question":{"questionId":"229","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u731c\u6570\u5b57\u6e38\u620f","question":{"questionId":"299","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6574\u6570\u62c6\u5206","question":{"questionId":"343","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u957f\u56de\u6587\u4e32","question":{"questionId":"409","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u641c\u7d22\u6811\u7684\u6700\u5c0f\u7edd\u5bf9\u5dee","question":{"questionId":"530","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5224\u65ad\u4e8c\u5206\u56fe","question":{"questionId":"801","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9664\u6cd5\u6c42\u503c","question":{"questionId":"399","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u957f\u7279\u6b8a\u5e8f\u5217 \u2160","question":{"questionId":"521","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u641c\u7d22\u6811\u4e2d\u7b2cK\u5c0f\u7684\u5143\u7d20","question":{"questionId":"230","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6241\u5e73\u5316\u5d4c\u5957\u5217\u8868\u8fed\u4ee3\u5668","question":{"questionId":"341","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u91d1\u5b57\u5854\u8f6c\u6362\u77e9\u9635","question":{"questionId":"757","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5c0f\u57fa\u56e0\u53d8\u5316","question":{"questionId":"433","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5bfb\u627e\u6570\u7ec4\u7684\u4e2d\u5fc3\u7d22\u5f15","question":{"questionId":"724","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6570\u5b57\u7684\u8865\u6570","question":{"questionId":"476","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"01 \u77e9\u9635","question":{"questionId":"542","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6574\u6570\u66ff\u6362","question":{"questionId":"397","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6839\u636e\u8eab\u9ad8\u91cd\u5efa\u961f\u5217","question":{"questionId":"406","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u79cd\u82b1\u95ee\u9898","question":{"questionId":"605","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u968f\u673a\u6570\u7d22\u5f15","question":{"questionId":"398","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u6811\u4e2d\u7b2c\u4e8c\u5c0f\u7684\u8282\u70b9","question":{"questionId":"671","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"K\u4e2a\u9006\u5e8f\u5bf9\u6570\u7ec4","question":{"questionId":"629","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6253\u4e71\u6570\u7ec4","question":{"questionId":"384","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u670b\u53cb\u5708","question":{"questionId":"547","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u6811\u7684\u6700\u8fd1\u516c\u5171\u7956\u5148","question":{"questionId":"236","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u524d K \u4e2a\u9ad8\u9891\u5143\u7d20","question":{"questionId":"347","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5168 O(1) \u7684\u6570\u636e\u7ed3\u6784","question":{"questionId":"432","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8def\u5f84\u603b\u548c III","question":{"questionId":"437","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5206\u7cd6\u679c","question":{"questionId":"575","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b57\u5178\u5e8f\u6392\u6570","question":{"questionId":"386","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5728LR\u5b57\u7b26\u4e32\u4e2d\u4ea4\u6362\u76f8\u90bb\u5b57\u7b26","question":{"questionId":"793","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9012\u589e\u5b50\u5e8f\u5217","question":{"questionId":"491","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9752\u86d9\u8fc7\u6cb3","question":{"questionId":"403","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5927\u56de\u6587\u6570\u4e58\u79ef","question":{"questionId":"479","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u73af\u5f62\u6570\u7ec4\u5faa\u73af","question":{"questionId":"457","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5bfb\u627e\u53f3\u533a\u95f4","question":{"questionId":"436","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5339\u914d\u5b50\u5e8f\u5217\u7684\u5355\u8bcd\u6570","question":{"questionId":"808","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u66ff\u6362\u540e\u7684\u6700\u957f\u91cd\u590d\u5b57\u7b26","question":{"questionId":"424","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6c42\u89e3\u65b9\u7a0b","question":{"questionId":"640","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6458\u6a31\u6843","question":{"questionId":"741","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"TinyURL \u7684\u52a0\u5bc6\u4e0e\u89e3\u5bc6","question":{"questionId":"535","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6709\u5e8f\u77e9\u9635\u4e2d\u7b2cK\u5c0f\u7684\u5143\u7d20","question":{"questionId":"378","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7956\u739b\u6e38\u620f","question":{"questionId":"488","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4fdd\u6301\u57ce\u5e02\u5929\u9645\u7ebf","question":{"questionId":"825","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":" \u8bbe\u7f6e\u4ea4\u96c6\u5927\u5c0f\u81f3\u5c11\u4e3a2","question":{"questionId":"759","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e24\u6570\u76f8\u52a0 II","question":{"questionId":"445","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u957f\u9012\u589e\u5b50\u5e8f\u5217\u7684\u4e2a\u6570","question":{"questionId":"673","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u76ee\u6807\u548c","question":{"questionId":"494","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8d85\u7ea7\u6b21\u65b9","question":{"questionId":"372","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5f3a\u5bc6\u7801\u68c0\u9a8c\u5668","question":{"questionId":"420","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5bfb\u627e\u6bd4\u76ee\u6807\u5b57\u6bcd\u5927\u7684\u6700\u5c0f\u5b57\u6bcd","question":{"questionId":"745","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e70\u5356\u80a1\u7968\u7684\u6700\u4f73\u65f6\u673a\u542b\u624b\u7eed\u8d39","question":{"questionId":"714","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6570\u7ec4\u7684\u5ea6","question":{"questionId":"697","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"LFU\u7f13\u5b58","question":{"questionId":"460","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u91cd\u590d\u53e0\u52a0\u5b57\u7b26\u4e32\u5339\u914d","question":{"questionId":"686","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8fde\u7eed\u6570\u7ec4","question":{"questionId":"525","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9a8c\u8bc1\u4e8c\u53c9\u6811\u7684\u524d\u5e8f\u5e8f\u5217\u5316","question":{"questionId":"331","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5220\u9664\u65e0\u6548\u7684\u62ec\u53f7","question":{"questionId":"301","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u81ea\u5b9a\u4e49\u5b57\u7b26\u4e32\u6392\u5e8f","question":{"questionId":"807","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u591a\u80fd\u5b8c\u6210\u6392\u5e8f\u7684\u5757","question":{"questionId":"780","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u591a\u80fd\u5b8c\u6210\u6392\u5e8f\u7684\u5757 II","question":{"questionId":"779","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5212\u5206\u5b57\u6bcd\u533a\u95f4","question":{"questionId":"768","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5230\u8fbe\u7ec8\u70b9\u6570\u5b57","question":{"questionId":"755","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u539f\u5b50\u7684\u6570\u91cf","question":{"questionId":"726","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5c0f\u79fb\u52a8\u6b21\u6570\u4f7f\u6570\u7ec4\u5143\u7d20\u76f8\u7b49","question":{"questionId":"453","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6570\u7ec4\u5d4c\u5957","question":{"questionId":"565","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e0b\u4e00\u4e2a\u66f4\u5927\u5143\u7d20 III","question":{"questionId":"556","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u706b\u67f4\u62fc\u6b63\u65b9\u5f62","question":{"questionId":"473","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9876\u7aef\u8fed\u4ee3\u5668","question":{"questionId":"284","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5206\u6c64","question":{"questionId":"826","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9636\u4e58\u51fd\u6570\u540eK\u4e2a\u96f6","question":{"questionId":"809","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e0b\u4e00\u4e2a\u66f4\u5927\u5143\u7d20 I","question":{"questionId":"496","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9519\u8bef\u7684\u96c6\u5408","question":{"questionId":"645","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e0d\u542b\u8fde\u7eed1\u7684\u975e\u8d1f\u6574\u6570","question":{"questionId":"600","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5927\u5355\u8bcd\u957f\u5ea6\u4e58\u79ef","question":{"questionId":"318","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6570\u7ec4\u4e2d\u4e24\u4e2a\u6570\u7684\u6700\u5927\u5f02\u6216\u503c","question":{"questionId":"421","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b57\u5178\u5e8f\u7684\u7b2cK\u5c0f\u6570\u5b57","question":{"questionId":"440","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b66\u751f\u51fa\u52e4\u8bb0\u5f55 II","question":{"questionId":"552","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9664\u81ea\u8eab\u4ee5\u5916\u6570\u7ec4\u7684\u4e58\u79ef","question":{"questionId":"238","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u56de\u6587\u5b50\u4e32","question":{"questionId":"647","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6570\u7ec4\u4e2d\u7684K-diff\u6570\u5bf9","question":{"questionId":"532","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6570\u7ec4\u4e2d\u91cd\u590d\u7684\u6570\u636e","question":{"questionId":"442","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5458\u5de5\u7684\u91cd\u8981\u6027","question":{"questionId":"690","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7532\u677f\u4e0a\u7684\u6218\u8230","question":{"questionId":"419","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5c0f\u9ad8\u5ea6\u6811","question":{"questionId":"310","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u524d\u7f00\u548c\u540e\u7f00\u641c\u7d22","question":{"questionId":"746","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e09\u4e2a\u65e0\u91cd\u53e0\u5b50\u6570\u7ec4\u7684\u6700\u5927\u548c","question":{"questionId":"689","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u957f\u56de\u6587\u5b50\u5e8f\u5217","question":{"questionId":"516","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u56de\u65cb\u9556\u7684\u6570\u91cf","question":{"questionId":"447","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u65e0\u91cd\u53e0\u533a\u95f4","question":{"questionId":"435","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4ece\u82f1\u6587\u4e2d\u91cd\u5efa\u6570\u5b57","question":{"questionId":"423","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u65cb\u8f6c\u51fd\u6570","question":{"questionId":"396","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8d85\u7ea7\u4e11\u6570","question":{"questionId":"313","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8ba1\u7b97\u5404\u4e2a\u4f4d\u6570\u4e0d\u540c\u7684\u6570\u5b57\u4e2a\u6570","question":{"questionId":"357","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6446\u52a8\u6392\u5e8f II","question":{"questionId":"324","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5947\u602a\u7684\u6253\u5370\u673a","question":{"questionId":"664","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b50\u57df\u540d\u8bbf\u95ee\u8ba1\u6570","question":{"questionId":"829","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e24\u4e2a\u5b57\u7b26\u4e32\u7684\u6700\u5c0fASCII\u5220\u9664\u548c","question":{"questionId":"712","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7ffb\u8f6c\u5bf9","question":{"questionId":"493","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u8fdb\u5236\u8868\u793a\u4e2d\u8d28\u6570\u4e2a\u8ba1\u7b97\u7f6e\u4f4d","question":{"questionId":"767","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e0b\u4e00\u4e2a\u66f4\u5927\u5143\u7d20 II","question":{"questionId":"503","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6ed1\u52a8\u7a97\u53e3\u6700\u5927\u503c","question":{"questionId":"239","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u626b\u96f7\u6e38\u620f","question":{"questionId":"529","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5220\u9664\u4e0e\u83b7\u5f97\u70b9\u6570","question":{"questionId":"740","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u6811\u6700\u5927\u5bbd\u5ea6","question":{"questionId":"662","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4f7f\u5e8f\u5217\u9012\u589e\u7684\u6700\u5c0f\u4ea4\u6362\u6b21\u6570","question":{"questionId":"819","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"24 \u70b9\u6e38\u620f","question":{"questionId":"679","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6709\u6548\u4e09\u89d2\u5f62\u7684\u4e2a\u6570","question":{"questionId":"611","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4efb\u52a1\u8c03\u5ea6\u5668","question":{"questionId":"621","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6807\u7b7e\u9a8c\u8bc1\u5668","question":{"questionId":"591","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9999\u69df\u5854","question":{"questionId":"815","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5c0f\u533a\u95f4","question":{"questionId":"632","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u53e6\u4e00\u4e2a\u6811\u7684\u5b50\u6811","question":{"questionId":"572","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u590d\u6570\u4e58\u6cd5","question":{"questionId":"537","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b89\u88c5\u6805\u680f","question":{"questionId":"587","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"O(1) \u65f6\u95f4\u63d2\u5165\u3001\u5220\u9664\u548c\u83b7\u53d6\u968f\u673a\u5143\u7d20 - \u5141\u8bb8\u91cd\u590d","question":{"questionId":"381","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5e38\u6570\u65f6\u95f4\u63d2\u5165\u3001\u5220\u9664\u548c\u83b7\u53d6\u968f\u673a\u5143\u7d20","question":{"questionId":"380","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5728\u4e8c\u53c9\u6811\u4e2d\u589e\u52a0\u4e00\u884c","question":{"questionId":"623","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e00\u548c\u96f6","question":{"questionId":"474","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"132\u6a21\u5f0f","question":{"questionId":"456","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5c9b\u5c7f\u7684\u5468\u957f","question":{"questionId":"463","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6839\u636e\u5b57\u7b26\u51fa\u73b0\u9891\u7387\u6392\u5e8f","question":{"questionId":"451","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u91cd\u590d\u7684\u5b50\u5b57\u7b26\u4e32","question":{"questionId":"459","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6c49\u660e\u8ddd\u79bb\u603b\u548c","question":{"questionId":"477","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u76f8\u5bf9\u540d\u6b21","question":{"questionId":"506","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u7ef4\u533a\u57df\u548c\u68c0\u7d22 - \u77e9\u9635\u4e0d\u53ef\u53d8","question":{"questionId":"304","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b57\u7b26\u4e32\u89e3\u7801","question":{"questionId":"394","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"UTF-8 \u7f16\u7801\u9a8c\u8bc1","question":{"questionId":"393","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u81f3\u5c11\u6709K\u4e2a\u91cd\u590d\u5b57\u7b26\u7684\u6700\u957f\u5b50\u4e32","question":{"questionId":"395","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5224\u65ad\u5b50\u5e8f\u5217","question":{"questionId":"392","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7f51\u7edc\u5ef6\u8fdf\u65f6\u95f4","question":{"questionId":"744","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u731c\u6570\u5b57\u5927\u5c0f II","question":{"questionId":"375","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8f93\u51fa\u4e8c\u53c9\u6811","question":{"questionId":"655","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u60c5\u4fa3\u7275\u624b","question":{"questionId":"770","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u94fe\u8868\u968f\u673a\u8282\u70b9","question":{"questionId":"382","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5927\u4e09\u89d2\u5f62\u9762\u79ef","question":{"questionId":"830","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5927\u5e73\u5747\u503c\u548c\u7684\u5206\u7ec4","question":{"questionId":"831","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7528\u961f\u5217\u5b9e\u73b0\u6808","question":{"questionId":"225","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9884\u6d4b\u8d62\u5bb6","question":{"questionId":"486","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8303\u56f4\u6c42\u548c II","question":{"questionId":"598","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u516c\u4ea4\u8def\u7ebf","question":{"questionId":"833","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u56fe\u50cf\u6e32\u67d3","question":{"questionId":"733","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u67e5\u627e\u548c\u6700\u5c0f\u7684K\u5bf9\u6570\u5b57","question":{"questionId":"373","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7b49\u5dee\u6570\u5217\u5212\u5206","question":{"questionId":"413","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5bfb\u627e\u6700\u8fd1\u7684\u56de\u6587\u6570","question":{"questionId":"564","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8d5b\u8f66","question":{"questionId":"836","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5e38\u89c1\u7684\u5355\u8bcd","question":{"questionId":"837","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6784\u9020\u77e9\u5f62","question":{"questionId":"492","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e24\u4e2a\u5b57\u7b26\u4e32\u7684\u5220\u9664\u64cd\u4f5c","question":{"questionId":"583","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u6811\u526a\u679d","question":{"questionId":"832","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6709\u6548\u7684\u4e95\u5b57\u6e38\u620f","question":{"questionId":"810","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u627e\u5230\u5b57\u7b26\u4e32\u4e2d\u6240\u6709\u5b57\u6bcd\u5f02\u4f4d\u8bcd","question":{"questionId":"438","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b57\u7b26\u7684\u6700\u77ed\u8ddd\u79bb","question":{"questionId":"841","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5bf9\u89d2\u7ebf\u904d\u5386","question":{"questionId":"498","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5947\u5076\u94fe\u8868","question":{"questionId":"328","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4f9b\u6696\u5668","question":{"questionId":"475","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u884c\u661f\u78b0\u649e","question":{"questionId":"735","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e3a\u8fd0\u7b97\u8868\u8fbe\u5f0f\u8bbe\u8ba1\u4f18\u5148\u7ea7","question":{"questionId":"241","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u751f\u547d\u6e38\u620f","question":{"questionId":"289","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u77e9\u9635\u4e2d\u7684\u6700\u957f\u9012\u589e\u8def\u5f84","question":{"questionId":"329","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9003\u8131\u963b\u788d\u8005","question":{"questionId":"805","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u60c5\u611f\u4e30\u5bcc\u7684\u6587\u5b57","question":{"questionId":"827","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7d2f\u52a0\u6570","question":{"questionId":"306","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8fde\u63a5\u8bcd","question":{"questionId":"472","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6211\u7684\u65e5\u7a0b\u5b89\u6392\u8868 I","question":{"questionId":"729","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6211\u7684\u65e5\u7a0b\u5b89\u6392\u8868 II","question":{"questionId":"731","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6211\u7684\u65e5\u7a0b\u5b89\u6392\u8868 III","question":{"questionId":"732","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5220\u9664\u4e8c\u53c9\u641c\u7d22\u6811\u4e2d\u7684\u8282\u70b9","question":{"questionId":"450","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u53ea\u6709\u4e24\u4e2a\u952e\u7684\u952e\u76d8","question":{"questionId":"650","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u957f\u91cd\u590d\u5b50\u6570\u7ec4","question":{"questionId":"718","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u51fd\u6570\u7684\u72ec\u5360\u65f6\u95f4","question":{"questionId":"636","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6309\u8981\u6c42\u8865\u9f50\u6570\u7ec4","question":{"questionId":"330","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5355\u8c03\u9012\u589e\u7684\u6570\u5b57","question":{"questionId":"738","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u4f73\u4e70\u5356\u80a1\u7968\u65f6\u673a\u542b\u51b7\u51bb\u671f","question":{"questionId":"309","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u901a\u8fc7\u5220\u9664\u5b57\u6bcd\u5339\u914d\u5230\u5b57\u5178\u91cc\u6700\u957f\u5355\u8bcd","question":{"questionId":"524","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u4f18\u9664\u6cd5","question":{"questionId":"553","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u952e\u503c\u6620\u5c04","question":{"questionId":"677","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8fde\u7eed\u6574\u6570\u6c42\u548c","question":{"questionId":"856","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9a8c\u8bc1IP\u5730\u5740","question":{"questionId":"468","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"N\u53c9\u6811\u7684\u6700\u5927\u6df1\u5ea6","question":{"questionId":"774","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"N\u53c9\u6811\u7684\u524d\u5e8f\u904d\u5386","question":{"questionId":"775","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"N\u53c9\u6811\u7684\u540e\u5e8f\u904d\u5386","question":{"questionId":"776","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"N\u53c9\u6811\u7684\u5c42\u5e8f\u904d\u5386","question":{"questionId":"764","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6570\u636e\u6d41\u4e2d\u7684\u7b2cK\u5927\u5143\u7d20","question":{"questionId":"789","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u641c\u7d22\u6811\u4e2d\u7684\u641c\u7d22","question":{"questionId":"783","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7ffb\u8f6c\u56fe\u50cf","question":{"questionId":"861","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5927\u4eba\u5de5\u5c9b","question":{"questionId":"854","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u641c\u7d22\u6811\u4e2d\u7684\u63d2\u5165\u64cd\u4f5c","question":{"questionId":"784","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u533a\u57df\u548c\u68c0\u7d22 - \u6570\u7ec4\u53ef\u4fee\u6539","question":{"questionId":"307","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u77e9\u5f62\u91cd\u53e0","question":{"questionId":"866","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u63a8\u591a\u7c73\u8bfa","question":{"questionId":"868","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u65b021\u70b9","question":{"questionId":"867","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u76f8\u4f3c\u5b57\u7b26\u4e32\u7ec4","question":{"questionId":"869","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5927\u793c\u5305","question":{"questionId":"638","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u533a\u95f4\u548c\u7684\u4e2a\u6570","question":{"questionId":"327","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u72ec\u7279\u5b57\u7b26\u4e32","question":{"questionId":"855","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8f83\u5927\u5206\u7ec4\u7684\u4f4d\u7f6e","question":{"questionId":"857","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6d88\u9664\u6e38\u620f","question":{"questionId":"390","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4fc4\u7f57\u65af\u5957\u5a03\u4fe1\u5c01\u95ee\u9898","question":{"questionId":"354","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5c06\u6570\u7ec4\u62c6\u5206\u6210\u6590\u6ce2\u90a3\u5951\u5e8f\u5217","question":{"questionId":"872","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u77e9\u9635\u4e2d\u7684\u5e7b\u65b9","question":{"questionId":"870","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u94a5\u5319\u548c\u623f\u95f4","question":{"questionId":"871","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u731c\u731c\u8fd9\u4e2a\u5355\u8bcd","question":{"questionId":"873","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9ed1\u677f\u5f02\u6216\u6e38\u620f","question":{"questionId":"828","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6446\u52a8\u5e8f\u5217","question":{"questionId":"376","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6811\u4e2d\u8ddd\u79bb\u4e4b\u548c","question":{"questionId":"863","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u68ee\u6797\u4e2d\u7684\u5154\u5b50","question":{"questionId":"797","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5c71\u7f8a\u62c9\u4e01\u6587","question":{"questionId":"851","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u957f\u6570\u5bf9\u94fe","question":{"questionId":"646","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5206\u6570\u52a0\u51cf\u8fd0\u7b97","question":{"questionId":"592","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7279\u6b8a\u7684\u4e8c\u8fdb\u5236\u5e8f\u5217","question":{"questionId":"763","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6587\u4ef6\u7684\u6700\u957f\u7edd\u5bf9\u8def\u5f84","question":{"questionId":"388","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e58\u79ef\u5c0f\u4e8eK\u7684\u5b50\u6570\u7ec4","question":{"questionId":"713","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u51fa\u754c\u7684\u8def\u5f84\u6570","question":{"questionId":"576","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7ec4\u5408\u603b\u548c \u2163","question":{"questionId":"377","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4f18\u7f8e\u7684\u6392\u5217","question":{"questionId":"526","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6bd4\u8f83\u542b\u9000\u683c\u7684\u5b57\u7b26\u4e32","question":{"questionId":"874","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6570\u7ec4\u4e2d\u7684\u6700\u957f\u5c71\u8109","question":{"questionId":"875","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e00\u624b\u987a\u5b50","question":{"questionId":"876","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8bbf\u95ee\u6240\u6709\u8282\u70b9\u7684\u6700\u77ed\u8def\u5f84","question":{"questionId":"877","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9002\u9f84\u7684\u670b\u53cb","question":{"questionId":"852","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8fde\u7eed\u7684\u5b50\u6570\u7ec4\u548c","question":{"questionId":"523","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5bfb\u627e\u91cd\u590d\u7684\u5b50\u6811","question":{"questionId":"652","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u77e9\u5f62\u533a\u57df\u4e0d\u8d85\u8fc7 K \u7684\u6700\u5927\u6570\u503c\u548c","question":{"questionId":"363","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u706f\u6ce1\u5f00\u5173 \u2161","question":{"questionId":"672","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b57\u6bcd\u79fb\u4f4d","question":{"questionId":"878","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5230\u6700\u8fd1\u7684\u4eba\u7684\u6700\u5927\u8ddd\u79bb","question":{"questionId":"879","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u77e9\u5f62\u9762\u79ef II","question":{"questionId":"880","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u55a7\u95f9\u548c\u5bcc\u6709","question":{"questionId":"881","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6211\u80fd\u8d62\u5417","question":{"questionId":"464","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5c71\u8109\u6570\u7ec4\u7684\u5cf0\u9876\u7d22\u5f15","question":{"questionId":"882","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8f66\u961f","question":{"questionId":"883","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u76f8\u4f3c\u5ea6\u4e3a K \u7684\u5b57\u7b26\u4e32","question":{"questionId":"884","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8003\u573a\u5c31\u5ea7","question":{"questionId":"885","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7816\u5899","question":{"questionId":"554","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8d85\u7ea7\u6d17\u8863\u673a","question":{"questionId":"517","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u795e\u5947\u5b57\u7b26\u4e32","question":{"questionId":"481","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u641c\u7d22\u6811\u4e2d\u7684\u4f17\u6570","question":{"questionId":"501","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5bc6\u94a5\u683c\u5f0f\u5316","question":{"questionId":"482","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"K \u7ad9\u4e2d\u8f6c\u5185\u6700\u4fbf\u5b9c\u7684\u822a\u73ed","question":{"questionId":"803","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4eb2\u5bc6\u5b57\u7b26\u4e32","question":{"questionId":"889","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u955c\u9762\u53cd\u5c04","question":{"questionId":"888","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u62ec\u53f7\u7684\u5206\u6570","question":{"questionId":"886","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u96c7\u4f63 K \u540d\u5de5\u4eba\u7684\u6700\u4f4e\u6210\u672c","question":{"questionId":"887","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5206\u5272\u7b49\u548c\u5b50\u96c6","question":{"questionId":"416","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u67e0\u6aac\u6c34\u627e\u96f6","question":{"questionId":"890","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7ffb\u8f6c\u77e9\u9635\u540e\u7684\u5f97\u5206","question":{"questionId":"891","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u548c\u81f3\u5c11\u4e3a K \u7684\u6700\u77ed\u5b50\u6570\u7ec4","question":{"questionId":"892","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u6811\u4e2d\u6240\u6709\u8ddd\u79bb\u4e3a K \u7684\u7ed3\u70b9","question":{"questionId":"893","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8f6c\u7f6e\u77e9\u9635","question":{"questionId":"898","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u83b7\u53d6\u6240\u6709\u94a5\u5319\u7684\u6700\u77ed\u8def\u5f84","question":{"questionId":"895","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5177\u6709\u6240\u6709\u6700\u6df1\u7ed3\u70b9\u7684\u6700\u5c0f\u5b50\u6811","question":{"questionId":"896","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u56de\u6587\u7d20\u6570","question":{"questionId":"897","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4f18\u52bf\u6d17\u724c","question":{"questionId":"901","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u91cd\u65b0\u6392\u5e8f\u5f97\u5230 2 \u7684\u5e42","question":{"questionId":"900","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u8fdb\u5236\u95f4\u8ddd","question":{"questionId":"899","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u4f4e\u52a0\u6cb9\u6b21\u6570","question":{"questionId":"902","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"IPO","question":{"questionId":"502","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u79fb\u9664\u76d2\u5b50","question":{"questionId":"546","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u56fe\u50cf\u91cd\u53e0","question":{"questionId":"864","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b89\u6392\u5de5\u4f5c\u4ee5\u8fbe\u5230\u6700\u5927\u6536\u76ca","question":{"questionId":"853","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7edf\u8ba1\u91cd\u590d\u4e2a\u6570","question":{"questionId":"466","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"Lisp \u8bed\u6cd5\u89e3\u6790","question":{"questionId":"736","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5e8f\u5217\u5316\u548c\u53cd\u5e8f\u5217\u5316\u4e8c\u53c9\u641c\u7d22\u6811","question":{"questionId":"449","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7edf\u8ba1\u4e0d\u540c\u56de\u6587\u5b50\u5b57\u7b26\u4e32","question":{"questionId":"730","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5927\u52a0\u53f7\u6807\u5fd7","question":{"questionId":"769","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6ed1\u52a8\u7a97\u53e3\u4e2d\u4f4d\u6570","question":{"questionId":"480","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9690\u85cf\u4e2a\u4eba\u4fe1\u606f","question":{"questionId":"858","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8f6c\u6362\u6210\u5c0f\u5199\u5b57\u6bcd","question":{"questionId":"742","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8bbe\u8ba1\u54c8\u5e0c\u96c6\u5408","question":{"questionId":"816","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8bbe\u8ba1\u54c8\u5e0c\u6620\u5c04","question":{"questionId":"817","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6a21\u7cca\u5750\u6807","question":{"questionId":"834","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u53f6\u5b50\u76f8\u4f3c\u7684\u6811","question":{"questionId":"904","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u957f\u7684\u6590\u6ce2\u90a3\u5951\u5b50\u5e8f\u5217\u7684\u957f\u5ea6","question":{"questionId":"905","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6a21\u62df\u884c\u8d70\u673a\u5668\u4eba","question":{"questionId":"906","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7231\u5403\u9999\u8549\u7684\u73c2\u73c2","question":{"questionId":"907","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7528 Rand7() \u5b9e\u73b0 Rand10()","question":{"questionId":"903","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"Dota2 \u53c2\u8bae\u9662","question":{"questionId":"649","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e3a\u9ad8\u5c14\u592b\u6bd4\u8d5b\u780d\u6811","question":{"questionId":"675","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4f18\u7f8e\u7684\u6392\u5217 II","question":{"questionId":"667","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8bbe\u8ba1\u5faa\u73af\u961f\u5217","question":{"questionId":"860","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5206\u5272\u6570\u7ec4\u4e3a\u8fde\u7eed\u5b50\u5e8f\u5217","question":{"questionId":"659","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u51fa\u73b0\u6b21\u6570\u6700\u591a\u7684\u5b50\u6811\u5143\u7d20\u548c","question":{"questionId":"508","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6389\u843d\u7684\u65b9\u5757","question":{"questionId":"699","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5355\u8bcd\u7684\u538b\u7f29\u7f16\u7801","question":{"questionId":"839","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u592a\u5e73\u6d0b\u5927\u897f\u6d0b\u6c34\u6d41\u95ee\u9898","question":{"questionId":"417","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u5206\u67e5\u627e","question":{"questionId":"792","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5c06\u6570\u636e\u6d41\u53d8\u4e3a\u591a\u4e2a\u4e0d\u76f8\u4ea4\u533a\u95f4","question":{"questionId":"352","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8bbe\u8ba1\u94fe\u8868","question":{"questionId":"838","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6253\u5f00\u8f6c\u76d8\u9501","question":{"questionId":"753","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8bfe\u7a0b\u8868 III","question":{"questionId":"630","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5e26\u56e0\u5b50\u7684\u4e8c\u53c9\u6811","question":{"questionId":"843","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u91cd\u65b0\u5b89\u6392\u884c\u7a0b","question":{"questionId":"332","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u957f\u7279\u6b8a\u5e8f\u5217 II","question":{"questionId":"522","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5168\u5c40\u5012\u7f6e\u4e0e\u5c40\u90e8\u5012\u7f6e","question":{"questionId":"790","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u94fe\u8868\u7684\u4e2d\u95f4\u7ed3\u70b9","question":{"questionId":"908","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7b2c N \u4e2a\u795e\u5947\u6570\u5b57","question":{"questionId":"910","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u76c8\u5229\u8ba1\u5212","question":{"questionId":"911","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u77f3\u5b50\u6e38\u620f","question":{"questionId":"909","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6c34\u4f4d\u4e0a\u5347\u7684\u6cf3\u6c60\u4e2d\u6e38\u6cf3","question":{"questionId":"794","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9ed1\u540d\u5355\u4e2d\u7684\u968f\u673a\u6570","question":{"questionId":"894","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5efa\u7acb\u56db\u53c9\u6811","question":{"questionId":"772","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6240\u6709\u53ef\u80fd\u7684\u8def\u5f84","question":{"questionId":"813","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6ed1\u52a8\u8c1c\u9898","question":{"questionId":"787","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7834\u89e3\u4fdd\u9669\u7bb1","question":{"questionId":"754","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6551\u751f\u8247","question":{"questionId":"917","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e09\u7ef4\u5f62\u4f53\u6295\u5f71\u9762\u79ef","question":{"questionId":"919","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7d22\u5f15\u5904\u7684\u89e3\u7801\u5b57\u7b26\u4e32","question":{"questionId":"916","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7ec6\u5206\u56fe\u4e2d\u7684\u53ef\u5230\u8fbe\u7ed3\u70b9","question":{"questionId":"918","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u627e\u5230 K \u4e2a\u6700\u63a5\u8fd1\u7684\u5143\u7d20","question":{"questionId":"658","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u81ea\u7531\u4e4b\u8def","question":{"questionId":"514","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5c0f\u597d\u8fdb\u5236","question":{"questionId":"483","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e24\u53e5\u8bdd\u4e2d\u7684\u4e0d\u5e38\u89c1\u5355\u8bcd","question":{"questionId":"920","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u87ba\u65cb\u77e9\u9635 III","question":{"questionId":"921","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u53ef\u80fd\u7684\u4e8c\u5206\u6cd5","question":{"questionId":"922","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9e21\u86cb\u6389\u843d","question":{"questionId":"923","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6241\u5e73\u5316\u591a\u7ea7\u53cc\u5411\u94fe\u8868","question":{"questionId":"766","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u73af\u7ed5\u5b57\u7b26\u4e32\u4e2d\u552f\u4e00\u7684\u5b50\u5b57\u7b26\u4e32","question":{"questionId":"467","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7b2c K \u4e2a\u6700\u5c0f\u7684\u7d20\u6570\u5206\u6570","question":{"questionId":"802","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6309\u6743\u91cd\u968f\u673a\u9009\u62e9","question":{"questionId":"912","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5728\u5706\u5185\u968f\u673a\u751f\u6210\u70b9","question":{"questionId":"915","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u627e\u5230\u6700\u7ec8\u7684\u5b89\u5168\u72b6\u6001","question":{"questionId":"820","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u968f\u673a\u7ffb\u8f6c\u77e9\u9635","question":{"questionId":"913","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5728\u7cfb\u7edf\u4e2d\u67e5\u627e\u91cd\u590d\u6587\u4ef6","question":{"questionId":"609","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8bbe\u8ba1\u5faa\u73af\u53cc\u7aef\u961f\u5217","question":{"questionId":"859","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u516c\u5e73\u7684\u7cd6\u679c\u4ea4\u6362","question":{"questionId":"924","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6839\u636e\u524d\u5e8f\u548c\u540e\u5e8f\u904d\u5386\u6784\u9020\u4e8c\u53c9\u6811","question":{"questionId":"925","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b50\u5e8f\u5217\u5bbd\u5ea6\u4e4b\u548c","question":{"questionId":"927","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u67e5\u627e\u548c\u66ff\u6362\u6a21\u5f0f","question":{"questionId":"926","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e09\u7ef4\u5f62\u4f53\u7684\u8868\u9762\u79ef","question":{"questionId":"928","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6240\u6709\u53ef\u80fd\u7684\u6ee1\u4e8c\u53c9\u6811","question":{"questionId":"930","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7279\u6b8a\u7b49\u4ef7\u5b57\u7b26\u4e32\u7ec4","question":{"questionId":"929","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5927\u9891\u7387\u6808","question":{"questionId":"931","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u591a\u7c73\u8bfa\u548c\u6258\u7c73\u8bfa\u5e73\u94fa","question":{"questionId":"806","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8ff7\u4f60\u8bed\u6cd5\u5206\u6790\u5668","question":{"questionId":"385","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5206\u9694\u94fe\u8868","question":{"questionId":"725","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7ffb\u8f6c\u5361\u7247\u6e38\u620f","question":{"questionId":"842","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5355\u8c03\u6570\u5217","question":{"questionId":"932","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b50\u6570\u7ec4\u6309\u4f4d\u6216\u64cd\u4f5c","question":{"questionId":"934","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9012\u589e\u987a\u5e8f\u67e5\u627e\u6811","question":{"questionId":"933","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6709\u5e8f\u961f\u5217","question":{"questionId":"935","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5230\u8fbe\u7ec8\u70b9","question":{"questionId":"796","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u94fe\u8868\u7ec4\u4ef6","question":{"questionId":"835","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"DI \u5e8f\u5217\u7684\u6709\u6548\u6392\u5217","question":{"questionId":"939","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5927\u4e3a N \u7684\u6570\u5b57\u7ec4\u5408","question":{"questionId":"938","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u80a1\u7968\u4ef7\u683c\u8de8\u5ea6","question":{"questionId":"937","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"RLE \u8fed\u4ee3\u5668","question":{"questionId":"936","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6309\u5947\u5076\u6392\u5e8f\u6570\u7ec4","question":{"questionId":"941","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8d85\u7ea7\u56de\u6587\u6570","question":{"questionId":"942","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b50\u6570\u7ec4\u7684\u6700\u5c0f\u503c\u4e4b\u548c","question":{"questionId":"943","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6c34\u679c\u6210\u7bee","question":{"questionId":"940","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5c0f\u5dee\u503c I","question":{"questionId":"944","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5c0f\u5dee\u503c II","question":{"questionId":"946","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u86c7\u68af\u68cb","question":{"questionId":"945","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5728\u7ebf\u9009\u4e3e","question":{"questionId":"947","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9694\u79bb\u75c5\u6bd2","question":{"questionId":"750","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u77ed\u5b8c\u6574\u8bcd","question":{"questionId":"749","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5361\u724c\u5206\u7ec4","question":{"questionId":"950","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5206\u5272\u6570\u7ec4","question":{"questionId":"951","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5355\u8bcd\u5b50\u96c6","question":{"questionId":"952","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u732b\u548c\u8001\u9f20","question":{"questionId":"949","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4ec5\u4ec5\u53cd\u8f6c\u5b57\u6bcd","question":{"questionId":"953","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u73af\u5f62\u5b50\u6570\u7ec4\u7684\u6700\u5927\u548c","question":{"questionId":"954","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u64ad\u653e\u5217\u8868\u7684\u6570\u91cf","question":{"questionId":"956","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b8c\u5168\u4e8c\u53c9\u6811\u63d2\u5165\u5668","question":{"questionId":"955","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u53d8\u4e3a\u68cb\u76d8","question":{"questionId":"798","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u56db\u53c9\u6811\u4ea4\u96c6","question":{"questionId":"773","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4f7f\u62ec\u53f7\u6709\u6548\u7684\u6700\u5c11\u6dfb\u52a0","question":{"questionId":"957","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6309\u5947\u5076\u6392\u5e8f\u6570\u7ec4 II","question":{"questionId":"958","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e09\u6570\u4e4b\u548c\u7684\u591a\u79cd\u53ef\u80fd","question":{"questionId":"959","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5c3d\u91cf\u51cf\u5c11\u6076\u610f\u8f6f\u4ef6\u7684\u4f20\u64ad","question":{"questionId":"960","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u975e\u91cd\u53e0\u77e9\u5f62\u4e2d\u7684\u968f\u673a\u70b9","question":{"questionId":"914","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7b49\u5dee\u6570\u5217\u5212\u5206 II - \u5b50\u5e8f\u5217","question":{"questionId":"446","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"Range \u6a21\u5757","question":{"questionId":"715","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b57\u7b26\u4e32\u4e2d\u7684\u67e5\u627e\u4e0e\u66ff\u6362","question":{"questionId":"862","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5f97\u5206\u6700\u9ad8\u7684\u6700\u5c0f\u8f6e\u8c03","question":{"questionId":"814","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8d34\u7eb8\u62fc\u8bcd","question":{"questionId":"691","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u57fa\u672c\u8ba1\u7b97\u5668 IV","question":{"questionId":"781","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u957f\u6309\u952e\u5165","question":{"questionId":"961","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e09\u7b49\u5206","question":{"questionId":"963","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5c06\u5b57\u7b26\u4e32\u7ffb\u8f6c\u5230\u5355\u8c03\u9012\u589e","question":{"questionId":"962","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5c3d\u91cf\u51cf\u5c11\u6076\u610f\u8f6f\u4ef6\u7684\u4f20\u64ad II","question":{"questionId":"964","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u548c\u76f8\u540c\u7684\u4e8c\u5143\u5b50\u6570\u7ec4","question":{"questionId":"966","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e0b\u964d\u8def\u5f84\u6700\u5c0f\u548c","question":{"questionId":"967","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6f02\u4eae\u6570\u7ec4","question":{"questionId":"968","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u72ec\u7279\u7684\u7535\u5b50\u90ae\u4ef6\u5730\u5740","question":{"questionId":"965","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u77ed\u7684\u6865","question":{"questionId":"971","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9a91\u58eb\u62e8\u53f7\u5668","question":{"questionId":"972","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u8fd1\u7684\u8bf7\u6c42\u6b21\u6570","question":{"questionId":"969","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6233\u5370\u5e8f\u5217","question":{"questionId":"973","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u91cd\u65b0\u6392\u5217\u65e5\u5fd7\u6587\u4ef6","question":{"questionId":"974","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u641c\u7d22\u6811\u7684\u8303\u56f4\u548c","question":{"questionId":"975","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5c0f\u9762\u79ef\u77e9\u5f62","question":{"questionId":"976","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e0d\u540c\u7684\u5b50\u5e8f\u5217 II","question":{"questionId":"977","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6709\u6548\u7684\u5c71\u8109\u6570\u7ec4","question":{"questionId":"978","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u589e\u51cf\u5b57\u7b26\u4e32\u5339\u914d","question":{"questionId":"979","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u77ed\u8d85\u7ea7\u4e32","question":{"questionId":"980","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5220\u5217\u9020\u5e8f","question":{"questionId":"981","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4f7f\u6570\u7ec4\u552f\u4e00\u7684\u6700\u5c0f\u589e\u91cf","question":{"questionId":"982","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9a8c\u8bc1\u6808\u5e8f\u5217","question":{"questionId":"983","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u79fb\u9664\u6700\u591a\u7684\u540c\u884c\u6216\u540c\u5217\u77f3\u5934","question":{"questionId":"984","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4ee4\u724c\u653e\u7f6e","question":{"questionId":"985","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7ed9\u5b9a\u6570\u5b57\u80fd\u7ec4\u6210\u7684\u6700\u5927\u65f6\u95f4","question":{"questionId":"986","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6309\u516c\u56e0\u6570\u8ba1\u7b97\u6700\u5927\u7ec4\u4ef6\u5927\u5c0f","question":{"questionId":"989","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6309\u9012\u589e\u987a\u5e8f\u663e\u793a\u5361\u724c","question":{"questionId":"987","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7ffb\u8f6c\u7b49\u4ef7\u4e8c\u53c9\u6811","question":{"questionId":"988","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9a8c\u8bc1\u5916\u661f\u8bed\u8bcd\u5178","question":{"questionId":"990","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u500d\u6570\u5bf9\u6570\u7ec4","question":{"questionId":"991","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u9ad8\u7684\u5e7f\u544a\u724c","question":{"questionId":"993","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5220\u5217\u9020\u5e8f II","question":{"questionId":"992","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7531\u659c\u6760\u5212\u5206\u533a\u57df","question":{"questionId":"999","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"N \u5929\u540e\u7684\u7262\u623f","question":{"questionId":"994","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u6811\u7684\u5b8c\u5168\u6027\u68c0\u9a8c","question":{"questionId":"998","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5220\u5217\u9020\u5e8f III","question":{"questionId":"1000","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u91cd\u590d N \u6b21\u7684\u5143\u7d20","question":{"questionId":"1001","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5927\u5bbd\u5ea6\u5761","question":{"questionId":"1002","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5c0f\u9762\u79ef\u77e9\u5f62 II","question":{"questionId":"1003","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8868\u793a\u6570\u5b57\u7684\u6700\u5c11\u8fd0\u7b97\u7b26","question":{"questionId":"1004","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5355\u503c\u4e8c\u53c9\u6811","question":{"questionId":"1005","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8fde\u7eed\u5dee\u76f8\u540c\u7684\u6570\u5b57","question":{"questionId":"1007","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u76d1\u63a7\u4e8c\u53c9\u6811","question":{"questionId":"1008","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5143\u97f3\u62fc\u5199\u68c0\u67e5\u5668","question":{"questionId":"1006","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5f3a\u6574\u6570","question":{"questionId":"1010","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u714e\u997c\u6392\u5e8f","question":{"questionId":"1009","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7ffb\u8f6c\u4e8c\u53c9\u6811\u4ee5\u5339\u914d\u5148\u5e8f\u904d\u5386","question":{"questionId":"1011","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u76f8\u7b49\u7684\u6709\u7406\u6570","question":{"questionId":"1012","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6590\u6ce2\u90a3\u5951\u6570","question":{"questionId":"1013","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e09\u89d2\u5f62\u7684\u6700\u5927\u5468\u957f","question":{"questionId":"1018","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u548c\u53ef\u88ab K \u6574\u9664\u7684\u5b50\u6570\u7ec4","question":{"questionId":"1016","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u63a5\u8fd1\u539f\u70b9\u7684 K \u4e2a\u70b9","question":{"questionId":"1014","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5947\u5076\u8df3","question":{"questionId":"1017","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6709\u5e8f\u6570\u7ec4\u7684\u5e73\u65b9","question":{"questionId":"1019","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u957f\u6e4d\u6d41\u5b50\u6570\u7ec4","question":{"questionId":"1020","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5728\u4e8c\u53c9\u6811\u4e2d\u5206\u914d\u786c\u5e01","question":{"questionId":"1021","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e0d\u540c\u8def\u5f84 III","question":{"questionId":"1022","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6309\u4f4d\u4e0e\u4e3a\u96f6\u7684\u4e09\u5143\u7ec4","question":{"questionId":"1024","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e0d\u542b AAA \u6216 BBB \u7684\u5b57\u7b26\u4e32","question":{"questionId":"1026","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u57fa\u4e8e\u65f6\u95f4\u7684\u952e\u503c\u5b58\u50a8","question":{"questionId":"1023","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u4f4e\u7968\u4ef7","question":{"questionId":"1025","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4ece\u53f6\u7ed3\u70b9\u5f00\u59cb\u7684\u6700\u5c0f\u5b57\u7b26\u4e32","question":{"questionId":"1030","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u533a\u95f4\u5217\u8868\u7684\u4ea4\u96c6","question":{"questionId":"1028","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u67e5\u8be2\u540e\u7684\u5076\u6570\u548c","question":{"questionId":"1027","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u6811\u7684\u5782\u5e8f\u904d\u5386","question":{"questionId":"1029","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6570\u7ec4\u5f62\u5f0f\u7684\u6574\u6570\u52a0\u6cd5","question":{"questionId":"1031","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7b49\u5f0f\u65b9\u7a0b\u7684\u53ef\u6ee1\u8db3\u6027","question":{"questionId":"1032","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u574f\u4e86\u7684\u8ba1\u7b97\u5668","question":{"questionId":"1033","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"K \u4e2a\u4e0d\u540c\u6574\u6570\u7684\u5b50\u6570\u7ec4","question":{"questionId":"1034","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u6811\u7684\u5802\u5144\u5f1f\u8282\u70b9","question":{"questionId":"1035","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8150\u70c2\u7684\u6a58\u5b50","question":{"questionId":"1036","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"K \u8fde\u7eed\u4f4d\u7684\u6700\u5c0f\u7ffb\u8f6c\u6b21\u6570","question":{"questionId":"1037","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6b63\u65b9\u5f62\u6570\u7ec4\u7684\u6570\u76ee","question":{"questionId":"1038","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u627e\u5230\u5c0f\u9547\u7684\u6cd5\u5b98","question":{"questionId":"1039","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7f51\u683c\u7167\u660e","question":{"questionId":"1043","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5927\u4e8c\u53c9\u6811 II","question":{"questionId":"1040","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8f66\u7684\u53ef\u7528\u6355\u83b7\u91cf","question":{"questionId":"1041","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5408\u5e76\u77f3\u5934\u7684\u6700\u4f4e\u6210\u672c","question":{"questionId":"1042","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u67e5\u627e\u5e38\u7528\u5b57\u7b26","question":{"questionId":"1044","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5927\u8fde\u7eed1\u7684\u4e2a\u6570 III","question":{"questionId":"1046","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u68c0\u67e5\u66ff\u6362\u540e\u7684\u8bcd\u662f\u5426\u6709\u6548","question":{"questionId":"1045","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5148\u5e8f\u904d\u5386\u6784\u9020\u4e8c\u53c9\u6811","question":{"questionId":"1050","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"K \u6b21\u53d6\u53cd\u540e\u6700\u5927\u5316\u7684\u6570\u7ec4\u548c","question":{"questionId":"1047","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u884c\u76f8\u7b49\u7684\u6700\u5c11\u591a\u7c73\u8bfa\u65cb\u8f6c","question":{"questionId":"1049","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7b28\u9636\u4e58","question":{"questionId":"1048","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5f62\u6210\u5b57\u7b26\u4e32\u7684\u6700\u77ed\u8def\u5f84","question":{"questionId":"1051","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5c0f\u5316\u820d\u5165\u8bef\u5dee\u4ee5\u6ee1\u8db3\u76ee\u6807","question":{"questionId":"1053","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5341\u8fdb\u5236\u6574\u6570\u7684\u53cd\u7801","question":{"questionId":"1054","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u603b\u6301\u7eed\u65f6\u95f4\u53ef\u88ab 60 \u6574\u9664\u7684\u6b4c\u66f2","question":{"questionId":"1055","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u81f3\u5c11\u6709 1 \u4f4d\u91cd\u590d\u7684\u6570\u5b57","question":{"questionId":"1057","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5728 D \u5929\u5185\u9001\u8fbe\u5305\u88f9\u7684\u80fd\u529b","question":{"questionId":"1056","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6821\u56ed\u81ea\u884c\u8f66\u5206\u914d","question":{"questionId":"1052","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4ece\u59cb\u70b9\u5230\u7ec8\u70b9\u7684\u6240\u6709\u8def\u5f84","question":{"questionId":"511","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5c06\u6570\u7ec4\u5206\u6210\u548c\u76f8\u7b49\u7684\u4e09\u4e2a\u90e8\u5206","question":{"questionId":"1062","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u4f73\u89c2\u5149\u7ec4\u5408","question":{"questionId":"1063","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u53ef\u88ab K \u6574\u9664\u7684\u6700\u5c0f\u6574\u6570","question":{"questionId":"1064","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b50\u4e32\u80fd\u8868\u793a\u4ece 1 \u5230 N \u6570\u5b57\u7684\u4e8c\u8fdb\u5236\u4e32","question":{"questionId":"1065","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6709\u6548\u5b50\u6570\u7ec4\u7684\u6570\u76ee","question":{"questionId":"1061","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6709\u5e8f\u6570\u7ec4\u4e2d\u7684\u7f3a\u5931\u5143\u7d20","question":{"questionId":"1059","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u957f\u91cd\u590d\u5b50\u4e32","question":{"questionId":"1060","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6309\u5b57\u5178\u5e8f\u6392\u5217\u6700\u5c0f\u7684\u7b49\u6548\u5b57\u7b26\u4e32","question":{"questionId":"1058","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8d1f\u4e8c\u8fdb\u5236\u8f6c\u6362","question":{"questionId":"1070","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u53ef\u88ab 5 \u6574\u9664\u7684\u4e8c\u8fdb\u5236\u524d\u7f00","question":{"questionId":"1071","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u98de\u5730\u7684\u6570\u91cf","question":{"questionId":"1073","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u94fe\u8868\u4e2d\u7684\u4e0b\u4e00\u4e2a\u66f4\u5927\u8282\u70b9","question":{"questionId":"1072","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5355\u8bcd\u89c4\u5f8b II","question":{"questionId":"291","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5220\u9664\u6700\u5916\u5c42\u7684\u62ec\u53f7","question":{"questionId":"1078","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4ece\u6839\u5230\u53f6\u7684\u4e8c\u8fdb\u5236\u6570\u4e4b\u548c","question":{"questionId":"1079","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u89c6\u9891\u62fc\u63a5","question":{"questionId":"1081","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9a7c\u5cf0\u5f0f\u5339\u914d","question":{"questionId":"1080","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9664\u6570\u535a\u5f08","question":{"questionId":"1086","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u957f\u7b49\u5dee\u6570\u5217","question":{"questionId":"1087","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8282\u70b9\u4e0e\u5176\u7956\u5148\u4e4b\u95f4\u7684\u6700\u5927\u5dee\u503c","question":{"questionId":"1092","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4ece\u5148\u5e8f\u904d\u5386\u8fd8\u539f\u4e8c\u53c9\u6811","question":{"questionId":"1093","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6613\u6df7\u6dc6\u6570","question":{"questionId":"1069","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e0a\u4e0b\u7ffb\u8f6c\u4e8c\u53c9\u6811","question":{"questionId":"156","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5458\u5de5\u5956\u91d1","question":{"questionId":"577","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u81f3\u591a\u5305\u542b\u4e24\u4e2a\u4e0d\u540c\u5b57\u7b26\u7684\u6700\u957f\u5b50\u4e32","question":{"questionId":"159","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u77ed\u5355\u8bcd\u8ddd\u79bb","question":{"questionId":"243","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u77ed\u5355\u8bcd\u8ddd\u79bb II","question":{"questionId":"244","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e24\u5730\u8c03\u5ea6","question":{"questionId":"1095","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e24\u4e2a\u975e\u91cd\u53e0\u5b50\u6570\u7ec4\u7684\u6700\u5927\u548c","question":{"questionId":"1096","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b57\u7b26\u6d41","question":{"questionId":"1097","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8ddd\u79bb\u987a\u5e8f\u6392\u5217\u77e9\u9635\u5355\u5143\u683c","question":{"questionId":"1094","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e2d\u5fc3\u5bf9\u79f0\u6570","question":{"questionId":"246","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e2d\u5fc3\u5bf9\u79f0\u6570 II","question":{"questionId":"247","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e2d\u5fc3\u5bf9\u79f0\u6570 III","question":{"questionId":"248","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u77ed\u5355\u8bcd\u8ddd\u79bb III","question":{"questionId":"245","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4f1a\u8bae\u5ba4","question":{"questionId":"252","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4f1a\u8bae\u5ba4 II","question":{"questionId":"253","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7528 Read4 \u8bfb\u53d6 N \u4e2a\u5b57\u7b26","question":{"questionId":"157","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7528 Read4 \u8bfb\u53d6 N \u4e2a\u5b57\u7b26 II","question":{"questionId":"158","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6392\u5e8f\u6570\u7ec4","question":{"questionId":"948","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u76f8\u9694\u4e3a 1 \u7684\u7f16\u8f91\u8ddd\u79bb","question":{"questionId":"161","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7f3a\u5931\u7684\u533a\u95f4","question":{"questionId":"163","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e24\u6570\u4e4b\u548c III - \u6570\u636e\u7ed3\u6784\u8bbe\u8ba1","question":{"questionId":"170","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7ffb\u8f6c\u5b57\u7b26\u4e32\u91cc\u7684\u5355\u8bcd II","question":{"questionId":"186","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u65e0\u5411\u56fe\u4e2d\u8fde\u901a\u5206\u91cf\u7684\u6570\u76ee","question":{"questionId":"323","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u79fb\u4f4d\u5b57\u7b26\u4e32\u5206\u7ec4","question":{"questionId":"249","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u548c\u7b49\u4e8e k \u7684\u6700\u957f\u5b50\u6570\u7ec4\u957f\u5ea6","question":{"questionId":"325","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7edf\u8ba1\u540c\u503c\u5b50\u6811","question":{"questionId":"250","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5c55\u5f00\u4e8c\u7ef4\u5411\u91cf","question":{"questionId":"251","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u56e0\u5b50\u7684\u7ec4\u5408","question":{"questionId":"254","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5927 BST \u5b50\u6811","question":{"questionId":"333","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5d4c\u5957\u5217\u8868\u6743\u91cd\u548c","question":{"questionId":"339","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u81f3\u591a\u5305\u542b K \u4e2a\u4e0d\u540c\u5b57\u7b26\u7684\u6700\u957f\u5b50\u4e32","question":{"questionId":"340","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9a8c\u8bc1\u524d\u5e8f\u904d\u5386\u5e8f\u5217\u4e8c\u53c9\u641c\u7d22\u6811","question":{"questionId":"255","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7c89\u5237\u623f\u5b50","question":{"questionId":"256","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8f83\u5c0f\u7684\u4e09\u6570\u4e4b\u548c","question":{"questionId":"259","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4ee5\u56fe\u5224\u6811","question":{"questionId":"261","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6570\u636e\u6d41\u4e2d\u7684\u79fb\u52a8\u5e73\u5747\u503c","question":{"questionId":"346","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8303\u56f4\u5185\u7684\u6570\u5b57\u8ba1\u6570","question":{"questionId":"1068","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u79fb\u52a8\u77f3\u5b50\u76f4\u5230\u8fde\u7eed","question":{"questionId":"1103","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8fb9\u6846\u7740\u8272","question":{"questionId":"1104","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e0d\u76f8\u4ea4\u7684\u7ebf","question":{"questionId":"1105","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9003\u79bb\u5927\u8ff7\u5bab","question":{"questionId":"1106","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7c89\u5237\u623f\u5b50 II","question":{"questionId":"265","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u56de\u6587\u6392\u5217","question":{"questionId":"266","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u56de\u6587\u6392\u5217 II","question":{"questionId":"267","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u706b\u661f\u8bcd\u5178","question":{"questionId":"269","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u63a5\u8fd1\u7684\u4e8c\u53c9\u641c\u7d22\u6811\u503c","question":{"questionId":"270","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b57\u7b26\u4e32\u7684\u7f16\u7801\u4e0e\u89e3\u7801","question":{"questionId":"271","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5224\u5b9a\u4e95\u5b57\u68cb\u80dc\u8d1f","question":{"questionId":"348","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b89\u5353\u7cfb\u7edf\u624b\u52bf\u89e3\u9501","question":{"questionId":"351","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"K \u8ddd\u79bb\u95f4\u9694\u91cd\u6392\u5b57\u7b26\u4e32","question":{"questionId":"358","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8d2a\u5403\u86c7","question":{"questionId":"353","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u76f4\u7ebf\u955c\u50cf","question":{"questionId":"356","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u65e5\u5fd7\u901f\u7387\u9650\u5236\u5668","question":{"questionId":"359","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6709\u5e8f\u8f6c\u5316\u6570\u7ec4","question":{"questionId":"360","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8f70\u70b8\u654c\u4eba","question":{"questionId":"361","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6572\u51fb\u8ba1\u6570\u5668","question":{"questionId":"362","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u52a0\u6743\u5d4c\u5957\u5e8f\u5217\u548c II","question":{"questionId":"364","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5bfb\u627e\u5b8c\u5168\u4e8c\u53c9\u6811\u7684\u53f6\u5b50\u8282\u70b9","question":{"questionId":"366","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7ed9\u5355\u94fe\u8868\u52a0\u4e00","question":{"questionId":"369","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u533a\u95f4\u52a0\u6cd5","question":{"questionId":"370","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7535\u8bdd\u76ee\u5f55\u7ba1\u7406\u7cfb\u7edf","question":{"questionId":"379","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6709\u6548\u5355\u8bcd\u7f29\u5199","question":{"questionId":"408","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u77ed\u7279\u5f02\u5355\u8bcd\u7f29\u5199","question":{"questionId":"411","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u77e9\u9635\u4e2d\u6700\u957f\u7684\u8fde\u7eed1\u7ebf\u6bb5","question":{"questionId":"562","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u63a5\u8fd1\u7684\u4e8c\u53c9\u641c\u7d22\u6811\u503c II","question":{"questionId":"272","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6805\u680f\u6d82\u8272","question":{"questionId":"276","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u6811\u4e2d\u6700\u957f\u7684\u8fde\u7eed\u5e8f\u5217","question":{"questionId":"549","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u641c\u5bfb\u540d\u4eba","question":{"questionId":"277","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6446\u52a8\u6392\u5e8f","question":{"questionId":"280","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u952f\u9f7f\u8fed\u4ee3\u5668","question":{"questionId":"281","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5c06\u6570\u7ec4\u5206\u5272\u6210\u548c\u76f8\u7b49\u7684\u5b50\u6570\u7ec4","question":{"questionId":"548","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u641c\u7d22\u6811\u4e2d\u7684\u987a\u5e8f\u540e\u7ee7","question":{"questionId":"285","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5899\u4e0e\u95e8","question":{"questionId":"286","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5f53\u9009\u8005","question":{"questionId":"574","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7ffb\u8f6c\u6e38\u620f","question":{"questionId":"293","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7ffb\u8f6c\u6e38\u620f II","question":{"questionId":"294","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u4f73\u7684\u78b0\u5934\u5730\u70b9","question":{"questionId":"296","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5355\u8bcd\u7684\u552f\u4e00\u7f29\u5199","question":{"questionId":"288","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5c9b\u5c7f\u6570\u91cf II","question":{"questionId":"305","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5c4f\u5e55\u53ef\u663e\u793a\u53e5\u5b50\u7684\u6570\u91cf","question":{"questionId":"418","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6709\u6548\u7684\u5355\u8bcd\u65b9\u5757","question":{"questionId":"422","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5355\u8bcd\u65b9\u5757","question":{"questionId":"425","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5c06\u4e8c\u53c9\u641c\u7d22\u6811\u8f6c\u5316\u4e3a\u6392\u5e8f\u7684\u53cc\u5411\u94fe\u8868","question":{"questionId":"758","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5e8f\u5217\u5316\u548c\u53cd\u5e8f\u5217\u5316 N \u53c9\u6811","question":{"questionId":"765","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u6811\u6700\u957f\u8fde\u7eed\u5e8f\u5217","question":{"questionId":"298","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5305\u542b\u5168\u90e8\u9ed1\u8272\u50cf\u7d20\u7684\u6700\u5c0f\u77e9\u5f62","question":{"questionId":"302","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5c11\u4ea4\u6362\u6b21\u6570\u6765\u7ec4\u5408\u6240\u6709\u7684 1","question":{"questionId":"1107","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u79fb\u52a8\u77f3\u5b50\u76f4\u5230\u8fde\u7eed II","question":{"questionId":"1113","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4ece\u4e8c\u53c9\u641c\u7d22\u6811\u5230\u66f4\u5927\u548c\u6811","question":{"questionId":"1114","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5c06 N \u53c9\u6811\u7f16\u7801\u4e3a\u4e8c\u53c9\u6811","question":{"questionId":"771","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u591a\u8fb9\u5f62\u4e09\u89d2\u5256\u5206\u7684\u6700\u4f4e\u5f97\u5206","question":{"questionId":"1111","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e09\u5143\u8868\u8fbe\u5f0f\u89e3\u6790\u5668","question":{"questionId":"439","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5e8f\u5217\u91cd\u5efa","question":{"questionId":"444","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5206\u5272\u8fde\u63a5\u5b57\u7b26\u4e32","question":{"questionId":"555","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u516c\u8def\u6d41\u91cf","question":{"questionId":"1110","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5458\u5de5\u85aa\u6c34\u4e2d\u4f4d\u6570","question":{"questionId":"569","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u677e\u9f20\u6a21\u62df","question":{"questionId":"573","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u67e5\u8be2\u5458\u5de5\u7684\u7d2f\u8ba1\u85aa\u6c34","question":{"questionId":"579","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u81f3\u5c11\u67095\u540d\u76f4\u63a5\u4e0b\u5c5e\u7684\u7ecf\u7406","question":{"questionId":"570","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7ed9\u5b9a\u6570\u5b57\u7684\u9891\u7387\u67e5\u8be2\u4e2d\u4f4d\u6570","question":{"questionId":"571","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u67e5\u8be2\u56de\u7b54\u7387\u6700\u9ad8\u7684\u95ee\u9898","question":{"questionId":"578","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6709\u6548\u7684\u56de\u65cb\u9556","question":{"questionId":"1115","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b57\u7b26\u4e32\u7684\u7d22\u5f15\u5bf9","question":{"questionId":"1075","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5927\u4f11\u5047\u5929\u6570","question":{"questionId":"568","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7a00\u758f\u77e9\u9635\u7684\u4e58\u6cd5","question":{"questionId":"311","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u7ef4\u533a\u57df\u548c\u68c0\u7d22 - \u53ef\u53d8","question":{"questionId":"308","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5217\u4e3e\u5355\u8bcd\u7684\u5168\u90e8\u7f29\u5199","question":{"questionId":"320","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u79bb\u5efa\u7b51\u7269\u6700\u8fd1\u7684\u8ddd\u79bb","question":{"questionId":"317","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u6811\u7684\u5782\u76f4\u904d\u5386","question":{"questionId":"314","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8ff7\u5bab","question":{"questionId":"490","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b64\u72ec\u50cf\u7d20 I","question":{"questionId":"531","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b64\u72ec\u50cf\u7d20 II","question":{"questionId":"533","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u4f18\u8d26\u5355\u5e73\u8861","question":{"questionId":"465","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u51f8\u591a\u8fb9\u5f62","question":{"questionId":"469","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7f16\u7801\u6700\u77ed\u957f\u5ea6\u7684\u5b57\u7b26\u4e32","question":{"questionId":"471","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5bfb\u627e\u6392\u5217","question":{"questionId":"484","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b66\u751f\u5730\u7406\u4fe1\u606f\u62a5\u544a","question":{"questionId":"618","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5c0f\u56e0\u5f0f\u5206\u89e3","question":{"questionId":"625","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7edf\u8ba1\u5404\u4e13\u4e1a\u5b66\u751f\u4eba\u6570","question":{"questionId":"580","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5bfb\u627e\u6570\u7ec4\u7684\u9519\u4f4d\u6392\u5217","question":{"questionId":"634","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5927\u8fde\u7eed1\u7684\u4e2a\u6570 II","question":{"questionId":"487","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u626b\u5730\u673a\u5668\u4eba","question":{"questionId":"865","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8ff7\u5bab II","question":{"questionId":"505","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8ff7\u5bab III","question":{"questionId":"499","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u641c\u7d22\u6811\u4e2d\u7684\u4e2d\u5e8f\u540e\u7ee7 II","question":{"questionId":"509","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5355\u8bcd\u7f29\u5199","question":{"questionId":"527","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4ece\u5b57\u7b26\u4e32\u751f\u6210\u4e8c\u53c9\u6811","question":{"questionId":"536","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6740\u6b7b\u8fdb\u7a0b","question":{"questionId":"582","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5bfb\u627e\u7528\u6237\u63a8\u8350\u4eba","question":{"questionId":"584","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2016\u5e74\u7684\u6295\u8d44","question":{"questionId":"585","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8ba2\u5355\u6700\u591a\u7684\u5ba2\u6237","question":{"questionId":"586","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8bbe\u8ba1\u5185\u5b58\u6587\u4ef6\u7cfb\u7edf","question":{"questionId":"588","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8f93\u51fa\u6bd4\u8d5b\u5339\u914d\u5bf9","question":{"questionId":"544","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u6811\u7684\u8fb9\u754c","question":{"questionId":"545","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u597d\u53cb\u7533\u8bf7 I \uff1a\u603b\u4f53\u901a\u8fc7\u7387","question":{"questionId":"597","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u597d\u53cb\u7533\u8bf7 II \uff1a\u8c01\u6709\u6700\u591a\u7684\u597d\u53cb","question":{"questionId":"602","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8fde\u7eed\u7a7a\u4f59\u5ea7\u4f4d","question":{"questionId":"603","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8fed\u4ee3\u538b\u7f29\u5b57\u7b26\u4e32","question":{"questionId":"604","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9500\u552e\u5458","question":{"questionId":"607","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6811\u8282\u70b9","question":{"questionId":"608","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5224\u65ad\u4e09\u89d2\u5f62","question":{"questionId":"610","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5e73\u9762\u4e0a\u7684\u6700\u8fd1\u8ddd\u79bb","question":{"questionId":"612","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u76f4\u7ebf\u4e0a\u7684\u6700\u8fd1\u8ddd\u79bb","question":{"questionId":"613","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u7ea7\u5173\u6ce8\u8005","question":{"questionId":"614","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5e73\u5747\u5de5\u8d44\uff1a\u90e8\u95e8\u4e0e\u516c\u53f8\u6bd4\u8f83","question":{"questionId":"615","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7ed9\u5b57\u7b26\u4e32\u6dfb\u52a0\u52a0\u7c97\u6807\u7b7e","question":{"questionId":"616","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u53ea\u51fa\u73b0\u4e00\u6b21\u7684\u6700\u5927\u6570\u5b57","question":{"questionId":"619","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6570\u7ec4\u5217\u8868\u4e2d\u7684\u6700\u5927\u8ddd\u79bb","question":{"questionId":"624","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5c0f\u7a97\u53e3\u5b50\u5e8f\u5217","question":{"questionId":"727","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5927\u6808","question":{"questionId":"716","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7c89\u788e\u7cd6\u679c","question":{"questionId":"723","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"4\u952e\u952e\u76d8","question":{"questionId":"651","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5927\u5e73\u5747\u5b50\u6bb5\u548c II","question":{"questionId":"644","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5747\u5300\u6811\u5212\u5206","question":{"questionId":"663","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u79fb\u9664 9","question":{"questionId":"660","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u91d1\u5e01\u8def\u5f84","question":{"questionId":"656","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u53e5\u5b50\u76f8\u4f3c\u6027","question":{"questionId":"734","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u53e5\u5b50\u76f8\u4f3c\u6027 II","question":{"questionId":"737","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u6811\u6700\u8fd1\u7684\u53f6\u8282\u70b9","question":{"questionId":"743","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8def\u5f84\u548c IV","question":{"questionId":"666","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u8fd1\u65f6\u523b","question":{"questionId":"681","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"K \u4e2a\u7a7a\u82b1\u76c6","question":{"questionId":"683","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u957f\u91cd\u590d\u5b50\u4e32","question":{"questionId":"1122","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5206\u9694\u6570\u7ec4\u4ee5\u5f97\u5230\u6700\u5927\u548c","question":{"questionId":"1121","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e0d\u540c\u5c9b\u5c7f\u7684\u6570\u91cf","question":{"questionId":"694","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u56f0\u4e8e\u73af\u4e2d\u7684\u673a\u5668\u4eba","question":{"questionId":"1119","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e0d\u540c\u5c9b\u5c7f\u7684\u6570\u91cf II","question":{"questionId":"711","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e0d\u90bb\u63a5\u690d\u82b1","question":{"questionId":"1120","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u89d2\u77e9\u5f62\u7684\u6570\u91cf","question":{"questionId":"751","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"IP \u5230 CIDR","question":{"questionId":"752","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u641c\u7d22\u957f\u5ea6\u672a\u77e5\u7684\u6709\u5e8f\u6570\u7ec4","question":{"questionId":"786","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5faa\u73af\u6709\u5e8f\u5217\u8868\u7684\u63d2\u5165","question":{"questionId":"850","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8bbe\u8ba1 Excel \u6c42\u548c\u516c\u5f0f","question":{"questionId":"631","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8bbe\u8ba1\u65e5\u5fd7\u5b58\u50a8\u7cfb\u7edf","question":{"questionId":"635","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8bbe\u8ba1\u641c\u7d22\u81ea\u52a8\u8865\u5168\u7cfb\u7edf","question":{"questionId":"642","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5012\u6c34","question":{"questionId":"756","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b57\u7b26\u4e32\u4e2d\u7684\u52a0\u7c97\u5355\u8bcd","question":{"questionId":"760","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5458\u5de5\u7a7a\u95f2\u65f6\u95f4","question":{"questionId":"761","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u627e\u51fa\u53d8\u4f4d\u6620\u5c04","question":{"questionId":"762","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u57fa\u672c\u8ba1\u7b97\u5668 III","question":{"questionId":"785","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5c0f\u5316\u53bb\u52a0\u6cb9\u7ad9\u7684\u6700\u5927\u8ddd\u79bb","question":{"questionId":"788","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u62c6\u5206\u4e8c\u53c9\u641c\u7d22\u6811","question":{"questionId":"791","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u76f8\u4f3c RGB \u989c\u8272","question":{"questionId":"818","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u540e\u4e00\u5757\u77f3\u5934\u7684\u91cd\u91cf","question":{"questionId":"1127","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u540e\u4e00\u5757\u77f3\u5934\u7684\u91cd\u91cf II","question":{"questionId":"1130","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5220\u9664\u5b57\u7b26\u4e32\u4e2d\u7684\u6240\u6709\u76f8\u90bb\u91cd\u590d\u9879","question":{"questionId":"1128","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u957f\u5b57\u7b26\u4e32\u94fe","question":{"questionId":"1129","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9ad8\u5ea6\u68c0\u67e5\u5668","question":{"questionId":"1137","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4ea4\u6362\u4e00\u6b21\u7684\u5148\u524d\u6392\u5217","question":{"questionId":"1139","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8ddd\u79bb\u76f8\u7b49\u7684\u6761\u5f62\u7801","question":{"questionId":"1140","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7231\u751f\u6c14\u7684\u4e66\u5e97\u8001\u677f","question":{"questionId":"1138","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5c0f\u4e8e K \u7684\u4e24\u6570\u4e4b\u548c","question":{"questionId":"1083","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e0d\u52a8\u70b9","question":{"questionId":"1066","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6821\u56ed\u81ea\u884c\u8f66\u5206\u914d II","question":{"questionId":"1067","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6309\u5217\u7ffb\u8f6c\u5f97\u5230\u6700\u5927\u503c\u7b49\u884c\u6570","question":{"questionId":"1147","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8d1f\u4e8c\u8fdb\u5236\u6570\u76f8\u52a0","question":{"questionId":"1148","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5143\u7d20\u548c\u4e3a\u76ee\u6807\u503c\u7684\u5b50\u77e9\u9635\u6570\u91cf","question":{"questionId":"1145","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b57\u7b26\u4e32\u7684\u6700\u5927\u516c\u56e0\u5b50","question":{"questionId":"1146","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5408\u4f5c\u8fc7\u81f3\u5c11\u4e09\u6b21\u7684\u6f14\u5458\u548c\u5bfc\u6f14","question":{"questionId":"1136","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e70\u4e0b\u6240\u6709\u4ea7\u54c1\u7684\u5ba2\u6237","question":{"questionId":"1135","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e0d\u540c\u5b57\u7b26\u7684\u6700\u5c0f\u5b50\u5e8f\u5217","question":{"questionId":"1159","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"Bigram \u5206\u8bcd","question":{"questionId":"1156","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6d3b\u5b57\u5370\u5237","question":{"questionId":"1160","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6839\u5230\u53f6\u8def\u5f84\u4e0a\u7684\u4e0d\u8db3\u8282\u70b9","question":{"questionId":"1157","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u590d\u5199\u96f6","question":{"questionId":"1168","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u53d7\u6807\u7b7e\u5f71\u54cd\u7684\u6700\u5927\u503c","question":{"questionId":"1169","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u77ed\u516c\u5171\u8d85\u5e8f\u5217","question":{"questionId":"1170","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u8fdb\u5236\u77e9\u9635\u4e2d\u7684\u6700\u77ed\u8def\u5f84","question":{"questionId":"1171","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5c0f\u5143\u7d20\u5404\u6570\u4f4d\u4e4b\u548c","question":{"questionId":"1082","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u524d\u4e94\u79d1\u7684\u5747\u5206","question":{"questionId":"1074","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b57\u6bcd\u5207\u6362","question":{"questionId":"1076","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6613\u6df7\u6dc6\u6570 II","question":{"questionId":"1077","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7edf\u8ba1\u53ea\u542b\u5355\u4e00\u5b57\u6bcd\u7684\u5b50\u4e32","question":{"questionId":"1131","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u67e5\u627e\u4e24\u68f5\u4e8c\u53c9\u641c\u7d22\u6811\u4e4b\u548c","question":{"questionId":"1150","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u62fc\u8f66","question":{"questionId":"1184","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5927\u6837\u672c\u7edf\u8ba1","question":{"questionId":"1183","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5c71\u8109\u6570\u7ec4\u4e2d\u67e5\u627e\u76ee\u6807\u503c","question":{"questionId":"1185","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u82b1\u62ec\u53f7\u5c55\u5f00 II","question":{"questionId":"1188","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5f97\u5206\u6700\u9ad8\u7684\u8def\u5f84","question":{"questionId":"1099","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u957f\u5ea6\u4e3a K \u7684\u65e0\u91cd\u590d\u5b57\u7b26\u5b50\u4e32","question":{"questionId":"1084","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5f7c\u6b64\u719f\u8bc6\u7684\u6700\u65e9\u65f6\u95f4","question":{"questionId":"1085","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u6811\u5bfb\u8def","question":{"questionId":"1194","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u89e3\u6790\u5e03\u5c14\u8868\u8fbe\u5f0f","question":{"questionId":"1197","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5206\u7cd6\u679c II","question":{"questionId":"1195","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u586b\u5145\u4e66\u67b6","question":{"questionId":"1196","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"IP \u5730\u5740\u65e0\u6548\u5316","question":{"questionId":"1205","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u822a\u73ed\u9884\u8ba2\u7edf\u8ba1","question":{"questionId":"1206","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5220\u70b9\u6210\u6797","question":{"questionId":"1207","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u5c0f\u5b66\u7ec4 \u7b2c\u516d\u9898","question":{"questionId":"100008","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u5c0f\u5b66\u7ec4 \u7b2c\u4e00\u9898","question":{"questionId":"100003","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u5c0f\u5b66\u7ec4 \u7b2c\u4e8c\u9898","question":{"questionId":"100004","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u5c0f\u5b66\u7ec4 \u7b2c\u4e09\u9898","question":{"questionId":"100005","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u5c0f\u5b66\u7ec4 \u7b2c\u56db\u9898","question":{"questionId":"100006","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u5c0f\u5b66\u7ec4 \u7b2c\u4e94\u9898","question":{"questionId":"100007","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u521d\u4e2d\u7ec4 \u7b2c\u4e00\u9898","question":{"questionId":"100009","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u521d\u4e2d\u7ec4 \u7b2c\u4e8c\u9898","question":{"questionId":"100010","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u521d\u4e2d\u7ec4 \u7b2c\u4e09\u9898","question":{"questionId":"100011","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u521d\u4e2d\u7ec4 \u7b2c\u56db\u9898","question":{"questionId":"100012","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u521d\u4e2d\u7ec4 \u7b2c\u4e94\u9898","question":{"questionId":"100013","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u521d\u4e2d\u7ec4 \u7b2c\u516d\u9898","question":{"questionId":"100014","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u9ad8\u4e2d\u7ec4 \u7b2c\u4e00\u9898","question":{"questionId":"100015","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u9ad8\u4e2d\u7ec4 \u7b2c\u4e8c\u9898","question":{"questionId":"100016","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u9ad8\u4e2d\u7ec4 \u7b2c\u4e09\u9898","question":{"questionId":"100017","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u9ad8\u4e2d\u7ec4 \u7b2c\u56db\u9898","question":{"questionId":"100018","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u9ad8\u4e2d\u7ec4 \u7b2c\u4e94\u9898","question":{"questionId":"100019","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u9ad8\u4e2d\u7ec4 \u7b2c\u516d\u9898","question":{"questionId":"100020","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e09\u4e2a\u6709\u5e8f\u6570\u7ec4\u7684\u4ea4\u96c6","question":{"questionId":"1149","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6570\u7ec4\u53d8\u6362","question":{"questionId":"1175","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6709\u6548\u62ec\u53f7\u7684\u5d4c\u5957\u6df1\u5ea6","question":{"questionId":"1208","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u5c0f\u5b66\u7ec4 \u521d\u8d5b\u7b2c\u4e00\u9898","question":{"questionId":"100002","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u5c0f\u5b66\u7ec4 \u521d\u8d5b\u7b2c\u4e8c\u9898","question":{"questionId":"100021","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u5c0f\u5b66\u7ec4 \u521d\u8d5b\u7b2c\u4e09\u9898","question":{"questionId":"100022","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u5c0f\u5b66\u7ec4 \u521d\u8d5b\u7b2c\u56db\u9898","question":{"questionId":"100023","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u5c0f\u5b66\u7ec4 \u521d\u8d5b\u7b2c\u4e94\u9898","question":{"questionId":"100024","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u5c0f\u5b66\u7ec4 \u521d\u8d5b\u7b2c\u516d\u9898","question":{"questionId":"100025","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u521d\u4e2d\u7ec4 \u521d\u8d5b\u7b2c\u4e00\u9898","question":{"questionId":"100026","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u521d\u4e2d\u7ec4 \u521d\u8d5b\u7b2c\u4e8c\u9898","question":{"questionId":"100027","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u521d\u4e2d\u7ec4 \u521d\u8d5b\u7b2c\u4e09\u9898","question":{"questionId":"100028","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u521d\u4e2d\u7ec4 \u521d\u8d5b\u7b2c\u56db\u9898","question":{"questionId":"100029","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u521d\u4e2d\u7ec4 \u521d\u8d5b\u7b2c\u4e94\u9898","question":{"questionId":"100030","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u521d\u4e2d\u7ec4 \u521d\u8d5b\u7b2c\u516d\u9898","question":{"questionId":"100031","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u9ad8\u4e2d\u7ec4 \u521d\u8d5b\u7b2c\u4e00\u9898","question":{"questionId":"100032","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u9ad8\u4e2d\u7ec4 \u521d\u8d5b\u7b2c\u4e8c\u9898","question":{"questionId":"100033","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u9ad8\u4e2d\u7ec4 \u521d\u8d5b\u7b2c\u4e09\u9898","question":{"questionId":"100034","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u9ad8\u4e2d\u7ec4 \u521d\u8d5b\u7b2c\u56db\u9898","question":{"questionId":"100035","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u9ad8\u4e2d\u7ec4 \u521d\u8d5b\u7b2c\u4e94\u9898","question":{"questionId":"100036","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u9ad8\u4e2d\u7ec4 \u521d\u8d5b\u7b2c\u516d\u9898","question":{"questionId":"100037","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e00\u6708\u6709\u591a\u5c11\u5929","question":{"questionId":"1088","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5220\u53bb\u5b57\u7b26\u4e32\u4e2d\u7684\u5143\u97f3","question":{"questionId":"1089","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b50\u6811\u7684\u6700\u5927\u5e73\u5747\u503c","question":{"questionId":"1091","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5c06\u6570\u7ec4\u5206\u6210\u51e0\u4e2a\u9012\u589e\u5e8f\u5217","question":{"questionId":"1118","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u6df1\u53f6\u8282\u70b9\u7684\u6700\u8fd1\u516c\u5171\u7956\u5148","question":{"questionId":"1218","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8868\u73b0\u826f\u597d\u7684\u6700\u957f\u65f6\u95f4\u6bb5","question":{"questionId":"1219","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6570\u7ec4\u7684\u76f8\u5bf9\u6392\u5e8f","question":{"questionId":"1217","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5c0f\u7684\u5fc5\u8981\u56e2\u961f","question":{"questionId":"1220","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6309\u5e8f\u6253\u5370","question":{"questionId":"1203","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"H2O \u751f\u6210","question":{"questionId":"1186","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4ea4\u66ff\u6253\u5370FooBar","question":{"questionId":"1187","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5efa\u9020\u8857\u533a\u7684\u6700\u77ed\u65f6\u95f4","question":{"questionId":"1167","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6253\u5370\u96f6\u4e0e\u5947\u5076\u6570","question":{"questionId":"1216","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7b49\u4ef7\u591a\u7c73\u8bfa\u9aa8\u724c\u5bf9\u7684\u6570\u91cf","question":{"questionId":"1227","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u989c\u8272\u4ea4\u66ff\u7684\u6700\u77ed\u8def\u5f84","question":{"questionId":"1229","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7edd\u5bf9\u503c\u8868\u8fbe\u5f0f\u7684\u6700\u5927\u503c","question":{"questionId":"1230","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u53f6\u503c\u7684\u6700\u5c0f\u4ee3\u4ef7\u751f\u6210\u6811","question":{"questionId":"1228","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5927\u552f\u4e00\u6570","question":{"questionId":"1098","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u963f\u59c6\u65af\u7279\u6717\u6570","question":{"questionId":"1090","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5927\u7684\u4ee5 1 \u4e3a\u8fb9\u754c\u7684\u6b63\u65b9\u5f62","question":{"questionId":"1239","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7b2c N \u4e2a\u6cf0\u6ce2\u90a3\u5951\u6570","question":{"questionId":"1236","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b57\u6bcd\u677f\u4e0a\u7684\u8def\u5f84","question":{"questionId":"1238","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u4f4e\u6210\u672c\u8054\u901a\u6240\u6709\u57ce\u5e02","question":{"questionId":"1100","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u77f3\u5b50\u6e38\u620f II","question":{"questionId":"1240","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5e73\u884c\u8bfe\u7a0b","question":{"questionId":"1101","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u78b0\u649e\u6b21\u6570","question":{"questionId":"100038","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b57\u6bcd\u8def\u5f84","question":{"questionId":"100058","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u53bb\u9664\u91cd\u590d\u5b57\u6bcd","question":{"questionId":"100057","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8868\u73b0\u826f\u597d\u7684\u6700\u957f\u65f6\u95f4\u6bb5","question":{"questionId":"100056","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u89e3\u7801\u65b9\u6cd5","question":{"questionId":"100054","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6708\u7403\u8f66","question":{"questionId":"100053","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9012\u51cf\u5143\u7d20\u4f7f\u6570\u7ec4\u5448\u952f\u9f7f\u72b6","question":{"questionId":"1247","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e8c\u53c9\u6811\u7740\u8272\u6e38\u620f","question":{"questionId":"1248","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5feb\u7167\u6570\u7ec4","question":{"questionId":"1249","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6bb5\u5f0f\u56de\u6587","question":{"questionId":"1251","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u5c0f\u5b66\u7ec4\u73b0\u573a\u8d5b \u7b2c\u4e00\u9898","question":{"questionId":"100039","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u5c0f\u5b66\u7ec4\u73b0\u573a\u8d5b \u7b2c\u4e8c\u9898","question":{"questionId":"100040","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u5c0f\u5b66\u7ec4\u73b0\u573a\u8d5b \u7b2c\u4e09\u9898","question":{"questionId":"100041","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u5c0f\u5b66\u7ec4\u73b0\u573a\u8d5b \u7b2c\u56db\u9898","question":{"questionId":"100042","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u5c0f\u5b66\u7ec4\u73b0\u573a\u8d5b \u7b2c\u4e94\u9898","question":{"questionId":"100043","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u5c0f\u5b66\u7ec4\u73b0\u573a\u8d5b \u7b2c\u516d\u9898","question":{"questionId":"100044","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u5c0f\u5b66\u7ec4\u73b0\u573a\u8d5b \u8eab\u4efd\u9a8c\u8bc1\u9898","question":{"questionId":"100052","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u521d\u4e2d\u7ec4\u73b0\u573a\u8d5b \u7b2c\u4e00\u9898","question":{"questionId":"100045","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u521d\u4e2d\u7ec4\u73b0\u573a\u8d5b \u7b2c\u4e8c\u9898","question":{"questionId":"100046","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u521d\u4e2d\u7ec4\u73b0\u573a\u8d5b \u7b2c\u4e09\u9898","question":{"questionId":"100047","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u521d\u4e2d\u7ec4\u73b0\u573a\u8d5b \u7b2c\u56db\u9898","question":{"questionId":"100048","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u521d\u4e2d\u7ec4\u73b0\u573a\u8d5b \u7b2c\u4e94\u9898","question":{"questionId":"100049","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u521d\u4e2d\u7ec4\u73b0\u573a\u8d5b \u7b2c\u516d\u9898","question":{"questionId":"100050","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"2019 \u5e74\u4e0a\u6d77\u5e02\u521b\u610f\u7f16\u7a0b\u4e0e\u667a\u80fd\u8bbe\u8ba1\u5927\u8d5b \u7b97\u6cd5\u7f16\u7a0b \u521d\u4e2d\u7ec4\u73b0\u573a\u8d5b \u8eab\u4efd\u9a8c\u8bc1\u9898","question":{"questionId":"100051","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b57\u7b26\u4e32\u8f6c\u5316","question":{"questionId":"1124","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u68c0\u67e5\u4e00\u4e2a\u6570\u662f\u5426\u5728\u6570\u7ec4\u4e2d\u5360\u7edd\u5927\u591a\u6570","question":{"questionId":"1102","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7528\u6237\u7f51\u7ad9\u8bbf\u95ee\u884c\u4e3a\u5206\u6790","question":{"questionId":"1108","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e00\u5e74\u4e2d\u7684\u7b2c\u51e0\u5929","question":{"questionId":"1260","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5355\u5b57\u7b26\u91cd\u590d\u5b50\u4e32\u7684\u6700\u5927\u957f\u5ea6","question":{"questionId":"1261","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u63b7\u9ab0\u5b50\u7684N\u79cd\u65b9\u6cd5","question":{"questionId":"1263","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b50\u6570\u7ec4\u4e2d\u5360\u7edd\u5927\u591a\u6570\u7684\u5143\u7d20","question":{"questionId":"1262","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5c9b\u5c7f\u7684\u6700\u5927\u9762\u79ef","question":{"questionId":"100072","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"LRU \u5185\u5b58\u673a\u5236","question":{"questionId":"100069","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u519b\u961f\u77e9\u9635","question":{"questionId":"100071","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6570\u7ec4\u76f8\u5bf9\u6392\u5e8f","question":{"questionId":"100068","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8c03\u5e45AM","question":{"questionId":"100073","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5c0f\u8303\u56f4","question":{"questionId":"100074","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u957f\u7684\u5b50\u5e8f\u5217","question":{"questionId":"100075","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8fd8\u539fIPv4\u5730\u5740","question":{"questionId":"100076","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8d44\u8baf\u4fdd\u62a4","question":{"questionId":"100077","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8131\u6c27\u6838\u7cd6\u6838\u9178","question":{"questionId":"100078","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u94fe\u8868\u7ec4\u4ef6","question":{"questionId":"100079","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u996e\u6c34\u673a\u6c34\u6e29","question":{"questionId":"100080","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u88c5\u76d2\u5b50","question":{"questionId":"100070","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5730\u56fe\u5206\u6790","question":{"questionId":"1117","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u62fc\u5199\u5355\u8bcd","question":{"questionId":"1112","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5927\u5c42\u5185\u5143\u7d20\u548c","question":{"questionId":"1116","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6309\u5b57\u5178\u5e8f\u6392\u5728\u6700\u540e\u7684\u5b50\u4e32","question":{"questionId":"1133","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u751f\u6210\u62ec\u5f27","question":{"questionId":"100081","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4ea7\u54c1\u9500\u552e\u5206\u6790 II","question":{"questionId":"1154","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9500\u552e\u5206\u6790 I ","question":{"questionId":"1172","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5c0f\u4f17\u4e66\u7c4d","question":{"questionId":"1198","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9879\u76ee\u5458\u5de5 III","question":{"questionId":"1163","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7ec6\u83cc\u4f53","question":{"questionId":"100082","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u68cb\u76d8","question":{"questionId":"100083","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u544a\u8b66","question":{"questionId":"100084","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b66\u4e60\u82f1\u8bed\u5355\u8bcd","question":{"questionId":"100085","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u627e\u5230\u53bf\u57ce\u7684\u79d8\u5bc6\u53f8\u6cd5\u4eba\u5458","question":{"questionId":"100086","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e50\u9ad8\u79ef\u6728\u65b9\u5f62\u62fc\u56fe","question":{"questionId":"100087","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5927\u8de8\u5ea6\u6c42\u89e3","question":{"questionId":"100088","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6d88\u606f\u53d1\u9001\u673a","question":{"questionId":"100089","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6839\u636e\u4f53\u91cd\u91cd\u5efa\u961f\u5217","question":{"questionId":"100090","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5355\u884c\u952e\u76d8","question":{"questionId":"1123","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8fde\u63a5\u68d2\u6750\u7684\u6700\u4f4e\u8d39\u7528","question":{"questionId":"1126","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6c34\u8d44\u6e90\u5206\u914d\u4f18\u5316","question":{"questionId":"1144","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8bbe\u8ba1\u6587\u4ef6\u7cfb\u7edf","question":{"questionId":"1125","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9910\u76d8\u6808","question":{"questionId":"1270","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u67e5\u8be2\u65e0\u6548\u4ea4\u6613","question":{"questionId":"1272","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6bd4\u8f83\u5b57\u7b26\u4e32\u6700\u5c0f\u5b57\u6bcd\u51fa\u73b0\u9891\u6b21","question":{"questionId":"1273","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4ece\u94fe\u8868\u4e2d\u5220\u53bb\u603b\u548c\u503c\u4e3a\u96f6\u7684\u8fde\u7eed\u8282\u70b9","question":{"questionId":"1267","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u529b\u6263\u8c61\u68cb\u5b66\u5802","question":{"questionId":"100091","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5206\u5f0f\u5316\u7b80","question":{"questionId":"100092","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8986\u76d6","question":{"questionId":"100093","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u53d1 LeetCoin","question":{"questionId":"100094","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5e38\u91cf\u5b57\u7b26\u4e32\u7684\u7f16\u8bd1\u4f18\u5316","question":{"questionId":"100095","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u673a\u5668\u4eba\u5927\u5192\u9669","question":{"questionId":"100096","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5206\u53d1\u5b50\u5f39","question":{"questionId":"100097","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8865\u5168\u6570\u5b57\u533a\u57df","question":{"questionId":"100098","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5bfb\u627e\u7b26\u5408\u67d0\u8981\u6c42\u7684\u6700\u957f\u65f6\u95f4\u6bb5","question":{"questionId":"100099","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5bfb\u6c42\u81ea\u52a8\u9a7e\u9a76\u6a21\u62df\u77e9\u9635\u4e2d\u6700\u957f\u7684\u8fde\u7eed\u4e3a 1 \u7684\u8def\u6bb5","question":{"questionId":"100100","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u53d8\u8d28\u7684\u67ff\u5b50","question":{"questionId":"100101","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8f6f\u4ef6License\u5e8f\u5217\u53f7\u683c\u5f0f\u5316","question":{"questionId":"100102","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8d28\u6570\u6392\u5217","question":{"questionId":"1279","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5065\u8eab\u8ba1\u5212\u8bc4\u4f30","question":{"questionId":"1280","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u731c\u5b57\u8c1c","question":{"questionId":"1282","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6784\u5efa\u56de\u6587\u4e32\u68c0\u6d4b","question":{"questionId":"1281","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6e38\u620f\u73a9\u6cd5\u5206\u6790 I","question":{"questionId":"1179","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4ea7\u54c1\u9500\u552e\u5206\u6790 I","question":{"questionId":"1153","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u524d\u540e\u62fc\u63a5","question":{"questionId":"1132","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e0e\u76ee\u6807\u989c\u8272\u95f4\u7684\u6700\u77ed\u8ddd\u79bb","question":{"questionId":"1134","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u77e9\u9635\u4e2d 1 \u7684\u6700\u5927\u6570\u91cf","question":{"questionId":"1152","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e00\u5468\u4e2d\u7684\u7b2c\u51e0\u5929","question":{"questionId":"1289","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u516c\u4ea4\u7ad9\u95f4\u7684\u8ddd\u79bb","question":{"questionId":"1287","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5220\u9664\u4e00\u6b21\u5f97\u5230\u5b50\u6570\u7ec4\u6700\u5927\u548c","question":{"questionId":"1288","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4f7f\u6570\u7ec4\u4e25\u683c\u9012\u589e","question":{"questionId":"1290","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6590\u6ce2\u90a3\u5951\u6570\u5217","question":{"questionId":"100103","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5168\u6392\u5217","question":{"questionId":"100104","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u56f4\u6210\u4e00\u5708","question":{"questionId":"100105","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9879\u76ee\u5458\u5de5 I","question":{"questionId":"1161","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6392\u5e8f","question":{"questionId":"100106","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u731c\u6570\u5b57","question":{"questionId":"100107","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u67e5\u627e\u96c6\u7fa4\u5185\u7684\u300c\u5173\u952e\u8fde\u63a5\u300d","question":{"questionId":"1300","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"K \u6b21\u4e32\u8054\u540e\u6700\u5927\u5b50\u6570\u7ec4\u4e4b\u548c","question":{"questionId":"1299","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u53cd\u8f6c\u6bcf\u5bf9\u62ec\u53f7\u95f4\u7684\u5b50\u4e32","question":{"questionId":"1298","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u201c\u6c14\u7403\u201d \u7684\u6700\u5927\u6570\u91cf","question":{"questionId":"1297","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6e38\u620f\u73a9\u6cd5\u5206\u6790 II","question":{"questionId":"1180","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9500\u552e\u5206\u6790 II","question":{"questionId":"1173","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9879\u76ee\u5458\u5de5II","question":{"questionId":"1162","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9500\u552e\u5206\u6790III","question":{"questionId":"1174","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e11\u6570 III","question":{"questionId":"1307","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5c0f\u7edd\u5bf9\u5dee","question":{"questionId":"1306","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u591a\u53ef\u4ee5\u4e70\u5230\u7684\u82f9\u679c\u6570\u91cf","question":{"questionId":"1141","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8fdb\u51fb\u7684\u9a91\u58eb","question":{"questionId":"1142","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u627e\u51fa\u6240\u6709\u884c\u4e2d\u6700\u5c0f\u516c\u5171\u5143\u7d20","question":{"questionId":"1143","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9879\u76ee\u7ba1\u7406","question":{"questionId":"1309","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4ea4\u6362\u5b57\u7b26\u4e32\u4e2d\u7684\u5143\u7d20","question":{"questionId":"1308","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6e38\u620f\u73a9\u6cd5\u5206\u6790 III","question":{"questionId":"1181","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6bcf\u6708\u4ea4\u6613 I","question":{"questionId":"1317","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u80a1\u7968\u5e02\u573a","question":{"questionId":"100109","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4f20\u8f93\u6570\u636e\u6700\u591a\u7684\u7ad9\u70b9","question":{"questionId":"100064","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5927\u5b57\u7b26\u4e32\u5b50\u96c6","question":{"questionId":"100066","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6587\u672c\u5355\u8bcd\u538b\u7f29\u7b97\u6cd5","question":{"questionId":"100110","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u670d\u52a1\u5668\u901a\u4fe1","question":{"questionId":"100111","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"IP\u5730\u5740\u5230CIDR\u8f6c\u6362","question":{"questionId":"100112","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":" TOP5\u7f51\u5740\u8bbf\u95ee\u5e73\u5747\u6b21\u6570","question":{"questionId":"100113","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u65e5\u5fd7\u7cfb\u7edf","question":{"questionId":"100114","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6e38\u620f\u73a9\u6cd5\u5206\u6790 IV","question":{"questionId":"1182","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u957f\u516c\u5171\u5b50\u5e8f\u5217","question":{"questionId":"1250","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4ea4\u66ff\u6253\u5370\u5b57\u7b26\u4e32","question":{"questionId":"1316","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5220\u9664\u5b57\u7b26\u4e32\u4e2d\u7684\u6240\u6709\u76f8\u90bb\u91cd\u590d\u9879 II","question":{"questionId":"1320","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5c3d\u53ef\u80fd\u4f7f\u5b57\u7b26\u4e32\u76f8\u7b49","question":{"questionId":"1321","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u72ec\u4e00\u65e0\u4e8c\u7684\u51fa\u73b0\u6b21\u6570","question":{"questionId":"1319","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7a7f\u8fc7\u8ff7\u5bab\u7684\u6700\u5c11\u79fb\u52a8\u6b21\u6570","question":{"questionId":"1322","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4ea7\u54c1\u9500\u552e\u5206\u6790 III","question":{"questionId":"1155","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5c0f\u4ea4\u6362\u6b21\u6570\u4f7f\u5f97\u6570\u7ec4\u6709\u5e8f","question":{"questionId":"100065","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6b65\u8fdb\u6570","question":{"questionId":"1151","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9a8c\u8bc1\u56de\u6587\u5b57\u7b26\u4e32 III","question":{"questionId":"1178","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u957f\u5b9a\u5dee\u5b50\u5e8f\u5217","question":{"questionId":"1330","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7edf\u8ba1\u5143\u97f3\u5b57\u6bcd\u5e8f\u5217\u7684\u6570\u76ee","question":{"questionId":"1332","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9ec4\u91d1\u77ff\u5de5","question":{"questionId":"1331","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u73a9\u7b79\u7801","question":{"questionId":"1329","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8bbe\u8ba1\u8df3\u8868","question":{"questionId":"1337","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u9526\u6807\u8d5b\u4f18\u80dc\u8005","question":{"questionId":"1318","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6bcf\u6708\u4ea4\u6613II","question":{"questionId":"1328","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6e38\u620f\u73a9\u6cd5\u5206\u6790 V","question":{"questionId":"1193","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u91cd\u65b0\u683c\u5f0f\u5316\u90e8\u95e8\u8868","question":{"questionId":"1301","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5f3a\u5236\u5173\u95ed\u8fdb\u7a0b","question":{"questionId":"100116","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8bbe\u8ba1\u4e00\u4e2a\u5185\u5b58\u7cfb\u7edf","question":{"questionId":"100117","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4e00\u7ec4\u5bc4\u5b58\u5668\u5468\u671f\u53d8\u5316","question":{"questionId":"100119","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u670d\u52a1\u5668\u91cd\u65b0\u6392\u5217","question":{"questionId":"100120","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5206\u5272\u5e73\u8861\u5b57\u7b26\u4e32","question":{"questionId":"1341","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u53ef\u4ee5\u653b\u51fb\u56fd\u738b\u7684\u7687\u540e","question":{"questionId":"1342","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u63b7\u9ab0\u5b50\u6a21\u62df","question":{"questionId":"1343","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6700\u5927\u76f8\u7b49\u9891\u7387","question":{"questionId":"1344","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5408\u5e76\u4efb\u52a1\u4f18\u5148\u7ea7\u5217\u8868","question":{"questionId":"100121","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u4fe1\u5143\u503c\u5207\u7247","question":{"questionId":"100122","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5076\u6570\u4f4d\u7684\u6570\u5b57","question":{"questionId":"100123","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u66ff\u6362\u5b50\u4e32\u5f97\u5230\u5e73\u8861\u5b57\u7b26\u4e32","question":{"questionId":"1351","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5220\u9664\u5b50\u6587\u4ef6\u5939","question":{"questionId":"1350","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7f00\u70b9\u6210\u7ebf","question":{"questionId":"1349","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u6bcf\u65e5\u65b0\u7528\u6237\u7edf\u8ba1","question":{"questionId":"1204","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u8bbe\u8ba1\u6709\u9650\u963b\u585e\u961f\u5217","question":{"questionId":"1209","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u89c4\u5212\u517c\u804c\u5de5\u4f5c","question":{"questionId":"1352","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5206\u4eab\u5de7\u514b\u529b","question":{"questionId":"1192","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u5b89\u6392\u4f1a\u8bae\u65e5\u7a0b","question":{"questionId":"1165","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u629b\u63b7\u786c\u5e01","question":{"questionId":"1166","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u7b49\u5dee\u6570\u5217\u4e2d\u7f3a\u5931\u7684\u6570\u5b57","question":{"questionId":"1164","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"},{"title":"\u534e\u4e3a\u667a\u6167\u4ea4\u901a","question":{"questionId":"100124","__typename":"QuestionNode"},"__typename":"AppliedTranslationNode"}]}} \ No newline at end of file diff --git a/algorithms/algorithm-common/pom.xml b/algorithms/algorithm-common/pom.xml new file mode 100644 index 00000000..3afe2696 --- /dev/null +++ b/algorithms/algorithm-common/pom.xml @@ -0,0 +1,15 @@ + + + + algorithms + cn.lastwhisper + 1.0-SNAPSHOT + + 4.0.0 + + algorithm-common + + + \ No newline at end of file diff --git a/algorithms/algorithm-common/src/main/java/cn/lastwhisper/leetcode/common/array/ArrayUtils.java b/algorithms/algorithm-common/src/main/java/cn/lastwhisper/leetcode/common/array/ArrayUtils.java new file mode 100644 index 00000000..893e41f3 --- /dev/null +++ b/algorithms/algorithm-common/src/main/java/cn/lastwhisper/leetcode/common/array/ArrayUtils.java @@ -0,0 +1,97 @@ +package cn.lastwhisper.leetcode.common.array; + +import java.util.ArrayList; +import java.util.List; + +/** + * + * @author lastwhisper + * @date 2020/2/4 + */ +public class ArrayUtils { + + /** + * {"ab","cd"}=> + * 创建二维字符数组 + */ + public static char[][] createCharArrays(String[] arr) { + int m = arr.length, n = arr[0].length(); + char[][] chars = new char[m][n]; + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + chars[i][j] = arr[i].charAt(j); + } + } + return chars; + } + + /** + * {{"a","b","c","d"}}=> + * 创建二维字符数组 + */ + public static char[][] createCharArrays(String[][] arr) { + int m = arr.length, n = arr[0].length; + char[][] chars = new char[m][n]; + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + chars[i][j] = arr[i][j].charAt(0); + } + } + return chars; + } + + /** + * 创建二维数组 + */ + public static int[][] createIntArrays(String[] arr) { + int m = arr.length, n = arr[0].length(); + int[][] ints = new int[m][n]; + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + ints[i][j] = arr[i].charAt(j) - '0'; + } + } + return ints; + } + + + /** + * 创建list + */ + public static List> createList(int[][] arrays) { + List> lists = new ArrayList<>(arrays.length); + for (int[] array : arrays) { + List list = new ArrayList<>(array.length); + for (int num : array) { + list.add(num); + } + lists.add(list); + } + return lists; + } + + + /** + * 生成无序数组 + * @param length 生成数组的长度 + * @param region 生成数字的范围 + */ + public static int[] generateArrByRandom(int length, int region) { + int[] arr = new int[length]; + for (int i = 0; i < length; i++) { + arr[i] = (int) (Math.random() * region); // region=8000000 生成一个[0,8000000) 的一个数 + } + return arr; + } + + /** + * 生成n~0倒序数组 + */ + public static int[] generateArrByOrder(int n) { + int[] arr = new int[n]; + for (int i = n - 1; i > 0; i--) { + arr[i] = i + 1; + } + return arr; + } +} diff --git a/algorithms/algorithm-common/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/LinkedListUtils.java b/algorithms/algorithm-common/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/LinkedListUtils.java new file mode 100644 index 00000000..01c2d3ce --- /dev/null +++ b/algorithms/algorithm-common/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/LinkedListUtils.java @@ -0,0 +1,289 @@ +package cn.lastwhisper.leetcode.common.linkedlist; + + +import java.util.ArrayList; +import java.util.List; + +/** + * 操作链表工具类 + * @author lastwhisper + * @date 1/7/2020 + */ +public class LinkedListUtils { + + /** + * 创建单链表 + */ + public static ListNode createListNode(int... arr) { + if (arr == null) { + return null; + } + ListNode head = new ListNode(arr[0]); + ListNode current = head; + + for (int i = 1; i < arr.length; i++) { + current.next = new ListNode(arr[i]); + current = current.next; + } + return head; + } + + /** + * 创建环形链表 + * 应用题目:https://leetcode-cn.com/problems/linked-list-cycle/ + * @param pos 成环位置 + * @param arr 链表元素 + */ + public static ListNode createLoopListNode(int pos, int... arr) { + if (arr == null) { + return null; + } + ListNode head = new ListNode(arr[0]); + ListNode current = head; + // 锚点,记录成环的位置 + ListNode anchor = null; + if (pos == 0) { + anchor = head; + } + for (int i = 1; i < arr.length; i++) { + current.next = new ListNode(arr[i]); + // 记录成环位置 + if (pos == i) { + if (pos == arr.length - 1) { + anchor = current; + } else { + anchor = current.next; + } + } + current = current.next; + } + current.next = anchor; + return head; + } + + /** + * 创建两个相交链表 + * 应用题目:https://leetcode-cn.com/problems/intersection-of-two-linked-lists/ + * @param intersectVal 相交点的值 + * @param listA 链表A元素数组 + * @param listB 链表B元素数组 + * @param skipA 链表A相交前节点数 + * @param skipB 链表B相交前节点数 + */ + public static List createIntersectListNode( + int intersectVal, int[] listA, int[] listB, int skipA, int skipB) { + List listNodes = new ArrayList<>(2); + + ListNode listNodeA = new ListNode(listA[0]); + ListNode currentA = listNodeA; + ListNode listNodeB = new ListNode(listB[0]); + ListNode currentB = listNodeB; + + for (int i = 1; i < skipA; i++) { + currentA.next = new ListNode(listA[i]); + currentA = currentA.next; + } + + for (int i = 1; i < skipB; i++) { + currentB.next = new ListNode(listB[i]); + currentB = currentB.next; + } + + ListNode intersectListNode = new ListNode(listA[skipA]); + ListNode currentIntersect = intersectListNode; + + for (int i = skipA + 1; i < listA.length; i++) { + currentIntersect.next = new ListNode(listA[i]); + currentIntersect = currentIntersect.next; + } + + currentA.next = intersectListNode; + currentB.next = intersectListNode; + + listNodes.add(listNodeA); + listNodes.add(listNodeB); + + return listNodes; + } + + private static ListNode createListNode(String arr) { + if (arr == null) { + return null; + } + ListNode head = new ListNode(arr.charAt(0) - '0'); + ListNode current = head; + + for (int i = 1; i < arr.length(); i++) { + current.next = new ListNode(arr.charAt(i) - '0'); + current = current.next; + } + return head; + } + + /** + * 反序创建链表 + */ + private static ListNode createReverseListNode(String arr) { + if (arr == null) { + return null; + } + + ListNode head = new ListNode(arr.charAt(arr.length() - 1) - '0'); + ListNode current = head; + + for (int i = arr.length() - 2; i >= 0; i--) { + current.next = new ListNode(arr.charAt(i) - '0'); + current = current.next; + } + return head; + } + + /** + * 两个字符串整数相加 + */ + public String add(String a, String b) { + StringBuilder sb = new StringBuilder(); + // 进位 + int carry = 0; + int aIndex = a.length() - 1, bIndex = b.length() - 1; + + while (aIndex >= 0 || bIndex >= 0) { + int x, y, sum; + x = aIndex >= 0 ? a.charAt(aIndex) - '0' : 0; + y = bIndex >= 0 ? b.charAt(bIndex) - '0' : 0; + + sum = carry + x + y; + carry = sum / 10; + sb.append(sum % 10); + + aIndex--; + bIndex--; + } + + if (carry > 0) { + sb.append(carry); + } + return sb.toString(); + } + + /** + * 打印单链表 + */ + public static void printListNode(String msg, ListNode head) { + System.out.println(msg + appendVal(head)); + } + + /** + * 打印单链表 + */ + public static void printListNode(ListNode head) { + System.out.println(appendVal(head)); + } + + private static String appendVal(ListNode head) { + StringBuilder sb = new StringBuilder(); + ListNode current = head; + while (current != null) { + sb.append(current.val); + sb.append("->"); + current = current.next; + } + sb.append("NULL"); + return sb.toString(); + } + + /** + * 反转链表 + */ + public static ListNode reverseListNode(ListNode head) { + ListNode prev = null; + ListNode current = head; + ListNode next = null; + + while (current != null) { + next = current.next; + + current.next = prev; + prev = current; + current = next; + } + return prev; + } + + /** + * 交替合并两个链表,返回新的链表 + */ + public static ListNode alterNoteMerge(ListNode l1, ListNode l2) { + + return null; + } + + /** + * 交替合并两个链表,到第一个链表 + * https://leetcode-cn.com/problems/reorder-list + */ + public static void alterNoteMergeOne(ListNode firstHead, ListNode secondHead) { + ListNode firstNext; + ListNode secondNext; + + while (secondHead != null) { + // 1.记录两个链表的next节点 + firstNext = firstHead.next; + secondNext = secondHead.next; + // 2.将链表1的当前节点指向链表2的当前节点,链表2的当前节点指向链表1的下一个节点 + // 左链表:1->2->3 右链表:5->4 + // 合并后的链表1:1->5->2 + firstHead.next = secondHead; + secondHead.next = firstNext; + // 3.将之前保存的next更新为当前节点,继续循环 + firstHead = firstNext; + secondHead = secondNext; + // 防止奇数节点链表成环 https://leetcode-cn.com/problems/reorder-list/ + if (secondHead == null) { + firstHead.next = null; + } + } + } + + /** + * 找到链表中间的前一个节点 + */ + public static ListNode middleBeforeNode(ListNode head) { + ListNode fast = head; + ListNode slow = head; + while (fast.next != null && fast.next.next != null) { + fast = fast.next.next; + slow = slow.next; + } + return slow; + } + + /** + * 找到链表中间的一个节点 + * https://leetcode-cn.com/problems/middle-of-the-linked-list/ + */ + public static ListNode middleNode(ListNode head) { + ListNode fast = head; + ListNode slow = head; + while (fast != null && fast.next != null) { + fast = fast.next.next; + slow = slow.next; + } + return slow; + } + + public static void main(String[] args) { + //printListNode(createListNode(1, 2, 3, 4, 5, 6, 7)); + //ListNode headLoop = createLoopListNode(0, 4, 5, 6); + //ListNode centerLoop = createLoopListNode(1, 4, 5, 6); + + int intersectVal = 8, skipA = 2, skipB = 3; + int[] listA = {4, 1, 8, 4, 5}; + int[] listB = {5, 0, 1, 8, 4, 5}; + List intersectListNode = createIntersectListNode(intersectVal, listA, listB, skipA, skipB); + for (ListNode listNode : intersectListNode) { + printListNode(listNode); + } + + } +} diff --git a/algorithms/algorithm-common/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/ListNode.java b/algorithms/algorithm-common/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/ListNode.java new file mode 100644 index 00000000..4d78a4b2 --- /dev/null +++ b/algorithms/algorithm-common/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/ListNode.java @@ -0,0 +1,11 @@ +package cn.lastwhisper.leetcode.common.linkedlist; + +public class ListNode { + public int val; + public ListNode next; + + public ListNode(int x) { + val = x; + } + +} \ No newline at end of file diff --git a/algorithms/algorithm-common/src/main/java/cn/lastwhisper/leetcode/common/print/PrintUtils.java b/algorithms/algorithm-common/src/main/java/cn/lastwhisper/leetcode/common/print/PrintUtils.java new file mode 100644 index 00000000..9bc15820 --- /dev/null +++ b/algorithms/algorithm-common/src/main/java/cn/lastwhisper/leetcode/common/print/PrintUtils.java @@ -0,0 +1,93 @@ +package cn.lastwhisper.leetcode.common.print; + +import java.util.Collection; +import java.util.List; + + +/** + * 打印工具类 + * @author lastwhisper + * @date 2020/2/1 + */ +public class PrintUtils { + + /** + * 层次打印二维数组 + */ + public static void printLists(List> lists) { + System.out.println("["); + int counter1 = 1; + for (List list : lists) { + System.out.print("\t[\""); + int counter2 = 1; + for (Integer i : list) { + if (counter2 != list.size()) { + System.out.print(i + "\",\""); + } else { + System.out.print(i); + } + counter2++; + } + if (counter1 != lists.size()) { + System.out.print("\"],\n"); + } else { + System.out.print("\"]\n"); + } + counter1++; + } + System.out.println("]"); + } + + public static void printStringLists(List> lists) { + System.out.println("["); + int counter1 = 1; + for (List list : lists) { + System.out.print("\t[\""); + int counter2 = 1; + for (String i : list) { + if (counter2 != list.size()) { + System.out.print(i + "\",\""); + } else { + System.out.print(i ); + } + counter2++; + } + if (counter1 != lists.size()) { + System.out.print("\"],\n"); + } else { + System.out.print("\"]\n"); + } + counter1++; + } + System.out.println("]"); + } + + /** + * 打印数组 + */ + public static void printList(Collection collection) { + System.out.println(collection2String(collection)); + } + + /** + * 将Collection扁平化迭代成String + */ + public static String collection2String(Collection collection) { + StringBuilder sb = new StringBuilder(); + try { + sb.append("[\""); + int counter = 1; + for (Object object : collection) { + sb.append(object); + if (counter != collection.size()) { + sb.append("\",\""); + } + counter++; + } + sb.append("\"]"); + } catch (Exception e) { + e.printStackTrace(); + } + return sb.toString(); + } +} diff --git a/algorithms/algorithm-common/src/main/java/cn/lastwhisper/leetcode/common/tree/TreeNode.java b/algorithms/algorithm-common/src/main/java/cn/lastwhisper/leetcode/common/tree/TreeNode.java new file mode 100644 index 00000000..273e04b9 --- /dev/null +++ b/algorithms/algorithm-common/src/main/java/cn/lastwhisper/leetcode/common/tree/TreeNode.java @@ -0,0 +1,11 @@ +package cn.lastwhisper.leetcode.common.tree; + +public class TreeNode { + public int val; + public TreeNode left; + public TreeNode right; + + public TreeNode(int x) { + val = x; + } +} \ No newline at end of file diff --git a/algorithms/algorithm-common/src/main/java/cn/lastwhisper/leetcode/common/tree/TreeUtils.java b/algorithms/algorithm-common/src/main/java/cn/lastwhisper/leetcode/common/tree/TreeUtils.java new file mode 100644 index 00000000..89ec67f7 --- /dev/null +++ b/algorithms/algorithm-common/src/main/java/cn/lastwhisper/leetcode/common/tree/TreeUtils.java @@ -0,0 +1,259 @@ +package cn.lastwhisper.leetcode.common.tree; + +import javafx.util.Pair; + +import java.util.*; + +import static cn.lastwhisper.leetcode.common.print.PrintUtils.printLists; + + +/** + * 树相关工具类 + * @author lastwhisper + * @date 1/16/2020 + */ +public class TreeUtils { + + /** + * 根据数组创建二叉树 + * 一、[5,4,8,11,null,13,4,7,2,null,null,null,1] + * 5 + * / \ + * 4 8 + * / / \ + * 11 13 4 + * / \ \ + * 7 2 1 + * 二、[1,null,2,3] + * 1 + * \ + * 2 + * / + * 3 + * https://blog.csdn.net/lenfranky/article/details/84444816 + * @param array 数组 + */ + public static TreeNode createTree(Integer... array) { + if (array.length == 0) return new TreeNode(0); + Deque nodeQueue = new LinkedList<>(); + // 创建一个根节点 + TreeNode root = new TreeNode(array[0]); + nodeQueue.offer(root); + TreeNode current; + // 记录当前行节点的数量(注意不一定是2的幂,而是上一行中非空节点的数量乘2) + int lineNodeNum = 2; + // 记录当前行中数字在数组中的开始位置 + int startIndex = 1; + // 记录数组中剩余的元素的数量 + int restLength = array.length - 1; + + while (restLength > 0) { + // 只有最后一行可以不满,其余行必须是满的 +// // 若输入的数组的数量是错误的,直接跳出程序 +// if (restLength < lineNodeNum) { +// System.out.println("Wrong Input!"); +// return new TreeNode(0); +// } + for (int i = startIndex; i < startIndex + lineNodeNum; i = i + 2) { + // 说明已经将nums中的数字用完,此时应停止遍历,并可以直接返回root + if (i == array.length) return root; + current = nodeQueue.poll(); + if (array[i] != null) { + current.left = new TreeNode(array[i]); + nodeQueue.offer(current.left); + } + // 同上,说明已经将nums中的数字用完,此时应停止遍历,并可以直接返回root + if (i + 1 == array.length) return root; + if (array[i + 1] != null) { + current.right = new TreeNode(array[i + 1]); + nodeQueue.offer(current.right); + } + } + startIndex += lineNodeNum; + restLength -= lineNodeNum; + lineNodeNum = nodeQueue.size() * 2; + } + + return root; + } + + /** + * 二叉树层次遍历 + */ + public static List> levelOrder(TreeNode root) { + List> result = new ArrayList<>(); + if (root == null) + return result; + + Queue queue = new LinkedList<>(); + queue.add(root); + while (!queue.isEmpty()) { + // 遍历每层的数据 + int size = queue.size(); + List list = new ArrayList<>(); + while (size > 0) { + root = queue.poll(); + list.add(root.val); + if (root.left != null) { + queue.add(root.left); + } + if (root.right != null) { + queue.add(root.right); + } + size--; + } + result.add(list); + } + return result; + } + + /** + * 相同的树 + * + * + * 输入: 1 1 + * / \ / \ + * 2 3 2 3 + * + * [1,2,3], [1,2,3] + * + * 输出: true + */ + public static boolean isSameTree(TreeNode p, TreeNode q) { + LinkedList queue = new LinkedList<>(); + queue.add(p); + queue.add(q); + while (!queue.isEmpty()) { + p = queue.poll(); + q = queue.poll(); + + if (p == null && q == null) continue; + if (p == null || q == null) return false; + if (p.val != q.val) return false; + + queue.add(p.left); + queue.add(q.left); + queue.add(p.right); + queue.add(q.right); + } + return true; + } + + /** + * 完全二叉树的左子树或右子树的高度 + * + * @param root 根节点的左子树或右子树 + * @return int 高度 + */ + private int countLevel(TreeNode root) { + int level = 0; + while (root != null) { + level++; + root = root.left; + } + return level; + } + + /** + * 所有节点之和 + * + * @param root + * @return int + */ + public int sumOfLeaves(TreeNode root) { + if (root == null) { + return 0; + } + return sumOfLeaves(root.left) + sumOfLeaves(root.right) + root.val; + } + + /** + * 二叉树根节点至叶子节点的最高高度 + * + * @param root 根节点 + * @return int 高度 + */ + public int maxDepth(TreeNode root) { + LinkedList> stack = new LinkedList<>(); + if (root != null) { + stack.push(new Pair<>(root, 0)); + } + int maxDepth = 0; + // stack模拟递归系统栈 + while (!stack.isEmpty()) { + Pair pair = stack.poll(); + root = pair.getKey(); + Integer height = pair.getValue(); + // dfs过程中更新最大深度 + maxDepth = Math.max(maxDepth, height); + if (root != null) { + stack.push(new Pair<>(root.right, height + 1)); + stack.push(new Pair<>(root.left, height + 1)); + } + } + return maxDepth; + } + + /** + * 二叉树根节点至叶子节点的最小高度 + * + * @param root 根节点 + * @return int 高度 + */ + public int minDepth(TreeNode root) { + if (root == null) { + return 0; + } + LinkedList> queue = new LinkedList<>(); + queue.add(new Pair<>(root, 1)); + + // 当前深度 + int currentDepth = 0; + Pair pair = null; + while (!queue.isEmpty()) { + pair = queue.poll(); + root = pair.getKey(); + currentDepth = pair.getValue(); + // 找到层中第一个叶子节点 + if (root.left == null && root.right == null) { + break; + } + if (root.left != null) { + queue.add(new Pair<>(root.left, currentDepth + 1)); + } + if (root.right != null) { + queue.add(new Pair<>(root.right, currentDepth + 1)); + } + + } + return currentDepth; + } + + /** + * 反转二叉树 + * + * @param root 根节点 + */ + public TreeNode invertTree(TreeNode root) { + if (root == null) + return null; + // 翻转当前节点的左右子节点 + TreeNode tempNode = root.left; + root.left = invertTree(root.right); + root.right = invertTree(tempNode); + return root; + } + + /** + * 输出二叉树层次遍历的结果 + */ + public static void printLevelOrder(TreeNode root) { + printLists(levelOrder(root)); + } + + public static void main(String[] args) { + printLevelOrder(createTree(1, null, 2, 3)); + //printLevelOrder(createTree(5, 4, 8, 11, null, 13, 4, 7, 2, null, null, null, 1)); + //printLevelOrder(createTree(1,2,3,null,4,5,null)); + } +} diff --git a/algorithms/algorithm/pom.xml b/algorithms/algorithm/pom.xml index 216ffb65..88f18783 100644 --- a/algorithms/algorithm/pom.xml +++ b/algorithms/algorithm/pom.xml @@ -4,12 +4,11 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> algorithms - lastwhisper + cn.lastwhisper 1.0-SNAPSHOT 4.0.0 - cn.lastwhisper algorithm diff --git a/algorithms/algorithm/src/main/java/cn/lastwhisper/bf/BF.java b/algorithms/algorithm/src/main/java/cn/lastwhisper/bf/BF.java deleted file mode 100644 index 313a5f45..00000000 --- a/algorithms/algorithm/src/main/java/cn/lastwhisper/bf/BF.java +++ /dev/null @@ -1,63 +0,0 @@ -package cn.lastwhisper.bf; - -/** - * BF算法 - * @author cn.lastwhisper - */ -public class BF { - public static void main(String[] args) { - String str1 = "硅硅谷 尚硅谷你尚硅 尚硅谷你尚硅谷你尚硅你好"; - String str2 = "尚硅谷你尚硅你"; - int search = search(str1, str2, 0); - //int search = search1(str1, str2, 0); - System.out.println(search); - } - - - public static int search(String txt, String pat, int pos) { - int m = pat.length(); - int n = txt.length(); - for (int i = 0; i < n - m; i++) { - int j; - for (j = 0; j < m; j++) { - if (txt.charAt(i + j) != pat.charAt(j)) { - break; - } - } - if (j == m) { - return i; - } - } - return n; - } - - /** - * @param txt 主串 - * @param pat 子串 - * @param pos 匹配起始位置 - * @return int - */ - public static int search1(String txt, String pat, int pos) { - char[] txtChar = txt.toCharArray(); - char[] patChar = pat.toCharArray(); - // 主串指针 - int i = pos; - // 子串指针 - int j = 0; - - while (i < txtChar.length && j < patChar.length) { - if (txtChar[i] == patChar[j]) { - i++; - j++; - } else { - //没有匹配成功 - i = i - j + 1; - j = 0; - } - } - if (j == patChar.length) { - return i - j; - } - return -1; - } -} diff --git a/algorithms/algorithm/src/main/java/cn/lastwhisper/bloomfilter/BloomFilter.java b/algorithms/algorithm/src/main/java/cn/lastwhisper/bloomfilter/BloomFilter.java new file mode 100644 index 00000000..a6eca615 --- /dev/null +++ b/algorithms/algorithm/src/main/java/cn/lastwhisper/bloomfilter/BloomFilter.java @@ -0,0 +1,74 @@ +package cn.lastwhisper.bloomfilter; + +import java.io.Serializable; +import java.util.BitSet; +import java.util.Random; + +/** + * 原文:https://www.iteye.com/blog/imtinx-1290636 + * Long类型元素的布隆过滤器 + */ +class BloomFilter implements Serializable { + private static final long serialVersionUID = 1L; + private static final int ELEM_NUM = 1000; // 欲容纳的元素个数 + private static final double PERCENTAGE = 0.001; // 希望的误差率 + private int hashNum; // hash函数的数量 + private int size; // 位向量的长度 + private BitSet bitVector; // 位向量 + + public BloomFilter() { + size = (int) Math.abs(ELEM_NUM * Math.log(PERCENTAGE) + / (Math.log(2) * Math.log(2))) + 1; + hashNum = (int) (Math.log(2) * ((double) size / ELEM_NUM)); + bitVector = new BitSet(size); + } + + /** + * 查找元素是否在集合中 + */ + public boolean search(Long elem) { + boolean flag = true; + int temp; + Random random = new Random(elem); + for (int i = 0; i < hashNum; i++) { + temp = random.nextInt(size); + if (!bitVector.get(temp)) {// 元素不在集合中 + bitVector.set(temp); + flag = false; + } + } + return flag; + } + + /** + * 获取位向量的长度 + */ + public int size() { + return bitVector.size(); + } + + + public int getHashNum() { + return hashNum; + } + + public void setHashNum(int hashNum) { + this.hashNum = hashNum; + } + + public int getSize() { + return size; + } + + public void setSize(int size) { + this.size = size; + } + + public BitSet getBitVector() { + return bitVector; + } + + public void setBitVector(BitSet bitVector) { + this.bitVector = bitVector; + } +} \ No newline at end of file diff --git a/algorithms/algorithm/src/main/java/cn/lastwhisper/consistenthash/ConsistentHash.java b/algorithms/algorithm/src/main/java/cn/lastwhisper/consistenthash/ConsistentHash.java new file mode 100644 index 00000000..f718c144 --- /dev/null +++ b/algorithms/algorithm/src/main/java/cn/lastwhisper/consistenthash/ConsistentHash.java @@ -0,0 +1,71 @@ +package cn.lastwhisper.consistenthash; + +import java.util.Collection; +import java.util.Objects; +import java.util.SortedMap; +import java.util.TreeMap; + +/** + * https://www.iteye.com/blog/imtinx-1290696 + * + */ +class ConsistentHash { + /** + * 计算使用的hash函数,推荐使用MD5 + */ + private final Objects hashFunction; + /** + * 虚拟节点的倍数 + */ + private final int numberOfReplicas; + /** + * cache节点环 + */ + private final SortedMap circle = new TreeMap(); + public ConsistentHash(Objects hashFunction, int numberOfReplicas, + Collection nodes) { + this.hashFunction = hashFunction; + this.numberOfReplicas = numberOfReplicas; + for (T node : nodes) { + add(node); + } + } + /** + * @description 添加ceche服务器节点 + * @param node 服务器节点,可以用服务器的IP表示 + * @add date 2011-10-30 + */ + public void add(T node) { + for (int i = 0; i < numberOfReplicas; i++) { + circle.put(hashFunction.hash(node.toString() + i), node); + } + } + /** + * @description 删除服务器节点 + * @param node 服务器节点,可以用服务器的IP表示 + * @add date 2011-10-30 + */ + public void remove(T node) { + for (int i = 0; i < numberOfReplicas; i++) { + circle.remove(hashFunction.hash(node.toString() + i)); + } + } + /** + * @description 获取对象对应的cache服务器 + * @param key 需要存储的对象 + * @return 目标cache服务器 + * @add date 2011-10-30 + */ + public T get(Object key) { + if (circle.isEmpty()) { + return null; + } + int hash = hashFunction.hash(key); + if (!circle.containsKey(hash)) { + //顺时针查找最近的节点 + SortedMap tailMap = circle.tailMap(hash); + hash = tailMap.isEmpty() ? circle.firstKey() : tailMap.firstKey(); + } + return circle.get(hash); + } +} \ No newline at end of file diff --git a/algorithms/algorithm/src/main/java/cn/lastwhisper/dynamic/KnapsackProblem.java b/algorithms/algorithm/src/main/java/cn/lastwhisper/dynamic/KnapsackProblem.java deleted file mode 100644 index 788aa085..00000000 --- a/algorithms/algorithm/src/main/java/cn/lastwhisper/dynamic/KnapsackProblem.java +++ /dev/null @@ -1,72 +0,0 @@ -package cn.lastwhisper.dynamic; - -/** - * 背包问题 - * @author cn.lastwhisper - */ -public class KnapsackProblem { - public static void main(String[] args) { - //物品的重量 - int[] weight = {1, 4, 3}; - //物品的价值 - int[] value = {1500, 3000, 2000}; - //背包的容量 - int capacity = 4; - // 物品的个数 - int n = value.length; - - // v[i][j]表示在前i个物品中能够装入容量为j的背包中的最大价值 - // v[i][j]的有效值是从下标1开始 - int[][] v = new int[n + 1][capacity + 1]; - //为了记录放入商品的情况,我们定一个二维数组 - int[][] path = new int[n + 1][capacity + 1]; - // 初始化数组 - // 第一列全为0 - for (int i = 0; i < v.length; i++) { - v[i][0] = 0; - } - // 第一行全为0 - for (int i = 0; i < v[0].length; i++) { - v[0][i] = 0; - } - - // i表示当前物品 吉他、音响、电脑 - for (int i = 1; i < v.length; i++) { - // j表示当前背包容量 1,2,3,4... - for (int j = 1; j < v[0].length; j++) { - // 当前物品容量大于当前背包容量,使用上一个单元格的装入策略 - if (weight[i - 1] > j) { - v[i][j] = v[i - 1][j]; - } else { - // 当前物品容量小于当前背包容量时,说明可以放的下物品, - // 需要比较“上一个物品(i - 1)容量(j)时的最大价值的装入策略”与 - // “当前物品的价值+上一个物品(i - 1)容量(j-weight[i],其中weight[i]是当前物品重量)时的最大价值的装入策略” - //v[i][j] = Math.max(v[i - 1][j], value[i - 1] + v[i - 1][j - weight[i - 1]]); - - // 为了记录商品存入背包的情况,不能直接使用上面的写法,需要改写为if-else - if (v[i - 1][j] < value[i - 1] + v[i - 1][j - weight[i - 1]]) { - v[i][j] = value[i - 1] + v[i - 1][j - weight[i - 1]]; - path[i][j] = 1; - } else { - v[i][j] = v[i - 1][j]; - } - } - } - } - - System.out.println("最大价值:"+v[n][capacity]); - // 行 - int i = path.length - 1; - // 列 - int j = path[0].length - 1; - while (i > 0 && j > 0) { - if (path[i][j] == 1) { - System.out.printf("第%d个商品放入到背包\n", i); - j -= weight[i - 1]; - } - i--; - } - - - } -} diff --git a/algorithms/algorithm/src/main/java/cn/lastwhisper/gcdlcm/Gcd1.java b/algorithms/algorithm/src/main/java/cn/lastwhisper/gcdlcm/Gcd1.java new file mode 100644 index 00000000..07d2014b --- /dev/null +++ b/algorithms/algorithm/src/main/java/cn/lastwhisper/gcdlcm/Gcd1.java @@ -0,0 +1,43 @@ +package cn.lastwhisper.gcdlcm; + +import org.junit.Assert; + +/** + * 最小公倍数 + * @author lastwhisper + * @date 2020/3/12 + */ +class Gcd1 { + + /** + * (1)辗转相除法 + * 有两整数a和b: + * ① a%b得余数c + * ② 若c=0,则b即为两数的最大公约数 + * ③ 若c≠0,则a=b,b=c,再回去执行① + * + * 例如求27和15的最大公约数过程为: + * 27÷15 余12 + * 15÷12 余3 + * 12÷3 余0 因此,3即为最大公约数 + */ + public int gcd(int a, int b) { + int m=a,n=b; + if (b > a) { + int temp = a;a = b;b = temp; + } + + int c; + while (b != 0) /* 余数不为0,继续相除,直到余数为0 */ { + c = a % b; + a = b; + b = c; + } + return a;// m*n/a最小公倍数 + } + + public static void main(String[] args) { + Gcd1 main = new Gcd1(); + Assert.assertEquals(3, main.gcd(27, 15)); + } +} diff --git a/algorithms/algorithm/src/main/java/cn/lastwhisper/gcdlcm/Gcd2.java b/algorithms/algorithm/src/main/java/cn/lastwhisper/gcdlcm/Gcd2.java new file mode 100644 index 00000000..66cc920b --- /dev/null +++ b/algorithms/algorithm/src/main/java/cn/lastwhisper/gcdlcm/Gcd2.java @@ -0,0 +1,38 @@ +package cn.lastwhisper.gcdlcm; + +import org.junit.Assert; + +/** + * 相减法 + * @author lastwhisper + * @date 2020/3/12 + */ +class Gcd2 { + + /** + * ⑵ 相减法 + * 有两整数a和b: + * ① 若a>b,则a=a-b + * ② 若a12 ) + * 15-12=3( 12>3 ) + * 12-3=9( 9>3 ) + * 9-3=6( 6>3 ) + * 6-3=3( 3==3 ) + */ + public int gcd(int a, int b) { + while (a != b) { + if (a > b) a = a - b; + else b = b - a; + } + return a; + } + + public static void main(String[] args) { + Gcd2 main = new Gcd2(); + Assert.assertEquals(3, main.gcd(27, 15)); + } +} diff --git a/algorithms/algorithm/src/main/java/cn/lastwhisper/gcdlcm/Gcd3.java b/algorithms/algorithm/src/main/java/cn/lastwhisper/gcdlcm/Gcd3.java new file mode 100644 index 00000000..bc29cc22 --- /dev/null +++ b/algorithms/algorithm/src/main/java/cn/lastwhisper/gcdlcm/Gcd3.java @@ -0,0 +1,24 @@ +package cn.lastwhisper.gcdlcm; + +import org.junit.Assert; + +/** + * 穷举法 + * @author lastwhisper + * @date 2020/3/12 + */ +class Gcd3 { + + // https://www.cnblogs.com/ECJTUACM-873284962/p/6679839.html + public int gcd(int a, int b) { + int t = 0; + for (int i = 1; i <= a; i++) + if (a % i == 0 && b % i == 0) t = i; + return t; + } + + public static void main(String[] args) { + Gcd3 main = new Gcd3(); + Assert.assertEquals(3, main.gcd(27, 15)); + } +} diff --git a/algorithms/algorithm/src/main/java/cn/lastwhisper/greedy/GreedyAlgorithm.java b/algorithms/algorithm/src/main/java/cn/lastwhisper/greedy/GreedyAlgorithm.java deleted file mode 100644 index e5f52905..00000000 --- a/algorithms/algorithm/src/main/java/cn/lastwhisper/greedy/GreedyAlgorithm.java +++ /dev/null @@ -1,92 +0,0 @@ -package cn.lastwhisper.greedy; - -import java.util.*; - -/** - * 贪心解决集合覆盖问题 - * @author cn.lastwhisper - */ -public class GreedyAlgorithm { - - public static void main(String[] args) { - // 广播电台和对应覆盖范围 - Map> broadcasts = new HashMap<>(); - // 覆盖地区 - Set area1 = new HashSet<>(); - area1.add("北京"); - area1.add("上海"); - area1.add("天津"); - Set area2 = new HashSet<>(); - area2.add("广州"); - area2.add("北京"); - area2.add("深圳"); - Set area3 = new HashSet<>(); - area3.add("成都"); - area3.add("上海"); - area3.add("杭州"); - Set area4 = new HashSet<>(); - area4.add("上海"); - area4.add("天津"); - Set area5 = new HashSet<>(); - area5.add("杭州"); - area5.add("大连"); - broadcasts.put("k1", area1); - broadcasts.put("k2", area2); - broadcasts.put("k3", area3); - broadcasts.put("k4", area4); - broadcasts.put("k5", area5); - - // 需要覆盖的范围 - Set allAreas = new HashSet<>(); - allAreas.add("北京"); - allAreas.add("上海"); - allAreas.add("天津"); - allAreas.add("广州"); - allAreas.add("深圳"); - allAreas.add("成都"); - allAreas.add("杭州"); - allAreas.add("大连"); - - // 存放已选择电台的集合 - List selects = new ArrayList(); - // 存放“遍历到的key对应的覆盖的范围地区的集合”和“需要覆盖的范围地区的集合”的交集 - Set tempSet = new HashSet<>(); - // 存放遍历过程中,能够覆盖最大未覆盖地区对应电台的key - String maxKey = null; - while (allAreas.size() != 0) { - // maxKey置空 - maxKey = null; - for (String key : broadcasts.keySet()) { - // 清除集合上一次的缓存 - tempSet.clear(); - // areas key对应的覆盖的范围地区的集合 - Set areas = broadcasts.get(key); - tempSet.addAll(areas); - // allAreas 需要覆盖的范围地区的集合 - tempSet.retainAll(allAreas); - // 贪心算法的核心 - // tempSet.size() > broadcasts.get(maxKey).size())当前这个集合包含的未覆盖地区的数量,比maxKey指向的集合地区还多 - // 将把tempSet.size()对应的key,更新掉maxKey - if (tempSet.size() > 0 && (maxKey == null || - tempSet.size() > broadcasts.get(maxKey).size())) { - maxKey = key; - } - - } - // maxKey存在 - if (maxKey != null) { - // 将maxKey加入已选择电台集合中 - selects.add(maxKey); - // 并从未覆盖地区删除maxKey对应覆盖的地区 - allAreas.removeAll(broadcasts.get(maxKey)); - // 从广播中移除 - broadcasts.remove(maxKey); - } - - } - - System.out.println(selects); - - } - -} diff --git a/algorithms/algorithm/src/main/java/cn/lastwhisper/hanoitower/Hanoitower.java b/algorithms/algorithm/src/main/java/cn/lastwhisper/hanoitower/Hanoitower.java deleted file mode 100644 index f6844589..00000000 --- a/algorithms/algorithm/src/main/java/cn/lastwhisper/hanoitower/Hanoitower.java +++ /dev/null @@ -1,33 +0,0 @@ -package cn.lastwhisper.hanoitower; - -/** - * 汉诺塔问题(递归) - * @author cn.lastwhisper - */ -public class Hanoitower { - public static void main(String[] args) { - move(3, 'A', 'B', 'C'); - } - - /** - * - * - * @param n 盘子的数量 - * @param a 起始位置 - * @param b 中间缓存位置 - * @param c 终点位置 - * @return void - */ - public static void move(int n, char a, char b, char c) { - if (n == 1) { - System.out.printf("第1个盘从 %s->%s\n", a, c); - } else { - // 以a为起始位置,c为中间缓存位置,b为终点位置 - move(n - 1, a, c, b); - System.out.printf("第%d个盘从 %s->%s\n", n, a, c); - // 以b为起始位置,a为中间缓存位置,c为终点位置 - move(n - 1, b, a, c); - } - } - -} diff --git a/algorithms/algorithm/src/main/java/cn/lastwhisper/kmp/KMP.java b/algorithms/algorithm/src/main/java/cn/lastwhisper/kmp/KMP.java deleted file mode 100644 index 5952d845..00000000 --- a/algorithms/algorithm/src/main/java/cn/lastwhisper/kmp/KMP.java +++ /dev/null @@ -1,96 +0,0 @@ -package cn.lastwhisper.kmp; - -/** - * kmp算法 - * @author cn.lastwhisper - */ -public class KMP { - public static void main(String[] args) { - String str1 = "BBC ABCDAB ABCDABCDABDE"; - String str2 = "ABCDABD"; - //int[] next = kmpNext1("AAA"); // 不考虑调整j的大小 - //int[] next = kmpNext("ABCDABD"); // 不考虑调整j的大小 - //System.out.println(Arrays.toString(next)); - int[] next = kmpNext("ABCDABD"); - //int index = kmpSearch1(str1, "BBC", next); // 不考虑调整j的大小 - int index = kmpSearch(str1, str2, next); // 不考虑调整j的大小 - System.out.println(index); - } - - public static int kmpSearch(String txt, String pat, int[] next) { - // i指向str1,j指向str2 - for (int i = 0, j = 0; i < txt.length(); i++) { - // 处理txt.charAt(i) != pat.charAt(j) - while (j > 0 && txt.charAt(i) != pat.charAt(j)) { - j = next[j - 1]; - } - if (txt.charAt(i) == pat.charAt(j)) { - j++; - } - if (j == pat.length()) { - return i - j + 1; - } - } - return -1; - } - - // 不考虑j的修改 - public static int kmpSearch1(String txt, String pat, int[] next) { - // i指向str1,j指向str2 - for (int i = 0, j = 0; i < txt.length(); i++) { - if (txt.charAt(i) == pat.charAt(j)) { - j++; - } - if (j == pat.length()) { - return i - j + 1; - } - } - return -1; - } - - /** - * 根据子串算出部分匹配表 - * - * @param dest 子串 - * @return int[] 部分匹配表 - */ - public static int[] kmpNext(String dest) { - // 初始化部分匹配表 - int[] next = new int[dest.length()]; - // 部分匹配表第一个字符串为0 - next[0] = 0; - // i表示,j表示上次的匹配值 - for (int i = 1, j = 0; i < dest.length(); i++) { - // dest.charAt(i) != dest.charAt(j),从next[j-1]获取新的j - while (j > 0 && dest.charAt(i) != dest.charAt(j)) { - j = next[j - 1]; - } - // dest.charAt(i) == dest.charAt(j),部分匹配值+1 - if (dest.charAt(i) == dest.charAt(j)) { - j++; - } - next[i] = j; - } - return next; - } - - // 不考虑调整j的大小 - public static int[] kmpNext1(String dest) { - // 初始化部分匹配表 - int[] next = new int[dest.length()]; - // 部分匹配表第一个字符串为0 - next[0] = 0; - // i表示,j表示匹配值 - for (int i = 1, j = 0; i < dest.length(); i++) { - // 暂时不考虑不等 - // dest.charAt(i) == dest.charAt(j),部分匹配值+1 - if (dest.charAt(i) == dest.charAt(j)) { - j++; - } - next[i] = j; - } - return next; - } - - -} diff --git a/algorithms/algorithm/src/main/java/cn/lastwhisper/mst/KurskalAlgorithm.java b/algorithms/algorithm/src/main/java/cn/lastwhisper/mst/KurskalAlgorithm.java deleted file mode 100644 index 590bc482..00000000 --- a/algorithms/algorithm/src/main/java/cn/lastwhisper/mst/KurskalAlgorithm.java +++ /dev/null @@ -1,200 +0,0 @@ -package cn.lastwhisper.mst; - -import java.util.Arrays; - -/** - * @author cn.lastwhisper - */ -public class KurskalAlgorithm { - //使用 INF 表示两个顶点不能连通 - private static final int INF = Integer.MAX_VALUE; - // 边的个数 - int edgeNum; - // 顶点数组 - char[] vertexs; - // 邻接矩阵 - int[][] matrix; - - /** - * 初始化 - * - * @param vertexs 顶点数组 - * @param matrix 邻接矩阵 - * @return - */ - public KurskalAlgorithm(char[] vertexs, int[][] matrix) { - // 顶点个数 - int vlen = vertexs.length; - // 初始化顶点 - this.vertexs = new char[vlen]; - for (int i = 0; i < vlen; i++) { - this.vertexs[i] = vertexs[i]; - } - // 初始化边 - this.matrix = new int[vlen][vlen]; - for (int i = 0; i < vlen; i++) { - for (int j = 0; j < vlen; j++) { - this.matrix[i][j] = matrix[i][j]; - } - } - // 统计边的个数 - for (int i = 0; i < vlen; i++) { - for (int j = i + 1; j < vlen; j++) { - if (this.matrix[i][j] != INF) { - this.edgeNum++; - } - } - } - } - - // 打印结点 - public void print() { - for (int i = 0; i < matrix.length; i++) { - for (int j = 0; j < matrix[i].length; j++) { - System.out.printf("%12d", matrix[i][j]); - } - System.out.println();//换行 - } - } - - // 排序 - public void sortEdges(EData[] edges) { - for (int i = 0; i < edges.length; i++) { - for (int j = 0; j < edges.length - i - 1; j++) { - if (edges[j].weight > edges[j + 1].weight) { - EData temp = edges[j + 1]; - edges[j + 1] = edges[j]; - edges[j] = temp; - } - } - } - - } - - // 根据邻接矩阵构造边对象数组 - public EData[] getEdges() { - int index = 0; - EData[] edges = new EData[edgeNum]; - for (int i = 0; i < vertexs.length; i++) { - for (int j = i + 1; j < vertexs.length; j++) { - if (matrix[i][j] != INF) { - edges[index++] = new EData(vertexs[i], vertexs[j], matrix[i][j]); - } - } - } - return edges; - } - - /** - * 功能: 获取下标为i的顶点的终点(), 用于后面判断两个顶点的终点是否相同 - * @param ends : 数组就是记录了各个顶点对应的终点是哪个,ends 数组是在遍历过程中,逐步形成 - * @param i : 表示传入的顶点对应的下标 - * @return 返回的就是 下标为i的这个顶点对应的终点的下标, 一会回头还有来理解 - */ - private int getEnd(int[] ends, int i) { // i = 4 [0,0,0,0,5,0,0,0,0,0,0,0] - while (ends[i] != 0) { - i = ends[i]; - } - return i; - } - - /** - * - * @param ch 顶点的值,比如'A','B' - * @return 返回ch顶点对应的下标,如果找不到,返回-1 - */ - private int getPosition(char ch) { - for (int i = 0; i < vertexs.length; i++) { - if (vertexs[i] == ch) {//找到 - return i; - } - } - //找不到,返回-1 - return -1; - } - - public void kruskal() { - int index = 0; //表示最后结果数组的索引 - int[] ends = new int[edgeNum]; //用于保存"已有最小生成树" 中的每个顶点在最小生成树中的终点 - //创建结果数组, 保存最后的最小生成树 - EData[] rets = new EData[edgeNum]; - - //获取图中 所有的边的集合 , 一共有12边 - EData[] edges = getEdges(); - System.out.println("图的边的集合=" + Arrays.toString(edges) + " 共"+ edges.length); //12 - - //按照边的权值大小进行排序(从小到大) - sortEdges(edges); - - //遍历edges 数组,将边添加到最小生成树中时,判断是准备加入的边否形成了回路,如果没有,就加入 rets, 否则不能加入 - for(int i=0; i < edgeNum; i++) { - //获取到第i条边的第一个顶点(起点) - int p1 = getPosition(edges[i].start); //p1=4 - //获取到第i条边的第2个顶点 - int p2 = getPosition(edges[i].end); //p2 = 5 - - //获取p1这个顶点在已有最小生成树中的终点 - int m = getEnd(ends, p1); //m = 4 - //获取p2这个顶点在已有最小生成树中的终点 - int n = getEnd(ends, p2); // n = 5 - //是否构成回路 - if(m != n) { //没有构成回路 - ends[m] = n; // 设置m 在"已有最小生成树"中的终点 [0,0,0,0,5,0,0,0,0,0,0,0] - rets[index++] = edges[i]; //有一条边加入到rets数组 - } - } - // 。 - //统计并打印 "最小生成树", 输出 rets - System.out.println("最小生成树为"); - for(int i = 0; i < index; i++) { - System.out.println(rets[i]); - } - - - } - - public static void main(String[] args) { - char[] vertexs = {'A', 'B', 'C', 'D', 'E', 'F', 'G'}; - //克鲁斯卡尔算法的邻接矩阵 - int matrix[][] = { - /*A*//*B*//*C*//*D*//*E*//*F*//*G*/ - /*A*/ {0, 12, INF, INF, INF, 16, 14}, - /*B*/ {12, 0, 10, INF, INF, 7, INF}, - /*C*/ {INF, 10, 0, 3, 5, 6, INF}, - /*D*/ {INF, INF, 3, 0, 4, INF, INF}, - /*E*/ {INF, INF, 5, 4, 0, 2, 8}, - /*F*/ {16, 7, 6, INF, 2, 0, 9}, - /*G*/ {14, INF, INF, INF, 8, 9, 0}}; - KurskalAlgorithm kurskalAlgorithm = new KurskalAlgorithm(vertexs, matrix); - //kurskalAlgorithm.print(); - //EData[] edges = kurskalAlgorithm.getEdges(); - //kurskalAlgorithm.sortEdges(edges); - //System.out.println(Arrays.toString(edges)); - kurskalAlgorithm.kruskal(); - } -} - -// 代表一条边 -class EData { - // 起点 - char start; - // 终点 - char end; - // 权重 - int weight; - - public EData(char start, char end, int weight) { - this.start = start; - this.end = end; - this.weight = weight; - } - - @Override - public String toString() { - return "EData{" + - "start=" + start + - ", end=" + end + - ", weight=" + weight + - '}'; - } -} \ No newline at end of file diff --git a/algorithms/algorithm/src/main/java/cn/lastwhisper/mst/Prim.java b/algorithms/algorithm/src/main/java/cn/lastwhisper/mst/Prim.java deleted file mode 100644 index d39e5450..00000000 --- a/algorithms/algorithm/src/main/java/cn/lastwhisper/mst/Prim.java +++ /dev/null @@ -1,110 +0,0 @@ -package cn.lastwhisper.mst; - -import java.util.Arrays; - -/** - * @author cn.lastwhisper - */ -public class Prim { - - - public static void main(String[] args) { - // 图顶点的数据 - char[] data = new char[]{'A', 'B', 'C', 'D', 'E', 'F', 'G'}; - int vertexs = data.length; - //邻接矩阵的关系使用二维数组表示,10000表示两个点不联通(Integer.MAX_VALUE) - int[][] matrix = new int[][]{ - {10000, 5, 7, 10000, 10000, 10000, 2}, - {5, 10000, 10000, 9, 10000, 10000, 3}, - {7, 10000, 10000, 10000, 8, 10000, 10000}, - {10000, 9, 10000, 10000, 10000, 4, 10000}, - {10000, 10000, 8, 10000, 10000, 5, 4}, - {10000, 10000, 10000, 4, 5, 10000, 6}, - {2, 3, 10000, 10000, 4, 6, 10000},}; - - //创建MGraph对象 - MGraph graph = new MGraph(vertexs); - // 最小生成树 - MinTree minTree = new MinTree(); - minTree.createGraph(graph, vertexs, data, matrix); - minTree.showGraph(graph); - minTree.prim(graph, 0); - } - -} - -// 最小生成树 -class MinTree { - - /** - * - * @param graph 图 - * @param vertexs 顶点个数 - * @param data 顶点数据 - * @param matrix 顶点的关联映射的邻接矩阵 - * @return void - */ - public void createGraph(MGraph graph, int vertexs, char[] data, int[][] matrix) { - // 初始化顶点数据 - for (int i = 0; i < vertexs; i++) { - graph.data[i] = data[i]; - // 初始化邻接矩阵 - for (int j = 0; j < vertexs; j++) { - graph.matrix[i][j] = matrix[i][j]; - } - } - } - - //显示图的邻接矩阵 - public void showGraph(MGraph graph) { - for (int[] link : graph.matrix) { - System.out.println(Arrays.toString(link)); - } - } - - /** - * 根据图求得最小生成树 - * @param graph 图对象 - * @param v 起始顶点 - * @return void - */ - public void prim(MGraph graph, int v) { - // 记录已经访问过的顶点,true为访问过,false为没有访问过 - boolean[] visited = new boolean[graph.vertexs]; - visited[v] = true; - int index1 = -1, index2 = -1; - int minWeight = 10000; - // n个顶点会产生n-1条边 - for (int k = 1; k < graph.vertexs; k++) { - // 以i为顶点,向周围顶点访问,找到权值最小的连通顶点 - for (int i = 0; i < graph.vertexs; i++) { - for (int j = 0; j < graph.vertexs; j++) { - if (visited[i] && !visited[j] && graph.matrix[i][j] < minWeight) { - minWeight = graph.matrix[i][j]; - index1 = i; - index2 = j; - } - } - } - System.out.printf("边<%s,%s> 权值:%d\n", graph.data[index1], graph.data[index2], minWeight); - minWeight = 10000; - visited[index2] = true; - } - } -} - -// 图 -class MGraph { - // 顶点个数 - int vertexs; - // 顶点数据 - char[] data; - // 邻接矩阵 - int[][] matrix; - - public MGraph(int vertexs) { - this.vertexs = vertexs; - data = new char[vertexs]; - matrix = new int[vertexs][vertexs]; - } -} diff --git a/algorithms/algorithm/src/main/java/cn/lastwhisper/sort/QuickSort.java b/algorithms/algorithm/src/main/java/cn/lastwhisper/sort/QuickSort.java new file mode 100644 index 00000000..778f8cad --- /dev/null +++ b/algorithms/algorithm/src/main/java/cn/lastwhisper/sort/QuickSort.java @@ -0,0 +1,78 @@ +package cn.lastwhisper.sort; + + +import cn.lastwhisper.util.ArrayUtil; + +import java.util.Arrays; + +/** + * 快排 + * + * 整个快速排序的核心是分区(partition),分区的目的是传入一个数组和选定的一个元素,把所有小于那个元素的其他元素放在左边,大于的放在右边。 + * 元素的选择一般有如下几种: + * 永远选择第一个元素 + * 永远选择最后一个元素 + * 随机选择元素 + * 取中间值 + * @author lastwhisper + * @date 2020/3/15 + */ +public class QuickSort { + + + public static void sort(int[] arr) { + sort(arr, 0, arr.length - 1); + } + + public static void sort(int[] arr, int left, int right) { + if (left >= right) return; + int mid = partition(arr, left, right); + sort(arr, left, mid - 1); + sort(arr, mid + 1, right); + } + + /** + * 选取最后的元素,把所有小于那个元素的其他元素放在左边,大于的放在右边 + * + * 7, 3, 2, 8, 1, 9, 5, 4, 6 ==》 + * 4, 3, 2, 5, 1, 6, 8, 7, 9 + * + * @param arr 待排序数组 + * @return int 返回数组 + */ + private static int partition(int[] arr, int leftBound, int rightBound) { + int i = leftBound; + int pivot = arr[rightBound]; + int j = rightBound - 1;//-1是因为最后一个元素以及选择了 + while (i <= j) { + while (i <= j && arr[i] <= pivot) { + i++; + } + while (i <= j && arr[j] > pivot) { + j--; + } + if (i < j) swap(arr, i, j); + } + swap(arr, i, rightBound); + System.out.println(Arrays.toString(arr)); + return i; + } + + private static void swap(int[] arr, int i, int j) { + int temp = arr[i]; + arr[i] = arr[j]; + arr[j] = temp; + } + + public static void main(String[] args) { + int[] arr = {7, 3, 2, 8, 1, 9, 5, 4, 6}; + //int arr[] = {7, 3, 2, 8, 1, 9, 5, 4, 6, 0};//为什么left++和right--条件里面要加 left <= right 限定 + //int arr[] = {7, 3, 2, 8, 1, 9, 5, 4, 6, 10}; + //int arr[] = {7, 3, 2, 6, 8, 1, 9, 5, 4, 6, 10, 6, 6}; // 为什么不取等 arr[right] > pivot + //int arr[] = {4, 6}; //小bug测试 // 为什么while (left <= right)里面要取等 + //sort(arr); + sort(ArrayUtil.generateArrByRandom(10)); + //sort(arr,0,5); + //System.err.println(Arrays.toString(arr)); + } +} diff --git a/algorithms/algorithm/src/main/java/cn/lastwhisper/util/ArrayUtil.java b/algorithms/algorithm/src/main/java/cn/lastwhisper/util/ArrayUtil.java new file mode 100644 index 00000000..b91dfa7c --- /dev/null +++ b/algorithms/algorithm/src/main/java/cn/lastwhisper/util/ArrayUtil.java @@ -0,0 +1,24 @@ +package cn.lastwhisper.util; + +/** + * @author cn.lastwhisper + */ +public class ArrayUtil { + + public static int[] generateArrByRandom(int max) { + int[] arr = new int[max]; + for (int i = 0; i < max; i++) { + arr[i] = (int) (Math.random() * 8000000); // 生成一个[0,8000000) 的一个数 + } + return arr; + } + + public static int[] generateArrByOrder(int max) { + int[] arr = new int[max]; + for (int i = 0; i < max; i++) { + arr[i] = i + 1; + } + + return arr; + } +} diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/ArrayUtil.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/ArrayUtil.java deleted file mode 100644 index f26c42f4..00000000 --- a/algorithms/datastructure/src/main/java/cn/lastwhisper/ArrayUtil.java +++ /dev/null @@ -1,24 +0,0 @@ -package cn.lastwhisper; - -/** - * @author cn.lastwhisper - */ -public class ArrayUtil { - - public static int[] generateArrByRandom(int max) { - int[] arr = new int[max]; - for (int i = 0; i < max; i++) { - arr[i] = (int) (Math.random() * 8000000); // 生成一个[0,8000000) 的一个数 - } - return arr; - } - - public static int[] generateArrByOrder(int max) { - int[] arr = new int[max]; - for (int i = 0; i < max; i++) { - arr[i] = i + 1; - } - - return arr; - } -} diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/graph/Graph.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/graph/Graph.java similarity index 79% rename from algorithms/datastructure/src/main/java/cn/lastwhisper/graph/Graph.java rename to algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/graph/Graph.java index a5226b25..4f69cc9f 100644 --- a/algorithms/datastructure/src/main/java/cn/lastwhisper/graph/Graph.java +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/graph/Graph.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.graph; +package cn.lastwhisper.atguigu.graph; import java.util.ArrayList; import java.util.Arrays; @@ -13,7 +13,7 @@ public class Graph { private List vertexList; // 存储顶点集合 private int[][] matrix; // 存储图对应的邻接矩阵 private int numOfEdges; // 记录边的数量 - private boolean[] isVisited; // 记录某结点是否被访问 + private boolean[] isVisited; // 记录某节点是否被访问 // 初始化图的参数 public Graph(int n) { @@ -56,7 +56,7 @@ public static void main(String[] args) { graph.bfs(); } - //遍历所有的结点,都进行广度优先搜索 + //遍历所有的节点,都进行广度优先搜索 public void bfs() { isVisited = new boolean[vertexList.size()]; for (int i = 0; i < getNumOfVertex(); i++) { @@ -69,28 +69,28 @@ public void bfs() { // 广度优先 public void bfs(boolean[] isVisited, int i) { - int u; // 表示队列头结点对应下标 - int w; // 邻接结点w - // 记录结点访问的顺序 + int u; // 表示队列头节点对应下标 + int w; // 邻接节点w + // 记录节点访问的顺序 LinkedList queue = new LinkedList<>(); System.out.print(getValueByIndex(i) + "=>"); - // 标记结点已经访问 + // 标记节点已经访问 isVisited[i] = true; queue.addLast(i); while (!queue.isEmpty()) { - // 出队,遍历当前出队结点的所有邻接结点,并放入队列中 + // 出队,遍历当前出队节点的所有邻接节点,并放入队列中 u = queue.removeFirst(); - // 获取u的第一个邻接结点下标 + // 获取u的第一个邻接节点下标 w = getFristNeighbor(u); while (w != -1) { if (!isVisited[w]) { System.out.print(getValueByIndex(w) + "=>"); - // 标记结点已经访问 + // 标记节点已经访问 isVisited[w] = true; //入队,用于下一次出队 queue.addLast(w); } - // 从队列头结点,找到邻接结点w之后的邻接结点 + // 从队列头节点,找到邻接节点w之后的邻接节点 w = getNextNeighbor(u, w); } } @@ -109,23 +109,23 @@ public void dfs() { // 深度优先遍历算法 public void dfs(boolean[] isVisited, int i) { - // 首先我们访问该结点,输出 + // 首先我们访问该节点,输出 System.out.print(getValueByIndex(i) + "->"); - // 将结点设置为已经访问 + // 将节点设置为已经访问 isVisited[i] = true; - // 查找结点i的第一个邻接结点j + // 查找节点i的第一个邻接节点j int w = getFristNeighbor(i); while (w != -1) { if (!isVisited[w]) { dfs(isVisited, w); } - // 第i个结点下标i,matrix的row;w是邻接结点下标,matrix的column + // 第i个节点下标i,matrix的row;w是邻接节点下标,matrix的column w = getNextNeighbor(i, w); } } /** - * 根据前一个邻接结点的下标来获取下一个邻接结点 + * 根据前一个邻接节点的下标来获取下一个邻接节点 * * 0 1 2 3 4 * A B C D E @@ -134,7 +134,7 @@ public void dfs(boolean[] isVisited, int i) { * 2 C[1, 1, 0, 0, 0] * 3 D[0, 1, 0, 0, 0] * 4 E[0, 1, 0, 0, 0] - * v1=1,v2=1,下一个邻接结点下标为1 + * v1=1,v2=1,下一个邻接节点下标为1 * @param v1 当前weight横下标 * @param v2 当前weight纵下标 * @return int @@ -149,7 +149,7 @@ public int getNextNeighbor(int v1, int v2) { } /** - * 得到某一个结点的第一个邻接结点的下标 + * 得到某一个节点的第一个邻接节点的下标 * 例如: * 0 1 2 3 4 * A B C D E @@ -158,8 +158,8 @@ public int getNextNeighbor(int v1, int v2) { * 2 C[1, 1, 0, 0, 0] * 3 D[0, 1, 0, 0, 0] * 4 E[0, 1, 0, 0, 0] - * index=0,第一个结点A的第一个邻接结点就是B,第一个邻接结点的下标就是1 - * @param index 某一个结点 + * index=0,第一个节点A的第一个邻接节点就是B,第一个邻接节点的下标就是1 + * @param index 某一个节点 * @return int */ public int getFristNeighbor(int index) { @@ -171,12 +171,12 @@ public int getFristNeighbor(int index) { return -1; } - // 返回结点下标对应的数据 + // 返回节点下标对应的数据 public String getValueByIndex(int i) { return vertexList.get(i); } - // 添加结点 + // 添加节点 public void addVertex(String vertex) { vertexList.add(vertex); } @@ -184,8 +184,8 @@ public void addVertex(String vertex) { /** * 添加边 * - * @param v1 结点1的下标 - * @param v2 结点2的下标 + * @param v1 节点1的下标 + * @param v2 节点2的下标 * @param weight 1表示有通路,0表示无通路 */ public void addEdge(int v1, int v2, int weight) { @@ -201,7 +201,7 @@ public void show() { } } - //返回结点的个数 + //返回节点的个数 public int getNumOfVertex() { return vertexList.size(); } diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/hashtab/HashTabDemo.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/hashtab/HashTabDemo.java similarity index 99% rename from algorithms/datastructure/src/main/java/cn/lastwhisper/hashtab/HashTabDemo.java rename to algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/hashtab/HashTabDemo.java index eccb9cc8..8eb6eee7 100644 --- a/algorithms/datastructure/src/main/java/cn/lastwhisper/hashtab/HashTabDemo.java +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/hashtab/HashTabDemo.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.hashtab; +package cn.lastwhisper.atguigu.hashtab; /** * diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/linkedlist/DoubleLinkedListDemo.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/linkedlist/DoubleLinkedListDemo.java similarity index 77% rename from algorithms/datastructure/src/main/java/cn/lastwhisper/linkedlist/DoubleLinkedListDemo.java rename to algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/linkedlist/DoubleLinkedListDemo.java index cd0ea117..8d725b43 100644 --- a/algorithms/datastructure/src/main/java/cn/lastwhisper/linkedlist/DoubleLinkedListDemo.java +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/linkedlist/DoubleLinkedListDemo.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.linkedlist; +package cn.lastwhisper.atguigu.linkedlist; /** * 双向链表 @@ -15,23 +15,23 @@ public static void main(String[] args) { doubleLinkedList.add(hero2); doubleLinkedList.add(hero3); doubleLinkedList.add(hero4); - System.out.println("===============查看链表所有结点================"); + System.out.println("===============查看链表所有节点================"); doubleLinkedList.list(); - System.out.println("===============删除链表某结点=================="); + System.out.println("===============删除链表某节点=================="); doubleLinkedList.delete(2); - System.out.println("===============查看链表所有结点================"); + System.out.println("===============查看链表所有节点================"); doubleLinkedList.list(); - System.out.println("================更新链表结点,4================="); + System.out.println("================更新链表节点,4================="); doubleLinkedList.update(new HeroNode2(4, "林冲", "豹子头~~~")); - System.out.println("===============查看链表所有结点================"); + System.out.println("===============查看链表所有节点================"); doubleLinkedList.list(); - System.out.println("===============按序插入结点,8================"); + System.out.println("===============按序插入节点,8================"); doubleLinkedList.addByNoOrder(new HeroNode2(8, "武松", "行者")); - System.out.println("===============查看链表所有结点================"); + System.out.println("===============查看链表所有节点================"); doubleLinkedList.list(); - System.out.println("===============按序插入结点,6================"); + System.out.println("===============按序插入节点,6================"); doubleLinkedList.addByNoOrder(new HeroNode2(6, "入云龙", "公孙胜")); - System.out.println("===============查看链表所有结点================"); + System.out.println("===============查看链表所有节点================"); doubleLinkedList.list(); } } @@ -63,13 +63,13 @@ public void delete(int no) { HeroNode2 tempNode = head; while (true) { if (tempNode.next == null) { - System.out.printf("未找到no==%d 结点\n", no); + System.out.printf("未找到no==%d 节点\n", no); break; } tempNode = tempNode.next; if (tempNode.no == no) { tempNode.pre.next = tempNode.next; - System.out.printf("已删除no==%d 结点\n", no); + System.out.printf("已删除no==%d 节点\n", no); break; } } @@ -80,22 +80,22 @@ public void update(HeroNode2 updateNode) { HeroNode2 tempNode = head; while (true) { if (tempNode.next == null) { - System.out.printf("未找到no==%d 结点\n", updateNode.no); + System.out.printf("未找到no==%d 节点\n", updateNode.no); break; } tempNode = tempNode.next; - // 找到待更新结点 + // 找到待更新节点 if (tempNode.no == updateNode.no) { tempNode.name = updateNode.name; tempNode.nickName = updateNode.nickName; - System.out.printf("已更新no==%d 结点\n", updateNode.no); + System.out.printf("已更新no==%d 节点\n", updateNode.no); break; } } } /** - * 展示所有结点,沿着头结点遍历 + * 展示所有节点,沿着头节点遍历 * * @param * @return void @@ -125,7 +125,7 @@ public void addByNoOrder(HeroNode2 heroNode) { } //preNode = tempNode; tempNode = tempNode.next; - // tempNode是待插入结点的前一个结点 + // tempNode是待插入节点的前一个节点 if (heroNode.no == tempNode.no) { flag = false; System.out.println("已存在排名,添加失败" + heroNode); @@ -134,9 +134,9 @@ public void addByNoOrder(HeroNode2 heroNode) { if (heroNode.no < tempNode.no) { // 1,3,4 heroNode.no=2 tempNode.next.no=3 2<3 可以添加 - // heroNode指向no=3结点,即2,3 + // heroNode指向no=3节点,即2,3 heroNode.next = tempNode; - // tempNode.pre为no=1的结点 即1,2 + // tempNode.pre为no=1的节点 即1,2 // preNode.next = heroNode; tempNode.pre.next = heroNode; flag = false; @@ -144,7 +144,7 @@ public void addByNoOrder(HeroNode2 heroNode) { } } if (flag) { - // 待插入结点no最大 + // 待插入节点no最大 tempNode.next = heroNode; heroNode.pre = tempNode; } @@ -152,15 +152,15 @@ public void addByNoOrder(HeroNode2 heroNode) { } /** - * 双向链表结点 + * 双向链表节点 * */ class HeroNode2 { public int no; public String name; public String nickName; - public HeroNode2 next; // 当前结点的后一个结点 - public HeroNode2 pre; //当前结点的前一个结点 + public HeroNode2 next; // 当前节点的后一个节点 + public HeroNode2 pre; //当前节点的前一个节点 public HeroNode2(int no, String name, String nickName) { this.no = no; diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/linkedlist/Josepfu.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/linkedlist/Josepfu.java similarity index 95% rename from algorithms/datastructure/src/main/java/cn/lastwhisper/linkedlist/Josepfu.java rename to algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/linkedlist/Josepfu.java index dd269af1..05df13fc 100644 --- a/algorithms/datastructure/src/main/java/cn/lastwhisper/linkedlist/Josepfu.java +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/linkedlist/Josepfu.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.linkedlist; +package cn.lastwhisper.atguigu.linkedlist; /** * 约瑟夫环 @@ -32,7 +32,7 @@ public void createCircle(int num) { System.out.println("错误的num"); return; } - // 定位最后一个boy的位置,方便添加结点 + // 定位最后一个boy的位置,方便添加节点 Boy currBoy = null; for (int i = 1; i <= num; i++) { Boy boy = new Boy(i); @@ -51,7 +51,7 @@ public void createCircle(int num) { } /** - * 打印当前环链的结点信息 + * 打印当前环链的节点信息 */ public void showBoy() { if (frist == null) { diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/linkedlist/SingleLinkedListDemo.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/linkedlist/SingleLinkedListDemo.java similarity index 80% rename from algorithms/datastructure/src/main/java/cn/lastwhisper/linkedlist/SingleLinkedListDemo.java rename to algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/linkedlist/SingleLinkedListDemo.java index 964574a5..6f915a4d 100644 --- a/algorithms/datastructure/src/main/java/cn/lastwhisper/linkedlist/SingleLinkedListDemo.java +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/linkedlist/SingleLinkedListDemo.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.linkedlist; +package cn.lastwhisper.atguigu.linkedlist; import org.junit.Test; @@ -27,32 +27,32 @@ public class SingleLinkedListDemo { public static void main(String[] args) { - System.out.println("===============查看链表所有结点================"); + System.out.println("===============查看链表所有节点================"); singleLinkedList.list(); - System.out.println("===============删除链表某结点=================="); + System.out.println("===============删除链表某节点=================="); singleLinkedList.delete(2); - System.out.println("===============查看链表所有结点================"); + System.out.println("===============查看链表所有节点================"); singleLinkedList.list(); - System.out.println("================更新链表结点,4================="); + System.out.println("================更新链表节点,4================="); singleLinkedList.update(new HeroNode(4, "林冲", "豹子头~~~")); - System.out.println("===============查看链表所有结点================"); + System.out.println("===============查看链表所有节点================"); singleLinkedList.list(); - System.out.println("===============按序插入结点,2,3================"); + System.out.println("===============按序插入节点,2,3================"); singleLinkedList.addByNoOrder(new HeroNode(2, "卢俊义回来了~~~", "玉麒麟")); singleLinkedList.addByNoOrder(new HeroNode(3, "吴用", "智多星")); //singleLinkedList.addByNoOrderIsEqual(new HeroNode(2, "卢俊义回来了~~~", "玉麒麟")); //singleLinkedList.addByNoOrderIsEqual(new HeroNode(3, "吴用", "智多星")); - System.out.println("===============查看链表所有结点================"); + System.out.println("===============查看链表所有节点================"); singleLinkedList.list(); - System.out.println("===============按序插入结点,8================"); + System.out.println("===============按序插入节点,8================"); singleLinkedList.addByNoOrder(new HeroNode(8, "武松", "行者")); - System.out.println("===============查看链表所有结点================"); + System.out.println("===============查看链表所有节点================"); singleLinkedList.list(); - System.out.println("===============按序插入结点,7================"); + System.out.println("===============按序插入节点,7================"); singleLinkedList.addByNoOrder(new HeroNode(7, "入云龙", "公孙胜")); - System.out.println("===============查看链表所有结点================"); + System.out.println("===============查看链表所有节点================"); singleLinkedList.list(); - System.out.println("---------------获取链表长度,不包括头结点-----------"); + System.out.println("---------------获取链表长度,不包括头节点-----------"); System.out.println(singleLinkedList.size()); System.out.println("---------------获取链表倒数第2个元素-----------"); System.out.println(singleLinkedList.findLastIndexNode(2)); @@ -74,7 +74,7 @@ public static void main(String[] args) { singleLinkedList2.add(hero23); singleLinkedList2.add(hero25); singleLinkedList2.add(hero27); - System.out.println("---------------查看二号链表所有结点---------------"); + System.out.println("---------------查看二号链表所有节点---------------"); singleLinkedList2.list(); SingleLinkedList singleLinkedList3 = new SingleLinkedList(); HeroNode hero32 = new HeroNode(2, "柴进", "小旋风"); @@ -85,11 +85,11 @@ public static void main(String[] args) { singleLinkedList3.add(hero34); singleLinkedList3.add(hero36); singleLinkedList3.add(hero38); - System.out.println("---------------查看三号链表所有结点---------------"); + System.out.println("---------------查看三号链表所有节点---------------"); singleLinkedList3.list(); System.out.println("-----------------合并结束-------------------"); singleLinkedList2.mergeOrderLinkedList(singleLinkedList3); - System.out.println("-----------------查看二号链表所有结点-----------------"); + System.out.println("-----------------查看二号链表所有节点-----------------"); singleLinkedList2.list(); } @@ -112,12 +112,12 @@ class SingleLinkedList { private HeroNode head = new HeroNode(0, "", ""); /** - * 添加结点 + * 添加节点 * 找到单链表lastNode,lastNode.next=newNode */ public void add(HeroNode heroNode) { HeroNode tempNode = head; - // 找到最后一个结点 + // 找到最后一个节点 while (true) { if (tempNode.next == null) { break; @@ -153,23 +153,23 @@ public void addByNoOrder(HeroNode heroNode) { if (heroNode.no < tempNode.no) { // 1,3,4 heroNode.no=2 tempNode.next.no=3 2<3 可以添加 - // heroNode指向no=3结点 + // heroNode指向no=3节点 heroNode.next = tempNode; - // tempNode指向heroNode结点 + // tempNode指向heroNode节点 preNode.next = heroNode; flag = false; break; } } if (flag) { - // 待插入结点no最大 + // 待插入节点no最大 tempNode.next = heroNode; } } /** * 根据排名插入到指定位置 - * 可以存在相同编号的结点 + * 可以存在相同编号的节点 * @param heroNode * @return void */ @@ -186,22 +186,22 @@ public void addByNoOrderIsEqual(HeroNode heroNode) { if (heroNode.no <= tempNode.no) { // 1,3,4 heroNode.no=2 tempNode.next.no=3 2<3 可以添加 - // heroNode指向no=3结点 + // heroNode指向no=3节点 heroNode.next = tempNode; - // tempNode指向heroNode结点 + // tempNode指向heroNode节点 preNode.next = heroNode; flag = false; break; } } if (flag) { - // 待插入结点no最大 + // 待插入节点no最大 tempNode.next = heroNode; } } /** - * 展示所有结点,沿着头结点遍历 + * 展示所有节点,沿着头节点遍历 * * @param * @return void @@ -235,32 +235,32 @@ public void deleteDuplicate() { } /** - * 根据no删除结点 + * 根据no删除节点 * * @param no * @return void */ public void delete(int no) { - // 1、沿着头结点tempNode遍历,找到node.no=no的前一个结点preNode + // 1、沿着头节点tempNode遍历,找到node.no=no的前一个节点preNode HeroNode preNode = head; while (true) { if (preNode.next == null) { - System.out.printf("未找到no==%d 结点\n", no); + System.out.printf("未找到no==%d 节点\n", no); break; } - // tempNode是待删除结点的前一个结点 + // tempNode是待删除节点的前一个节点 preNode = preNode.next; - // 2. 找到待删除结点的前一个结点 + // 2. 找到待删除节点的前一个节点 if (preNode.next.no == no) { preNode.next = preNode.next.next; - System.out.printf("已删除no==%d 结点\n", no); + System.out.printf("已删除no==%d 节点\n", no); break; } } } /** - * 根据no更新结点 + * 根据no更新节点 * * @param updateNode * @return void @@ -269,22 +269,22 @@ public void update(HeroNode updateNode) { HeroNode tempNode = head; while (true) { if (tempNode.next == null) { - System.out.printf("未找到no==%d 结点\n", updateNode.no); + System.out.printf("未找到no==%d 节点\n", updateNode.no); break; } tempNode = tempNode.next; - // 找到待更新结点 + // 找到待更新节点 if (tempNode.no == updateNode.no) { tempNode.name = updateNode.name; tempNode.nickName = updateNode.nickName; - System.out.printf("已更新no==%d 结点\n", updateNode.no); + System.out.printf("已更新no==%d 节点\n", updateNode.no); break; } } } /** - * 获取单链表的结点个数(不统计头结点) + * 获取单链表的节点个数(不统计头节点) * * @param * @return int @@ -300,7 +300,7 @@ public int size() { } /** - * 获取单链表倒数第k个结点 + * 获取单链表倒数第k个节点 * 思路:倒数第k个等价于正数size-k+1个 * 示例:7个元素,倒数第2个==正数第6个 * @param k @@ -320,16 +320,16 @@ public HeroNode findLastIndexNode(int k) { /** * 单链表反转 - * 将原链表结点依次插入到反转链表的第一个位置 + * 将原链表节点依次插入到反转链表的第一个位置 */ public void reverse() { - // 如果单链表中无结点或者只有一个结点 + // 如果单链表中无节点或者只有一个节点 if (head.next == null || head.next.next == null) { return; } - // currNode的作用:指向待插入反转链表结点的指针。遍历原单链表 + // currNode的作用:指向待插入反转链表节点的指针。遍历原单链表 HeroNode currNode = head.next; - // nextNode的作用:暂存待插入反转链表结点的下一个结点 + // nextNode的作用:暂存待插入反转链表节点的下一个节点 HeroNode nextNode; HeroNode reverseHead = new HeroNode(0, "", ""); @@ -339,10 +339,10 @@ public void reverse() { nextNode = currNode.next; currNode.next = reverseHead.next; reverseHead.next = currNode; - // currNode每一次循环都会后移一个结点 + // currNode每一次循环都会后移一个节点 currNode = nextNode; } - // 将原链表头结点指向反转链表头结点.next + // 将原链表头节点指向反转链表头节点.next head.next = reverseHead.next; } @@ -368,12 +368,12 @@ public void reverseList() { /** * 合并两个有序链表(合并后还有序) - * 方法一:遍历2号链表,将每一个结点都放入1号链表.addByNoOrderIsEqual方法中 + * 方法一:遍历2号链表,将每一个节点都放入1号链表.addByNoOrderIsEqual方法中 * 优点:方便简洁,代码容易理解。缺点:性能低。 * 方法二: * 1号链表:1,3,6,7 2号链表:2,4,6,8 - * 由于是有序链表,2号链表的2结点插入到1号链表的1,3结点之中后, - * 2号链表的4结点没有必要从1号结点的1,2,3开始遍历,直接从刚插入结点2结点开始遍历即可 + * 由于是有序链表,2号链表的2节点插入到1号链表的1,3节点之中后, + * 2号链表的4节点没有必要从1号节点的1,2,3开始遍历,直接从刚插入节点2节点开始遍历即可 * @param singleLinkedList * @return void */ @@ -387,24 +387,24 @@ public void mergeOrderLinkedList(SingleLinkedList singleLinkedList) { // currNode = nextNode; //} // 方法二: - // 2号链表 currNode1当前待合并结点 + // 2号链表 currNode1当前待合并节点 HeroNode currNode2 = singleLinkedList.head.next; - // nextNode是currNode.next,防止2号链表后续结点丢失 + // nextNode是currNode.next,防止2号链表后续节点丢失 HeroNode nextNode2; - // 缓存刚插入结点的位置 + // 缓存刚插入节点的位置 HeroNode currNodeChche2 = null; while (currNode2 != null) { nextNode2 = currNode2.next; // 1号链表 - // 记录2号链表结点在1号链表结点插入的位置 + // 记录2号链表节点在1号链表节点插入的位置 HeroNode tempNode1 = currNodeChche2; if (tempNode1 == null) { tempNode1 = this.head; } HeroNode preNode1; - boolean flag = true; //标识该结点是否插到最后一位 + boolean flag = true; //标识该节点是否插到最后一位 while (true) { if (tempNode1.next == null) { break; @@ -413,9 +413,9 @@ public void mergeOrderLinkedList(SingleLinkedList singleLinkedList) { tempNode1 = tempNode1.next; if (currNode2.no <= tempNode1.no) { // 1,3,4 nextNode.no=2 nextNode.next.no=3 2<3 可以添加 - // nextNode指向no=3结点 + // nextNode指向no=3节点 currNode2.next = tempNode1; - // tempNode指向nextNode结点 + // tempNode指向nextNode节点 preNode1.next = currNode2; flag = false; break; @@ -423,18 +423,18 @@ public void mergeOrderLinkedList(SingleLinkedList singleLinkedList) { } if (flag) { - // 待插入结点no最大 + // 待插入节点no最大 tempNode1.next = currNode2; } currNodeChche2 = currNode2; - // 存储2号链表的当前结点后移 + // 存储2号链表的当前节点后移 currNode2 = nextNode2; } } } /** - * 单链表的结点 + * 单链表的节点 */ class HeroNode { public int no; diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/linkedlist/skiplist/v1/SkipSet.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/linkedlist/skiplist/v1/SkipSet.java new file mode 100644 index 00000000..014114ee --- /dev/null +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/linkedlist/skiplist/v1/SkipSet.java @@ -0,0 +1,165 @@ +package cn.lastwhisper.atguigu.linkedlist.skiplist.v1; + +/** + * https://www.iteye.com/blog/imtinx-1291165 + * 跳表节点数据存储结构 + */ +class SkipNode> { + public final E value; //节点存储的数据 + public final SkipNode[] forward; //节点的指针数组 + + /** + * 根据节点的层级构造一个节点 + * @param level 节点层级 + * @param value 节点存储值 + */ + @SuppressWarnings("unchecked") + public SkipNode(int level, E value) { + forward = new SkipNode[level + 1];//level层的元素后面带着level+1的指针数组 + this.value = value; + } + +} + +public class SkipSet> { + + /** + * 概率因子,实验证明p=1/e比p=0.5要好,e是个神奇的数字! + */ +// public static final double P = 0.5; + public static final double P = 1 / Math.E; + /** + * 最大层级 + */ + public static final int MAX_LEVEL = 6; + + /** + * 开始节点,不存值,贯穿所有层 + */ + public final SkipNode header = new SkipNode(MAX_LEVEL, null); + /** + * 当前跳表的最高层级 + */ + public int level = 0; + + /** + * 插入一个元素 + * @param value 待插入值 + */ + @SuppressWarnings("unchecked") + public void insert(E value) { + SkipNode x = header; + SkipNode[] update = new SkipNode[MAX_LEVEL + 1]; + //查找元素的位置,这里其实做了一次contain操作,注释见contain + for (int i = level; i >= 0; i--) { + while (x.forward[i] != null + && x.forward[i].value.compareTo(value) < 0) { + x = x.forward[i]; + } + //update[i]是比value小的数里面最大的,是value的前置节点 + update[i] = x; + } + x = x.forward[0]; + + //此处不允许插入相同元素,为一个set + if (x == null || !x.value.equals(value)) {//跳表中不包含所要插的元素 + //随机产生插入的层级 + int lvl = randomLevel(); + //产生的随机层级比当前跳表的最高层级大,需要添加相应的层级,并更新最高层级 + if (lvl > level) { + for (int i = level + 1; i <= lvl; i++) { + update[i] = header; + } + level = lvl; + } + + //生成新节点 + x = new SkipNode(lvl, value); + //调整节点的指针,和指向它的指针 + for (int i = 0; i <= lvl; i++) { + x.forward[i] = update[i].forward[i]; + update[i].forward[i] = x; + } + + } + } + + /** + * 删除一个元素 + * @param value 待删除值 + */ + @SuppressWarnings("unchecked") + public void delete(E value) { + SkipNode x = header; + SkipNode[] update = new SkipNode[MAX_LEVEL + 1]; + //查找元素的位置,这里其实做了一次contain操作,注释见contain + for (int i = level; i >= 0; i--) { + while (x.forward[i] != null + && x.forward[i].value.compareTo(value) < 0) { + x = x.forward[i]; + } + update[i] = x; + } + x = x.forward[0]; + //删除元素,调整指针 + if (x.value.equals(value)) { + for (int i = 0; i <= level; i++) { + if (update[i].forward[i] != x) + break; + update[i].forward[i] = x.forward[i]; + } + //如果元素为本层最后一个元素,则删除同时降低当前层级 + while (level > 0 && header.forward[level] == null) { + level--; + } + + } + } + + /** + * 查找是否包含此元素 + * @param searchValue 带查找值 + * @return true:包含;false:不包含 + */ + public boolean contains(E searchValue) { + SkipNode x = header; + //从开始节点的最高层级开始查找 + for (int i = level; i >= 0; i--) { + //当到达本层级的NULL节点或者遇到比查找值大的节点时,转到下一层级查找 + while (x.forward[i] != null + && x.forward[i].value.compareTo(searchValue) < 0) { + x = x.forward[i]; + } + } + x = x.forward[0]; + //此时x有三种可能,1.x=null,2.x.value=searchValue,3.x.value>searchValue + return x != null && x.value.equals(searchValue); + } + + /** + * 这里是跳表的精髓所在,通过随机概率来判断节点的层级 + * @return 节点的层级 + */ + public static int randomLevel() { + int lvl = (int) (Math.log(1. - Math.random()) / Math.log(1. - P)); + return Math.min(lvl, MAX_LEVEL); + } + + /** + * 输出跳表的所有元素 + * 遍历最底层的元素即可 + */ + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("{"); + SkipNode x = header.forward[0]; + while (x != null) { + sb.append(x.value); + x = x.forward[0]; + if (x != null) + sb.append(","); + } + sb.append("}"); + return sb.toString(); + } +} \ No newline at end of file diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/linkedlist/skiplist/v2/SkipList.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/linkedlist/skiplist/v2/SkipList.java new file mode 100644 index 00000000..999ca80a --- /dev/null +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/linkedlist/skiplist/v2/SkipList.java @@ -0,0 +1,150 @@ +package cn.lastwhisper.atguigu.linkedlist.skiplist.v2; + +/** + * 跳表的一种实现方法。 + * 跳表中存储的是正整数,并且存储的是不重复的。 + * + * ------------------------------------------------------------------------- + * 以每两个结点抽取一个做上级索引为例分析: + * 时间复杂度:O(logn) + * 空间复杂度:O(n),需要抽出n/2+n/4+n/8…+8+4+2=n-2 + */ +public class SkipList { + + private static final float SKIPLIST_P = 0.5f; + private static final int MAX_LEVEL = 16; + + private int levelCount = 1; + // 带头链表 + private Node head = new Node(); + + public static class Node { + private int data = -1; + private Node[] forwards = new Node[MAX_LEVEL]; + private int maxLevel = 0; + + @Override + public String toString() { + return "{ data: " + + data + + "; levels: " + + maxLevel + + " }"; + } + } + + public Node find(int value) { + Node p = head; + for (int i = levelCount - 1; i >= 0; --i) { + while (p.forwards[i] != null && p.forwards[i].data < value) { + p = p.forwards[i]; + } + } + + if (p.forwards[0] != null && p.forwards[0].data == value) { + return p.forwards[0]; + } else { + return null; + } + } + + public void insert(int value) { + int level = randomLevel(); + Node newNode = new Node(); + newNode.data = value; + newNode.maxLevel = level; + Node[] update = new Node[level]; + for (int i = 0; i < level; ++i) { + update[i] = head; + } + + // record every level largest value which smaller than insert value in update[] + Node p = head; + for (int i = level - 1; i >= 0; --i) { + while (p.forwards[i] != null && p.forwards[i].data < value) { + p = p.forwards[i]; + } + update[i] = p;// use update save node in search path + } + + // in search path node next node become new node forwords(next) + for (int i = 0; i < level; ++i) { + newNode.forwards[i] = update[i].forwards[i]; + update[i].forwards[i] = newNode; + } + + // update node hight + if (levelCount < level) { + levelCount = level; + } + } + + public void delete(int value) { + Node[] update = new Node[levelCount]; + Node p = head; + for (int i = levelCount - 1; i >= 0; --i) { + while (p.forwards[i] != null && p.forwards[i].data < value) { + p = p.forwards[i]; + } + update[i] = p; + } + + if (p.forwards[0] != null && p.forwards[0].data == value) { + for (int i = levelCount - 1; i >= 0; --i) { + if (update[i].forwards[i] != null && update[i].forwards[i].data == value) { + update[i].forwards[i] = update[i].forwards[i].forwards[i]; + } + } + } + + while (levelCount > 1 && head.forwards[levelCount] == null) { + levelCount--; + } + + } + + // 理论来讲,一级索引中元素个数应该占原始数据的 50%,二级索引中元素个数占 25%,三级索引12.5% ,一直到最顶层。 + // 因为这里每一层的晋升概率是 50%。对于每一个新插入的节点,都需要调用 randomLevel 生成一个合理的层数。 + // 该 randomLevel 方法会随机生成 1~MAX_LEVEL 之间的数,且 : + // 50%的概率返回 1 + // 25%的概率返回 2 + // 12.5%的概率返回 3 ... + private int randomLevel() { + int level = 1; + + while (Math.random() < SKIPLIST_P && level < MAX_LEVEL) { + level += 1; + } + return level; + } + + public void printAll() { + Node p = head; + while (p.forwards[0] != null) { + System.out.print(p.forwards[0] + " "); + p = p.forwards[0]; + } + System.out.println(); + } + + public static void main(String[] args) { + SkipList list = new SkipList(); + list.insert(1); + list.insert(2); + // 寻找2 + Node node = list.find(2); + System.out.println(node == null ? "不存在" : node.data); + list.insert(6); + list.insert(7); + // 删除2 + list.delete(2); + node = list.find(2); + System.out.println(node == null ? "不存在" : node.data); + list.insert(8); + list.insert(3); + list.insert(4); + list.insert(5); + + list.printAll(); + } +} diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/linkedlist/skiplist/v3/SkipList2.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/linkedlist/skiplist/v3/SkipList2.java new file mode 100644 index 00000000..acc518bb --- /dev/null +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/linkedlist/skiplist/v3/SkipList2.java @@ -0,0 +1,307 @@ +package cn.lastwhisper.atguigu.linkedlist.skiplist.v3; + +import java.util.Random; + +/** + * 1,跳表的一种实现方法,用于练习。跳表中存储的是正整数,并且存储的是不重复的。 + * 2,本类是参考作者zheng ,自己学习,优化了添加方法 + * 3,看完这个,我觉得再看ConcurrentSkipListMap 源码,会有很大收获 + * Author:ldb + */ +public class SkipList2 { + + private static final int MAX_LEVEL = 16; + private int levelCount = 1; + + /** + * 带头链表 + */ + private Node head = new Node(MAX_LEVEL); + private Random r = new Random(); + + /** + * 跳表的节点,每个节点记录了当前节点数据和所在层数数据 + */ + public class Node { + private int data = -1; + /** + * 表示当前节点位置的下一个节点所有层的数据,从上层切换到下层,就是数组下标-1, + * forwards[3]表示当前节点在第三层的下一个节点。 + */ + private Node forwards[]; + + /** + * 这个值其实可以不用,看优化insert() + */ + private int maxLevel = 0; + + public Node(int level) { + forwards = new Node[level]; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("{ data: "); + builder.append(data); + builder.append("; levels: "); + builder.append(maxLevel); + builder.append(" }"); + return builder.toString(); + } + } + + public Node find(int value) { + Node p = head; + // 从最大层开始查找,找到前一节点,通过--i,移动到下层再开始查找 + for (int i = levelCount - 1; i >= 0; --i) { + while (p.forwards[i] != null && p.forwards[i].data < value) { + // 找到前一节点 + p = p.forwards[i]; + } + } + + if (p.forwards[0] != null && p.forwards[0].data == value) { + return p.forwards[0]; + } else { + return null; + } + } + + /** + * 优化了作者zheng的插入方法 + * + * @param value 值 + */ + public void insert(int value) { + int level = head.forwards[0] == null ? 1 : randomLevel(); + // 每次只增加一层,如果条件满足 + if (level > levelCount) { + level = ++levelCount; + } + Node newNode = new Node(level); + newNode.data = value; + Node update[] = new Node[level]; + for (int i = 0; i < level; ++i) { + update[i] = head; + } + + Node p = head; + // 从最大层开始查找,找到前一节点,通过--i,移动到下层再开始查找 + for (int i = levelCount - 1; i >= 0; --i) { + while (p.forwards[i] != null && p.forwards[i].data < value) { + // 找到前一节点 + p = p.forwards[i]; + } + // levelCount 会 > level,所以加上判断 + if (level > i) { + update[i] = p; + } + + } + for (int i = 0; i < level; ++i) { + newNode.forwards[i] = update[i].forwards[i]; + update[i].forwards[i] = newNode; + } + + } + + /** + * 优化了作者zheng的插入方法2 + * + * @param value 值 + */ + public void insert2(int value) { + int level = head.forwards[0] == null ? 1 : randomLevel(); + // 每次只增加一层,如果条件满足 + if (level > levelCount) { + level = ++levelCount; + } + Node newNode = new Node(level); + newNode.data = value; + Node p = head; + // 从最大层开始查找,找到前一节点,通过--i,移动到下层再开始查找 + for (int i = levelCount - 1; i >= 0; --i) { + while (p.forwards[i] != null && p.forwards[i].data < value) { + // 找到前一节点 + p = p.forwards[i]; + } + // levelCount 会 > level,所以加上判断 + if (level > i) { + if (p.forwards[i] == null) { + p.forwards[i] = newNode; + } else { + Node next = p.forwards[i]; + p.forwards[i] = newNode; + newNode.forwards[i] = next; + } + } + + } + + } + + /** + * 作者zheng的插入方法,未优化前,优化后参见上面insert() + * + * @param value + * @param level 0 表示随机层数,不为0,表示指定层数,指定层数 + * 可以让每次打印结果不变动,这里是为了便于学习理解 + */ + public void insert(int value, int level) { + // 随机一个层数 + if (level == 0) { + level = randomLevel(); + } + // 创建新节点 + Node newNode = new Node(level); + newNode.data = value; + // 表示从最大层到低层,都要有节点数据 + newNode.maxLevel = level; + // 记录要更新的层数,表示新节点要更新到哪几层 + Node update[] = new Node[level]; + for (int i = 0; i < level; ++i) { + update[i] = head; + } + + /** + * + * 1,说明:层是从下到上的,这里最下层编号是0,最上层编号是15 + * 2,这里没有从已有数据最大层(编号最大)开始找,(而是随机层的最大层)导致有些问题。 + * 如果数据量为1亿,随机level=1 ,那么插入时间复杂度为O(n) + */ + Node p = head; + for (int i = level - 1; i >= 0; --i) { + while (p.forwards[i] != null && p.forwards[i].data < value) { + p = p.forwards[i]; + } + // 这里update[i]表示当前层节点的前一节点,因为要找到前一节点,才好插入数据 + update[i] = p; + } + + // 将每一层节点和后面节点关联 + for (int i = 0; i < level; ++i) { + // 记录当前层节点后面节点指针 + newNode.forwards[i] = update[i].forwards[i]; + // 前一个节点的指针,指向当前节点 + update[i].forwards[i] = newNode; + } + + // 更新层高 + if (levelCount < level) levelCount = level; + } + + public void delete(int value) { + Node[] update = new Node[levelCount]; + Node p = head; + for (int i = levelCount - 1; i >= 0; --i) { + while (p.forwards[i] != null && p.forwards[i].data < value) { + p = p.forwards[i]; + } + update[i] = p; + } + + if (p.forwards[0] != null && p.forwards[0].data == value) { + for (int i = levelCount - 1; i >= 0; --i) { + if (update[i].forwards[i] != null && update[i].forwards[i].data == value) { + update[i].forwards[i] = update[i].forwards[i].forwards[i]; + } + } + } + } + + /** + * 随机 level 次,如果是奇数层数 +1,防止伪随机 + * + * @return + */ + private int randomLevel() { + int level = 1; + for (int i = 1; i < MAX_LEVEL; ++i) { + if (r.nextInt() % 2 == 1) { + level++; + } + } + return level; + } + + /** + * 打印每个节点数据和最大层数 + */ + public void printAll() { + Node p = head; + while (p.forwards[0] != null) { + System.out.print(p.forwards[0] + " "); + p = p.forwards[0]; + } + System.out.println(); + } + + /** + * 打印所有数据 + */ + public void printAll_beautiful() { + Node p = head; + Node[] c = p.forwards; + Node[] d = c; + int maxLevel = c.length; + for (int i = maxLevel - 1; i >= 0; i--) { + do { + System.out.print((d[i] != null ? d[i].data : null) + ":" + i + "-------"); + } while (d[i] != null && (d = d[i].forwards)[i] != null); + System.out.println(); + d = c; + } + } + + public static void main(String[] args) { + SkipList2 list = new SkipList2(); + list.insert(1, 3); + list.insert(2, 3); + list.insert(3, 2); + list.insert(4, 4); + list.insert(5, 10); + list.insert(6, 4); + list.insert(8, 5); + list.insert(7, 4); + list.printAll_beautiful(); + list.printAll(); + /** + * 结果如下: + * null:15------- + * null:14------- + * null:13------- + * null:12------- + * null:11------- + * null:10------- + * 5:9------- + * 5:8------- + * 5:7------- + * 5:6------- + * 5:5------- + * 5:4------- 8:4------- + * 4:3-------5:3-------6:3-------7:3-------8:3------- + * 1:2-------2:2------- 4:2-------5:2-------6:2-------7:2-------8:2------- + * 1:1-------2:1-------3:1-------4:1-------5:1-------6:1-------7:1-------8:1------- + * 1:0-------2:0-------3:0-------4:0-------5:0-------6:0-------7:0-------8:0------- + * { data: 1; levels: 3 } { data: 2; levels: 3 } { data: 3; levels: 2 } { data: 4; levels: 4 } + * { data: 5; levels: 10 } { data: 6; levels: 4 } { data: 7; levels: 4 } { data: 8; levels: 5 } + */ + // 优化后insert() + + SkipList2 list2 = new SkipList2(); + list2.insert2(1); + list2.insert2(2); + list2.insert2(6); + list2.insert2(7); + list2.insert2(8); + list2.insert2(3); + list2.insert2(4); + list2.insert2(5); + System.out.println(); + list2.printAll_beautiful(); + + + } + +} diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/queue/ArrayQueueDemo.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/queue/ArrayQueueDemo.java similarity index 98% rename from algorithms/datastructure/src/main/java/cn/lastwhisper/queue/ArrayQueueDemo.java rename to algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/queue/ArrayQueueDemo.java index 1ee3f0ef..5e924141 100644 --- a/algorithms/datastructure/src/main/java/cn/lastwhisper/queue/ArrayQueueDemo.java +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/queue/ArrayQueueDemo.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.queue; +package cn.lastwhisper.atguigu.queue; /** * 数组实现队列 diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/queue/CircleArrayQueueDemo.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/queue/CircleArrayQueueDemo.java similarity index 98% rename from algorithms/datastructure/src/main/java/cn/lastwhisper/queue/CircleArrayQueueDemo.java rename to algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/queue/CircleArrayQueueDemo.java index 8c00f061..bd6aa057 100644 --- a/algorithms/datastructure/src/main/java/cn/lastwhisper/queue/CircleArrayQueueDemo.java +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/queue/CircleArrayQueueDemo.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.queue; +package cn.lastwhisper.atguigu.queue; /** * 数组实现循环队列 diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/recursion/Maze.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/recursion/Maze.java similarity index 98% rename from algorithms/datastructure/src/main/java/cn/lastwhisper/recursion/Maze.java rename to algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/recursion/Maze.java index 8fe19f72..e496578b 100644 --- a/algorithms/datastructure/src/main/java/cn/lastwhisper/recursion/Maze.java +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/recursion/Maze.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.recursion; +package cn.lastwhisper.atguigu.recursion; /** * 递归解决迷宫问题 diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/recursion/Queue8.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/recursion/Queue8.java similarity index 98% rename from algorithms/datastructure/src/main/java/cn/lastwhisper/recursion/Queue8.java rename to algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/recursion/Queue8.java index dfed6385..cec867c9 100644 --- a/algorithms/datastructure/src/main/java/cn/lastwhisper/recursion/Queue8.java +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/recursion/Queue8.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.recursion; +package cn.lastwhisper.atguigu.recursion; /** * 递归解决八皇后问题 diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/recursion/Recursion.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/recursion/Recursion.java similarity index 96% rename from algorithms/datastructure/src/main/java/cn/lastwhisper/recursion/Recursion.java rename to algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/recursion/Recursion.java index 2d88f90b..3d253071 100644 --- a/algorithms/datastructure/src/main/java/cn/lastwhisper/recursion/Recursion.java +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/recursion/Recursion.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.recursion; +package cn.lastwhisper.atguigu.recursion; /** * 递归通俗解释: diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/search/BinarySearch.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/search/BinarySearch.java similarity index 98% rename from algorithms/datastructure/src/main/java/cn/lastwhisper/search/BinarySearch.java rename to algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/search/BinarySearch.java index 4baf7db3..c180a504 100644 --- a/algorithms/datastructure/src/main/java/cn/lastwhisper/search/BinarySearch.java +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/search/BinarySearch.java @@ -1,6 +1,6 @@ -package cn.lastwhisper.search; +package cn.lastwhisper.atguigu.search; -import cn.lastwhisper.ArrayUtil; +import cn.lastwhisper.util.ArrayUtil; import java.util.ArrayList; import java.util.List; diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/search/FibonacciSearch.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/search/FibonacciSearch.java similarity index 92% rename from algorithms/datastructure/src/main/java/cn/lastwhisper/search/FibonacciSearch.java rename to algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/search/FibonacciSearch.java index d1536407..c9dcfd56 100644 --- a/algorithms/datastructure/src/main/java/cn/lastwhisper/search/FibonacciSearch.java +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/search/FibonacciSearch.java @@ -1,6 +1,6 @@ -package cn.lastwhisper.search; +package cn.lastwhisper.atguigu.search; -import cn.lastwhisper.ArrayUtil; +import cn.lastwhisper.util.ArrayUtil; /** * diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/search/InsertValueSearch.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/search/InsertValueSearch.java similarity index 93% rename from algorithms/datastructure/src/main/java/cn/lastwhisper/search/InsertValueSearch.java rename to algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/search/InsertValueSearch.java index 65240a80..904e621f 100644 --- a/algorithms/datastructure/src/main/java/cn/lastwhisper/search/InsertValueSearch.java +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/search/InsertValueSearch.java @@ -1,6 +1,6 @@ -package cn.lastwhisper.search; +package cn.lastwhisper.atguigu.search; -import cn.lastwhisper.ArrayUtil; +import cn.lastwhisper.util.ArrayUtil; /** * diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/search/SeqSearch.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/search/SeqSearch.java similarity index 94% rename from algorithms/datastructure/src/main/java/cn/lastwhisper/search/SeqSearch.java rename to algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/search/SeqSearch.java index fe55f2d5..31f1993c 100644 --- a/algorithms/datastructure/src/main/java/cn/lastwhisper/search/SeqSearch.java +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/search/SeqSearch.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.search; +package cn.lastwhisper.atguigu.search; /** * @author cn.lastwhisper diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/sort/DubbleSort.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/sort/DubbleSort.java similarity index 95% rename from algorithms/datastructure/src/main/java/cn/lastwhisper/sort/DubbleSort.java rename to algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/sort/DubbleSort.java index 982fa7ea..fdfc3682 100644 --- a/algorithms/datastructure/src/main/java/cn/lastwhisper/sort/DubbleSort.java +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/sort/DubbleSort.java @@ -1,6 +1,6 @@ -package cn.lastwhisper.sort; +package cn.lastwhisper.atguigu.sort; -import cn.lastwhisper.ArrayUtil; +import cn.lastwhisper.util.ArrayUtil; /** * @author cn.lastwhisper diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/sort/HeapSort.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/sort/HeapSort.java new file mode 100644 index 00000000..c591191a --- /dev/null +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/sort/HeapSort.java @@ -0,0 +1,71 @@ +package cn.lastwhisper.atguigu.sort; + +import java.util.Arrays; + +/** + * 堆排序 + * + * @author cn.lastwhisper + */ +public class HeapSort { + public static void main(String[] args) { + //int[] arr = {4, 6, 8, 5, 9, 58, -10}; + int[] arr = {4, 6, 8, 5, 9}; + heapSort(arr); + System.out.println("数组:" + Arrays.toString(arr)); + } + + public static void heapSort(int[] arr) { + + //adjustHeap(arr, 1, arr.length); + //System.out.println("第1次" + Arrays.toString(arr)); // 4,9,8,5,6 + + //adjustHeap(arr, 0, arr.length); + //System.out.println("第2次" + Arrays.toString(arr)); // 9,6,8,5,4 + // 1. 满二叉树从右向左、从下往上构建大顶堆;完全二叉树从左向右、从下往上构建大顶堆; + // i--意味着,从下到上,每一次都是[i,arr.length]的数组(二叉树)进行重构大顶堆 + // [0,arr.length]重构了数组(二叉树)头部几个元素的大顶堆,同时也会重构下面的二叉树 + for (int i = arr.length / 2 - 1; i >= 0; i--) { + adjustHeap(arr, i, arr.length); + } + // 2. 交换堆顶元素与末尾元素,调整堆结构 + for (int j = arr.length - 1; j >= 0; j--) { + // 交换 + int temp = arr[j]; + arr[j] = arr[0]; + arr[0] = temp; + adjustHeap(arr, 0, j); + } + } + + + /** + * 将一个数组(二叉树), 调整成一个大顶堆 + * 功能: 将以i对应的非叶子节点的树调整成大顶堆 + * 举例 int arr[] = {4, 6, 8, 5, 9}; => i = 1 => adjustHeap => 得到 {4, 9, 8, 5, 6} + * 如果我们再次调用 adjustHeap 传入的是 i = 0 => {4, 9, 8, 5, 6} => {9, 6, 8, 5, 4} + * @param arr 待调整的数组 + * @param i 表示非叶子节点在数组中索引 + * @param length 表示对多少个元素继续调整, length 是在逐渐的减少 + */ + public static void adjustHeap(int[] arr, int i, int length) { + // 当前i节点 + int temp = arr[i]; + // k是i节点的左子节点,k + 1是右子节点 + for (int k = 2 * i + 1; k < length; k = 2 * k + 1) { + // arr[k] < arr[k + 1]左节点小于右节点 + if (k + 1 < length && arr[k] < arr[k + 1]) { + // k指向数值最大的节点 + k++; + } + if (arr[k] > temp) {//子节点大于父节点 + arr[i] = arr[k];//将子节点赋值到父节点 + i = k;//记录子节点的下标,为了最后 arr[i] = temp; + } else { + break; + } + } + //i = k; arr[i]此时已经是子节点的位置了,前面父节点已经拿到了子节点的值了,这里要将子节点的值赋为父节点的值 + arr[i] = temp; + } +} diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/sort/InsertSort.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/sort/InsertSort.java new file mode 100644 index 00000000..24d2e60a --- /dev/null +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/sort/InsertSort.java @@ -0,0 +1,108 @@ +package cn.lastwhisper.atguigu.sort; + +import cn.lastwhisper.util.ArrayUtil; + +import java.util.Arrays; + +/** + * @author cn.lastwhisper + */ +public class InsertSort { + public static void main(String[] args) { + //int[] arr = {101, 34, 119, 1}; + //insertSort1(arr); // 插入排序算法实现步骤 + + int[] arr = ArrayUtil.generateArrByRandom(100000); + // 计算耗时 + long start = System.currentTimeMillis(); + insertSort(arr); + long end = System.currentTimeMillis(); + System.out.println("耗时:" + (end - start) + " ms"); + + //System.out.println(Arrays.toString(arr)); + } + + /** + * 插入排序O(n^2) + * insertVal < arr[insertIndex降序 + * insertVal > arr[insertIndex升序 + * @param arr + * @return void + */ + public static void insertSort(int[] arr) { + int insertVal; + int insertIndex; + // 有序列表[0];[1...arr.length]无序列表 + for (int i = 1; i < arr.length; i++) { + // insertVal的意义:缓存无序列表的第一个数,这个数也是待插入有序列表的数 + insertVal = arr[i]; + // insertIndex的意义:记录有序列表的最后一个数的下标 + insertIndex = i - 1; + // [insertIndex+1...i-1]后移到[insertIndex+2...i](从前往后移动) + while (insertIndex >= 0 && insertVal < arr[insertIndex]) { + arr[insertIndex + 1] = arr[insertIndex]; + insertIndex--; + } + // insertIndex == i - 1; 说明数组并未后移,无需赋值 + if (insertIndex != i - 1) { + // arr[insertIndex + 1]为待插入位置 + arr[insertIndex + 1] = insertVal; + } + } + } + + /** + * 插入排序的实现步骤 + * + * @param arr + * @return void + */ + public static void insertSort1(int[] arr) { + // 第1轮 + // 有序列表{101},无序列表{34, 119, 1} + // {101, 34, 119, 1} + + // insertVal的意义:缓存无序列表的第一个数,这个数也是待插入有序列表的数 + int insertVal = arr[1]; + // insertIndex的意义:记录有序列表的最后一个数的下标 + int insertIndex = 1 - 1; + // insertIndex >= 0的意义:防止数组越界; + // insertVal < arr[insertIndex]的意义:找到insertVal要插入位置的前一个位置 + // 整个while循环的意义:数组覆盖后移,找到待插入位置的前一个位置 + while (insertIndex >= 0 && insertVal < arr[insertIndex]) { + // 第1轮原数组:{101, 34, 119, 1} + // arr[1]=arr[0] {101, 101, 119, 1} + arr[insertIndex + 1] = arr[insertIndex]; + //继续向前 + insertIndex--; + } + // arr[0]=insertVal {34, 101, 119, 1} + arr[insertIndex + 1] = insertVal; + + System.out.printf("第1轮插入,数组:%s\n", Arrays.toString(arr)); + + // 第2轮 + insertVal = arr[2]; + insertIndex = 2 - 1; + while (insertIndex >= 0 && insertVal < arr[insertIndex]) { + arr[insertIndex + 1] = arr[insertIndex]; + insertIndex--; + } + arr[insertIndex + 1] = insertVal; + System.out.printf("第2轮插入,数组:%s\n", Arrays.toString(arr)); + + // 第3轮 + insertVal = arr[3]; + insertIndex = 3 - 1; + while (insertIndex >= 0 && insertVal < arr[insertIndex]) { + // 第三轮原数组:{34, 101, 119, 1} + // arr[3]=arr[2] {34, 101, 119, 119} + // arr[2]=arr[1] {34, 101, 101, 119} + // arr[1]=arr[0] {34, 34, 101, 119} + arr[insertIndex + 1] = arr[insertIndex]; + insertIndex--; + } + arr[insertIndex + 1] = insertVal; + System.out.printf("第3轮插入,数组:%s\n", Arrays.toString(arr)); + } +} diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/sort/MergeSort.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/sort/MergeSort.java new file mode 100644 index 00000000..dfe39e34 --- /dev/null +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/sort/MergeSort.java @@ -0,0 +1,79 @@ +package cn.lastwhisper.atguigu.sort; + +import java.util.Arrays; + +/** + * @author cn.lastwhisper + */ +public class MergeSort { + + public static void main(String[] args) { + int[] arr = {9, 8, 7, 6, 5, 4, 3, 2, 1}; +// int[] arr = ArrayUtil.generateArrByRandom(10000000);// 1443 ms + // 计算耗时 + long start = System.currentTimeMillis(); + mergeSort(arr, 0, arr.length - 1); + long end = System.currentTimeMillis(); + System.out.println("耗时:" + (end - start) + " ms"); + + System.out.println(Arrays.toString(arr)); + } + + /** + * 归并排序 + * 分 + * + * @param arr 排序的原始数组 + * @param left 左边有序序列的初始索引 + * @param right 右边索引 + */ + public static void mergeSort(int[] arr, int left, int right) { + if (left < right) { + int mid = (left + right) / 2; + mergeSort(arr, left, mid); // 向左分 + mergeSort(arr, mid + 1, right); // 向右分 + merge(arr, left, mid, right);// 治 + } + } + + /** + * 治 + * + * @param arr 排序的原始数组 arr[left...mid] arr[mid+1...right] + * @param left 左边有序序列的初始索引 + * @param mid 中间索引 + * @param right 右边索引 + */ + public static void merge(int[] arr, int left, int mid, int right) { + //开辟额外大集合,设置指针 + int[] temp = new int[right - left + 1]; + + int i = left; //左边有序序列的初始索引 + int j = mid + 1; // 右边有序序列的初始化序索引 + int tempIdx = 0; // 指向temp数组的当前位置 + + // 1)、将左右两边(有序)的数据按照规则填充到temp数组,任意一边处理完毕为止 + while (i <= mid && j <= right) { + if (arr[i] < arr[j]) { + // 左小于右,将左数组第i个元素copy到temp数组的第t个位置 + temp[tempIdx++] = arr[i++]; + } else { + // 右小于或等于左,将右数组第j个元素copy到temp数组的第t个位置 + temp[tempIdx++] = arr[j++]; + } + } + + // 2)、把有剩余数据的一边的数据依次填充到temp + while (i <= mid) {// 说明 右数组还有剩余元素 + temp[tempIdx++] = arr[i++]; + } + while (j <= right) {// 说明 右数组还有剩余元素 + temp[tempIdx++] = arr[j++]; + } + + // 3)、将temp数组的数据copy到arr,注意从本次数组起始位置left,开始复制 + for (int k = left; k < temp.length; k++) { + arr[k] = temp[k]; + } + } +} diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/sort/QuickSort.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/sort/QuickSort.java new file mode 100644 index 00000000..45d903c9 --- /dev/null +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/sort/QuickSort.java @@ -0,0 +1,125 @@ +package cn.lastwhisper.atguigu.sort; + +import java.util.Arrays; + +/** + * @author cn.lastwhisper + */ +@Deprecated +public class QuickSort { + + public static void main(String[] args) { + //int[] arr = {-9, 78, 0, 23, -567, 70}; + //int[] arr = {-9, 78, 0, 23, 60, 70}; + //int[] arr = {9, 0, -567}; + int[] arr = {49, 38, 65, 97, 76, 13, 27}; + + //int[] arr = ArrayUtil.generateArrByRandom(10000000);//耗时:1519 ms + // 计算耗时 + long start = System.currentTimeMillis(); + //quickSort(arr, 0, arr.length - 1); + qSort(arr, 0, arr.length - 1); + long end = System.currentTimeMillis(); + System.out.println("耗时:" + (end - start) + " ms"); + + System.out.println(Arrays.toString(arr)); + } + + public static void qSort(int[] arr, int head, int tail) { + if (head >= tail || arr == null || arr.length <= 1) { + return; + } + //定义俩指针 用于移动 + int left = head; + int right = tail; + int pivot = arr[head]; //基准值,也可以arr[(head + tail) / 2] + + while (left <= right) { + while (arr[left] < pivot) { //左指针先走,找到大于等于基准数的停止 + ++left; + } + while (arr[right] > pivot) { //右指针后走,找到小于等于基准数的停止 + --right; + } + if (left < right) { + //交换arr[left]和arr[right]的位置 + int t = arr[left]; + arr[left] = arr[right]; + arr[right] = t; + //继续遍历 + ++left; + --right; + } else if (left == right) { + //遍历完,错开两指针,用于退出循环 + ++left; + //break; + } + } + + qSort(arr, head, right); + qSort(arr, left, tail); + } + + + /** + * 快速排序,选取数组中间的值 + * int pivot = arr[(left + right) / 2]; + * + * @param arr + * @param left + * @param right + * @return void + */ + public static void quickSort1(int[] arr, int left, int right) { + int l = left; // 左下标 + int r = right; // 右下标 + int temp; + // 中轴 + int pivot = arr[(left + right) / 2]; + // while循环的目的:小于或等于pivot的放左边,大于或等于pivot的放右边 + while (l < r) { + // 在pivot左边找比pivot大的值的下标l + while (arr[l] < pivot) { //找到arr[1]=98 >pivot=0 + l++; + } + // 在pivot右边找比pivot小的值的下标r + while (arr[r] > pivot) { //找到arr[4]=-567 < pivot=0 + r--; + } + // 如果l>=r说明pivot左右两边的值,已经满足: + // 小于或等于pivot的放左边,大于或等于pivot的放右边 ——递归结束条件 + if (l >= r) { + break; + } + // 交换 + temp = arr[l]; + arr[l] = arr[r]; + arr[r] = temp; + // 如果交换完后,发现arr[l] == pivot,r--,前移 退出循环 + if (arr[l] == pivot) { + r--; + } + + // 如果交换完后,发现arr[r] == pivot,l++,后移 退出循环 + if (arr[r] == pivot) { + l++; + } + } + + // 第二步 + + // 如果l==r,必须l++,r--,否则会栈溢出 + if (l == r) { + l = l + 1; + r = r - 1; + } + // 向左递归 + if (left < r) { + quickSort1(arr, left, r); + } + // 向右递归 + if (right > l) { + quickSort1(arr, l, right); + } + } +} diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/sort/QuickSort2.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/sort/QuickSort2.java new file mode 100644 index 00000000..0c4a1124 --- /dev/null +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/sort/QuickSort2.java @@ -0,0 +1,58 @@ +package cn.lastwhisper.atguigu.sort; + +/** + * @author lastwhisper + */ +public class QuickSort2 { + public static void main(String[] args) { +// int[] arr = {7, 3, 2, 8, 1, 9, 5, 4, 6}; + //int arr[] = {7, 3, 2, 8, 1, 9, 5, 4, 6, 0};//为什么left++和right--条件里面要加 left <= right 限定 + //int arr[] = {7, 3, 2, 8, 1, 9, 5, 4, 6, 10}; +// int arr[] = {7, 3, 2, 6, 8, 1, 9, 5, 4, 6, 10, 6, 6}; // 为什么不取等 arr[right] > pivot +// int[] arr = {4, 6}; //小bug测试 // 为什么while (left <= right)里面要取等 + +// int[] arr = {2, 10, 8, 22, 34, 5, 12, 28, 21, 11}; + int[] arr = {49, 38, 65, 97, 76, 13, 27}; +// int[] arr = {2, 10, 8, 1000}; + sort(arr, 0, arr.length - 1); + print(arr); + } + + private static void sort(int[] arr, int left, int right) { + if (left >= right) return; + int mid = partition(arr, left, right); + sort(arr, left, mid - 1); + sort(arr, mid + 1, right); + } + + /** + * @param arr 待分区数组 + * @param left 左边界 + * @param right 右边界 + */ + private static int partition(int[] arr, int left, int right) { + int pivot = arr[right]; + int start = left, end = right - 1; + // + while (start <= end) { + while (start <= end && arr[start] <= pivot) start++; + while (start <= end && arr[end] > pivot) end--; + if (start < end) swap(arr, start, end); + } + // 此时的start一定>=pivot(right),所以需要交互 + swap(arr, start, right); + return start; + } + + private static void swap(int[] arr, int i, int j) { + int temp = arr[i]; + arr[i] = arr[j]; + arr[j] = temp; + } + + private static void print(int[] arr) { + for (int value : arr) { + System.out.print(value + "\t"); + } + } +} diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/sort/RadixSort.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/sort/RadixSort.java new file mode 100644 index 00000000..b55a46a2 --- /dev/null +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/sort/RadixSort.java @@ -0,0 +1,152 @@ +package cn.lastwhisper.atguigu.sort; + +import cn.lastwhisper.util.ArrayUtil; + +import java.util.Arrays; + +/** + * @author cn.lastwhisper + */ +public class RadixSort { + + public static void main(String[] args) { + // 算法实现步骤 + //int[] arr = {53, 3, 542, 748, 14, 214}; + //int[] arr = {3, 205, 14}; + //radixSortStudy(arr); + + // 计算耗时 + // 占用内存 10000000 * 10 * 4 /1024 / 1024 /1024 = 0.3725290298461914‬ + int[] arr = ArrayUtil.generateArrByRandom(10000000); + long start = System.currentTimeMillis(); + radixSort(arr); + long end = System.currentTimeMillis(); + System.out.println("耗时:" + (end - start) + " ms"); + + //System.out.println(Arrays.toString(arr)); + } + + /** + * 基数排序,桶排序的扩展 + * + * @param arr + * @return void + */ + public static void radixSort(int[] arr) { + + int[][] bucket = new int[10][arr.length]; + // 桶元素计数器,记录每个桶中存放了多少数据 + int[] bucketElementCount = new int[10]; + // 原arr下标 + int arrIndex; + // 除数 + int divisor = 1; + // 最大值 + int max = arr[0]; + // 由于基数排序次数由最大数值的位数决定,所以需要求最大值 + for (int i = 1; i < arr.length; i++) { + if (max < arr[i]) { + max = arr[i]; + } + } + // 最大值得位数,即排序次数 + int maxLength = (max + "").length(); + for (int f = 0; f < maxLength; f++) { + for (int i = 0; i < arr.length; i++) { + // digitOfElement对应放在哪个bucket中 + int digitOfElement = arr[i] / divisor % 10; + // 放在第digitOfElement个bucket的第bucketElementCount[digitOfElement]下标位置 + bucket[digitOfElement][bucketElementCount[digitOfElement]] = arr[i]; + // 下次放在bucket的第bucketElementCount[digitOfElement]++下标位置 + bucketElementCount[digitOfElement]++; + } + + arrIndex = 0; + // 将桶中数据放回原数组 + for (int i = 0; i < bucketElementCount.length; i++) { + // 对应桶中有数据 + if (bucketElementCount[i] != 0) { + for (int j = 0; j < bucketElementCount[i]; j++) { + arr[arrIndex++] = bucket[i][j]; + } + } + // 将桶元素计数器清空 + bucketElementCount[i] = 0; + } + divisor *= 10; + } + + } + + /** + * 桶排序算法实现步骤 + * + * @param arr + */ + public static void radixSortStudy(int[] arr) { + // + int[][] bucket = new int[10][arr.length]; + // 桶元素计数器,记录每个桶中存放了多少数据 + int[] bucketElementCount = new int[10]; + // 原arr下标 + int arrIndex; + + for (int i = 0; i < arr.length; i++) { + // digitOfElement对应放在哪个bucket中 + int digitOfElement = arr[i] % 10; + // 放在第digitOfElement个bucket的第bucketElementCount[digitOfElement]下标位置 + bucket[digitOfElement][bucketElementCount[digitOfElement]] = arr[i]; + // 下次放在bucket的第bucketElementCount[digitOfElement]++下标位置 + bucketElementCount[digitOfElement]++; + } + + arrIndex = 0; + // 将桶中数据放回原数组 + for (int i = 0; i < bucketElementCount.length; i++) { + // 对应桶中有数据 + if (bucketElementCount[i] != 0) { + for (int j = 0; j < bucketElementCount[i]; j++) { + arr[arrIndex++] = bucket[i][j]; + } + } + // 将桶元素计数器清空 + bucketElementCount[i] = 0; + } + + System.out.println("第1轮,对个位的排序处理 arr =" + Arrays.toString(arr)); + + for (int i = 0; i < arr.length; i++) { + // digitOfElement对应放在哪个bucket中 + int digitOfElement = arr[i] / 10 % 10; + // 放在第digitOfElement个bucket的第bucketElementCount[digitOfElement]下标位置 + bucket[digitOfElement][bucketElementCount[digitOfElement]] = arr[i]; + // 下次放在bucket的第bucketElementCount[digitOfElement]++下标位置 + bucketElementCount[digitOfElement]++; + } + + arrIndex = 0; + // 将桶中数据放回原数组 + for (int i = 0; i < bucketElementCount.length; i++) { + // 对应桶中有数据 + if (bucketElementCount[i] != 0) { + for (int j = 0; j < bucketElementCount[i]; j++) { + arr[arrIndex++] = bucket[i][j]; + } + } + // 将桶元素计数器清空 + bucketElementCount[i] = 0; + } + + System.out.println("第2轮,对个位的排序处理 arr =" + Arrays.toString(arr)); + + //for (int i = 0; i < bucket.length; i++) { + // for (int j = 0; j < bucket[0].length; j++) { + // System.out.printf("%d\t", bucket[i][j]); + // } + // System.out.println(); + //} + + } + + +} diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/sort/SelectSort.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/sort/SelectSort.java new file mode 100644 index 00000000..14f8afb9 --- /dev/null +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/sort/SelectSort.java @@ -0,0 +1,82 @@ +package cn.lastwhisper.atguigu.sort; + +import cn.lastwhisper.util.ArrayUtil; + +import java.util.Arrays; + +/** + * @author cn.lastwhisper + */ +public class SelectSort { + + public static void main(String[] args) { + //int[] arr = {101, 34, 119, 1}; + //selectSort1(arr); + //System.out.println(Arrays.toString(arr)); + + int[] arr = ArrayUtil.generateArrByRandom(100000); + // 计算耗时 + long start = System.currentTimeMillis(); + selectSort(arr); + long end = System.currentTimeMillis(); + System.out.println("耗时:" + (end - start) + " ms"); + } + + /** + * 选择排序O(n^2) + * + * @param arr + * @return void + */ + public static void selectSort(int[] arr) { + for (int i = 0; i < arr.length; i++) { + int min = arr[i]; + int minIndex = i; + // 找出[1+i...arr.length]范围内的最小值,和最小值索引 + for (int j = i + 1; j < arr.length; j++) { + if (min > arr[j]) { + min = arr[j]; + minIndex = j; + } + } + // 交换最小值与第i个数的位置 + if (minIndex != i) { + arr[minIndex] = arr[i]; + arr[i] = min; + } + } + } + + /** + * 算法的实现步骤 + * + * @param arr + * @return void + */ + public static void selectSort1(int[] arr) { + // 第1轮 {101, 34, 119, 1} + + // 1、找最小值 + // 最小值 + int min = arr[0]; + // 最小值索引 + int minIndex = 0; + // {101, 34, 119, 1} 我们假设待排序数组第一个元素就是最小值,即min=arr[0],minIndex=0 + // 经过遍历后我们发现 min=1,minIndex=3 + for (int j = 0 + 1; j < arr.length; j++) { + // 找最小的数 + if (min > arr[j]) { + min = arr[j]; + minIndex = j; + } + } + // 2、交换。minIndex是最小值所在位置,min是最小值 + if (minIndex != 0) { + arr[minIndex] = arr[0]; + arr[0] = min; + } + + System.out.printf("第1轮选择,数组:%s", Arrays.toString(arr)); + } + +} diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/sort/ShellSort.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/sort/ShellSort.java new file mode 100644 index 00000000..edd5254a --- /dev/null +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/sort/ShellSort.java @@ -0,0 +1,132 @@ +package cn.lastwhisper.atguigu.sort; + +import java.util.Arrays; + +/** + * @author cn.lastwhisper + */ +public class ShellSort { + public static void main(String[] args) { + int[] arr = {8, 9, 1, 7, 2, 3, 5, 4, 6, 0}; + //int[] arr = ArrayUtil.generateArrByRandom(100000); + // 计算耗时 + long start = System.currentTimeMillis(); + //shellSort1(arr); // 10490 ms + shellSort2(arr); // 10490 ms + long end = System.currentTimeMillis(); + System.out.println("耗时:" + (end - start) + " ms"); + + System.out.printf("希尔排序(交换法),数组:%s\n", Arrays.toString(arr)); + } + + + /** + * 希尔排序(位移法)(插入排序) + * + * @param arr + * @return void + */ + public static void shellSort2(int[] arr) { + // {8, 9, 1, 7, 2, 3, 5, 4, 6, 0} + int gap = arr.length / 2; + int j; + int temp; + while (gap > 0) { + //gap=5,2,1,0 + // i=5——》{0,5} + // i=6——》{1,6} + // i=7——》{2,7} + // i=8——》{3,8} + // i=9——》{4,9} + // 对每个数组进行插入排序;由于每个数组并不是真的存在的数组,而是一个大数组 + // 所以通过gap进行取值 + for (int i = gap; i < arr.length; i++) { + j = i; // 缓存每个数组的起始下标 + temp = arr[i]; // 缓存每个数组的起始下标的数值 + if (temp < arr[j - gap]) { + while (j - gap >= 0 && temp < arr[j - gap]) { + // 从前往后移动 + arr[j] = arr[j - gap]; + j = j - gap; + } + // + arr[j] = temp; + } + } + gap = gap / 2; + } + } + + /** + * 希尔排序(交换法) + * + * @param arr + * @return void + */ + public static void shellSort1(int[] arr) { + // 第1轮 {8, 9, 1, 7, 2, 3, 5, 4, 6, 0} + // 增量 gap=length/2 + int gap = arr.length / 2; + int temp; + while (gap > 0) { + for (int i = gap; i < arr.length; i++) { + // 交换 + for (int j = i - gap; j >= 0; j -= gap) { + if (arr[j] > arr[j + gap]) { + temp = arr[j + gap]; + arr[j + gap] = arr[j]; + arr[j] = temp; + } + } + } + gap = gap / 2; + } + } + + /** + * 交换法希尔排序 + * + * @param arr + * @return void + */ + public static void shellSortStudy(int[] arr) { + // 第1轮 [8, 9, 1, 7, 2, 3, 5, 4, 6, 0] + // 增量 gap=length/2 + int temp; + for (int i = 5; i < arr.length; i++) { + // 交换 + for (int j = i - 5; j >= 0; j -= 5) { + if (arr[j] > arr[j + 5]) { + temp = arr[j + 5]; + arr[j + 5] = arr[j]; + arr[j] = temp; + } + } + } + System.out.printf("第1轮插入,数组:%s\n", Arrays.toString(arr)); + // 第二轮 [3, 5, 1, 6, 0, 8, 9, 4, 7, 2] + for (int i = 2; i < arr.length; i++) { + // 交换 + for (int j = i - 2; j >= 0; j -= 2) { + if (arr[j] > arr[j + 2]) { + temp = arr[j + 2]; + arr[j + 2] = arr[j]; + arr[j] = temp; + } + } + } + System.out.printf("第2轮插入,数组:%s\n", Arrays.toString(arr)); + // 第三轮 [0, 2, 1, 4, 3, 5, 7, 6, 9, 8] + for (int i = 1; i < arr.length; i++) { + // 交换 + for (int j = i - 1; j >= 0; j -= 1) { + if (arr[j] > arr[j + 1]) { + temp = arr[j + 1]; + arr[j + 1] = arr[j]; + arr[j] = temp; + } + } + } + System.out.printf("第3轮插入,数组:%s\n", Arrays.toString(arr)); + } +} diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/sort/TimeComplexity.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/sort/TimeComplexity.java similarity index 96% rename from algorithms/datastructure/src/main/java/cn/lastwhisper/sort/TimeComplexity.java rename to algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/sort/TimeComplexity.java index de4f13a3..36734634 100644 --- a/algorithms/datastructure/src/main/java/cn/lastwhisper/sort/TimeComplexity.java +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/sort/TimeComplexity.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.sort; +package cn.lastwhisper.atguigu.sort; /** * 时间复杂度举例 diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/sort/heap/Heap.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/sort/heap/Heap.java new file mode 100644 index 00000000..5e3cb8e0 --- /dev/null +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/sort/heap/Heap.java @@ -0,0 +1,100 @@ +package cn.lastwhisper.atguigu.sort.heap; + +import java.util.Arrays; + +public class Heap { + private int[] a; // 数组,从下标 1 开始存储数据 + private int n; // 堆可以存储的最大数据个数 + private int count; // 堆中已经存储的数据个数 + + public Heap(int capacity) { + a = new int[capacity + 1]; + n = capacity; + count = 0; + } + + /** + * 插入 + */ + public void insert(int data) { + if (count >= n) return; // 堆满了 + ++count; + a[count] = data; + int i = count; + while (i / 2 > 0 && a[i] > a[i / 2]) { // 自下往上堆化 + swap(a, i, i / 2); // swap() 函数作用:交换下标为 i 和 i/2 的两个元素 + i = i / 2; + } + } + + /** + * 删除堆顶 + */ + public void removeMax() { + if (count == 0) return; // 堆中没有数据 + a[1] = a[count]; + --count; + heapify(a, count, 1); + } + + /** + * 堆化大顶堆 + * 自上往下堆化 + * + * @param arr 数组 + * @param n 堆中元素个数 + * @param i 待堆化的元素 + */ + private static void heapify(int[] arr, int n, int i) { + while (true) { + // 待堆化元素、左、右子树最大值的下标 + int maxPos = i; + // 待堆化元素小于左子树 + if (i * 2 <= n && arr[i] < arr[i * 2]) { + maxPos = i * 2; + } + // 待堆化元素左子树小于右子树, + if (i * 2 + 1 <= n && arr[maxPos] < arr[i * 2 + 1]) { + maxPos = i * 2 + 1; + } + // 最大元素是自己无需向下堆化 + if (maxPos == i) break; + // 最大元素不是自己,交互值 + swap(arr, i, maxPos); + // 将被交互的元素继续向下堆化 + i = maxPos; + } + } + + private static void buildHeap(int[] a, int n) { + // 对非叶子节点进行,自上往下堆化 + for (int i = n / 2; i >= 1; --i) { + heapify(a, n, i); + } + } + + // n 表示数据的个数,数组 a 中的数据从下标 1 到 n 的位置。 + public static void sort(int[] a, int n) { + buildHeap(a, n); + int k = n; + while (k > 1) { + swap(a, 1, k); + --k; + heapify(a, k, 1); + } + } + + private static void swap(int[] arr, int i, int j) { + int temp = arr[i]; + arr[i] = arr[j]; + arr[j] = temp; + } + + public static void main(String[] args) { + int[] arr = new int[]{-99999, 9, 8, 7, 6, 5, 4, 3, 2, 1}; + System.out.println(Arrays.toString(arr)); + Heap.sort(arr, arr.length - 1); + System.out.println(Arrays.toString(arr)); + } + +} \ No newline at end of file diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/sort/heap/Heap2.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/sort/heap/Heap2.java new file mode 100644 index 00000000..2340e830 --- /dev/null +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/sort/heap/Heap2.java @@ -0,0 +1,69 @@ +package cn.lastwhisper.atguigu.sort.heap; + +import java.util.Arrays; + +public class Heap2 { + + + /** + * 堆化大顶堆 + * 自上往下堆化 + * + * @param arr 数组 + * @param n 堆中元素个数 + * @param i 待堆化的元素 + */ + private static void heapify(int[] arr, int n, int i) { + while (true) { + // 待堆化元素、左、右子树最大值的下标 + int maxPos = i; + // 待堆化元素小于左子树 + if (i * 2 + 1 <= n && arr[i] < arr[i * 2 + 1]) { + maxPos = i * 2 + 1; + } + // 待堆化元素左子树小于右子树, + if (i * 2 + 2 <= n && arr[maxPos] < arr[i * 2 + 2]) { + maxPos = i * 2 + 2; + } + // 最大元素是自己无需向下堆化 + if (maxPos == i) break; + // 最大元素不是自己,交互值 + swap(arr, i, maxPos); + // 将被交互的元素继续向下堆化 + i = maxPos; + } + } + + private static void buildHeap(int[] a, int n) { + // 对非叶子节点进行,自上往下堆化 + for (int i = n / 2 - 1; i >= 0; --i) { + heapify(a, n, i); + } + } + + public static void sort(int[] arr, int n) { + // 1. 构建大顶堆 + buildHeap(arr, n); + int disorder = n; + // 2. 交换堆顶元素与末尾元素,调整堆结构 + while (disorder > 0) { + swap(arr, 0, disorder); + disorder--; + heapify(arr, disorder, 0); + } + } + + private static void swap(int[] arr, int i, int j) { + int temp = arr[i]; + arr[i] = arr[j]; + arr[j] = temp; + } + + public static void main(String[] args) { + int[] arr = new int[]{9, 10, 7, 6, 5, 4, 3, 2, 1}; + System.out.println(Arrays.toString(arr)); + Heap2.sort(arr, arr.length - 1); + System.out.println(Arrays.toString(arr)); + } + +} \ No newline at end of file diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/sort/heap/HeapOperator.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/sort/heap/HeapOperator.java new file mode 100644 index 00000000..91466e9d --- /dev/null +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/sort/heap/HeapOperator.java @@ -0,0 +1,87 @@ +package cn.lastwhisper.atguigu.sort.heap; + +import java.util.Arrays; + +/** + * 对于二叉堆,如下有几种操作: + * 插入节点 + * 删除节点 + * 构建二叉堆 + * + * @author cunchang + * @date 2022/6/12 11:34 PM + */ +public class HeapOperator { + + + /** + * 上浮调整 + * @param array 待调整的堆 + */ + public static void upAdjust(int[] array) { + int childIndex = array.length - 1; + // child = 2*parent+1,则 parent = (child - 1) / 2 + int parentIndex = (childIndex - 1) / 2; + // temp保存插入的叶子节点值,用于最后的赋值 + int temp = array[childIndex]; + while (childIndex > 0 && temp < array[parentIndex]) { + //无需真正交换,单向赋值即可 + array[childIndex] = array[parentIndex]; + childIndex = parentIndex; + parentIndex = (parentIndex - 1) / 2; + } + array[childIndex] = temp; + } + + + /** + * 下沉调整 + * @param array 待调整的堆 + * @param parentIndex 要下沉的父节点 + * @param length 堆的有效大小 + */ + public static void downAdjust(int[] array, int parentIndex, int length) { + // temp保存父节点值,用于最后的赋值 + int temp = array[parentIndex]; + int childIndex = 2 * parentIndex + 1; + while (childIndex < length) { + // 如果有右孩子,且右孩子小于左孩子的值,则定位到右孩子 + if (childIndex + 1 < length && array[childIndex + 1] < array[childIndex]) { + childIndex++; + } + // 如果父节点小于任何一个孩子的值,直接跳出 + if (temp <= array[childIndex]) { + break; + } + //无需真正交换,单向赋值即可 + array[parentIndex] = array[childIndex]; + parentIndex = childIndex; + childIndex = 2 * childIndex + 1; + } + array[parentIndex] = temp; + } + + + /** + * 构建堆 + * + * @param array 待调整的堆 + */ + public static void buildHeap(int[] array) { + // 从最后一个非叶子节点开始,依次下沉调整 + for (int i = array.length / 2; i >= 0; i--) { + downAdjust(array, i, array.length - 1); + } + } + + public static void main(String[] args) { + int[] array = new int[]{1, 3, 2, 6, 5, 7, 8, 9, 10, 0}; + upAdjust(array); + System.out.println(Arrays.toString(array)); + array = new int[]{7, 1, 3, 10, 5, 2, 8, 9, 6}; + buildHeap(array); + System.out.println(Arrays.toString(array)); + } + + +} diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/sparsematrix/BestSpmatrix.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/sparsematrix/BestSpmatrix.java similarity index 98% rename from algorithms/datastructure/src/main/java/cn/lastwhisper/sparsematrix/BestSpmatrix.java rename to algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/sparsematrix/BestSpmatrix.java index 95b776e9..e1fd05b9 100644 --- a/algorithms/datastructure/src/main/java/cn/lastwhisper/sparsematrix/BestSpmatrix.java +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/sparsematrix/BestSpmatrix.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.sparsematrix; +package cn.lastwhisper.atguigu.sparsematrix; /** * @author cn.lastwhisper diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/sparsematrix/SparseMatrix.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/sparsematrix/SparseMatrix.java similarity index 98% rename from algorithms/datastructure/src/main/java/cn/lastwhisper/sparsematrix/SparseMatrix.java rename to algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/sparsematrix/SparseMatrix.java index f3035474..50f30722 100644 --- a/algorithms/datastructure/src/main/java/cn/lastwhisper/sparsematrix/SparseMatrix.java +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/sparsematrix/SparseMatrix.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.sparsematrix; +package cn.lastwhisper.atguigu.sparsematrix; /** * 稀疏矩阵压缩与还原 diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/stack/ArrayStackDemo.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/stack/ArrayStackDemo.java similarity index 90% rename from algorithms/datastructure/src/main/java/cn/lastwhisper/stack/ArrayStackDemo.java rename to algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/stack/ArrayStackDemo.java index 077f2614..5a20dc99 100644 --- a/algorithms/datastructure/src/main/java/cn/lastwhisper/stack/ArrayStackDemo.java +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/stack/ArrayStackDemo.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.stack; +package cn.lastwhisper.atguigu.stack; /** * @author cn.lastwhisper @@ -52,8 +52,7 @@ public int pop() { if (n > 0 && n == (arr.length / 4)) { resize(n / 2); } - int data = arr[--n]; - return data; + return arr[--n]; } // 查看栈顶元素 public int peek(){ @@ -69,9 +68,7 @@ public int size() { // resize public void resize(int maxSize) { int[] newArr = new int[maxSize]; - for (int i = 0; i < size(); i++) { - newArr[i] = arr[i]; - } + if (size() >= 0) System.arraycopy(arr, 0, newArr, 0, size()); this.arr = newArr; } } \ No newline at end of file diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/stack/InCalculator.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/stack/InCalculator.java similarity index 96% rename from algorithms/datastructure/src/main/java/cn/lastwhisper/stack/InCalculator.java rename to algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/stack/InCalculator.java index d2565072..1288660c 100644 --- a/algorithms/datastructure/src/main/java/cn/lastwhisper/stack/InCalculator.java +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/stack/InCalculator.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.stack; +package cn.lastwhisper.atguigu.stack; /** * 中缀表达式 @@ -53,11 +53,11 @@ public static void main(String[] args) { keepNum += ch - 48; // ch是否是最后一个字符 if (index == expression.length() - 1) { - numStack.push(Integer.valueOf(keepNum)); + numStack.push(Integer.parseInt(keepNum)); } else { // 如果后一位是运算符,则将当前keepNum入栈 if (operStack.isOper(expression.substring(index + 1, index + 2).charAt(0))) { - numStack.push(Integer.valueOf(keepNum)); + numStack.push(Integer.parseInt(keepNum)); // 每次清空多位数 keepNum = ""; } @@ -104,8 +104,7 @@ public int pop() { if (n > 0 && n == (arr.length / 4)) { resize(arr.length / 2); } - int data = arr[--n]; - return data; + return arr[--n]; } /** diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/stack/SuCalculator.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/stack/SuCalculator.java similarity index 98% rename from algorithms/datastructure/src/main/java/cn/lastwhisper/stack/SuCalculator.java rename to algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/stack/SuCalculator.java index e915c6cc..18d7afa0 100644 --- a/algorithms/datastructure/src/main/java/cn/lastwhisper/stack/SuCalculator.java +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/stack/SuCalculator.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.stack; +package cn.lastwhisper.atguigu.stack; import java.util.ArrayList; import java.util.List; @@ -103,7 +103,7 @@ public static String infixConverSufix(String infixExpression) { * 中缀表达式String转中缀表达式Lsit * * @param infixExpression - * @return java.util.List + * @return java.array.List */ public static List infixStrConvertInfixList(String infixExpression) { List infixList = new ArrayList<>(); diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/tree/ArrBinaryTreeDemo.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/tree/ArrBinaryTreeDemo.java similarity index 86% rename from algorithms/datastructure/src/main/java/cn/lastwhisper/tree/ArrBinaryTreeDemo.java rename to algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/tree/ArrBinaryTreeDemo.java index e6490716..59ca8711 100644 --- a/algorithms/datastructure/src/main/java/cn/lastwhisper/tree/ArrBinaryTreeDemo.java +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/tree/ArrBinaryTreeDemo.java @@ -1,6 +1,6 @@ -package cn.lastwhisper.tree; +package cn.lastwhisper.atguigu.tree; -import cn.lastwhisper.ArrayUtil; +import cn.lastwhisper.util.ArrayUtil; /** * @author cn.lastwhisper @@ -12,12 +12,12 @@ public static void main(String[] args) { ArrBinaryTree arrBinaryTree = new ArrBinaryTree(arr); System.out.println("先序:"); arrBinaryTree.preOrder(0);//1 2 4 5 3 6 7 - System.out.println(); - System.out.println("中序:"); - arrBinaryTree.infixOrder(0); - System.out.println(); - System.out.println("后序:"); - arrBinaryTree.postOrder(0); + //System.out.println(); + //System.out.println("中序:"); + //arrBinaryTree.infixOrder(0); + //System.out.println(); + //System.out.println("后序:"); + //arrBinaryTree.postOrder(0); } } diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/tree/BinaryTreeDemo.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/tree/BinaryTreeDemo.java similarity index 92% rename from algorithms/datastructure/src/main/java/cn/lastwhisper/tree/BinaryTreeDemo.java rename to algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/tree/BinaryTreeDemo.java index 30f49d76..50ff9a40 100644 --- a/algorithms/datastructure/src/main/java/cn/lastwhisper/tree/BinaryTreeDemo.java +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/tree/BinaryTreeDemo.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.tree; +package cn.lastwhisper.atguigu.tree; import org.junit.Test; @@ -9,6 +9,7 @@ /** * 二叉树的遍历:先序、中序、后序 * 二叉树的查找:查找指定节点 + * * @author cn.lastwhisper */ public class BinaryTreeDemo { @@ -114,7 +115,7 @@ public int height() { } /** - * 递归遍历直到叶子结点 + * 递归遍历直到叶子节点 * * @param node * @return int @@ -150,7 +151,7 @@ public int size(HeroNode node) { } } - // 返回某节点的父结点 + // 返回某节点的父节点 // 先序遍历查找 @@ -182,7 +183,7 @@ public HeroNode postOrderSearch(int no) { /** * 先序遍历(递归) - * 先访问根结点,再先序遍历左子树,再先序遍历右子树 + * 先访问根节点,再先序遍历左子树,再先序遍历右子树 * * @param node */ @@ -196,7 +197,8 @@ public void preOrder(HeroNode node) { /** * 中序遍历(递归) - * 先遍历左子树,再访问根结点,再中序遍历右子树 + * 先遍历左子树,再访问根节点,再中序遍历右子树 + * * @param node */ public void infixOrder(HeroNode node) { @@ -209,7 +211,8 @@ public void infixOrder(HeroNode node) { /** * 后序遍历(递归) - * 先遍历左子树,再后序遍历右子树,再访问根结点 + * 先遍历左子树,再后序遍历右子树,再访问根节点 + * * @param node */ public void postOrder(HeroNode node) { @@ -300,7 +303,7 @@ public String toString() { * @return cn.cn.lastwhisper.tree.HeroNode */ public HeroNode preOrderSearch(int no) { - // 1)、判断当前结点是否为查找的结点 + // 1)、判断当前节点是否为查找的节点 if (this.no == no) { return this; } @@ -335,7 +338,7 @@ public HeroNode infixOrderSearch(int no) { if (result != null) { return result; } - // 2)、判断当前结点是否为查找的结点 + // 2)、判断当前节点是否为查找的节点 if (this.no == no) { return this; } @@ -356,7 +359,7 @@ public HeroNode postOrderSearch(int no) { if (result != null) { return result; } - // 2)、判断该结点是否是寻找的节点 + // 2)、判断该节点是否是寻找的节点 if (this.no == no) { return this; } @@ -369,21 +372,21 @@ public HeroNode postOrderSearch(int no) { // 递归删除节点 public void clear(int no) { - // 1)、判断当前结点的左结点是否满足条件 + // 1)、判断当前节点的左节点是否满足条件 if (this.left != null && this.left.no == no) { this.left = null; return; } - // 2)、判断当前结点的右结点是否满足条件 + // 2)、判断当前节点的右节点是否满足条件 if (this.right != null && this.right.no == no) { this.right = null; return; } - // 3)、当前结点的左右结点不满足条件,递归左结点 + // 3)、当前节点的左右节点不满足条件,递归左节点 if (this.left != null) { this.left.clear(no); } - // 4)、当前结点的左右结点不满足条件,递归右结点 + // 4)、当前节点的左右节点不满足条件,递归右节点 if (this.right != null) { this.right.clear(no); } diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/tree/ThreadingBinaryTreeDemo.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/tree/ThreadingBinaryTreeDemo.java similarity index 76% rename from algorithms/datastructure/src/main/java/cn/lastwhisper/tree/ThreadingBinaryTreeDemo.java rename to algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/tree/ThreadingBinaryTreeDemo.java index a03977a4..b087fc40 100644 --- a/algorithms/datastructure/src/main/java/cn/lastwhisper/tree/ThreadingBinaryTreeDemo.java +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/tree/ThreadingBinaryTreeDemo.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.tree; +package cn.lastwhisper.atguigu.tree; /** * 线索化二叉树 @@ -6,7 +6,7 @@ */ public class ThreadingBinaryTreeDemo { public static void main(String[] args) { - // 创建结点 + // 创建节点 ThreadingHeroNode root = new ThreadingHeroNode(1, "宋江"); ThreadingHeroNode heroNode2 = new ThreadingHeroNode(3, "吴用"); ThreadingHeroNode heroNode3 = new ThreadingHeroNode(6, "卢俊义"); @@ -26,10 +26,10 @@ public static void main(String[] args) { ThreadingBinaryTree.preOrderThreading(); //System.out.println("===============中序线索化二叉树================"); //ThreadingBinaryTree.infixOrderThreading(); - System.out.println("===============前驱、后继结点================"); + System.out.println("===============前驱、后继节点================"); ThreadingHeroNode heroNode5Left = heroNode5.getLeft();// 3 ThreadingHeroNode heroNode5Right = heroNode5.getRight(); // - System.out.println("10号结点的前驱:" + heroNode5Left + "\n10号结点的后继:" + heroNode5Right); + System.out.println("10号节点的前驱:" + heroNode5Left + "\n10号节点的后继:" + heroNode5Right); System.out.println("===============先序遍历线索化二叉树================"); ThreadingBinaryTree.preOrder(); //System.out.println("===============中序遍历线索化二叉树================"); @@ -69,17 +69,17 @@ public void preOrder() { ThreadingHeroNode node = root; while (node != null) { System.out.println(node); - // 非线索化结点直接输出 + // 非线索化节点直接输出 while (node.getLeftType() == 0) { node = node.getLeft(); System.out.println(node); } - // 遍历带有线索化的结点,遍历结束时会输出一个非线索化结点 + // 遍历带有线索化的节点,遍历结束时会输出一个非线索化节点 while (node.getRightType() == 1) { node = node.getRight(); System.out.println(node); } - // 记录非线索化结点右子树 + // 记录非线索化节点右子树 node = node.getRight(); } } @@ -91,17 +91,17 @@ public void preOrder() { public void infixOrder() { ThreadingHeroNode node = root; while (node != null) { - // 找到type==1的线索化结点 + // 找到type==1的线索化节点 while (node.getLeftType() == 0) { node = node.getLeft(); } System.out.println(node); - // 遍历带有线索化的结点,遍历结束时会输出一个非线索化结点 + // 遍历带有线索化的节点,遍历结束时会输出一个非线索化节点 while (node.getRightType() == 1) { node = node.getRight(); System.out.println(node); } - // 记录非线索化结点右子树 + // 记录非线索化节点右子树 node = node.getRight(); } } @@ -109,28 +109,28 @@ public void infixOrder() { /** * 构建先序线索化二叉树 * - * @param node 当前需要线索化的结点 + * @param node 当前需要线索化的节点 */ public void preOrderThreading(ThreadingHeroNode node) { // 数据校验 if (node == null) { return; } - // 处理当前结点的前驱结点 - // 如果当前结点的左子树为空,说明出现了空指针域,需要构建线索前驱结点的线索 + // 处理当前节点的前驱节点 + // 如果当前节点的左子树为空,说明出现了空指针域,需要构建线索前驱节点的线索 if (node.getLeft() == null) { - // 设置当前结点的前驱节点 + // 设置当前节点的前驱节点 node.setLeft(preNode); node.setLeftType(1); } - // 处理前一个结点的后继结点 - // 如果前一个结点的左子树为空,说明出现了空指针域,需要构建线索后继结点的线索 + // 处理前一个节点的后继节点 + // 如果前一个节点的左子树为空,说明出现了空指针域,需要构建线索后继节点的线索 if (preNode != null && preNode.getRight() == null) { - // 设置前一个结点的后继结点为当前结点 + // 设置前一个节点的后继节点为当前节点 preNode.setRight(node); preNode.setRightType(1); } - // 每处理一个当前结点,就让当前结点是下一个结点的前驱节点 + // 每处理一个当前节点,就让当前节点是下一个节点的前驱节点 preNode = node; // type==0表示link if (node.getLeftType() == 0) { @@ -147,7 +147,7 @@ public void preOrderThreading(ThreadingHeroNode node) { /** * 构建中序线索化二叉树 * - * @param node 当前需要线索化的结点 + * @param node 当前需要线索化的节点 */ public void infixOrderThreading(ThreadingHeroNode node) { // 数据校验 @@ -157,21 +157,21 @@ public void infixOrderThreading(ThreadingHeroNode node) { // 1)、先线索化左子树 infixOrderThreading(node.getLeft()); - // 2)、处理当前结点的前驱结点 - // 如果当前结点的左子树为空,说明出现了空指针域,需要构建线索前驱结点的线索 + // 2)、处理当前节点的前驱节点 + // 如果当前节点的左子树为空,说明出现了空指针域,需要构建线索前驱节点的线索 if (node.getLeft() == null) { - // 设置当前结点的前驱节点 + // 设置当前节点的前驱节点 node.setLeft(preNode); node.setLeftType(1); } - // 3)、处理前一个结点的后继结点 - // 如果前一个结点的左子树为空,说明出现了空指针域,需要构建线索后继结点的线索 + // 3)、处理前一个节点的后继节点 + // 如果前一个节点的左子树为空,说明出现了空指针域,需要构建线索后继节点的线索 if (preNode != null && preNode.getRight() == null) { - // 设置前一个结点的后继结点为当前结点 + // 设置前一个节点的后继节点为当前节点 preNode.setRight(node); preNode.setRightType(1); } - // 每处理一个当前结点,就让当前结点是下一个结点的前驱节点 + // 每处理一个当前节点,就让当前节点是下一个节点的前驱节点 preNode = node; // 4)、线索化右子树 @@ -179,15 +179,15 @@ public void infixOrderThreading(ThreadingHeroNode node) { } } -// 树的结点 +// 树的节点 class ThreadingHeroNode { private int no; private String name; private ThreadingHeroNode left; private ThreadingHeroNode right; - private int leftType; // leftType==0指向左子树,等于1指向前驱结点 - private int rightType;// rightType==0指向右子树,等于1指向后继结点 + private int leftType; // leftType==0指向左子树,等于1指向前驱节点 + private int rightType;// rightType==0指向右子树,等于1指向后继节点 public ThreadingHeroNode(int no, String name) { this.no = no; diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/tree/avl/AVLTreeDemo.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/tree/avl/AVLTreeDemo.java new file mode 100644 index 00000000..f50d1106 --- /dev/null +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/tree/avl/AVLTreeDemo.java @@ -0,0 +1,378 @@ +package cn.lastwhisper.atguigu.tree.avl; + +/** + * 平衡二叉树 + * @author cn.lastwhisper + */ +public class AVLTreeDemo { + public static void main(String[] args) { + // 测试左旋转 + //int[] arr = {4, 3, 6, 5, 7, 8}; + // 测试右旋转 + //int[] arr = {10, 12, 8, 9, 7, 6}; + // 测试双旋转 + int[] arr = {10, 11, 7, 6, 8, 9}; + AVLTree avlTree = new AVLTree(); + for (int i = 0; i < arr.length; i++) { + avlTree.add(new Node(arr[i])); + } + System.out.println("中序遍历"); + avlTree.infixOrder(); + Node avlTreeRoot = avlTree.getRoot(); + System.out.println("当前树的高度:" + avlTreeRoot.height()); + System.out.println("当前树的左子树高度:" + avlTreeRoot.left.height()); + System.out.println("当前树的右子树高度:" + avlTreeRoot.right.height()); + System.out.println("当前根节点:" + avlTreeRoot); + } +} + +/** + * 二叉排序树 + */ +class AVLTree { + // 根节点 + private Node root; + + public Node getRoot() { + return root; + } + + public void setRoot(Node root) { + this.root = root; + } + + // 查找节点 + public Node search(int value) { + if (root != null) { + return root.search(value); + } else { + return null; + } + } + + // 查找父节点 + public Node searchParent(int value) { + if (root != null) { + return root.searchParent(value); + } else { + return null; + } + } + + /** + * 找到该节点左子树最小值,并删除这个最小值节点 + * + * @param node + * @return int 最小值节点 + */ + public int delRightTreeMin(Node node) { + Node temp = node; + // 找到右子节点的最小值节点 + while (temp.left != null) { + temp = temp.left; + } + delNode(temp.value); + return temp.value; + } + + /** + * 找到该节点左子树最大值,并删除这个最大值节点 + * + * @param node + * @return int 最大值 + */ + public int delLeftTreeMax(Node node) { + Node temp = node; + while (temp.right != null) { + temp = temp.right; + } + delNode(temp.value); + return temp.value; + } + + + // 根据value删除节点 + public void delNode(int value) { + if (root == null) { + return; + } else { + // 待删除节点 + Node targetNode = search(value); + // 没有找到待删除节点 + if (targetNode == null) { + return; + } + // 待删除节点的父节点 + Node parentNode = searchParent(value); + // 1. 情况一:只有一个根节点 + if (root.left == null && root.right == null) { + root = null; + return; + } + // 2. 情况二:删除的节点是叶子节点(左右节点为空) + if (targetNode.left == null && targetNode.right == null) { + // 2.1 确定targetNode是parent的左子节点还是右子节点; + if (parentNode.left != null && parentNode.left.value == targetNode.value) { + // 左子节点 + parentNode.left = null; + } else if (parentNode.right != null && parentNode.right.value == targetNode.value) { + // 右子节点 + parentNode.right = null; + } + } else if (targetNode.left != null && targetNode.right != null) { + // 3. 情况四:删除带有两个子节点的targetNode + // 找到targetNode右子树的最小值,删除最小值节点,并将最小值赋值给targetNode + //targetNode.value = delRightTreeMin(targetNode.right); + targetNode.value = delLeftTreeMax(targetNode.left); + } else { + // 4. 情况三:删除只有一个子节点的targetNode + // 4.1 确定targetNode的子节点是左子节点还是右子节点 + // targetNode的子节点是左子节点 + if (targetNode.left != null) { + if (parentNode != null) { + // 4.2 确定targetNode在parentNode上是左子节点还是右子节点 + if (parentNode.left != null && parentNode.left.value == targetNode.value) { + // targetNode在parentNode上是左子节点 + parentNode.left = targetNode.left; + } else { + // targetNode在parentNode上是右子节点 + parentNode.right = targetNode.left; + } + } else { + // targetNode为根节点时,parentNode==null + // root = targetNode.left;即为删除target节点 + root = targetNode.left; + } + } else { + if (parentNode != null) { + //targetNode的子节点是右子节点 + if (parentNode.left != null && parentNode.left.value == targetNode.value) { + // targetNode在parentNode上是左子节点 + parentNode.left = targetNode.right; + } else { + // targetNode在parentNode上是右子节点 + parentNode.right = targetNode.right; + } + } else { + root = targetNode.right; + } + } + + } + + + } + + } + + // 中序 + public void infixOrder() { + if (root == null) { + System.out.println("树空"); + } else { + root.infixOrder(); + } + + } + + // 添加节点 + public void add(Node node) { + if (root == null) { + root = node; + } else { + root.add(node); + } + } + +} + + +class Node { + int value; + Node left; + Node right; + + public Node(int value) { + this.value = value; + } + + /** + * 以当前某节点进行右旋转,降低左子树的高度 + */ + public void rightRotate() { + // 1. 创建一个新节点,值等于当前节点的值 + Node newNode = new Node(this.value); + // 2. 将新节点的右子树设置为当前节点的右子树 + newNode.right = this.right; + // 3. 将新节点的左子树设置为当前节点的左子树的右子树(当前节点左子树最大的节点) + newNode.left = this.left.right; + // 4. 将当前节点的值设置为当前节点的左子树(节点)的值 + this.value = this.left.value; + // 5. 将当前节点的左子树设置为当前节点左子树的左子树 + this.left = this.left.left; + // 6. 将当期节点的右子树设置为新节点 + this.right = newNode; + } + + /** + * 以当前某节点进行左旋转,降低右子树的高度 + */ + public void leftRotate() { + // 1. 创建一个新节点,值等于当前节点的值 + Node newNode = new Node(this.value); + // 2. 将新节点的左子树设置为当前节点的左子树 + newNode.left = this.left; + // 3. 将新节点的右子树设置为当前节点右子树的左子树 + newNode.right = this.right.left; + // 4. 将当前节点的值设置为当前节点右子树的值 + this.value = this.right.value; + // 5. 将当前节点的右子树设置为当前节点右子树的右子树 + this.right = this.right.right; + // 6. 将当前节点左子树设置为新节点 + this.left = newNode; + } + + /** + * @return int 当前某节点左子树的高度 + */ + public int leftHeight() { + if (this.left != null) { + return this.left.height(); + } else { + return 0; + } + } + + /** + * @return int 当前某节点右子树的高度 + */ + public int rightHeight() { + if (this.right != null) { + return this.right.height(); + } else { + return 0; + } + } + + /** + * @return int 当前某节点的高度 + */ + public int height() { + int leftHeight = this.left == null ? 0 : this.left.height(); + int rightHeight = this.right == null ? 0 : this.right.height(); + return Math.max(leftHeight, rightHeight) + 1; + } + + /** + * 查找节点 + * + * @param value 节点的value + * @return cn.cn.lastwhisper.tree.binarysorttree.Node + */ + public Node search(int value) { + // 1. 判断当前节点是否是查找的节点 + if (this.value == value) { + return this; + } else if (this.value > value && this.left != null) { + // 2.1 当前节点的value大于value,往左边寻找 + return this.left.search(value); + } else if (this.value < value && this.right != null) { + // 2.2 当前节点的value小于value,往右边寻找 + return this.right.search(value); + } else { + // 3. this.left&&this.right==null,找不到该节点 + return null; + } + } + + // 查找节点的父节点 + public Node searchParent(int value) { + // 1. 判断当前节点是否是查找节点的父节点 + if ((this.left != null && this.left.value == value) || + (this.right != null && this.right.value == value)) { + return this; + } else { + if (this.value > value && this.left != null) { + // 2.1 当前节点的value大于value,往左边寻找 + return this.left.searchParent(value); + } else if (this.value < value && this.right != null) { + // 2.2 当前节点的value小于value,往右边寻找 + return this.right.searchParent(value); + } else { + // 3. this.left&&this.right==null,找不到该节点的父节点 + return null; + } + } + } + + // 中序 + public void infixOrder() { + if (this.left != null) { + this.left.infixOrder(); + } + System.out.println(this); + if (this.right != null) { + this.right.infixOrder(); + } + } + + /** + * 以自身为根节点按规则添加左右子树 + * 规则:对于非叶子节点p,左节点小于p,右节点大于p + * 满足AVL规则!!! + * @param node + * @return void + */ + public void add(Node node) { + // 1. 如果待添加节点为空直接返回 + if (node == null) { + return; + } + if (this.value > node.value) { + // 2.1 如果根节点大于待添加节点,将待添加节点放到左边 + if (this.left == null) { + this.left = node; + } else { + this.left.add(node); + } + } else { + // 2.2 如果根节点小于待添加节点,将待添加节点放到右边 + if (this.right == null) { + this.right = node; + } else { + this.right.add(node); + } + } + + // 当添加完节点后,满足(右子树的高度-左子树的高度) > 1 ,进行左旋转 + if (this.rightHeight() - this.leftHeight() > 1) { + // 如果当前节点的右子树的左子树的高度大于当前节点的右子树的右子树的高度 + if(this.right!=null&&(this.right.leftHeight()>this.right.rightHeight())){ + // 先当前节点的右子树进行右旋转,再左旋转 + this.right.rightRotate(); + } + leftRotate(); + return; + } + + // 当添加完节点后,满足(左子树的高度-右子树的高度) > 1 ,进行右旋转 + if (this.leftHeight() - this.rightHeight() > 1) { + // 如果当前节点的左子树的右子树的高度大于当前节点的左子树的左子树的高度 + if (this.left != null && (this.left.rightHeight() > this.left.leftHeight())) { + // 先对当前节点的左子树进行左旋转,再右旋转 + this.left.leftRotate(); + } + rightRotate(); + } + + } + + + @Override + public String toString() { + return "Node{" + + "value=" + value + + '}'; + } + +} \ No newline at end of file diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/tree/binarysorttree/BinarySortTreeDemo.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/tree/binarysorttree/BinarySortTreeDemo.java new file mode 100644 index 00000000..d582a014 --- /dev/null +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/tree/binarysorttree/BinarySortTreeDemo.java @@ -0,0 +1,298 @@ +package cn.lastwhisper.atguigu.tree.binarysorttree; + +/** + * 二叉排序树 + * @author cn.lastwhisper + */ +public class BinarySortTreeDemo { + public static void main(String[] args) { + int[] arr = {7, 3, 10, 12, 5, 1, 9, 2}; + BinarySortTree binarySortTree = new BinarySortTree(); + for (int i = 0; i < arr.length; i++) { + binarySortTree.add(new Node(arr[i])); + } + System.out.println("中序遍历"); + binarySortTree.infixOrder(); + + //binarySortTree.delNode(2); // 删除叶子节点 + //binarySortTree.delNode(1); // 删除只有一个子节点 + //binarySortTree.delNode(7); // 删除有两个子节点 + + binarySortTree.delNode(2); + binarySortTree.delNode(5); + binarySortTree.delNode(9); + binarySortTree.delNode(12); + binarySortTree.delNode(7); + binarySortTree.delNode(3); + binarySortTree.delNode(1); + binarySortTree.delNode(10); + // 会报错 + //binarySortTree.delNode(10); + //binarySortTree.delNode(1); + + System.out.println("删除节点后,中序遍历"); + binarySortTree.infixOrder(); + } + +} + +/** + * 二叉排序树 + */ +class BinarySortTree { + // 根节点 + private Node root; + + public Node getRoot() { + return root; + } + + public void setRoot(Node root) { + this.root = root; + } + + // 查找节点 + public Node search(int value) { + if (root != null) { + return root.search(value); + } else { + return null; + } + } + + // 查找父节点 + public Node searchParent(int value) { + if (root != null) { + return root.searchParent(value); + } else { + return null; + } + } + + /** + * 找到该节点左子树最小值,并删除这个最小值节点 + * + * @param node + * @return int 最小值节点 + */ + public int delRightTreeMin(Node node) { + Node temp = node; + // 找到右子节点的最小值节点 + while (temp.left != null) { + temp = temp.left; + } + delNode(temp.value); + return temp.value; + } + + /** + * 找到该节点左子树最大值,并删除这个最大值节点 + * + * @param node + * @return int 最大值 + */ + public int delLeftTreeMax(Node node) { + Node temp = node; + while (temp.right != null) { + temp = temp.right; + } + delNode(temp.value); + return temp.value; + } + + + // 根据value删除节点 + public void delNode(int value) { + if (root == null) { + } else { + // 待删除节点 + Node targetNode = search(value); + // 没有找到待删除节点 + if (targetNode == null) { + return; + } + // 待删除节点的父节点 + Node parentNode = searchParent(value); + // 1. 情况一:只有一个根节点 + if (root.left == null && root.right == null) { + root = null; + return; + } + // 2. 情况二:删除的节点是叶子节点(左右节点为空) + if (targetNode.left == null && targetNode.right == null) { + // 2.1 确定targetNode是parent的左子节点还是右子节点; + if (parentNode.left != null && parentNode.left.value == targetNode.value) { + // 左子节点 + parentNode.left = null; + } else if (parentNode.right != null && parentNode.right.value == targetNode.value) { + // 右子节点 + parentNode.right = null; + } + } else if (targetNode.left != null && targetNode.right != null) { + // 3. 情况四:删除带有两个子节点的targetNode + // 找到targetNode右子树的最小值,删除最小值节点,并将最小值赋值给targetNode + //targetNode.value = delRightTreeMin(targetNode.right); + targetNode.value = delLeftTreeMax(targetNode.left); + } else { + // 4. 情况三:待删除节点只有一个子节点 + // 4.1 确定targetNode的子节点是左子节点还是右子节点 + // targetNode的子节点是左子节点 + if (targetNode.left != null) { + if (parentNode != null) { + // 4.2 确定targetNode在parentNode上是左子节点还是右子节点 + if (parentNode.left != null && parentNode.left.value == targetNode.value) { + // targetNode在parentNode上是左子节点 + parentNode.left = targetNode.left; + } else { + // targetNode在parentNode上是右子节点 + parentNode.right = targetNode.left; + } + } else { + // targetNode为根节点时,parentNode==null + // root = targetNode.left;即为删除target节点 + root = targetNode.left; + } + } else { + if (parentNode != null) { + //targetNode的子节点是右子节点 + if (parentNode.left != null && parentNode.left.value == targetNode.value) { + // targetNode在parentNode上是左子节点 + parentNode.left = targetNode.right; + } else { + // targetNode在parentNode上是右子节点 + parentNode.right = targetNode.right; + } + } else { + root = targetNode.right; + } + } + + } + + + } + + } + + // 中序 + public void infixOrder() { + if (root == null) { + System.out.println("树空"); + } else { + root.infixOrder(); + } + + } + + // 添加节点 + public void add(Node node) { + if (root == null) { + root = node; + } else { + root.add(node); + } + } + +} + + +class Node { + int value; + Node left; + Node right; + + public Node(int value) { + this.value = value; + } + + /** + * 查找节点 + * + * @param value 节点的value + * @return cn.cn.lastwhisper.tree.binarysorttree.Node + */ + public Node search(int value) { + // 1. 判断当前节点是否是查找的节点 + if (this.value == value) { + return this; + } else if (this.value > value && this.left != null) { + // 2.1 当前节点的value大于value,往左边寻找,因为左子树的值都小于当前节点 + return this.left.search(value); + } else if (this.value < value && this.right != null) { + // 2.2 当前节点的value小于value,往右边寻找,因为右子树的值都大于当前节点 + return this.right.search(value); + } else { + // 3. this.left&&this.right==null,找不到该节点 + return null; + } + } + + // 查找节点的父节点 + public Node searchParent(int value) { + // 1. 判断当前节点是否是查找节点的父节点 + if ((this.left != null && this.left.value == value) || + (this.right != null && this.right.value == value)) { + return this; + } else { + if (this.value > value && this.left != null) { + // 2.1 当前节点的value大于value,往左边寻找 + return this.left.searchParent(value); + } else if (this.value < value && this.right != null) { + // 2.2 当前节点的value小于value,往右边寻找 + return this.right.searchParent(value); + } else { + // 3. this.left&&this.right==null,找不到该节点的父节点 + return null; + } + } + } + + // 中序 + public void infixOrder() { + if (this.left != null) { + this.left.infixOrder(); + } + System.out.println(this); + if (this.right != null) { + this.right.infixOrder(); + } + } + + /** + * 以自身为根节点按规则添加左右子树 + * 规则:对于非叶子节点p,左节点小于p,右节点大于p + * + * @param node + * @return void + */ + public void add(Node node) { + // 1. 如果待添加节点为空直接返回 + if (node == null) { + return; + } + if (this.value > node.value) { + // 2.1 如果根节点大于待添加节点,将待添加节点放到左边 + if (this.left == null) { + this.left = node; + } else { + this.left.add(node); + } + } else { + // 2.2 如果根节点小于待添加节点,将待添加节点放到右边 + if (this.right == null) { + this.right = node; + } else { + this.right.add(node); + } + } + } + + + @Override + public String toString() { + return "Node{" + + "value=" + value + + '}'; + } + +} \ No newline at end of file diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/tree/huffmancode/HuffmanCode.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/tree/huffmancode/HuffmanCode.java similarity index 95% rename from algorithms/datastructure/src/main/java/cn/lastwhisper/tree/huffmancode/HuffmanCode.java rename to algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/tree/huffmancode/HuffmanCode.java index 35cefc4d..11ba50fc 100644 --- a/algorithms/datastructure/src/main/java/cn/lastwhisper/tree/huffmancode/HuffmanCode.java +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/tree/huffmancode/HuffmanCode.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.tree.huffmancode; +package cn.lastwhisper.atguigu.tree.huffmancode; import java.io.*; import java.util.*; @@ -357,8 +357,8 @@ public static byte[] zip(byte[] bytes, Map huffmanCodes) { /** * 根据哈夫曼树建立哈弗曼编码表 * - * @param root 根结点 - * @return java.util.Map + * @param root 根节点 + * @return java.array.Map */ public static Map getCodes(Node root) { if (root == null) { @@ -371,7 +371,7 @@ public static Map getCodes(Node root) { /** * 根据哈夫曼树建立哈弗曼编码表(递归) - * @param node 以node结点为root开始建立哈夫曼编码表 + * @param node 以node节点为root开始建立哈夫曼编码表 * @param code 左边为0,右边为1 * @param stringBuffer 拼接编码的值 * @param huffmanCodes 存储哈夫曼编码表 @@ -380,14 +380,14 @@ public static void getCodes(Node node, String code, StringBuffer stringBuffer, M // 拼接编码的值,如 a:1——a:11——a:110 StringBuffer sb = new StringBuffer(stringBuffer); sb.append(code); - // 非叶子结点,哈夫曼树只有叶子结点有data + // 非叶子节点,哈夫曼树只有叶子节点有data if (node.data == null) { // 向左递归 getCodes(node.left, "0", sb, huffmanCodes); // 向右递归 getCodes(node.right, "1", sb, huffmanCodes); } else { - // 叶子结点, + // 叶子节点, huffmanCodes.put(node.data, sb.toString()); } } @@ -402,19 +402,19 @@ public static void preOrder(Node root) { } /** - * 创建哈夫曼树,并返回root结点 + * 创建哈夫曼树,并返回root节点 * - * @param nodes 二叉树结点 - * @return Node 哈夫曼树根结点 + * @param nodes 二叉树节点 + * @return Node 哈夫曼树根节点 */ public static Node createHuffmanTree(List nodes) { while (nodes.size() > 1) { - // 1)、将序列升序排序,每一个结点都可以看做是一颗最简单的二叉树 + // 1)、将序列升序排序,每一个节点都可以看做是一颗最简单的二叉树 Collections.sort(nodes); - // 2)、找到权值最小的二叉树(结点) + // 2)、找到权值最小的二叉树(节点) Node leftNode = nodes.get(0); - // 2)、找到权值次小的二叉树(结点) + // 2)、找到权值次小的二叉树(节点) Node rightNode = nodes.get(1); // 3)、将两个权值最小的二叉树构成一颗新的二叉树,新二叉树的权值为前面两个二叉树权值之和。 Node node = new Node(leftNode.weight + rightNode.weight); @@ -429,9 +429,9 @@ public static Node createHuffmanTree(List nodes) { } /** - * 将字符串转换成哈夫曼树结点 + * 将字符串转换成哈夫曼树节点 * @param zipStr 待压缩字符串 - * @return java.util.List + * @return java.array.List */ public static List getListNode(String zipStr) { byte[] zipStrBytes = zipStr.getBytes(); @@ -439,9 +439,9 @@ public static List getListNode(String zipStr) { } /** - * 将字符串转换成哈夫曼树结点 + * 将字符串转换成哈夫曼树节点 * @param zipBytes 待压缩字节数组 - * @return java.util.List + * @return java.array.List */ public static List getListNode(byte[] zipBytes) { // 将字节数组按字节拆分,统计每个字节出现的次数(select count(byte) weight from zipBytes order by byte) @@ -465,7 +465,7 @@ public static List getListNode(byte[] zipBytes) { } -// 哈夫曼树结点 +// 哈夫曼树节点 class Node implements Comparable { Byte data; // 字节 int weight; // 权值,主要用于构建哈夫曼树 diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/tree/huffmantree/HuffmanTree.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/tree/huffmantree/HuffmanTree.java similarity index 87% rename from algorithms/datastructure/src/main/java/cn/lastwhisper/tree/huffmantree/HuffmanTree.java rename to algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/tree/huffmantree/HuffmanTree.java index 578aa60a..4dd1b9a4 100644 --- a/algorithms/datastructure/src/main/java/cn/lastwhisper/tree/huffmantree/HuffmanTree.java +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/atguigu/tree/huffmantree/HuffmanTree.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.tree.huffmantree; +package cn.lastwhisper.atguigu.tree.huffmantree; import java.util.Collections; import java.util.LinkedList; @@ -26,7 +26,7 @@ public static void preOrder(Node root) { } /** - * 创建哈夫曼树,并返回root结点 + * 创建哈夫曼树,并返回root节点 * * @param arr * @return cn.cn.lastwhisper.tree.huffmantree.Node @@ -39,11 +39,11 @@ public static Node createHuffmanTree(int[] arr) { } while (nodes.size() > 1) { - // 1)、将序列升序排序,每一个结点都可以看做是一颗最简单的二叉树 + // 1)、将序列升序排序,每一个节点都可以看做是一颗最简单的二叉树 Collections.sort(nodes); - // 2)、找到权值最小的二叉树(结点) + // 2)、找到权值最小的二叉树(节点) Node leftNode = nodes.get(0); - // 2)、找到权值次小的二叉树(结点) + // 2)、找到权值次小的二叉树(节点) Node rightNode = nodes.get(1); // 3)、将两个权值最小的二叉树构成一颗新的二叉树,新二叉树的权值为前面两个二叉树权值之和。 Node node = new Node(leftNode.value + rightNode.value); @@ -61,7 +61,7 @@ public static Node createHuffmanTree(int[] arr) { } -// 哈夫曼树结点 +// 哈夫曼树节点 class Node implements Comparable { int value;// 权值 Node left;//左子树 diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/sort/HeapSort.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/sort/HeapSort.java deleted file mode 100644 index 3a98a80a..00000000 --- a/algorithms/datastructure/src/main/java/cn/lastwhisper/sort/HeapSort.java +++ /dev/null @@ -1,72 +0,0 @@ -package cn.lastwhisper.sort; - -import java.util.Arrays; - -/** - * 堆排序 - * - * @author cn.lastwhisper - */ -public class HeapSort { - public static void main(String[] args) { - //int[] arr = {4, 6, 8, 5, 9, 58, -10}; - int[] arr = {4, 6, 8, 5, 9}; - heapSort(arr); - System.out.println("数组:" + Arrays.toString(arr)); - } - - public static void heapSort(int[] arr) { - - //adjustHeap(arr, 1, arr.length); - //System.out.println("第1次" + Arrays.toString(arr)); // 4,9,8,5,6 - - //adjustHeap(arr, 0, arr.length); - //System.out.println("第2次" + Arrays.toString(arr)); // 9,6,8,5,4 - int temp; - // 1. 满二叉树从右向左、从下往上构建大顶堆;完全二叉树从左向右、从下往上构建大顶堆; - // i--意味着,从下到上,每一次都是[i,arr.length]的数组(二叉树)进行重构大顶堆 - // [0,arr.length]重构了数组(二叉树)头部几个元素的大顶堆,同时也会重构下面的二叉树 - for (int i = arr.length / 2 - 1; i >= 0; i--) { - adjustHeap(arr, i, arr.length); - } - // 2. 交换堆顶元素与末尾元素,调整堆结构 - for (int j = arr.length - 1; j >= 0; j--) { - // 交换 - temp = arr[j]; - arr[j] = arr[0]; - arr[0] = temp; - adjustHeap(arr, 0, j); - } - } - - - /** - * 将一个数组(二叉树), 调整成一个大顶堆 - * 功能: 将以i对应的非叶子结点的树调整成大顶堆 - * 举例 int arr[] = {4, 6, 8, 5, 9}; => i = 1 => adjustHeap => 得到 {4, 9, 8, 5, 6} - * 如果我们再次调用 adjustHeap 传入的是 i = 0 => {4, 9, 8, 5, 6} => {9, 6, 8, 5, 4} - * @param arr 待调整的数组 - * @param i 表示非叶子结点在数组中索引 - * @param length 表示对多少个元素继续调整, length 是在逐渐的减少 - */ - public static void adjustHeap(int[] arr, int i, int length) { - // 当前i结点 - int temp = arr[i]; - // k是i结点的左子结点,k + 1是右子结点 - for (int k = 2 * i + 1; k < length; k = 2 * k + 1) { - // arr[k] < arr[k + 1]左结点小于右结点 - if (k + 1 < length && arr[k] < arr[k + 1]) { - // k指向数值最大的结点 - k++; - } - if (arr[k] > temp) {//子节点大于父结点 - arr[i] = arr[k];//将子节点赋值到父结点 - i = k;//记录子结点的下标,为了最后 arr[i] = temp; - } else { - break; - } - } - //i = k; arr[i]此时已经是子结点的位置了,前面父结点已经拿到了子结点的值了,这里要将子结点的值赋为父结点的值 - arr[i] = temp; - } -} diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/sort/InsertSort.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/sort/InsertSort.java deleted file mode 100644 index 7119410d..00000000 --- a/algorithms/datastructure/src/main/java/cn/lastwhisper/sort/InsertSort.java +++ /dev/null @@ -1,108 +0,0 @@ -package cn.lastwhisper.sort; - -import cn.lastwhisper.ArrayUtil; - -import java.util.Arrays; - -/** - * @author cn.lastwhisper - */ -public class InsertSort { - public static void main(String[] args) { - //int[] arr = {101, 34, 119, 1}; - //insertSort1(arr); // 插入排序算法实现步骤 - - int[] arr = ArrayUtil.generateArrByRandom(100000); - // 计算耗时 - long start = System.currentTimeMillis(); - insertSort(arr); - long end = System.currentTimeMillis(); - System.out.println("耗时:" + (end - start) + " ms"); - - //System.out.println(Arrays.toString(arr)); - } - - /** - * 插入排序O(n^2) - * insertVal < arr[insertIndex降序 - * insertVal > arr[insertIndex升序 - * @param arr - * @return void - */ - public static void insertSort(int[] arr) { - int insertVal; - int insertIndex; - // 有序列表[0];[1...arr.length]无序列表 - for (int i = 1; i < arr.length; i++) { - // insertVal的意义:缓存无序列表的第一个数,这个数也是待插入有序列表的数 - insertVal = arr[i]; - // insertIndex的意义:记录有序列表的最后一个数的下标 - insertIndex = i - 1; - // [insertIndex+1...i-1]后移到[insertIndex+2...i](从前往后移动) - while (insertIndex >= 0 && insertVal < arr[insertIndex]) { - arr[insertIndex + 1] = arr[insertIndex]; - insertIndex--; - } - // insertIndex == i - 1; 说明数组并未后移,无需赋值 - if (insertIndex != i - 1) { - // arr[insertIndex + 1]为待插入位置 - arr[insertIndex + 1] = insertVal; - } - } - } - - /** - * 插入排序的实现步骤 - * - * @param arr - * @return void - */ - public static void insertSort1(int[] arr) { - // 第1轮 - // 有序列表{101},无序列表{34, 119, 1} - // {101, 34, 119, 1} - - // insertVal的意义:缓存无序列表的第一个数,这个数也是待插入有序列表的数 - int insertVal = arr[1]; - // insertIndex的意义:记录有序列表的最后一个数的下标 - int insertIndex = 1 - 1; - // insertIndex >= 0的意义:防止数组越界; - // insertVal < arr[insertIndex]的意义:找到insertVal要插入位置的前一个位置 - // 整个while循环的意义:数组覆盖后移,找到待插入位置的前一个位置 - while (insertIndex >= 0 && insertVal < arr[insertIndex]) { - // 第1轮原数组:{101, 34, 119, 1} - // arr[1]=arr[0] {101, 101, 119, 1} - arr[insertIndex + 1] = arr[insertIndex]; - //继续向前 - insertIndex--; - } - // arr[0]=insertVal {34, 101, 119, 1} - arr[insertIndex + 1] = insertVal; - - System.out.printf("第1轮插入,数组:%s\n", Arrays.toString(arr)); - - // 第2轮 - insertVal = arr[2]; - insertIndex = 2 - 1; - while (insertIndex >= 0 && insertVal < arr[insertIndex]) { - arr[insertIndex + 1] = arr[insertIndex]; - insertIndex--; - } - arr[insertIndex + 1] = insertVal; - System.out.printf("第2轮插入,数组:%s\n", Arrays.toString(arr)); - - // 第3轮 - insertVal = arr[3]; - insertIndex = 3 - 1; - while (insertIndex >= 0 && insertVal < arr[insertIndex]) { - // 第三轮原数组:{34, 101, 119, 1} - // arr[3]=arr[2] {34, 101, 119, 119} - // arr[2]=arr[1] {34, 101, 101, 119} - // arr[1]=arr[0] {34, 34, 101, 119} - arr[insertIndex + 1] = arr[insertIndex]; - insertIndex--; - } - arr[insertIndex + 1] = insertVal; - System.out.printf("第3轮插入,数组:%s\n", Arrays.toString(arr)); - } -} diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/sort/MergeSort.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/sort/MergeSort.java deleted file mode 100644 index 576c9896..00000000 --- a/algorithms/datastructure/src/main/java/cn/lastwhisper/sort/MergeSort.java +++ /dev/null @@ -1,97 +0,0 @@ -package cn.lastwhisper.sort; - -import cn.lastwhisper.ArrayUtil; - -/** - * @author cn.lastwhisper - */ -public class MergeSort { - - public static void main(String[] args) { - //int[] arr = {9, 8, 7, 6, 5, 4, 3, 2, 1}; - int[] arr = ArrayUtil.generateArrByRandom(10000000);// 1443 ms - // 计算耗时 - long start = System.currentTimeMillis(); - int[] temp = new int[arr.length]; - mergeSort(arr, 0, arr.length - 1, temp); - long end = System.currentTimeMillis(); - System.out.println("耗时:" + (end - start) + " ms"); - - //System.out.println(Arrays.toString(arr)); - } - - /** - * 归并排序 - * 分 - * - * @param arr 排序的原始数组 - * @param left 左边有序序列的初始索引 - * @param right 右边索引 - * @param temp 中转数组 - */ - public static void mergeSort(int[] arr, int left, int right, int[] temp) { - int mid; - if (left < right) { - mid = (left + right) / 2; - // 向左分 - mergeSort(arr, left, mid, temp); - // 向右分 - mergeSort(arr, mid + 1, right, temp); - // 治 - merge(arr, left, mid, right, temp); - } - } - - /** - * 治 - * @param arr 排序的原始数组 arr[left...mid] arr[mid+1...right] - * @param left 左边有序序列的初始索引 - * @param mid 中间索引 - * @param right 右边索引 - * @param temp 中转数组 - */ - public static void merge(int[] arr, int left, int mid, int right, int[] temp) { - int i = left; //左边有序序列的初始索引 - int j = mid + 1; // 右边有序序列的初始化序索引 - int t = 0; // 指向temp数组的当前位置 - - // 1)、将左右两边(有序)的数据按照规则填充到temp数组,任意一边处理完毕为止 - while (i <= mid && j <= right) { - - if (arr[i] < arr[j]) { - // 左小于右,将左数组第i个元素copy到temp数组的第t个位置 - temp[t] = arr[i]; - i += 1; - } else { - // 右小于或等于左,将右数组第j个元素copy到temp数组的第t个位置 - temp[t] = arr[j]; - j += 1; - } - t += 1; - } - - // 2)、把有剩余数据的一边的数据依次填充到temp - while (i <= mid) { - // 说明 右数组还有剩余元素 - temp[t] = arr[i]; - t += 1; - i += 1; - } - while (j <= right) { - // 说明 右数组还有剩余元素 - temp[t] = arr[j]; - t += 1; - j += 1; - } - - // 3)、将temp数组的数据copy到arr(并不是每次都copy所有) - t = 0; - int tempLeft = left; - while (tempLeft <= right) { // 0 1;2 3;0 3 - arr[tempLeft] = temp[t]; - t += 1; - tempLeft += 1; - } - - } -} diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/sort/QuickSort.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/sort/QuickSort.java deleted file mode 100644 index 0e7c5a51..00000000 --- a/algorithms/datastructure/src/main/java/cn/lastwhisper/sort/QuickSort.java +++ /dev/null @@ -1,123 +0,0 @@ -package cn.lastwhisper.sort; - -import java.util.Arrays; - -/** - * @author cn.lastwhisper - */ -public class QuickSort { - - public static void main(String[] args) { - //int[] arr = {-9, 78, 0, 23, -567, 70}; - //int[] arr = {-9, 78, 0, 23, 60, 70}; - //int[] arr = {9, 0, -567}; - int[] arr = {49, 38, 65, 97, 76, 13, 27}; - - //int[] arr = ArrayUtil.generateArrByRandom(10000000);//耗时:1519 ms - // 计算耗时 - long start = System.currentTimeMillis(); - //quickSort(arr, 0, arr.length - 1); - qSort(arr, 0, arr.length - 1); - long end = System.currentTimeMillis(); - System.out.println("耗时:" + (end - start) + " ms"); - - System.out.println(Arrays.toString(arr)); - } - - public static void qSort(int[] arr, int head, int tail) { - if (head >= tail || arr == null || arr.length <= 1) { - return; - } - //定义俩指针 用于移动 - int left = head; - int right = tail; - int pivot = arr[head]; //基准值,也可以arr[(head + tail) / 2] - - while (left <= right) { - while (arr[left] < pivot) { //左指针先走,找到大于等于基准数的停止 - ++left; - } - while (arr[right] > pivot) { //右指针后走,找到小于等于基准数的停止 - --right; - } - if (left < right) { - //交换arr[left]和arr[right]的位置 - int t = arr[left]; - arr[left] = arr[right]; - arr[right] = t; - //继续遍历 - ++left; - --right; - } else if (left == right) { - //遍历完,错开两指针,用于退出循环 - ++left; - //break; - } - } - - qSort(arr, head, right); - qSort(arr, left, tail); - } - - - /** - * 快速排序,选取数组中间的值 - * int pivot = arr[(left + right) / 2]; - * @param arr - * @param left - * @param right - * @return void - */ - public static void quickSort1(int[] arr, int left, int right) { - int l = left; // 左下标 - int r = right; // 右下标 - int temp; - // 中轴 - int pivot = arr[(left + right) / 2]; - // while循环的目的:小于或等于pivot的放左边,大于或等于pivot的放右边 - while (l < r) { - // 在pivot左边找比pivot大的值的下标l - while (arr[l] < pivot) { //找到arr[1]=98 >pivot=0 - l ++; - } - // 在pivot右边找比pivot小的值的下标r - while (arr[r] > pivot) { //找到arr[4]=-567 < pivot=0 - r--; - } - // 如果l>=r说明pivot左右两边的值,已经满足: - // 小于或等于pivot的放左边,大于或等于pivot的放右边 ——递归结束条件 - if (l >= r) { - break; - } - // 交换 - temp = arr[l]; - arr[l] = arr[r]; - arr[r] = temp; - // 如果交换完后,发现arr[l] == pivot,r--,前移 退出循环 - if (arr[l] == pivot) { - r --; - } - - // 如果交换完后,发现arr[r] == pivot,l++,后移 退出循环 - if (arr[r] == pivot) { - l ++; - } - } - - // 第二步 - - // 如果l==r,必须l++,r--,否则会栈溢出 - if (l == r) { - l = l + 1; - r = r - 1; - } - // 向左递归 - if (left < r) { - quickSort1(arr, left, r); - } - // 向右递归 - if (right > l) { - quickSort1(arr, l, right); - } - } -} diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/sort/QuickSort2.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/sort/QuickSort2.java deleted file mode 100644 index f30de4e3..00000000 --- a/algorithms/datastructure/src/main/java/cn/lastwhisper/sort/QuickSort2.java +++ /dev/null @@ -1,51 +0,0 @@ -package cn.lastwhisper.sort; - -/** - * @author lastwhisper - */ -public class QuickSort2 { - public static void main(String[] args) { - int arr[] = {7, 3, 2, 8, 1, 9, 5, 4, 6}; - //int arr[] = {7, 3, 2, 8, 1, 9, 5, 4, 6, 0};//为什么left++和right--条件里面要加 left <= right 限定 - //int arr[] = {7, 3, 2, 8, 1, 9, 5, 4, 6, 10}; - //int arr[] = {7, 3, 2, 6, 8, 1, 9, 5, 4, 6, 10, 6, 6}; // 为什么不取等 arr[right] > pivot - //int arr[] = {4, 6}; //小bug测试 // 为什么while (left <= right)里面要取等 - sort(arr, 0, arr.length - 1); - print(arr); - } - - private static void sort(int[] arr, int left, int right) { - if (left >= right) return; - int mid = partition(arr, left, right); - sort(arr, left, mid - 1); - sort(arr, mid + 1, right); - } - - // 分区 - private static int partition(int[] arr, int leftBound, int rightBound) { - int left = leftBound; - int pivot = arr[rightBound]; - int right = rightBound - 1; - - while (left <= right) { - while (left <= right && arr[left] <= pivot) left++;//left <= right是为了防止pivot最大,找不到比它大的数,导致越界 - while (left <= right && arr[right] > pivot) right--; - System.out.println("left:" + left + "\tright:" + right); - if (left < right) swap(arr, left, right); - } - swap(arr, left, rightBound); - return left; - } - - private static void swap(int[] arr, int i, int j) { - int temp = arr[i]; - arr[i] = arr[j]; - arr[j] = temp; - } - - private static void print(int[] arr) { - for (int i = 0; i < arr.length; i++) { - System.out.print(arr[i] + "\t"); - } - } -} diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/sort/RadixSort.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/sort/RadixSort.java deleted file mode 100644 index 2179cbea..00000000 --- a/algorithms/datastructure/src/main/java/cn/lastwhisper/sort/RadixSort.java +++ /dev/null @@ -1,152 +0,0 @@ -package cn.lastwhisper.sort; - -import cn.lastwhisper.ArrayUtil; - -import java.util.Arrays; - -/** - * @author cn.lastwhisper - */ -public class RadixSort { - - public static void main(String[] args) { - // 算法实现步骤 - //int[] arr = {53, 3, 542, 748, 14, 214}; - //int[] arr = {3, 205, 14}; - //radixSortStudy(arr); - - // 计算耗时 - // 占用内存 10000000 * 10 * 4 /1024 / 1024 /1024 = 0.3725290298461914‬ - int[] arr = ArrayUtil.generateArrByRandom(10000000); - long start = System.currentTimeMillis(); - radixSort(arr); - long end = System.currentTimeMillis(); - System.out.println("耗时:" + (end - start) + " ms"); - - //System.out.println(Arrays.toString(arr)); - } - - /** - * 基数排序 - * - * @param arr - * @return void - */ - public static void radixSort(int[] arr) { - - int[][] bucket = new int[10][arr.length]; - // 桶元素计数器,记录每个桶中存放了多少数据 - int[] bucketElementCount = new int[10]; - // 原arr下标 - int arrIndex; - // 除数 - int divisor = 1; - // 最大值 - int max = arr[0]; - // 由于基数排序次数由最大数值的位数决定,所以需要求最大值 - for (int i = 1; i < arr.length; i++) { - if (max < arr[i]) { - max = arr[i]; - } - } - // 最大值得位数,即排序次数 - int maxLength = (max + "").length(); - for (int f = 0; f < maxLength; f++) { - for (int i = 0; i < arr.length; i++) { - // digitOfElement对应放在哪个bucket中 - int digitOfElement = arr[i] / divisor % 10; - // 放在第digitOfElement个bucket的第bucketElementCount[digitOfElement]下标位置 - bucket[digitOfElement][bucketElementCount[digitOfElement]] = arr[i]; - // 下次放在bucket的第bucketElementCount[digitOfElement]++下标位置 - bucketElementCount[digitOfElement]++; - } - - arrIndex = 0; - // 将桶中数据放回原数组 - for (int i = 0; i < bucketElementCount.length; i++) { - // 对应桶中有数据 - if (bucketElementCount[i] != 0) { - for (int j = 0; j < bucketElementCount[i]; j++) { - arr[arrIndex++] = bucket[i][j]; - } - } - // 将桶元素计数器清空 - bucketElementCount[i] = 0; - } - divisor *= 10; - } - - } - - /** - * 桶排序算法实现步骤 - * - * @param arr - */ - public static void radixSortStudy(int[] arr) { - // - int[][] bucket = new int[10][arr.length]; - // 桶元素计数器,记录每个桶中存放了多少数据 - int[] bucketElementCount = new int[10]; - // 原arr下标 - int arrIndex; - - for (int i = 0; i < arr.length; i++) { - // digitOfElement对应放在哪个bucket中 - int digitOfElement = arr[i] % 10; - // 放在第digitOfElement个bucket的第bucketElementCount[digitOfElement]下标位置 - bucket[digitOfElement][bucketElementCount[digitOfElement]] = arr[i]; - // 下次放在bucket的第bucketElementCount[digitOfElement]++下标位置 - bucketElementCount[digitOfElement]++; - } - - arrIndex = 0; - // 将桶中数据放回原数组 - for (int i = 0; i < bucketElementCount.length; i++) { - // 对应桶中有数据 - if (bucketElementCount[i] != 0) { - for (int j = 0; j < bucketElementCount[i]; j++) { - arr[arrIndex++] = bucket[i][j]; - } - } - // 将桶元素计数器清空 - bucketElementCount[i] = 0; - } - - System.out.println("第1轮,对个位的排序处理 arr =" + Arrays.toString(arr)); - - for (int i = 0; i < arr.length; i++) { - // digitOfElement对应放在哪个bucket中 - int digitOfElement = arr[i] / 10 % 10; - // 放在第digitOfElement个bucket的第bucketElementCount[digitOfElement]下标位置 - bucket[digitOfElement][bucketElementCount[digitOfElement]] = arr[i]; - // 下次放在bucket的第bucketElementCount[digitOfElement]++下标位置 - bucketElementCount[digitOfElement]++; - } - - arrIndex = 0; - // 将桶中数据放回原数组 - for (int i = 0; i < bucketElementCount.length; i++) { - // 对应桶中有数据 - if (bucketElementCount[i] != 0) { - for (int j = 0; j < bucketElementCount[i]; j++) { - arr[arrIndex++] = bucket[i][j]; - } - } - // 将桶元素计数器清空 - bucketElementCount[i] = 0; - } - - System.out.println("第2轮,对个位的排序处理 arr =" + Arrays.toString(arr)); - - //for (int i = 0; i < bucket.length; i++) { - // for (int j = 0; j < bucket[0].length; j++) { - // System.out.printf("%d\t", bucket[i][j]); - // } - // System.out.println(); - //} - - } - - -} diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/sort/SelectSort.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/sort/SelectSort.java deleted file mode 100644 index 7075249f..00000000 --- a/algorithms/datastructure/src/main/java/cn/lastwhisper/sort/SelectSort.java +++ /dev/null @@ -1,82 +0,0 @@ -package cn.lastwhisper.sort; - -import cn.lastwhisper.ArrayUtil; - -import java.util.Arrays; - -/** - * @author cn.lastwhisper - */ -public class SelectSort { - - public static void main(String[] args) { - //int[] arr = {101, 34, 119, 1}; - //selectSort1(arr); - //System.out.println(Arrays.toString(arr)); - - int[] arr = ArrayUtil.generateArrByRandom(100000); - // 计算耗时 - long start = System.currentTimeMillis(); - selectSort(arr); - long end = System.currentTimeMillis(); - System.out.println("耗时:" + (end - start) + " ms"); - } - - /** - * 选择排序O(n^2) - * - * @param arr - * @return void - */ - public static void selectSort(int[] arr) { - for (int i = 0; i < arr.length; i++) { - int min = arr[i]; - int minIndex = i; - // 找出[1+i...arr.length]范围内的最小值,和最小值索引 - for (int j = i + 1; j < arr.length; j++) { - if (min > arr[j]) { - min = arr[j]; - minIndex = j; - } - } - // 交换最小值与第i个数的位置 - if (minIndex != i) { - arr[minIndex] = arr[i]; - arr[i] = min; - } - } - } - - /** - * 算法的实现步骤 - * - * @param arr - * @return void - */ - public static void selectSort1(int[] arr) { - // 第1轮 {101, 34, 119, 1} - - // 1、找最小值 - // 最小值 - int min = arr[0]; - // 最小值索引 - int minIndex = 0; - // {101, 34, 119, 1} 我们假设待排序数组第一个元素就是最小值,即min=arr[0],minIndex=0 - // 经过遍历后我们发现 min=1,minIndex=3 - for (int j = 0 + 1; j < arr.length; j++) { - // 找最小的数 - if (min > arr[j]) { - min = arr[j]; - minIndex = j; - } - } - // 2、交换。minIndex是最小值所在位置,min是最小值 - if (minIndex != 0) { - arr[minIndex] = arr[0]; - arr[0] = min; - } - - System.out.printf("第1轮选择,数组:%s", Arrays.toString(arr)); - } - -} diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/sort/ShellSort.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/sort/ShellSort.java deleted file mode 100644 index c37c6de4..00000000 --- a/algorithms/datastructure/src/main/java/cn/lastwhisper/sort/ShellSort.java +++ /dev/null @@ -1,132 +0,0 @@ -package cn.lastwhisper.sort; - -import java.util.Arrays; - -/** - * @author cn.lastwhisper - */ -public class ShellSort { - public static void main(String[] args) { - int[] arr = {8, 9, 1, 7, 2, 3, 5, 4, 6, 0}; - //int[] arr = ArrayUtil.generateArrByRandom(100000); - // 计算耗时 - long start = System.currentTimeMillis(); - //shellSort1(arr); // 10490 ms - shellSort2(arr); // 10490 ms - long end = System.currentTimeMillis(); - System.out.println("耗时:" + (end - start) + " ms"); - - System.out.printf("希尔排序(交换法),数组:%s\n", Arrays.toString(arr)); - } - - - /** - * 希尔排序(位移法)(插入排序) - * - * @param arr - * @return void - */ - public static void shellSort2(int[] arr) { - // {8, 9, 1, 7, 2, 3, 5, 4, 6, 0} - int gap = arr.length / 2; - int j; - int temp; - while (gap > 0) { - //gap=5,2,1,0 - // i=5——》{0,5} - // i=6——》{1,6} - // i=7——》{2,7} - // i=8——》{3,8} - // i=9——》{4,9} - // 对每个数组进行插入排序;由于每个数组并不是真的存在的数组,而是一个大数组 - // 所以通过gap进行取值 - for (int i = gap; i < arr.length; i++) { - j = i; // 缓存每个数组的起始下标 - temp = arr[i]; // 缓存每个数组的起始下标的数值 - if (temp < arr[j - gap]) { - while (j - gap >= 0 && temp < arr[j - gap]) { - // 从前往后移动 - arr[j] = arr[j - gap]; - j = j - gap; - } - // - arr[j] = temp; - } - } - gap = gap / 2; - } - } - - /** - * 希尔排序(交换法) - * - * @param arr - * @return void - */ - public static void shellSort1(int[] arr) { - // 第1轮 {8, 9, 1, 7, 2, 3, 5, 4, 6, 0} - // 增量 gap=length/2 - int gap = arr.length / 2; - int temp; - while (gap > 0) { - for (int i = gap; i < arr.length; i++) { - // 交换 - for (int j = i - gap; j >= 0; j -= gap) { - if (arr[j] > arr[j + gap]) { - temp = arr[j + gap]; - arr[j + gap] = arr[j]; - arr[j] = temp; - } - } - } - gap = gap / 2; - } - } - - /** - * 交换法希尔排序 - * - * @param arr - * @return void - */ - public static void shellSortStudy(int[] arr) { - // 第1轮 [8, 9, 1, 7, 2, 3, 5, 4, 6, 0] - // 增量 gap=length/2 - int temp; - for (int i = 5; i < arr.length; i++) { - // 交换 - for (int j = i - 5; j >= 0; j -= 5) { - if (arr[j] > arr[j + 5]) { - temp = arr[j + 5]; - arr[j + 5] = arr[j]; - arr[j] = temp; - } - } - } - System.out.printf("第1轮插入,数组:%s\n", Arrays.toString(arr)); - // 第二轮 [3, 5, 1, 6, 0, 8, 9, 4, 7, 2] - for (int i = 2; i < arr.length; i++) { - // 交换 - for (int j = i - 2; j >= 0; j -= 2) { - if (arr[j] > arr[j + 2]) { - temp = arr[j + 2]; - arr[j + 2] = arr[j]; - arr[j] = temp; - } - } - } - System.out.printf("第2轮插入,数组:%s\n", Arrays.toString(arr)); - // 第二轮 [0, 2, 1, 4, 3, 5, 7, 6, 9, 8] - for (int i = 1; i < arr.length; i++) { - // 交换 - for (int j = i - 1; j >= 0; j -= 1) { - if (arr[j] > arr[j + 1]) { - temp = arr[j + 1]; - arr[j + 1] = arr[j]; - arr[j] = temp; - } - } - } - System.out.printf("第2轮插入,数组:%s\n", Arrays.toString(arr)); - } -} diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/tree/avl/AVLTreeDemo.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/tree/avl/AVLTreeDemo.java deleted file mode 100644 index 35463314..00000000 --- a/algorithms/datastructure/src/main/java/cn/lastwhisper/tree/avl/AVLTreeDemo.java +++ /dev/null @@ -1,378 +0,0 @@ -package cn.lastwhisper.tree.avl; - -/** - * 平衡二叉树 - * @author cn.lastwhisper - */ -public class AVLTreeDemo { - public static void main(String[] args) { - // 测试左旋转 - //int[] arr = {4, 3, 6, 5, 7, 8}; - // 测试右旋转 - //int[] arr = {10, 12, 8, 9, 7, 6}; - // 测试双旋转 - int[] arr = {10, 11, 7, 6, 8, 9}; - AVLTree avlTree = new AVLTree(); - for (int i = 0; i < arr.length; i++) { - avlTree.add(new Node(arr[i])); - } - System.out.println("中序遍历"); - avlTree.infixOrder(); - Node avlTreeRoot = avlTree.getRoot(); - System.out.println("当前树的高度:" + avlTreeRoot.height()); - System.out.println("当前树的左子树高度:" + avlTreeRoot.left.height()); - System.out.println("当前树的右子树高度:" + avlTreeRoot.right.height()); - System.out.println("当前根结点:" + avlTreeRoot); - } -} - -/** - * 二叉排序树 - */ -class AVLTree { - // 根结点 - private Node root; - - public Node getRoot() { - return root; - } - - public void setRoot(Node root) { - this.root = root; - } - - // 查找结点 - public Node search(int value) { - if (root != null) { - return root.search(value); - } else { - return null; - } - } - - // 查找父结点 - public Node searchParent(int value) { - if (root != null) { - return root.searchParent(value); - } else { - return null; - } - } - - /** - * 找到该结点左子树最小值,并删除这个最小值结点 - * - * @param node - * @return int 最小值结点 - */ - public int delRightTreeMin(Node node) { - Node temp = node; - // 找到右子结点的最小值结点 - while (temp.left != null) { - temp = temp.left; - } - delNode(temp.value); - return temp.value; - } - - /** - * 找到该结点左子树最大值,并删除这个最大值结点 - * - * @param node - * @return int 最大值 - */ - public int delLeftTreeMax(Node node) { - Node temp = node; - while (temp.right != null) { - temp = temp.right; - } - delNode(temp.value); - return temp.value; - } - - - // 根据value删除结点 - public void delNode(int value) { - if (root == null) { - return; - } else { - // 待删除结点 - Node targetNode = search(value); - // 没有找到待删除结点 - if (targetNode == null) { - return; - } - // 待删除结点的父结点 - Node parentNode = searchParent(value); - // 1. 情况一:只有一个根结点 - if (root.left == null && root.right == null) { - root = null; - return; - } - // 2. 情况二:删除的结点是叶子结点(左右结点为空) - if (targetNode.left == null && targetNode.right == null) { - // 2.1 确定targetNode是parent的左子结点还是右子结点; - if (parentNode.left != null && parentNode.left.value == targetNode.value) { - // 左子结点 - parentNode.left = null; - } else if (parentNode.right != null && parentNode.right.value == targetNode.value) { - // 右子结点 - parentNode.right = null; - } - } else if (targetNode.left != null && targetNode.right != null) { - // 3. 情况四:删除带有两个子结点的targetNode - // 找到targetNode右子树的最小值,删除最小值结点,并将最小值赋值给targetNode - //targetNode.value = delRightTreeMin(targetNode.right); - targetNode.value = delLeftTreeMax(targetNode.left); - } else { - // 4. 情况三:删除只有一个子结点的targetNode - // 4.1 确定targetNode的子结点是左子结点还是右子结点 - // targetNode的子结点是左子结点 - if (targetNode.left != null) { - if (parentNode != null) { - // 4.2 确定targetNode在parentNode上是左子结点还是右子结点 - if (parentNode.left != null && parentNode.left.value == targetNode.value) { - // targetNode在parentNode上是左子结点 - parentNode.left = targetNode.left; - } else { - // targetNode在parentNode上是右子结点 - parentNode.right = targetNode.left; - } - } else { - // targetNode为根结点时,parentNode==null - // root = targetNode.left;即为删除target结点 - root = targetNode.left; - } - } else { - if (parentNode != null) { - //targetNode的子结点是右子结点 - if (parentNode.left != null && parentNode.left.value == targetNode.value) { - // targetNode在parentNode上是左子结点 - parentNode.left = targetNode.right; - } else { - // targetNode在parentNode上是右子结点 - parentNode.right = targetNode.right; - } - } else { - root = targetNode.right; - } - } - - } - - - } - - } - - // 中序 - public void infixOrder() { - if (root == null) { - System.out.println("树空"); - } else { - root.infixOrder(); - } - - } - - // 添加结点 - public void add(Node node) { - if (root == null) { - root = node; - } else { - root.add(node); - } - } - -} - - -class Node { - int value; - Node left; - Node right; - - public Node(int value) { - this.value = value; - } - - /** - * 以当前某结点进行右旋转,降低左子树的高度 - */ - public void rightRotate() { - // 1. 创建一个新结点,值等于当前结点的值 - Node newNode = new Node(this.value); - // 2. 将新结点的右子树设置为当前结点的右子树 - newNode.right = this.right; - // 3. 将新结点的左子树设置为当前结点的左子树的右子树(当前结点左子树最大的结点) - newNode.left = this.left.right; - // 4. 将当前结点的值设置为当前结点的左子树(结点)的值 - this.value = this.left.value; - // 5. 将当前结点的左子树设置为当前结点左子树的左子树 - this.left = this.left.left; - // 6. 将当期结点的右子树设置为新结点 - this.right = newNode; - } - - /** - * 以当前某结点进行左旋转,降低右子树的高度 - */ - public void leftRotate() { - // 1. 创建一个新结点,值等于当前结点的值 - Node newNode = new Node(this.value); - // 2. 将新结点的左子树设置为当前结点的左子树 - newNode.left = this.left; - // 3. 将新结点的右子树设置为当前结点右子树的左子树 - newNode.right = this.right.left; - // 4. 将当前结点的值设置为当前结点右子树的值 - this.value = this.right.value; - // 5. 将当前结点的右子树设置为当前结点右子树的右子树 - this.right = this.right.right; - // 6. 将当前结点左子树设置为新结点 - this.left = newNode; - } - - /** - * @return int 当前某结点左子树的高度 - */ - public int leftHeight() { - if (this.left != null) { - return this.left.height(); - } else { - return 0; - } - } - - /** - * @return int 当前某结点右子树的高度 - */ - public int rightHeight() { - if (this.right != null) { - return this.right.height(); - } else { - return 0; - } - } - - /** - * @return int 当前某结点的高度 - */ - public int height() { - int leftHeight = this.left == null ? 0 : this.left.height(); - int rightHeight = this.right == null ? 0 : this.right.height(); - return Math.max(leftHeight, rightHeight) + 1; - } - - /** - * 查找结点 - * - * @param value 结点的value - * @return cn.cn.lastwhisper.tree.binarysorttree.Node - */ - public Node search(int value) { - // 1. 判断当前结点是否是查找的结点 - if (this.value == value) { - return this; - } else if (this.value > value && this.left != null) { - // 2.1 当前结点的value大于value,往左边寻找 - return this.left.search(value); - } else if (this.value < value && this.right != null) { - // 2.2 当前结点的value小于value,往右边寻找 - return this.right.search(value); - } else { - // 3. this.left&&this.right==null,找不到该结点 - return null; - } - } - - // 查找结点的父结点 - public Node searchParent(int value) { - // 1. 判断当前结点是否是查找结点的父结点 - if ((this.left != null && this.left.value == value) || - (this.right != null && this.right.value == value)) { - return this; - } else { - if (this.value > value && this.left != null) { - // 2.1 当前结点的value大于value,往左边寻找 - return this.left.searchParent(value); - } else if (this.value < value && this.right != null) { - // 2.2 当前结点的value小于value,往右边寻找 - return this.right.searchParent(value); - } else { - // 3. this.left&&this.right==null,找不到该结点的父结点 - return null; - } - } - } - - // 中序 - public void infixOrder() { - if (this.left != null) { - this.left.infixOrder(); - } - System.out.println(this); - if (this.right != null) { - this.right.infixOrder(); - } - } - - /** - * 以自身为根结点按规则添加左右子树 - * 规则:对于非叶子结点p,左结点小于p,右结点大于p - * 满足AVL规则!!! - * @param node - * @return void - */ - public void add(Node node) { - // 1. 如果待添加结点为空直接返回 - if (node == null) { - return; - } - if (this.value > node.value) { - // 2.1 如果根结点大于待添加结点,将待添加结点放到左边 - if (this.left == null) { - this.left = node; - } else { - this.left.add(node); - } - } else { - // 2.2 如果根结点小于待添加结点,将待添加结点放到右边 - if (this.right == null) { - this.right = node; - } else { - this.right.add(node); - } - } - - // 当添加完结点后,满足(右子树的高度-左子树的高度) > 1 ,进行左旋转 - if (this.rightHeight() - this.leftHeight() > 1) { - // 如果当前结点的右子树的左子树的高度大于当前结点的右子树的右子树的高度 - if(this.right!=null&&(this.right.leftHeight()>this.right.rightHeight())){ - // 先当前结点的右子树进行右旋转,再左旋转 - this.right.rightRotate(); - } - leftRotate(); - return; - } - - // 当添加完结点后,满足(左子树的高度-右子树的高度) > 1 ,进行右旋转 - if (this.leftHeight() - this.rightHeight() > 1) { - // 如果当前结点的左子树的右子树的高度大于当前结点的左子树的左子树的高度 - if (this.left != null && (this.left.rightHeight() > this.left.leftHeight())) { - // 先对当前结点的左子树进行左旋转,再右旋转 - this.left.leftRotate(); - } - rightRotate(); - } - - } - - - @Override - public String toString() { - return "Node{" + - "value=" + value + - '}'; - } - -} \ No newline at end of file diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/tree/binarysorttree/BinarySortTreeDemo.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/tree/binarysorttree/BinarySortTreeDemo.java deleted file mode 100644 index 11e4f8dc..00000000 --- a/algorithms/datastructure/src/main/java/cn/lastwhisper/tree/binarysorttree/BinarySortTreeDemo.java +++ /dev/null @@ -1,299 +0,0 @@ -package cn.lastwhisper.tree.binarysorttree; - -/** - * 二叉排序树 - * @author cn.lastwhisper - */ -public class BinarySortTreeDemo { - public static void main(String[] args) { - int[] arr = {7, 3, 10, 12, 5, 1, 9, 2}; - BinarySortTree binarySortTree = new BinarySortTree(); - for (int i = 0; i < arr.length; i++) { - binarySortTree.add(new Node(arr[i])); - } - System.out.println("中序遍历"); - binarySortTree.infixOrder(); - - //binarySortTree.delNode(2); // 删除叶子结点 - //binarySortTree.delNode(1); // 删除只有一个子结点 - //binarySortTree.delNode(7); // 删除有两个子结点 - - binarySortTree.delNode(2); - binarySortTree.delNode(5); - binarySortTree.delNode(9); - binarySortTree.delNode(12); - binarySortTree.delNode(7); - binarySortTree.delNode(3); - binarySortTree.delNode(1); - binarySortTree.delNode(10); - // 会报错 - //binarySortTree.delNode(10); - //binarySortTree.delNode(1); - - System.out.println("删除结点后,中序遍历"); - binarySortTree.infixOrder(); - } - -} - -/** - * 二叉排序树 - */ -class BinarySortTree { - // 根结点 - private Node root; - - public Node getRoot() { - return root; - } - - public void setRoot(Node root) { - this.root = root; - } - - // 查找结点 - public Node search(int value) { - if (root != null) { - return root.search(value); - } else { - return null; - } - } - - // 查找父结点 - public Node searchParent(int value) { - if (root != null) { - return root.searchParent(value); - } else { - return null; - } - } - - /** - * 找到该结点左子树最小值,并删除这个最小值结点 - * - * @param node - * @return int 最小值结点 - */ - public int delRightTreeMin(Node node) { - Node temp = node; - // 找到右子结点的最小值结点 - while (temp.left != null) { - temp = temp.left; - } - delNode(temp.value); - return temp.value; - } - - /** - * 找到该结点左子树最大值,并删除这个最大值结点 - * - * @param node - * @return int 最大值 - */ - public int delLeftTreeMax(Node node) { - Node temp = node; - while (temp.right != null) { - temp = temp.right; - } - delNode(temp.value); - return temp.value; - } - - - // 根据value删除结点 - public void delNode(int value) { - if (root == null) { - return; - } else { - // 待删除结点 - Node targetNode = search(value); - // 没有找到待删除结点 - if (targetNode == null) { - return; - } - // 待删除结点的父结点 - Node parentNode = searchParent(value); - // 1. 情况一:只有一个根结点 - if (root.left == null && root.right == null) { - root = null; - return; - } - // 2. 情况二:删除的结点是叶子结点(左右结点为空) - if (targetNode.left == null && targetNode.right == null) { - // 2.1 确定targetNode是parent的左子结点还是右子结点; - if (parentNode.left != null && parentNode.left.value == targetNode.value) { - // 左子结点 - parentNode.left = null; - } else if (parentNode.right != null && parentNode.right.value == targetNode.value) { - // 右子结点 - parentNode.right = null; - } - } else if (targetNode.left != null && targetNode.right != null) { - // 3. 情况四:删除带有两个子结点的targetNode - // 找到targetNode右子树的最小值,删除最小值结点,并将最小值赋值给targetNode - //targetNode.value = delRightTreeMin(targetNode.right); - targetNode.value = delLeftTreeMax(targetNode.left); - } else { - // 4. 情况三:待删除结点只有一个子结点 - // 4.1 确定targetNode的子结点是左子结点还是右子结点 - // targetNode的子结点是左子结点 - if (targetNode.left != null) { - if (parentNode != null) { - // 4.2 确定targetNode在parentNode上是左子结点还是右子结点 - if (parentNode.left != null && parentNode.left.value == targetNode.value) { - // targetNode在parentNode上是左子结点 - parentNode.left = targetNode.left; - } else { - // targetNode在parentNode上是右子结点 - parentNode.right = targetNode.left; - } - } else { - // targetNode为根结点时,parentNode==null - // root = targetNode.left;即为删除target结点 - root = targetNode.left; - } - } else { - if (parentNode != null) { - //targetNode的子结点是右子结点 - if (parentNode.left != null && parentNode.left.value == targetNode.value) { - // targetNode在parentNode上是左子结点 - parentNode.left = targetNode.right; - } else { - // targetNode在parentNode上是右子结点 - parentNode.right = targetNode.right; - } - } else { - root = targetNode.right; - } - } - - } - - - } - - } - - // 中序 - public void infixOrder() { - if (root == null) { - System.out.println("树空"); - } else { - root.infixOrder(); - } - - } - - // 添加结点 - public void add(Node node) { - if (root == null) { - root = node; - } else { - root.add(node); - } - } - -} - - -class Node { - int value; - Node left; - Node right; - - public Node(int value) { - this.value = value; - } - - /** - * 查找结点 - * - * @param value 结点的value - * @return cn.cn.lastwhisper.tree.binarysorttree.Node - */ - public Node search(int value) { - // 1. 判断当前结点是否是查找的结点 - if (this.value == value) { - return this; - } else if (this.value > value && this.left != null) { - // 2.1 当前结点的value大于value,往左边寻找 - return this.left.search(value); - } else if (this.value < value && this.right != null) { - // 2.2 当前结点的value小于value,往右边寻找 - return this.right.search(value); - } else { - // 3. this.left&&this.right==null,找不到该结点 - return null; - } - } - - // 查找结点的父结点 - public Node searchParent(int value) { - // 1. 判断当前结点是否是查找结点的父结点 - if ((this.left != null && this.left.value == value) || - (this.right != null && this.right.value == value)) { - return this; - } else { - if (this.value > value && this.left != null) { - // 2.1 当前结点的value大于value,往左边寻找 - return this.left.searchParent(value); - } else if (this.value < value && this.right != null) { - // 2.2 当前结点的value小于value,往右边寻找 - return this.right.searchParent(value); - } else { - // 3. this.left&&this.right==null,找不到该结点的父结点 - return null; - } - } - } - - // 中序 - public void infixOrder() { - if (this.left != null) { - this.left.infixOrder(); - } - System.out.println(this); - if (this.right != null) { - this.right.infixOrder(); - } - } - - /** - * 以自身为根结点按规则添加左右子树 - * 规则:对于非叶子结点p,左结点小于p,右结点大于p - * - * @param node - * @return void - */ - public void add(Node node) { - // 1. 如果待添加结点为空直接返回 - if (node == null) { - return; - } - if (this.value > node.value) { - // 2.1 如果根结点大于待添加结点,将待添加结点放到左边 - if (this.left == null) { - this.left = node; - } else { - this.left.add(node); - } - } else { - // 2.2 如果根结点小于待添加结点,将待添加结点放到右边 - if (this.right == null) { - this.right = node; - } else { - this.right.add(node); - } - } - } - - - @Override - public String toString() { - return "Node{" + - "value=" + value + - '}'; - } - -} \ No newline at end of file diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/tree/traversal/Solution.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/tree/traversal/Solution.java deleted file mode 100644 index 0e04f7db..00000000 --- a/algorithms/datastructure/src/main/java/cn/lastwhisper/tree/traversal/Solution.java +++ /dev/null @@ -1,104 +0,0 @@ -package cn.lastwhisper.tree.traversal; - -import java.util.Stack; - -public class Solution { - // 二叉树后序遍历的两种易写的非递归写法 - 我要吃栗子的文章 - 知乎 - //https://zhuanlan.zhihu.com/p/80578741 - public static void main(String[] args) { - TreeNode root = new TreeNode(1); - TreeNode treeNode2 = new TreeNode(2); - TreeNode treeNode3 = new TreeNode(3); - TreeNode treeNode4 = new TreeNode(4); - TreeNode treeNode5 = new TreeNode(5); - root.left = treeNode2; - root.right = treeNode3; - treeNode2.left = treeNode4; - treeNode2.right = treeNode5; - - Solution solution = new Solution(); - //solution.preOrderTraversal(root); - //solution.postOrderTraversal1(root); - solution.postOrderTraversal2(root); - - } - - /** - * 非递归先序遍历,遍历顺序:根左右 - * 需要使用一个栈 - */ - public void preOrderTraversal(TreeNode root) { - Stack s = new Stack<>(); - TreeNode cur = root; - while (cur != null || !s.isEmpty()) { - while (cur != null) { // 经过并访问所有左节点 - System.out.println(cur.val); - s.push(cur); - cur = cur.left; - } - while (!s.isEmpty() && cur == null) cur = s.pop().right; // 自底向上找栈中节点的第一个非空右子树 - } - } - - /** - * 非递归后序遍历,遍历顺序:左右根 - * 使用两个栈 - * 参考非递归先序遍历的“根左右”顺序,使用栈反过来 - */ - public void postOrderTraversal1(TreeNode root) { - Stack s = new Stack<>(); - Stack res = new Stack<>(); // 保存节点序列的栈 - TreeNode cur = root; - while (cur != null || !s.isEmpty()) { - while (cur != null) { - res.push(cur.val); - s.push(cur); - cur = cur.right; // 修改处 - } - if (!s.isEmpty()) { - cur = s.pop(); - cur = cur.left; // 修改处 - } - } - while (!res.isEmpty()) System.out.println(res.pop());// 获取倒序的根右左序列 - } - - /** - * 非递归后序遍历,遍历顺序:左右根 - * 使用一个栈 - */ - public void postOrderTraversal2(TreeNode root) { - Stack s = new Stack<>(); - TreeNode cur = root; - TreeNode pre = null; // 用于记录上一次访问的节点 - while(cur!=null || !s.isEmpty()) { - while(cur!=null) { - s.push(cur); - cur = cur.left; - } - if(!s.isEmpty()) { - cur = s.pop(); - if(cur.right==null || pre==cur.right) { // 访问节点的条件 - System.out.println(cur.val); // 访问 - pre = cur; // 这一步是记录上一次访问的节点 - cur = null; // 此处为了跳过下一次循环的访问左子节点的过程,直接进入栈的弹出阶段,因为但凡在栈中的节点,它们的左子节点都肯定被经过且已放入栈中。 - } - else { // 不访问节点的条件 - s.push(cur); // 将已弹出的根节点放回栈中 - cur = cur.right; // 经过右子节点 - } - } - } - } - -} - -class TreeNode { - int val; - TreeNode left; - TreeNode right; - - TreeNode(int x) { - val = x; - } -} \ No newline at end of file diff --git a/algorithms/datastructure/src/main/java/cn/lastwhisper/util/ArrayUtil.java b/algorithms/datastructure/src/main/java/cn/lastwhisper/util/ArrayUtil.java new file mode 100644 index 00000000..b91dfa7c --- /dev/null +++ b/algorithms/datastructure/src/main/java/cn/lastwhisper/util/ArrayUtil.java @@ -0,0 +1,24 @@ +package cn.lastwhisper.util; + +/** + * @author cn.lastwhisper + */ +public class ArrayUtil { + + public static int[] generateArrByRandom(int max) { + int[] arr = new int[max]; + for (int i = 0; i < max; i++) { + arr[i] = (int) (Math.random() * 8000000); // 生成一个[0,8000000) 的一个数 + } + return arr; + } + + public static int[] generateArrByOrder(int max) { + int[] arr = new int[max]; + for (int i = 0; i < max; i++) { + arr[i] = i + 1; + } + + return arr; + } +} diff --git a/algorithms/datastructure/src/main/java/time/TestString.java b/algorithms/datastructure/src/main/java/time/TestString.java deleted file mode 100644 index f1ee2964..00000000 --- a/algorithms/datastructure/src/main/java/time/TestString.java +++ /dev/null @@ -1,15 +0,0 @@ -package time; - -/** - * @author lastwhisper - */ -public class TestString { - - public void test() { - String s = "a"; - s = s + "b" + "c"; - s = s + "b" + "c" + "d"; - System.out.println(s); - } - -} diff --git a/algorithms/datastructure/src/main/java/time/TimeTest.java b/algorithms/datastructure/src/main/java/time/TimeTest.java deleted file mode 100644 index 369bc8ea..00000000 --- a/algorithms/datastructure/src/main/java/time/TimeTest.java +++ /dev/null @@ -1,30 +0,0 @@ -package time; - -/** - * @author cn.lastwhisper - */ -public class TimeTest { - - public void test1() { - int x = 1; - for (int i = 0; i < 10000; i++) { - x++; - } - } - - public void test2(int n) { - int i = 1; - while (i < n) { - i = i * 2; - } - } - - public void test3(int n) { - //for (i = 0; i < n; i++) { - // for (j = 0; j < i; j++) { - // for (k = 0; k < j; k++) - // x = x + 2; - // } - //} - } -} diff --git "a/algorithms/go/algorithm/leetcode/array/\344\270\244\346\225\260\344\271\213\345\222\214_II_\350\276\223\345\205\245\346\234\211\345\272\217\346\225\260\347\273\204_167_\347\256\200\345\215\225/Solution1.go" "b/algorithms/go/algorithm/leetcode/array/\344\270\244\346\225\260\344\271\213\345\222\214_II_\350\276\223\345\205\245\346\234\211\345\272\217\346\225\260\347\273\204_167_\347\256\200\345\215\225/Solution1.go" new file mode 100644 index 00000000..eb316f9f --- /dev/null +++ "b/algorithms/go/algorithm/leetcode/array/\344\270\244\346\225\260\344\271\213\345\222\214_II_\350\276\223\345\205\245\346\234\211\345\272\217\346\225\260\347\273\204_167_\347\256\200\345\215\225/Solution1.go" @@ -0,0 +1,31 @@ +package main + +import ( + "fmt" +) + +/** + * 题目地址:https://leetcode-cn.com/problems/two-sum-ii-input-array-is-sorted/ + * 编号:167 + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:暴力搜索,找出所有组合进行对比 + * ------------------------------------------------------------------- + * 时间复杂度:O(n^2) + * 空间复杂度:O(1) + */ +func twoSum(numbers []int, target int) []int { + for i := 0; i < len(numbers); i++ { + for j := i + 1; j < len(numbers); j++ { // i + 1 是一个优化点 + if i != j && numbers[i]+numbers[j] == target { + return []int{i + 1, j + 1} + } + } + } + return nil +} + +func main() { + fmt.Println(twoSum([]int{2, 3, 4}, 6)) +} diff --git "a/algorithms/go/algorithm/leetcode/array/\344\270\244\346\225\260\344\271\213\345\222\214_II_\350\276\223\345\205\245\346\234\211\345\272\217\346\225\260\347\273\204_167_\347\256\200\345\215\225/Solution2.go" "b/algorithms/go/algorithm/leetcode/array/\344\270\244\346\225\260\344\271\213\345\222\214_II_\350\276\223\345\205\245\346\234\211\345\272\217\346\225\260\347\273\204_167_\347\256\200\345\215\225/Solution2.go" new file mode 100644 index 00000000..6ad9d169 --- /dev/null +++ "b/algorithms/go/algorithm/leetcode/array/\344\270\244\346\225\260\344\271\213\345\222\214_II_\350\276\223\345\205\245\346\234\211\345\272\217\346\225\260\347\273\204_167_\347\256\200\345\215\225/Solution2.go" @@ -0,0 +1,46 @@ +package main + +import ( + "fmt" +) + +/** + * 题目地址:https://leetcode-cn.com/problems/two-sum-ii-input-array-is-sorted/ + * 编号:167 + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:二分搜索 + * (1)遍历数组,对每一个值 nums[i],在 nums 数组中进行 [i,n] 范围的二分搜索 + * ------------------------------------------------------------------- + * 时间复杂度:O(n*logn) + * 空间复杂度:O(1) + */ +func twoSum(numbers []int, target int) []int { + for i := 0; i < len(numbers); i++ { + j := bs(numbers, i, len(numbers)-1, target-numbers[i]) + if j != -1 { + return []int{i + 1, j + 1} + } + } + return nil +} + +func bs(nums []int, l int, r int, target int) int { + // 这里是“<=”因为 [l,r] 内所有值都是可能的目标 + for l <= r { + mid := (l-r)/2 + r + if nums[mid] == target { + return mid + } else if nums[mid] > target { + r = mid - 1 + } else { + l = mid + 1 + } + } + return -1 +} + +func main() { + fmt.Println(twoSum([]int{2, 3, 4}, 6)) +} diff --git "a/algorithms/go/algorithm/leetcode/array/\344\270\244\346\225\260\344\271\213\345\222\214_II_\350\276\223\345\205\245\346\234\211\345\272\217\346\225\260\347\273\204_167_\347\256\200\345\215\225/Solution3.go" "b/algorithms/go/algorithm/leetcode/array/\344\270\244\346\225\260\344\271\213\345\222\214_II_\350\276\223\345\205\245\346\234\211\345\272\217\346\225\260\347\273\204_167_\347\256\200\345\215\225/Solution3.go" new file mode 100644 index 00000000..f3b51b13 --- /dev/null +++ "b/algorithms/go/algorithm/leetcode/array/\344\270\244\346\225\260\344\271\213\345\222\214_II_\350\276\223\345\205\245\346\234\211\345\272\217\346\225\260\347\273\204_167_\347\256\200\345\215\225/Solution3.go" @@ -0,0 +1,40 @@ +package main + +import ( + "fmt" +) + +/** + * 题目地址:https://leetcode-cn.com/problems/two-sum-ii-input-array-is-sorted/ + * 编号:167 + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:双指针(对撞指针) + * 这种思路的前提是数组有序 + * (1)定义两个初始指针 l,r 分别指向数组头尾。 + * (2)nums[l]+nums[r] > target,r-- + * (3)nums[l]+nums[r] < target,l++ + * (4)nums[l]+nums[r] == target,找到答案 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(1) + */ +func twoSum(numbers []int, target int) []int { + l, r := 0, len(numbers)-1 + // 这里不能等于,因为 index1 必须小于 index2 + for l < r { + if numbers[l]+numbers[r] == target { + return []int{l + 1, r + 1} + } else if numbers[l]+numbers[r] < target { + l++ + } else { + r-- + } + } + return nil +} + +func main() { + fmt.Println(twoSum([]int{2, 3, 4}, 6)) +} diff --git "a/algorithms/go/algorithm/leetcode/array/\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262_344_\347\256\200\345\215\225/Solution1.go" "b/algorithms/go/algorithm/leetcode/array/\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262_344_\347\256\200\345\215\225/Solution1.go" new file mode 100644 index 00000000..e8e1d727 --- /dev/null +++ "b/algorithms/go/algorithm/leetcode/array/\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262_344_\347\256\200\345\215\225/Solution1.go" @@ -0,0 +1,34 @@ +package main + +import ( + "fmt" +) + +/** + * 题目地址:https://leetcode-cn.com/problems/reverse-string/ + * 编号:344 + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:对撞指针交换元素 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(1) + */ +func reverseString(s []byte) { + l, r := 0, len(s)-1 + for l < r { + c := s[l] + s[l] = s[r] + s[r] = c + l++ + r-- + } +} + +func main() { + s := []byte{'h', 'e', 'l', 'l', 'o'} + fmt.Println(s) + reverseString(s) + fmt.Println(s) +} diff --git "a/algorithms/go/algorithm/leetcode/array/\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262\344\270\255\347\232\204\345\205\203\351\237\263\345\255\227\346\257\215_345_\347\256\200\345\215\225/Solution1.go" "b/algorithms/go/algorithm/leetcode/array/\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262\344\270\255\347\232\204\345\205\203\351\237\263\345\255\227\346\257\215_345_\347\256\200\345\215\225/Solution1.go" new file mode 100644 index 00000000..5df7b3ea --- /dev/null +++ "b/algorithms/go/algorithm/leetcode/array/\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262\344\270\255\347\232\204\345\205\203\351\237\263\345\255\227\346\257\215_345_\347\256\200\345\215\225/Solution1.go" @@ -0,0 +1,49 @@ +package main + +import ( + "fmt" +) + +/** + * 题目地址:https://leetcode-cn.com/problems/reverse-vowels-of-a-string/ + * 编号:345 + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:对撞指针条件交换元素 + * 元音字母:a,e,i,o,u 大小写 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(n) + */ +func reverseVowels(s string) string { + l, r := 0, len(s)-1 + chars := []uint8(s) + for l < r { + for l < r && !valid(chars[l]) { + l++ + } + for l < r && !valid(chars[r]) { + r-- + } + if l < r { // 需要判断 + c := chars[l] + chars[l] = chars[r] + chars[r] = c + l++ + r-- + } + } + return string(chars) +} + +func valid(c uint8) bool { + return c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u' || c == 'A' || + c == 'E' || c == 'I' || c == 'O' || c == 'U' +} + +func main() { + s := "hello" + fmt.Println(s) + fmt.Println(reverseVowels(s)) +} diff --git "a/algorithms/go/algorithm/leetcode/array/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\346\225\260\347\273\204_88_\347\256\200\345\215\225/Solution1.go" "b/algorithms/go/algorithm/leetcode/array/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\346\225\260\347\273\204_88_\347\256\200\345\215\225/Solution1.go" new file mode 100644 index 00000000..19048a82 --- /dev/null +++ "b/algorithms/go/algorithm/leetcode/array/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\346\225\260\347\273\204_88_\347\256\200\345\215\225/Solution1.go" @@ -0,0 +1,60 @@ +package main + +import "fmt" + +/** + * 题目地址:https://leetcode-cn.com/problems/merge-sorted-array/ + * 编号:88 + * ------------------------------------------------------------------- + * 思考: + * 数据特征:数组有序 + * ------------------------------------------------------------------- + * 思路: + * 归并排序,归的过程。 + * (1)从前到后比较(找小)复制只用 nums1,需要移动 nums1 中的元素,不如创建中间数据 + * (2)从后到前比较(找大)复制只用 nums1,无需移动 nums1 中的元素 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(n) + */ +func merge(nums1 []int, m int, nums2 []int, n int) { + temp := make([]int, m+n) + // p1 是 num1 已拷贝数据的指针,[0,p1] + p1, p2, t := 0, 0, 0 + // 从前到后找 num1 或 num2 最小的复制到 temp + for p1 < m && p2 < n { + if nums1[p1] > nums2[p2] { + temp[t] = nums2[p2] + p2++ + } else { + temp[t] = nums1[p1] + p1++ + } + t++ + } + // 将 num1 中剩余的数据 copy 到 temp + for p1 < m { + temp[t] = nums1[p1] + t++ + p1++ + } + // 将 num2 中剩余的数据 copy 到 temp + for p2 < n { + temp[t] = nums2[p2] + t++ + p2++ + } + // 将 temp 中所有数据 copy 到 num1 + for i := 0; i < len(temp); i++ { + nums1[i] = temp[i] + } +} + +func main() { + nums1 := []int{1, 2, 3, 0, 0, 0} + nums2 := []int{2, 5, 6} + m := 3 + n := 3 + merge(nums1, m, nums2, n) + fmt.Println(nums1) +} diff --git "a/algorithms/go/algorithm/leetcode/array/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\346\225\260\347\273\204_88_\347\256\200\345\215\225/Solution2.go" "b/algorithms/go/algorithm/leetcode/array/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\346\225\260\347\273\204_88_\347\256\200\345\215\225/Solution2.go" new file mode 100644 index 00000000..c0d54a69 --- /dev/null +++ "b/algorithms/go/algorithm/leetcode/array/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\346\225\260\347\273\204_88_\347\256\200\345\215\225/Solution2.go" @@ -0,0 +1,47 @@ +package main + +import "fmt" + +/** + * 题目地址:https://leetcode-cn.com/problems/merge-sorted-array/ + * 编号:88 + * ------------------------------------------------------------------- + * 思考: + * 数据特征:数组有序 + * ------------------------------------------------------------------- + * 思路: + * 从后向前复制 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(1) + */ +func merge(nums1 []int, m int, nums2 []int, n int) { + // 从后到前找 num1 或 num2 最大的复制到 num1 末尾 + p1, p2, end := m-1, n-1, m+n-1 + for p1 >= 0 && p2 >= 0 { + if nums1[p1] > nums2[p2] { + nums1[end] = nums1[p1] + p1-- + } else { + nums1[end] = nums2[p2] + p2-- + } + end-- + } + // 如果 num1 还没复制完,不用管,因为num1自身就是有序的 + // 将 num2 中剩余的数据 copy 到 temp + for p2 >= 0 { + nums1[end] = nums2[p2] + end-- + p2-- + } +} + +func main() { + nums1 := []int{1, 2, 3, 0, 0, 0} + nums2 := []int{2, 5, 6} + m := 3 + n := 3 + merge(nums1, m, nums2, n) + fmt.Println(nums1) +} diff --git "a/algorithms/go/algorithm/leetcode/array/\346\225\260\347\273\204\344\270\255\347\232\204\347\254\254K\344\270\252\346\234\200\345\244\247\345\205\203\347\264\240_215_\344\270\255\347\255\211/Solution1.go" "b/algorithms/go/algorithm/leetcode/array/\346\225\260\347\273\204\344\270\255\347\232\204\347\254\254K\344\270\252\346\234\200\345\244\247\345\205\203\347\264\240_215_\344\270\255\347\255\211/Solution1.go" new file mode 100644 index 00000000..6620e6b9 --- /dev/null +++ "b/algorithms/go/algorithm/leetcode/array/\346\225\260\347\273\204\344\270\255\347\232\204\347\254\254K\344\270\252\346\234\200\345\244\247\345\205\203\347\264\240_215_\344\270\255\347\255\211/Solution1.go" @@ -0,0 +1,12 @@ +package main + +import "sort" + +func findKthLargest(nums []int, k int) int { + sort.Ints(nums) + return nums[len(nums)-k] +} + +func main() { + +} diff --git "a/algorithms/go/algorithm/leetcode/array/\346\227\240\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262_3_\344\270\255\347\255\211/Solution1.go" "b/algorithms/go/algorithm/leetcode/array/\346\227\240\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262_3_\344\270\255\347\255\211/Solution1.go" new file mode 100644 index 00000000..eb157e31 --- /dev/null +++ "b/algorithms/go/algorithm/leetcode/array/\346\227\240\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262_3_\344\270\255\347\255\211/Solution1.go" @@ -0,0 +1,51 @@ +package main + +import ( + "fmt" +) + +/** + * 题目地址:https://leetcode-cn.com/problems/minimum-size-subarray-sum/ + * 编号:209 + * ------------------------------------------------------------------- + * 思考:边界值一定要考虑取还是不取,为什么? + * ------------------------------------------------------------------- + * 思路:滑动窗口 + * (1)双指针 l、r 维护一个滑动窗口 + * (2)窗口的左边界在数组范围内,则循环继续 + * (3)r未到数组尾且 sums 需要动态缩小窗口左边界 + * (5)循环内每次找 sum >= s 时的最小长度 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) // l 和 r 指针同时遍历了一遍数组 O(2n) + * 空间复杂度:O(1) + */ +func lengthOfLongestSubstring(s string) int { + freq := make([]uint8, 256) + // 窗口 [l,r] 内无重复元素 + l, r, res := 0, 0, 0 + for l < len(s) { + if r < len(s) && freq[s[r]] == 0 { + freq[s[r]]++ + r++ + } else { + freq[s[l]]-- + l++ + } + // 这里 r - l 不加一,因为 l、r 初始化值都是0,并且是先用在加的 + res = max(res, r-l) + } + return res +} + +func max(x int, y int) int { + if x > y { + return x + } + return y +} + +func main() { + s := "abcabcbb" + fmt.Println(lengthOfLongestSubstring(s)) +} diff --git "a/algorithms/go/algorithm/leetcode/array/\347\233\233\346\234\200\345\244\232\346\260\264\347\232\204\345\256\271\345\231\250_11_\344\270\255\347\255\211/Solution1.go" "b/algorithms/go/algorithm/leetcode/array/\347\233\233\346\234\200\345\244\232\346\260\264\347\232\204\345\256\271\345\231\250_11_\344\270\255\347\255\211/Solution1.go" new file mode 100644 index 00000000..c67ee938 --- /dev/null +++ "b/algorithms/go/algorithm/leetcode/array/\347\233\233\346\234\200\345\244\232\346\260\264\347\232\204\345\256\271\345\231\250_11_\344\270\255\347\255\211/Solution1.go" @@ -0,0 +1,36 @@ +package main + +import ( + "fmt" + "math" +) + +/** + * 题目地址:https://leetcode-cn.com/problems/container-with-most-water/ + * 编号:11 + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:双指针(对撞指针) + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(1) + */ +func maxArea(height []int) int { + l, r, max := 0, len(height)-1, float64(-1) + for l < r { + if height[l] < height[r] { + max = math.Max(max, float64(height[l]*(r-l))) + l++ + } else { + max = math.Max(max, float64(height[r]*(r-l))) + r-- + } + } + return int(max) +} + +func main() { + nums := []int{1, 8, 6, 2, 5, 4, 8, 3, 7} + fmt.Println(maxArea(nums)) +} diff --git "a/algorithms/go/algorithm/leetcode/array/\351\225\277\345\272\246\346\234\200\345\260\217\347\232\204\345\255\220\346\225\260\347\273\204_209_\344\270\255\347\255\211/Solution1.go" "b/algorithms/go/algorithm/leetcode/array/\351\225\277\345\272\246\346\234\200\345\260\217\347\232\204\345\255\220\346\225\260\347\273\204_209_\344\270\255\347\255\211/Solution1.go" new file mode 100644 index 00000000..7b603a86 --- /dev/null +++ "b/algorithms/go/algorithm/leetcode/array/\351\225\277\345\272\246\346\234\200\345\260\217\347\232\204\345\255\220\346\225\260\347\273\204_209_\344\270\255\347\255\211/Solution1.go" @@ -0,0 +1,60 @@ +package main + +import ( + "fmt" + "math" +) + +/** + * 题目地址:https://leetcode-cn.com/problems/minimum-size-subarray-sum/ + * 编号:209 + * ------------------------------------------------------------------- + * 思考:边界值一定要考虑取还是不取,为什么? + * ------------------------------------------------------------------- + * 思路:滑动窗口 + * (1)双指针 l、r 维护一个滑动窗口 + * (2)窗口的左边界在数组范围内,则循环继续 + * (3)r未到数组尾且 sums 需要动态缩小窗口左边界 + * (5)循环内每次找 sum >= s 时的最小长度 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) // l 和 r 指针同时遍历了一遍数组 O(2n) + * 空间复杂度:O(1) + */ +func minSubArrayLen(s int, nums []int) int { + // 滑动窗口[l,r] + l, r := 0, -1 + // 窗口和 + sum, result := 0, math.MaxInt64 + // 窗口左边界未越界,说明窗口还可以继续扩容或者缩小 + for l < len(nums) { + // sum= s { + result = min(result, r-l+1) + } + } + if result == math.MaxInt64 { + return 0 + } + return result +} + +func min(x int, y int) int { + if x > y { + return y + } + return x +} + +func main() { + s := 7 + nums := []int{2, 3, 1, 2, 4, 3} + fmt.Println(minSubArrayLen(s, nums)) +} diff --git "a/algorithms/go/algorithm/leetcode/array/\351\225\277\345\272\246\346\234\200\345\260\217\347\232\204\345\255\220\346\225\260\347\273\204_209_\344\270\255\347\255\211/Solution2.go" "b/algorithms/go/algorithm/leetcode/array/\351\225\277\345\272\246\346\234\200\345\260\217\347\232\204\345\255\220\346\225\260\347\273\204_209_\344\270\255\347\255\211/Solution2.go" new file mode 100644 index 00000000..5e234415 --- /dev/null +++ "b/algorithms/go/algorithm/leetcode/array/\351\225\277\345\272\246\346\234\200\345\260\217\347\232\204\345\255\220\346\225\260\347\273\204_209_\344\270\255\347\255\211/Solution2.go" @@ -0,0 +1,54 @@ +package main + +import ( + "fmt" + "math" +) + +/** + * 题目地址:https://leetcode-cn.com/problems/minimum-size-subarray-sum/ + * 编号:209 + * ------------------------------------------------------------------- + * 思考:边界值一定要考虑取还是不取,为什么? + * ------------------------------------------------------------------- + * 思路:滑动窗口 + * (1)双指针 l、r 维护一个滑动窗口 + * (2)窗口的左边界在数组范围内,则循环继续 + * (3)r未到数组尾且 sums 需要动态缩小窗口左边界 + * (5)循环内每次找 sum >= s 时的最小长度 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) // l 和 r 指针同时遍历了一遍数组 O(2n) + * 空间复杂度:O(1) + */ +func minSubArrayLen(s int, nums []int) int { + // 窗口和 + l, sum, result := 0, 0, math.MaxInt64 + // 一直扩容右边界,直到sum >= s,缩小左边界 + // 每次缩小,都计算最小子数组 + for r := 0; r < len(nums); r++ { + sum += nums[r] + for sum >= s { + result = min(result, r-l+1) + sum -= nums[l] + l++ + } + } + if result == math.MaxInt64 { + return 0 + } + return result +} + +func min(x int, y int) int { + if x > y { + return y + } + return x +} + +func main() { + s := 7 + nums := []int{2, 3, 1, 2, 4, 3} + fmt.Println(minSubArrayLen(s, nums)) +} diff --git "a/algorithms/go/algorithm/leetcode/array/\351\242\234\350\211\262\345\210\206\347\261\273_75_\344\270\255\347\255\211/Solution1.go" "b/algorithms/go/algorithm/leetcode/array/\351\242\234\350\211\262\345\210\206\347\261\273_75_\344\270\255\347\255\211/Solution1.go" new file mode 100644 index 00000000..51d91b90 --- /dev/null +++ "b/algorithms/go/algorithm/leetcode/array/\351\242\234\350\211\262\345\210\206\347\261\273_75_\344\270\255\347\255\211/Solution1.go" @@ -0,0 +1,37 @@ +package main + +import "fmt" + +/** + * 题目地址:https://leetcode-cn.com/problems/sort-colors/ + * 编号:75 + * ------------------------------------------------------------------- + * 思考: + * 数据特征:只有0,1,2 + * ------------------------------------------------------------------- + * 思路: + * 计数排序,统计每一个数出现的频率 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(1) + */ +func sortColors(nums []int) { + freq := [3]int{} + for i := 0; i < len(nums); i++ { + freq[nums[i]]++ + } + idx := 0 + for i := 0; i < len(freq); i++ { + for freq[i] > 0 { + nums[idx] = i + idx++ + freq[i]-- + } + } +} + +func main() { + var arr = []int{2, 0, 2, 1, 1, 0} + sortColors(arr) + fmt.Println(arr) +} diff --git "a/algorithms/go/algorithm/leetcode/array/\351\242\234\350\211\262\345\210\206\347\261\273_75_\344\270\255\347\255\211/Solution2.go" "b/algorithms/go/algorithm/leetcode/array/\351\242\234\350\211\262\345\210\206\347\261\273_75_\344\270\255\347\255\211/Solution2.go" new file mode 100644 index 00000000..cc952a6d --- /dev/null +++ "b/algorithms/go/algorithm/leetcode/array/\351\242\234\350\211\262\345\210\206\347\261\273_75_\344\270\255\347\255\211/Solution2.go" @@ -0,0 +1,51 @@ +package main + +import "fmt" + +/** + * 题目地址:https://leetcode-cn.com/problems/sort-colors/ + * 编号:75 + * ------------------------------------------------------------------- + * 思考: + * 数据特征:只有0,1,2 + * ------------------------------------------------------------------- + * 思路: + * 三路快速排序的思想,对整个数组只遍历了一遍 + * (1)双指针 left=-1,right=n + * (2)下标 i 遍历数组,num[i]==1,i++ + * (3)num[i]==0,将 0 移动到数组最前位置,swap(num,++left,i++) + * i++,即使 num[++left]==0,这次的交换和位移也是正确的 + * (4)num[i]==2,将 2 移动到数组最后位置,swap(num,--right,i) + * i不变,因为有可能num[--right]==2 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(1) + */ +func sortColors(nums []int) { + left := -1 + right := len(nums) + for i := 0; i < right; { + if nums[i] == 1 { + i++ + } else if nums[i] == 0 { + left++ + swap(nums, left, i) + i++ + } else if nums[i] == 2 { + right-- + swap(nums, right, i) + } + } +} + +func swap(nums []int, i, j int) { + temp := nums[i] + nums[i] = nums[j] + nums[j] = temp +} + +func main() { + var arr = []int{2, 0, 2, 1, 1, 0} + sortColors(arr) + fmt.Println(arr) +} diff --git "a/algorithms/go/algorithm/leetcode/array/\351\252\214\350\257\201\345\233\236\346\226\207\344\270\262_125_Easy/Solution1.go" "b/algorithms/go/algorithm/leetcode/array/\351\252\214\350\257\201\345\233\236\346\226\207\344\270\262_125_Easy/Solution1.go" new file mode 100644 index 00000000..e8d5b633 --- /dev/null +++ "b/algorithms/go/algorithm/leetcode/array/\351\252\214\350\257\201\345\233\236\346\226\207\344\270\262_125_Easy/Solution1.go" @@ -0,0 +1,45 @@ +package main + +import ( + "fmt" + "strings" +) + +/** + * 题目地址:https://leetcode-cn.com/problems/valid-palindrome/ + * 编号:125 + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * 对撞指针遍历比较 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(n) + */ +func isPalindrome(s string) bool { + upperS := strings.ToUpper(s) + l, r := 0, len(s)-1 + for l < r { + for l < r && !valid(upperS[l]) { + l++ + } + for l < r && !valid(upperS[r]) { + r-- + } + if upperS[l] != upperS[r] { + return false + } + l++ + r-- + } + return true +} + +func valid(c uint8) bool { + return (c >= 48 && c <= 57) || (c >= 65 && c <= 90) || (c >= 97 && c <= 122) +} + +func main() { + fmt.Println(isPalindrome("A man, a plan, a canal: Panama")) +} diff --git "a/algorithms/go/algorithm/leetcode/array/\351\252\214\350\257\201\345\233\236\346\226\207\344\270\262_125_Easy/Solution2.go" "b/algorithms/go/algorithm/leetcode/array/\351\252\214\350\257\201\345\233\236\346\226\207\344\270\262_125_Easy/Solution2.go" new file mode 100644 index 00000000..5aebc977 --- /dev/null +++ "b/algorithms/go/algorithm/leetcode/array/\351\252\214\350\257\201\345\233\236\346\226\207\344\270\262_125_Easy/Solution2.go" @@ -0,0 +1,45 @@ +package main + +import ( + "fmt" +) + +/** + * 题目地址:https://leetcode-cn.com/problems/valid-palindrome/ + * 编号:125 + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * 对撞指针遍历比较 + * 统一转成大写:ch & 0b11011111 简写:ch & 0xDF + * 统一转成小写:ch | 0b00100000 简写:ch | 0x20 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(1) + */ +func isPalindrome(s string) bool { + l, r := 0, len(s)-1 + for l < r { // 这里不能等于 + for l < r && !valid(s[l]) { + l++ + } + for l < r && !valid(s[r]) { + r-- + } + if (s[l] & 0xDF) != (s[r] & 0xDF) { + return false + } + l++ + r-- + } + return true +} + +func valid(c uint8) bool { + return (c >= 48 && c <= 57) || (c >= 65 && c <= 90) || (c >= 97 && c <= 122) +} + +func main() { + fmt.Println(isPalindrome("A man, a plan, a canal: Panama")) +} diff --git a/algorithms/go/algorithm/leetcode/lc69.go b/algorithms/go/algorithm/leetcode/lc69.go new file mode 100644 index 00000000..33b59de5 --- /dev/null +++ b/algorithms/go/algorithm/leetcode/lc69.go @@ -0,0 +1,15 @@ +package main + +import "fmt" + +func mySqrt(x int) int { + + + return 0 +} + +func main() { + fmt.Println(mySqrt(4)) + fmt.Println(mySqrt(8)) +} + diff --git a/algorithms/interview/pom.xml b/algorithms/interview/pom.xml index 495dea29..9d4710bc 100644 --- a/algorithms/interview/pom.xml +++ b/algorithms/interview/pom.xml @@ -3,13 +3,12 @@ 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"> - argorithms + algorithms cn.lastwhisper 1.0-SNAPSHOT 4.0.0 - cn.lastwhisper interview diff --git a/algorithms/interview/src/main/java/Main.java b/algorithms/interview/src/main/java/Main.java index aa3d3c30..a89bcd4c 100644 --- a/algorithms/interview/src/main/java/Main.java +++ b/algorithms/interview/src/main/java/Main.java @@ -1,3 +1,4 @@ +import java.util.Arrays; import java.util.HashSet; import java.util.Scanner; @@ -24,13 +25,11 @@ public static void main(String[] args) { 如果没有该行,则执行第一个in.nextLine()命令时的返回值是int n = in.nextInt()的值*/ sc.nextLine(); - HashSet set = new HashSet(); + HashSet set = new HashSet<>(); for (int i = 0; i < n; i++) { String line =sc.nextLine(); String[] arr = line.split(" "); - for (int j = 0; j < arr.length; j++) { - set.add(arr[j]); - } + set.addAll(Arrays.asList(arr)); } System.out.println("sum:" + set.size()); } diff --git "a/algorithms/interview/src/main/java/cn/lastwhisper/interview/dp/\346\225\264\346\225\260\347\232\204\345\210\206\350\247\243/Solution.java" "b/algorithms/interview/src/main/java/cn/lastwhisper/interview/dp/\346\225\264\346\225\260\347\232\204\345\210\206\350\247\243/Solution.java" deleted file mode 100644 index 2b61598c..00000000 --- "a/algorithms/interview/src/main/java/cn/lastwhisper/interview/dp/\346\225\264\346\225\260\347\232\204\345\210\206\350\247\243/Solution.java" +++ /dev/null @@ -1,45 +0,0 @@ -package cn.lastwhisper.interview.dp.整数的分解; - -public class Solution -{ - public static void main(String[] args) - { - int[] nums = {3,4,5,6,7}; - for (int num : nums) { - System.out.println(num + "\t(" + decompose(num)+ ") 种"); - } - } - - // 求整数的分数情况 - public static int decompose(int num) { - if (num < 3) return 0; - - // 从3开始,构建二维数组 - int[][] results = new int[num+1][]; - for (int i = 3; i <= num; i++) { - // 分解后最小数可能的种数 - int cols = (i-1)/2; - results[i] = new int[cols+1]; - results[i][0] = 0; - for (int j = 1; j <= cols; j++) { - // 对于最小为j的情况,至少有一个分解 - int count = 1; - int biger = i - j; - if (biger > 2*j) { - // 若大数为偶数,可以分解为biger/2 + biger/2 - if (biger % 2 == 0) count++; - // 其余的分解可用biger的分解中最小数j的情况确定 - for (int k = j; k < results[biger].length; k++) - count += results[biger][k]; - } - results[i][j] = count; - } - } - - int total = 0; - // 第num行所有的和为分解的所有情况 - for (int i = 0; i < results[num].length; i++) - total += results[num][i]; - return total; - } -} \ No newline at end of file diff --git a/algorithms/interview/src/main/java/cn/lastwhisper/interview/lejian/Test1.java b/algorithms/interview/src/main/java/cn/lastwhisper/interview/lejian/Test1.java new file mode 100644 index 00000000..8d64005c --- /dev/null +++ b/algorithms/interview/src/main/java/cn/lastwhisper/interview/lejian/Test1.java @@ -0,0 +1,113 @@ +package cn.lastwhisper.interview.lejian; + +import java.util.HashSet; +import java.util.Set; +import java.util.regex.Pattern; + +/** + * 最长对称子序列,本质上是在找最长公共子序列 + * + * @author gaojun + * + */ +public class Test1 { + + /** + * 输入一个字符串s,我们可以删除字符串s中的任意字符,让剩下的字符串形成一个对称字符串,且该字符串为最长对称字符串。 + * 如:输入google,则找到最长对称字符串为goog; + * 如:输入abcda则能找到3个最长对称字符串为aba/aca/ada。 + * 若最长对称字符串存在多个,则输出多个相同长度的最长对称字符串,且字符串中不包含特殊字符。 + * + */ + public static void main(String[] args) { + // TODO 输出最长对称字符串:goog + String input1 = "google"; + System.out.println(findMaxSymmetry(input1)); + // TODO 输出3个最长对称字符串:aba/aca/ada + String input2 = "abcda"; + System.out.println(findMaxSymmetry(input2)); + // TODO 输出2个最长对称字符串:pop/upu,不会输出特殊字符的对称字符串p-p + String input3 = "pop-upu"; + System.out.println(findMaxSymmetry(input3)); + } + + /** + * 遍历生成的二维数组,递归查找最长路径 + * @param a 第一个字符串 + * @param b 第二个字符串 + * @param mux 二维中间数组 + * @param i 二维数组raw位置 + * @param j 二维数组column位置 + * @param path 一次查找的字符串 + * @param paths 最终结果集合 + */ + private static void getAllLcs(String a, String b, int[][] mux, int i, int j, String path, Set paths) { + StringBuilder pathBuilder = new StringBuilder(path); + while (i > 0 && j > 0) { + if (a.charAt(i - 1) == b.charAt(j - 1)) { + pathBuilder.append(a.charAt(i - 1)); + --i; + --j; + } else { + if (mux[i - 1][j] > mux[i][j - 1]) { + --i; + } else if (mux[i - 1][j] < mux[i][j - 1]) { + --j; + } else { + getAllLcs(a, b, mux, i - 1, j, pathBuilder.toString(), paths); + getAllLcs(a, b, mux, i, j - 1, pathBuilder.toString(), paths); + return; + } + } + } + paths.add(pathBuilder.toString()); + } + + /** + * 查找最大公共子序列 + */ + private static String findLCS(String input) { + if (input == null || input.length() == 0) { + return ""; + } + String reverse = new StringBuilder(input).reverse().toString(); + int len = input.length(); + // 0行0列分别表示空串和input、reverse的 lcs 长度 + // 初始状态 + int[][] dp = new int[len + 1][len + 1]; + + for (int i = 1; i < len + 1; i++) { + for (int j = 1; j < len + 1; j++) { + if (input.charAt(i - 1) == reverse.charAt(j - 1)) { + // 找到一个 lcs 的元素 + dp[i][j] = dp[i - 1][j - 1] + 1; + } else { + // 找 lcs 长度最长的。 + dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]); + } + } + } + + // 查找路径时,存在多个路径是一个字符串的情况,set去重。 + Set paths = new HashSet<>(); + getAllLcs(input, reverse, dp, input.length(), reverse.length(), "", paths); + + return String.join("/", paths); + } + + /** + * 包括对特殊字符,结果格式生成 + * @param input 待处理字符串 + */ + public static String findMaxSymmetry(String input) { + String[] prepare = Pattern.compile("[^a-zA-Z0-9]").split(input); + StringBuilder sb = new StringBuilder(); + for (String str : prepare) { + String result = findLCS(str); + sb.append(result); + sb.append("/"); + } + return sb.substring(0, sb.length() - 1); + } + +} \ No newline at end of file diff --git a/algorithms/interview/src/main/java/cn/lastwhisper/interview/list/CountZero.java b/algorithms/interview/src/main/java/cn/lastwhisper/interview/list/CountZero.java deleted file mode 100644 index b9869365..00000000 --- a/algorithms/interview/src/main/java/cn/lastwhisper/interview/list/CountZero.java +++ /dev/null @@ -1,8 +0,0 @@ -package cn.lastwhisper.interview.list; - -/** - * @author lastwhisper - */ -public class CountZero { - -} diff --git a/algorithms/interview/src/main/java/cn/lastwhisper/interview/tangshang/perblom1/Main.java b/algorithms/interview/src/main/java/cn/lastwhisper/interview/tangshang/perblom1/Main.java deleted file mode 100644 index 9861d72e..00000000 --- a/algorithms/interview/src/main/java/cn/lastwhisper/interview/tangshang/perblom1/Main.java +++ /dev/null @@ -1,31 +0,0 @@ -package cn.lastwhisper.interview.tangshang.perblom1; - -import java.util.*; - -/** - * @author lastwhisper - */ -public class Main { - - public static void main(String[] args) { - Scanner in = new Scanner(System.in); - int n = in.nextInt(); - int m = in.nextInt(); - System.out.println(move(n, m)); - } - - public static int move(int n, int m) { - - int count = 0; - if (n == 1 || m == 1) { - return 1; - } - if (n > 1) { - count += move(n - 1, m); - } - if (m > 1) { - count += move(n, m - 1); - } - return count; - } -} diff --git a/algorithms/interview/src/main/java/cn/lastwhisper/interview/tangshang/perblom2/Main.java b/algorithms/interview/src/main/java/cn/lastwhisper/interview/tangshang/perblom2/Main.java deleted file mode 100644 index 496bab8e..00000000 --- a/algorithms/interview/src/main/java/cn/lastwhisper/interview/tangshang/perblom2/Main.java +++ /dev/null @@ -1,36 +0,0 @@ -package cn.lastwhisper.interview.tangshang.perblom2; - -import java.util.Scanner; - -/** - * @author lastwhisper - */ -public class Main { - public static void main(String[] args) { - Scanner in = new Scanner(System.in); - int n = in.nextInt(); - int[] arr = new int[n]; - for (int i = 0; i < n; i++) { - arr[i] = in.nextInt(); - } - int max = arr[0]; - int piovt = 0; - while (piovt < n) { - int sum = 0; - for (int i = piovt; i < n; i++) { - sum += arr[i]; - if (max < sum) { - max = sum; - } - } - for (int i = 0; i < piovt; i++) { - sum += arr[i]; - if (max < sum) { - max = sum; - } - } - piovt++; - } - System.out.println(max); - } -} diff --git a/algorithms/interview/src/main/java/cn/lastwhisper/interview/tangshang/perblom3/Main.java b/algorithms/interview/src/main/java/cn/lastwhisper/interview/tangshang/perblom3/Main.java deleted file mode 100644 index 1bce9f56..00000000 --- a/algorithms/interview/src/main/java/cn/lastwhisper/interview/tangshang/perblom3/Main.java +++ /dev/null @@ -1,38 +0,0 @@ -package cn.lastwhisper.interview.tangshang.perblom3; - -import java.util.Scanner; - -/** - * @author lastwhisper - */ -public class Main { - - public static void main(String[] args) { - Scanner in = new Scanner(System.in); - Long n = in.nextLong(); - Long x = in.nextLong(); - for (Long i = n - x >= 10 ? n - x : 10; i < n; i++) { - String ret = convert(n, i); - if (Long.parseLong(ret) <= x) { - System.out.println(i); //进制 - break; - } - } - - } - - - public static String convert(Long decimal, Long radix) { - StringBuilder sb = new StringBuilder(); - // 余数 - Long remainder = -1l; - // 被除数 - Long divisor = decimal; - while (divisor != 0 && divisor / radix >= 0) { - remainder = divisor % radix; //取余 - divisor = divisor / radix; // 整除 - sb.append(remainder); - } - return sb.reverse().toString(); - } -} diff --git a/algorithms/interview/src/main/java/cn/lastwhisper/interview/tangshang/perblom3/Main1.java b/algorithms/interview/src/main/java/cn/lastwhisper/interview/tangshang/perblom3/Main1.java deleted file mode 100644 index 644b2dad..00000000 --- a/algorithms/interview/src/main/java/cn/lastwhisper/interview/tangshang/perblom3/Main1.java +++ /dev/null @@ -1,16 +0,0 @@ -package cn.lastwhisper.interview.tangshang.perblom3; - -import java.util.Scanner; - -/** - * @author lastwhisper - */ -public class Main1 { - public static void main(String[] args) { - Scanner in = new Scanner(System.in); - int n = in.nextInt(); - int x = in.nextInt(); - String xStr = String.valueOf(x); - System.out.println(n - Integer.parseInt(xStr.substring(xStr.length() - 1))); - } -} diff --git a/algorithms/interview/src/main/java/cn/lastwhisper/interview/wangyi/perblom1/Main.java b/algorithms/interview/src/main/java/cn/lastwhisper/interview/wangyi/perblom1/Main.java deleted file mode 100644 index 3f5b6178..00000000 --- a/algorithms/interview/src/main/java/cn/lastwhisper/interview/wangyi/perblom1/Main.java +++ /dev/null @@ -1,35 +0,0 @@ -package cn.lastwhisper.interview.wangyi.perblom1; - -import java.util.Scanner; - -/** - * - * @author lastwhisper - */ -public class Main { - public static void main(String[] args) { - Scanner sc = new Scanner(System.in); - int n = sc.nextInt(); - int[] arr = new int[n]; - for (int i = 0; i < n; i++) { - arr[i] = sc.nextInt(); - } - for (int i = 0; i < n; i++) { - System.out.println(min(arr[i])); - } - } - - public static String min(int x) { - int n9 = x / 9; // 5 - int a = x % 9; // 余数 - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < n9; i++) { - sb.append("9"); - } - if (a != 0) { - sb.append(a); - } - return sb.reverse().toString(); - } - -} diff --git a/algorithms/interview/src/main/java/cn/lastwhisper/interview/wangyi/problom2/Main.java b/algorithms/interview/src/main/java/cn/lastwhisper/interview/wangyi/problom2/Main.java deleted file mode 100644 index 714205e3..00000000 --- a/algorithms/interview/src/main/java/cn/lastwhisper/interview/wangyi/problom2/Main.java +++ /dev/null @@ -1,33 +0,0 @@ -package cn.lastwhisper.interview.wangyi.problom2; - -import java.util.Scanner; - -/** - * @author lastwhisper - */ -public class Main { - - public static void main(String[] args) { - Scanner sc = new Scanner(System.in); - int n = sc.nextInt(); - for (int i = 0; i < n; i++) { - int a = sc.nextInt(); - int b = sc.nextInt(); - int p = sc.nextInt(); - int q = sc.nextInt(); - int count = 1; - while (a+p < b) { - int temp1 = a + p; - int temp2 = a + p * q; - if (temp1 > temp2) { - a = a + p; - } else { - p = p * q; - } - count++; - } - System.out.println(count); - } - } - -} diff --git a/algorithms/interview/src/main/java/cn/lastwhisper/interview/wangyi/problom4/Main.java b/algorithms/interview/src/main/java/cn/lastwhisper/interview/wangyi/problom4/Main.java deleted file mode 100644 index 40a65726..00000000 --- a/algorithms/interview/src/main/java/cn/lastwhisper/interview/wangyi/problom4/Main.java +++ /dev/null @@ -1,29 +0,0 @@ -package cn.lastwhisper.interview.wangyi.problom4; - -import java.util.HashMap; -import java.util.Map; -import java.util.Scanner; - -/** - * @author lastwhisper - */ -public class Main { - public static void main(String[] args) { - Scanner sc = new Scanner(System.in); - int n = sc.nextInt(); - int[] arr = new int[n]; - for (int i = 0; i < n; i++) { - arr[i] = sc.nextInt(); - } - int count = 0; - for (int i = 0; i < n; i++) { - for (int j = i+1; j < n; j++) { - if (arr[i] > arr[j]) { - count+=j-i; - } - } - } - System.out.println(count); - } - -} diff --git "a/algorithms/interview/src/main/java/cn/lastwhisper/interview/\347\276\216\345\233\242\347\202\271\350\257\204/\345\220\210\345\271\266\351\207\221\345\270\201/Test01.java" "b/algorithms/interview/src/main/java/cn/lastwhisper/interview/\347\276\216\345\233\242\347\202\271\350\257\204/\345\220\210\345\271\266\351\207\221\345\270\201/Test01.java" new file mode 100644 index 00000000..28c442e5 --- /dev/null +++ "b/algorithms/interview/src/main/java/cn/lastwhisper/interview/\347\276\216\345\233\242\347\202\271\350\257\204/\345\220\210\345\271\266\351\207\221\345\270\201/Test01.java" @@ -0,0 +1,56 @@ +package cn.lastwhisper.interview.美团点评.合并金币; + + +import java.util.Scanner; + +public class Test01 { + /** + * 有 N 堆金币排成一排,第 i 堆中有 C[i]块金币。 每次合并都会将相邻的两堆金币合并为一堆,成本为这两堆金币块数之和。 + * 经过N-1次合并,最终将所有金币合并为一堆。请找出将金币合并为一堆的最低成本。 + * + * 比如,n=3时表示共有3堆金币,每堆重量分别是2、1、9. + * 一种合并方案是2和9合并,新堆重量是11,消耗体力为11; + * 接着11和1合并,新堆重量是12,消耗体力为12,因此总消耗体力是11+12=23。 + * 另一种方案是:1和2合并,新堆重量是3,消耗体力为3; + * 接着3和9合并,新堆重量是12,消耗体力为12,因此总消耗体力是3+12=15。可以证明这就是最少消耗体力。 + * + * 其中,1 <= N <= 30,1 <= C[i] <= 100 + * + * f[i,j]=min{f[i,k]+f[k+1,j]+sum[i,j]|i<=k 0) + dp[i][i + l] = min + sum[i + l] - sum[i - 1]; + else dp[i][i + l] = min + sum[l]; + } + } + System.out.println(dp[0][n - 1]); + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + System.out.print(dp[i][j] + " "); + } + System.out.println(); + } + } +} \ No newline at end of file diff --git a/algorithms/leetcode/array/pom.xml b/algorithms/leetcode/array/pom.xml index d86e8f28..6689d525 100644 --- a/algorithms/leetcode/array/pom.xml +++ b/algorithms/leetcode/array/pom.xml @@ -13,4 +13,13 @@ array + + + algorithm-common + cn.lastwhisper + 1.0-SNAPSHOT + + + + \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\344\270\244\346\225\260\344\271\213\345\222\214_II_\350\276\223\345\205\245\346\234\211\345\272\217\346\225\260\347\273\204_167_\347\256\200\345\215\225/Solution1.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\344\270\244\346\225\260\344\271\213\345\222\214_II_\350\276\223\345\205\245\346\234\211\345\272\217\346\225\260\347\273\204_167_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..3114b286 --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\344\270\244\346\225\260\344\271\213\345\222\214_II_\350\276\223\345\205\245\346\234\211\345\272\217\346\225\260\347\273\204_167_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,34 @@ +package cn.lastwhisper.leetcode.array.两数之和_II_输入有序数组_167_简单; + +import org.junit.Assert; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/two-sum-ii-input-array-is-sorted/ + * 编号:167 + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:暴力搜索,找出所有组合进行对比 + * ------------------------------------------------------------------- + * 时间复杂度:O(n^2) + * 空间复杂度:O(1) + */ + public int[] twoSum(int[] numbers, int target) { + if (numbers == null || numbers.length < 2) { + throw new IllegalArgumentException("Illegal argument numbers"); + } + for (int i = 0; i < numbers.length; i++) { + for (int j = i + 1; j < numbers.length; j++) {// i + 1 是一个优化点 + if (i != j && numbers[i] + numbers[j] == target) { + return new int[]{i + 1, j + 1}; + } + } + } + throw new IllegalStateException("No results found"); + } + + public static void main(String[] args) { + Assert.assertArrayEquals(new int[]{1, 2}, new Solution1().twoSum(new int[]{2, 7, 11, 15}, 9)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\344\270\244\346\225\260\344\271\213\345\222\214_II_\350\276\223\345\205\245\346\234\211\345\272\217\346\225\260\347\273\204_167_\347\256\200\345\215\225/Solution2.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\344\270\244\346\225\260\344\271\213\345\222\214_II_\350\276\223\345\205\245\346\234\211\345\272\217\346\225\260\347\273\204_167_\347\256\200\345\215\225/Solution2.java" new file mode 100644 index 00000000..d6b0e31b --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\344\270\244\346\225\260\344\271\213\345\222\214_II_\350\276\223\345\205\245\346\234\211\345\272\217\346\225\260\347\273\204_167_\347\256\200\345\215\225/Solution2.java" @@ -0,0 +1,57 @@ +package cn.lastwhisper.leetcode.array.两数之和_II_输入有序数组_167_简单; + +import org.junit.Assert; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/two-sum-ii-input-array-is-sorted/ + * 编号:167 + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:二分搜索 + * (1)遍历数组,对每一个值 nums[i],在 nums 数组中进行 [i,n] 范围的二分搜索 + * ------------------------------------------------------------------- + * 时间复杂度:O(n*logn) + * 空间复杂度:O(1) + */ + public int[] twoSum(int[] numbers, int target) { + if (numbers == null || numbers.length < 2) { + throw new IllegalArgumentException("Illegal argument numbers"); + } + for (int i = 0; i < numbers.length; i++) { + int j = bs(numbers, i, numbers.length - 1, target - numbers[i]); + if (j != -1) { + return new int[]{i + 1, j + 1}; + } + } + throw new IllegalStateException("No results found"); + } + + /** + * @param nums 待搜索数组 + * @param l 起始索引 + * @param r 终止索引 + * @param target 目标数值 + * @return int 目标数值在数组中的索引 + */ + private int bs(int[] nums, int l, int r, int target) { + // 这里是“<=”因为 [l,r] 内所有值都是可能的目标 + while (l <= r) { + int mid = (l - r) / 2 + r; + if (nums[mid] == target) { + return mid; + } else if (nums[mid] > target) { + r = mid - 1; + } else { + l = mid + 1; + } + } + return -1; + } + + public static void main(String[] args) { + //Assert.assertArrayEquals(new int[]{1, 2}, new Solution2().twoSum(new int[]{2, 7, 11, 15}, 9)); + Assert.assertArrayEquals(new int[]{1, 3}, new Solution2().twoSum(new int[]{2, 3, 4}, 6)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\344\270\244\346\225\260\344\271\213\345\222\214_II_\350\276\223\345\205\245\346\234\211\345\272\217\346\225\260\347\273\204_167_\347\256\200\345\215\225/Solution3.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\344\270\244\346\225\260\344\271\213\345\222\214_II_\350\276\223\345\205\245\346\234\211\345\272\217\346\225\260\347\273\204_167_\347\256\200\345\215\225/Solution3.java" new file mode 100644 index 00000000..3cb95cf3 --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\344\270\244\346\225\260\344\271\213\345\222\214_II_\350\276\223\345\205\245\346\234\211\345\272\217\346\225\260\347\273\204_167_\347\256\200\345\215\225/Solution3.java" @@ -0,0 +1,43 @@ +package cn.lastwhisper.leetcode.array.两数之和_II_输入有序数组_167_简单; + +import org.junit.Assert; + +class Solution3 { + /** + * 题目地址:https://leetcode-cn.com/problems/two-sum-ii-input-array-is-sorted/ + * 编号:167 + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:双指针(对撞指针) + * 这种思路的前提是数组有序 + * (1)定义两个初始指针 l,r 分别指向数组头尾。 + * (2)nums[l]+nums[r] > target,r-- + * (3)nums[l]+nums[r] < target,l++ + * (4)nums[l]+nums[r] == target,找到答案 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(1) + */ + public int[] twoSum(int[] numbers, int target) { + if (numbers == null || numbers.length < 2) { + throw new IllegalArgumentException("Illegal argument numbers"); + } + int l = 0, r = numbers.length - 1; + // 这里不能等于,因为 index1 必须小于 index2 + while (l < r) { + if (numbers[l] + numbers[r] == target) { + return new int[]{l + 1, r + 1}; + } else if (numbers[l] + numbers[r] < target) { + l++; + } else { + r--; + } + } + throw new IllegalStateException("No results found"); + } + + public static void main(String[] args) { + Assert.assertArrayEquals(new int[]{1, 3}, new Solution3().twoSum(new int[]{2, 3, 4}, 6)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\344\275\277\346\225\260\347\273\204\345\224\257\344\270\200\347\232\204\346\234\200\345\260\217\345\242\236\351\207\217_945_\344\270\255\347\255\211/Solution1.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\344\275\277\346\225\260\347\273\204\345\224\257\344\270\200\347\232\204\346\234\200\345\260\217\345\242\236\351\207\217_945_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..42c50331 --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\344\275\277\346\225\260\347\273\204\345\224\257\344\270\200\347\232\204\346\234\200\345\260\217\345\242\236\351\207\217_945_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,25 @@ +package cn.lastwhisper.leetcode.array.使数组唯一的最小增量_945_中等; + +import org.junit.Assert; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/minimum-increment-to-make-array-unique/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public int minIncrementForUnique(int[] A) { + + return 0; + } + + public static void main(String[] args) { + Assert.assertEquals(6, new Solution1().minIncrementForUnique(new int[]{3, 2, 1, 2, 1, 7})); + } + +} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\205\266\344\273\226/\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271_26_Easy/Solution1.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\205\266\344\273\226/\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271_26_Easy/Solution1.java" deleted file mode 100644 index 2a60a1ba..00000000 --- "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\205\266\344\273\226/\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271_26_Easy/Solution1.java" +++ /dev/null @@ -1,32 +0,0 @@ -package cn.lastwhisper.leetcode.array.其他.删除排序数组中的重复项_26_Easy; - - -import java.util.Arrays; - -public class Solution1 { - public int removeDuplicates(int[] nums) { - if (nums == null || nums.length == 0) { - return 0; - } - int len = nums.length; - // 区间[0,...,pos]均为第一次出现元素 - int pos = 0; - // nums[0]肯定是第一次出现,所以i从1开始 - for (int i = 1; i < len; i++) { - // 如果第一(pos)个元素与第二(i)个元素不等(以此类推),说明是第一次出现。 - if (nums[pos] != nums[i]) { - pos++; - nums[pos] = nums[i]; - } - } - return pos + 1; - } - //以下为测试代码 - public static void main(String[] args) { - int[] arr = {0,0,1,1,2,3,4,4}; - System.out.println("原数组长度:" + arr.length); - int length = new Solution1().removeDuplicates(arr); - System.out.println("现数组长度:" + length); - System.out.println(Arrays.toString(arr)); - } -} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\205\266\344\273\226/\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271_26_Easy/Solution2.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\205\266\344\273\226/\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271_26_Easy/Solution2.java" deleted file mode 100644 index 2486d811..00000000 --- "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\205\266\344\273\226/\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271_26_Easy/Solution2.java" +++ /dev/null @@ -1,33 +0,0 @@ -package cn.lastwhisper.leetcode.array.其他.删除排序数组中的重复项_26_Easy; - - -import java.util.Arrays; - -public class Solution2 { - - public int removeDuplicates(int[] nums) { - if (nums == null || nums.length == 0) { - return 0; - } - // 区间[0,...,pos]均为第一次出现元素 - int pos = 0; - // 数字可出现的次数 - int frequency = 1; - for (int n : nums) { - if (pos < frequency || n > nums[pos - frequency]) { - nums[pos++] = n; - } - } - return pos; - } - - //以下为测试代码 - public static void main(String[] args) { - int[] arr = {0, 0, 1, 1, 2, 3, 4, 4, 4, 4, 4}; - System.out.println("原数组长度:" + arr.length); - int length = new Solution2().removeDuplicates(arr); - System.out.println("现数组长度:" + length); - System.out.println(Arrays.toString(arr)); - } - -} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\205\266\344\273\226/\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271_II_80_Medium/Solution1.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\205\266\344\273\226/\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271_II_80_Medium/Solution1.java" deleted file mode 100644 index 6463cdb6..00000000 --- "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\205\266\344\273\226/\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271_II_80_Medium/Solution1.java" +++ /dev/null @@ -1,35 +0,0 @@ -package cn.lastwhisper.leetcode.array.其他.删除排序数组中的重复项_II_80_Medium; - -public class Solution1 { - public int removeDuplicates(int[] nums) { - if (nums == null || nums.length == 0) { - return 0; - } - // 区间[0,...,pos]每个元素最多出现两次 - int pos = 0; - // 数字可出现的次数 - int frequency = 2; - for (int n : nums) { - if (pos < frequency || n > nums[pos - frequency]) { - nums[pos++] = n; - } - } - return pos; - } - - //以下为测试代码 - public static void main(String[] args) { - int[] arr = {0, 0, 1, 1, 1, 1, 2, 3, 3}; - System.out.println("原数组长度:" + arr.length); - int length = new Solution1().removeDuplicates(arr); - System.out.println("现数组长度:" + length); - for (int i = 0; i < length; i++) { - if (i != length - 1) { - System.out.print(arr[i] + ","); - } else { - System.out.print(arr[i]); - } - } - } - -} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\205\266\344\273\226/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\346\225\260\347\273\204_88_Easy/Solution1.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\205\266\344\273\226/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\346\225\260\347\273\204_88_Easy/Solution1.java" deleted file mode 100644 index 37e1a1e9..00000000 --- "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\205\266\344\273\226/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\346\225\260\347\273\204_88_Easy/Solution1.java" +++ /dev/null @@ -1,50 +0,0 @@ -package cn.lastwhisper.leetcode.array.其他.合并两个有序数组_88_Easy; - -import java.util.Arrays; - -class Solution1 { - /** - * https://leetcode-cn.com/problems/merge-sorted-array/ - * 合并两个有序数组 - * 核心思路:归并排序,并的算法思路 - */ - public void merge(int[] nums1, int m, int[] nums2, int n) { - if (nums1 == null|| nums1.length == 0 || nums2 == null ) { - return; - } - int[] temp = new int[m + n]; - int p0 = 0, p1 = 0, index = 0; - while (p0 < m && p1 < n) { - int num1 = nums1[p0]; - int num2 = nums2[p1]; - if (num1 <= num2) { - temp[index++] = num1; - p0++; - } else { - temp[index++] = num2; - p1++; - } - } - while (p0 < m) { - temp[index++] = nums1[p0]; - p0++; - } - while (p1 < n) { - temp[index++] = nums2[p1]; - p1++; - } - - for (int i = 0; i < temp.length; i++) { - nums1[i] = temp[i]; - } - - } - - public static void main(String[] args) { - int[] nums1 = {1, 2, 3, 0, 0, 0}; - int[] nums2 = {2, 5, 6}; - new Solution1().merge(nums1, 3, nums2, 3); - System.out.println(Arrays.toString(nums1)); - } - -} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\205\266\344\273\226/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\346\225\260\347\273\204_88_Easy/Solution2.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\205\266\344\273\226/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\346\225\260\347\273\204_88_Easy/Solution2.java" deleted file mode 100644 index 66d1aaf7..00000000 --- "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\205\266\344\273\226/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\346\225\260\347\273\204_88_Easy/Solution2.java" +++ /dev/null @@ -1,35 +0,0 @@ -package cn.lastwhisper.leetcode.array.其他.合并两个有序数组_88_Easy; - -import java.util.Arrays; - -class Solution2 { - /** - * https://leetcode-cn.com/problems/merge-sorted-array/ - * 核心思想:从后向前合并,不需要额外的空间 - * - */ - public void merge(int[] nums1, int m, int[] nums2, int n) { - if (nums1 == null || nums1.length == 0 || nums2 == null) { - return; - } - int p = m-- + n-- - 1;// num1和num2合并后的空间大小 - while (m >= 0 && n >= 0) { - nums1[p--] = nums1[m] > nums2[n] ? nums1[m--] : nums2[n--]; - } - // 如果nums1还没合并完,num2合并完了 - // 此时不用管,因为num1自身就是有序的,同时num1还是容器 - // 如果nums1合并完了,num2还没合并完 - while (n > 0) { - nums1[p--] = nums2[n--]; - } - - } - - public static void main(String[] args) { - int[] nums1 = {1, 2, 3, 0, 0, 0}; - int[] nums2 = {2, 5, 6}; - new Solution2().merge(nums1, 3, nums2, 3); - System.out.println(Arrays.toString(nums1)); - } - -} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\205\266\344\273\226/\346\225\260\347\273\204\344\270\255\347\232\204\347\254\254K\344\270\252\346\234\200\345\244\247\345\205\203\347\264\240_215_Medium/Solution1.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\205\266\344\273\226/\346\225\260\347\273\204\344\270\255\347\232\204\347\254\254K\344\270\252\346\234\200\345\244\247\345\205\203\347\264\240_215_Medium/Solution1.java" deleted file mode 100644 index 359ca757..00000000 --- "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\205\266\344\273\226/\346\225\260\347\273\204\344\270\255\347\232\204\347\254\254K\344\270\252\346\234\200\345\244\247\345\205\203\347\264\240_215_Medium/Solution1.java" +++ /dev/null @@ -1,47 +0,0 @@ -package cn.lastwhisper.leetcode.array.其他.数组中的第K个最大元素_215_Medium; - -class Solution1 { - /** - * 利用快排partition思想,将pivot放置在了其正确的位置上的性质 - */ - public int findKthLargest(int[] nums, int k) { - return partition(nums, 0, nums.length - 1, nums.length - k); - } - - public int partition(int[] nums, int leftBound, int rightBound, int k) { - int left = leftBound; - int right = rightBound; - int pivot = nums[leftBound]; - while (left < right) { - while (left < right && nums[left] <= pivot) { - left++; - } - while (left < right && nums[right] > pivot) { - right--; - } - if (left < right) { - swap(nums, left, right); - } - } - if (left == k) { - return pivot; - } else if (left > k) { - return partition(nums, leftBound, left - 1, k); - } else { - return partition(nums, left + 1, rightBound, k); - } - } - - public void swap(int[] arr, int i, int j) { - int temp = arr[j]; - arr[j] = arr[i]; - arr[i] = temp; - } - - public static void main(String[] args) { - int[] arr = {3, 2, 3, 1, 2, 4, 5, 5, 6}; - int k = 4; - int kthLargest = new Solution1().findKthLargest(arr, k); - System.out.println(kthLargest); - } -} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\205\266\344\273\226/\346\225\260\347\273\204\344\270\255\347\232\204\347\254\254K\344\270\252\346\234\200\345\244\247\345\205\203\347\264\240_215_Medium/Solution2.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\205\266\344\273\226/\346\225\260\347\273\204\344\270\255\347\232\204\347\254\254K\344\270\252\346\234\200\345\244\247\345\205\203\347\264\240_215_Medium/Solution2.java" deleted file mode 100644 index b5e481a7..00000000 --- "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\205\266\344\273\226/\346\225\260\347\273\204\344\270\255\347\232\204\347\254\254K\344\270\252\346\234\200\345\244\247\345\205\203\347\264\240_215_Medium/Solution2.java" +++ /dev/null @@ -1,36 +0,0 @@ -package cn.lastwhisper.leetcode.array.其他.数组中的第K个最大元素_215_Medium; - -class Solution2 { - /** - * 利用堆排序思想 - * O(n)桶排思想 - */ - public int findKthLargest(int[] nums, int k) { - int max = Integer.MIN_VALUE, min = Integer.MAX_VALUE; - for (int i : nums) { - max = Math.max(max, i); - min = Math.min(min, i); - } - int n = max - min; - int[] bucket = new int[n + 1]; - for (int i = 0; i < nums.length; i++) { - int tmp = nums[i] - min; - bucket[tmp]++; - } - for (int i = n; i >= 0; i--) { - if (bucket[i] > 0) - k -= bucket[i]; - if (k <= 0) - return i + min; - } - return 0; - } - - - public static void main(String[] args) { - int[] arr = {3, 2, 3, 1, 2, 4, 5, 5, 6}; - int k = 4; - int kthLargest = new Solution2().findKthLargest(arr, k); - System.out.println(kthLargest); - } -} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\205\266\344\273\226/\346\234\211\346\225\210\347\232\204\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215_242_Easy/Solution1.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\205\266\344\273\226/\346\234\211\346\225\210\347\232\204\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215_242_Easy/Solution1.java" deleted file mode 100644 index abd8f159..00000000 --- "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\205\266\344\273\226/\346\234\211\346\225\210\347\232\204\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215_242_Easy/Solution1.java" +++ /dev/null @@ -1,43 +0,0 @@ -package cn.lastwhisper.leetcode.array.其他.有效的字母异位词_242_Easy; - -import java.util.HashMap; -import java.util.Map; - -class Solution1 { - public boolean isAnagram(String s, String t) { - char[] sChar = s.toCharArray(); - char[] tChar = t.toCharArray(); - HashMap map = new HashMap<>(); - for (int i = 0; i < sChar.length; i++) { - Integer num = map.get(sChar[i]); - if (num == null) { - map.put(sChar[i], 1); - } else { - map.put(sChar[i], ++num); - } - } - - for (int i = 0; i < tChar.length; i++) { - Integer num = map.get(tChar[i]); - if (num == null) { - return false; - } else { - map.put(tChar[i], --num); - } - } - for (Map.Entry entry : map.entrySet()) { - if (entry.getValue() != 0) { - return false; - } - } - return true; - } - - public static void main(String[] args) { - //String s = "anagram", t = "nagaram"; - String s = "rat", t = "car"; - - System.out.println(new Solution1().isAnagram(s, t)); - } - -} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\205\266\344\273\226/\346\234\211\346\225\210\347\232\204\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215_242_Easy/Solution2.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\205\266\344\273\226/\346\234\211\346\225\210\347\232\204\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215_242_Easy/Solution2.java" deleted file mode 100644 index efe5b09d..00000000 --- "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\205\266\344\273\226/\346\234\211\346\225\210\347\232\204\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215_242_Easy/Solution2.java" +++ /dev/null @@ -1,39 +0,0 @@ -package cn.lastwhisper.leetcode.array.其他.有效的字母异位词_242_Easy; - -class Solution2 { - /** - * https://leetcode-cn.com/problems/valid-anagram/submissions/ - * hash - * 时间复杂度:O(n) - * 空间复杂度:O(1) - */ - public boolean isAnagram(String s, String t) { - if (s.length() != t.length()) { - return false; - } - char[] sChar = s.toCharArray(); - char[] tChar = t.toCharArray(); - byte[] freq = new byte[256]; - for (int i = 0; i < sChar.length; i++) { - freq[sChar[i]]++; - } - - for (int i = 0; i < tChar.length; i++) { - freq[tChar[i]]--; - } - for (int i = 0; i < freq.length; i++) { - if (freq[i] != 0) { - return false; - } - } - return true; - } - - public static void main(String[] args) { - String s = "anagram", t = "nagaram"; - //String s = "rat", t = "car"; - - System.out.println(new Solution2().isAnagram(s, t)); - } - -} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\205\266\344\273\226/\347\247\273\345\212\250\351\233\266_283_Easy/Solution1.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\205\266\344\273\226/\347\247\273\345\212\250\351\233\266_283_Easy/Solution1.java" deleted file mode 100644 index c5624e60..00000000 --- "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\205\266\344\273\226/\347\247\273\345\212\250\351\233\266_283_Easy/Solution1.java" +++ /dev/null @@ -1,34 +0,0 @@ -package cn.lastwhisper.leetcode.array.其他.移动零_283_Easy; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -public class Solution1 { - //时间复杂度:O(n) - //空间复杂度:O(n) - public void moveZeroes(int[] nums) { - // 缓存非0元素 - List nonZeroElements = new ArrayList(); - // 找出非0元素并将它缓存进nonZeroElements - for (int i = 0; i < nums.length; i++) { - if (nums[i] != 0) { - nonZeroElements.add(nums[i]); - } - } - // 将非0元素放入原数组中 - for (int i = 0; i < nonZeroElements.size(); i++) { - nums[i] = nonZeroElements.get(i); - } - // 将原数组剩余的位置放置为0 - for (int i = nonZeroElements.size(); i < nums.length; i++) { - nums[i] = 0; - } - } - //以下为测试代码 - public static void main(String[] args) { - int[] arr = {0, 1, 0, 3, 12}; - new Solution1().moveZeroes(arr); - System.out.println(Arrays.toString(arr)); - } -} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\205\266\344\273\226/\347\247\273\345\212\250\351\233\266_283_Easy/Solution2.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\205\266\344\273\226/\347\247\273\345\212\250\351\233\266_283_Easy/Solution2.java" deleted file mode 100644 index d7910c5a..00000000 --- "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\205\266\344\273\226/\347\247\273\345\212\250\351\233\266_283_Easy/Solution2.java" +++ /dev/null @@ -1,29 +0,0 @@ -package cn.lastwhisper.leetcode.array.其他.移动零_283_Easy; - - -import java.util.Arrays; - -public class Solution2 { - public void moveZeroes(int[] nums) { - // k保证从[0,...,k)均为非零元素 - int k = 0; - // 遍历到第i个元素后,保证[0,...,i]中所有非零元素, - // 都按顺序排列在[0,...,k)中 - for (int i = 0; i < nums.length; i++) { - if (nums[i] != 0) { - nums[k] = nums[i]; - k++; - } - } - // 同时保证[k,...,nums.length]中均为零元素 - for (int i = k; i < nums.length; i++) { - nums[i] = 0; - } - } - //以下为测试代码 - public static void main(String[] args) { - int[] arr = {0, 1, 0, 3, 12}; - new Solution2().moveZeroes(arr); - System.out.println(Arrays.toString(arr)); - } -} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\205\266\344\273\226/\347\247\273\345\212\250\351\233\266_283_Easy/Solution3.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\205\266\344\273\226/\347\247\273\345\212\250\351\233\266_283_Easy/Solution3.java" deleted file mode 100644 index 944a5029..00000000 --- "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\205\266\344\273\226/\347\247\273\345\212\250\351\233\266_283_Easy/Solution3.java" +++ /dev/null @@ -1,34 +0,0 @@ -package cn.lastwhisper.leetcode.array.其他.移动零_283_Easy; - - -import java.util.Arrays; - -public class Solution3 { - public void moveZeroes(int[] nums) { - // k保证从[0,...,k)均为非零元素 - int k = 0; - // temp用于交换时暂存数据 - int temp = 0; - // 遍历到第i个元素后,保证[0,...,i]中所有非零元素,都按顺序排列在[0,...,k)中 - // 同时保证[k,...,i]中均为零元素 - for (int i = 0; i < nums.length; i++) { - if (nums[i] != 0) { - // 防止全为非零元素 - if (i != k) { - temp = nums[k]; - nums[k] = nums[i]; - nums[i] = temp; - k++; - } else { - k++; - } - } - } - } - //以下为测试代码 - public static void main(String[] args) { - int[] arr = {0, 1, 0, 3, 12}; - new Solution3().moveZeroes(arr); - System.out.println(Arrays.toString(arr)); - } -} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\205\266\344\273\226/\347\247\273\351\231\244\345\205\203\347\264\240_27_Easy/Solution1.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\205\266\344\273\226/\347\247\273\351\231\244\345\205\203\347\264\240_27_Easy/Solution1.java" deleted file mode 100644 index bfcb01ae..00000000 --- "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\205\266\344\273\226/\347\247\273\351\231\244\345\205\203\347\264\240_27_Easy/Solution1.java" +++ /dev/null @@ -1,31 +0,0 @@ -package cn.lastwhisper.leetcode.array.其他.移除元素_27_Easy; - -import java.util.Arrays; - -public class Solution1 { - public int removeElement(int[] nums, int val) { - if (nums == null || nums.length == 0) { - return 0; - } - int len = nums.length; - // 区间[0,...,pos)均为不等于val的元素 - int pos = 0; - // nums中不等于val的值,按顺序移动到nums数组的前面。 - for (int i = 0; i < len; i++) { - if (nums[i] != val) { - nums[pos] = nums[i]; - pos++; - } - } - return pos; - } - - //以下为测试代码 - public static void main(String[] args) { - int[] arr = {0, 1, 2, 2, 3, 0, 4, 2}; - System.out.println("原数组长度:" + arr.length); - int length = new Solution1().removeElement(arr, 2); - System.out.println("现数组长度:" + length); - System.out.println(Arrays.toString(arr)); - } -} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\205\266\344\273\226/\351\242\234\350\211\262\345\210\206\347\261\273_75_Medium/Solution1.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\205\266\344\273\226/\351\242\234\350\211\262\345\210\206\347\261\273_75_Medium/Solution1.java" deleted file mode 100644 index f2d148ee..00000000 --- "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\205\266\344\273\226/\351\242\234\350\211\262\345\210\206\347\261\273_75_Medium/Solution1.java" +++ /dev/null @@ -1,57 +0,0 @@ -package cn.lastwhisper.leetcode.array.其他.颜色分类_75_Medium; - -import java.util.Arrays; - -public class Solution1 { - - /** - * 题目:https://leetcode-cn.com/problems/sort-colors/ - * 计数排序 - * 核心思想:统计每一个数出现的频率 - * 时间复杂度:O(n) - * 时间复杂度:O(1) - */ - public void sortColors(int[] nums) { - if (nums == null || nums.length == 0) { - return; - } - int[] count = new int[3]; - for (int i = 0; i < nums.length; i++) { - count[nums[i]]++; - } - - for (int i = 0; i < count[0]; i++) { - nums[i] = 0; - } - for (int i = count[0]; i < count[0] + count[1]; i++) { - nums[i] = 1; - } - for (int i = count[0] + count[1]; i < count[0] + count[1] + count[2]; i++) { - nums[i] = 2; - } - } - - // 优化 - public void sortColors1(int[] nums) { - if (nums == null || nums.length == 0) { - return; - } - int[] count = new int[3]; - for (int i = 0; i < nums.length; i++) { - count[nums[i]]++; - } - int index = 0; - for (int i = 0; i < 3; i++) { - int itemCount = count[i]; - while (itemCount-- > 0) { - nums[index++] = i; - } - } - } - - public static void main(String[] args) { - int[] arr = {2, 0, 2, 1, 1, 0}; - new Solution1().sortColors(arr); - System.out.println(Arrays.toString(arr)); - } -} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\205\266\344\273\226/\351\242\234\350\211\262\345\210\206\347\261\273_75_Medium/Solution2.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\205\266\344\273\226/\351\242\234\350\211\262\345\210\206\347\261\273_75_Medium/Solution2.java" deleted file mode 100644 index 7ea3427d..00000000 --- "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\205\266\344\273\226/\351\242\234\350\211\262\345\210\206\347\261\273_75_Medium/Solution2.java" +++ /dev/null @@ -1,45 +0,0 @@ -package cn.lastwhisper.leetcode.array.其他.颜色分类_75_Medium; - -import java.util.Arrays; - -/** - * @author lastwhisper - */ -public class Solution2 { - - /** - * 题目:https://leetcode-cn.com/problems/sort-colors/ - * 三路快速排序的思想,对整个数组只遍历了一遍 - * 时间复杂度: O(n) - * 空间复杂度: O(1) - */ - public void sortColors(int[] nums) { - if (nums == null || nums.length == 0) { - return; - } - int zero = 0, two = nums.length; - for (int i = 0; i < two; ) { // 小于two与i不加相对应 - int num = nums[i]; - if (num == 1) { - i++; - } else if (num == 0) { - swap(nums, zero++, i++); - } else if (num == 2) { - swap(nums, --two, i);// i不加 - } - } - } - - public void swap(int[] arr, int i, int j) { - int temp = arr[j]; - arr[j] = arr[i]; - arr[i] = temp; - } - - public static void main(String[] args) { - int[] arr = {2, 0, 2, 1, 1, 0}; - new Solution2().sortColors(arr); - System.out.println(Arrays.toString(arr)); - } - -} diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271_26_\347\256\200\345\215\225/Solution1.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271_26_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..3dab2b3b --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271_26_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,41 @@ +package cn.lastwhisper.leetcode.array.删除排序数组中的重复项_26_简单; + + +import org.junit.Assert; + +public class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array/ + * 编号:26 + * ------------------------------------------------------------------- + * 思考: + * 数据特征:从小到大有序 + * ------------------------------------------------------------------- + * 思路: + * 双指针 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(1) + */ + public int removeDuplicates(int[] nums) { + // 特判 + if (nums == null || nums.length == 0) { + return 0; + } + // 区间[0,...,pos]均为第一次出现元素 + int pos = 0; + + for (int i = 1; i < nums.length; i++) { + if (nums[pos] != nums[i]) { + nums[++pos] = nums[i]; + } + } + return pos + 1; + } + + //以下为测试代码 + public static void main(String[] args) { + int[] nums = {0, 0, 1, 1, 2, 3, 4, 4}; + Assert.assertEquals(5, new Solution1().removeDuplicates(nums)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271_26_\347\256\200\345\215\225/Solution2.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271_26_\347\256\200\345\215\225/Solution2.java" new file mode 100644 index 00000000..8e1ec9fb --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271_26_\347\256\200\345\215\225/Solution2.java" @@ -0,0 +1,30 @@ +package cn.lastwhisper.leetcode.array.删除排序数组中的重复项_26_简单; + + +import org.junit.Assert; + +public class Solution2 { + + public int removeDuplicates(int[] nums) { + if (nums == null || nums.length == 0) { + return 0; + } + // 区间[0,...,pos]均为第一次出现元素 + int pos = 0; + // 数字可出现的次数 + int frequency = 1; + for (int n : nums) { + if (pos < frequency || n > nums[pos - frequency]) { + nums[pos++] = n; + } + } + return pos; + } + + //以下为测试代码 + public static void main(String[] args) { + int[] nums = {0, 0, 1, 1, 2, 3, 4, 4}; + Assert.assertEquals(5, new Solution2().removeDuplicates(nums)); + } + +} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271_II_80_\344\270\255\347\255\211/Solution1.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271_II_80_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..d8382336 --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271_II_80_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,40 @@ +package cn.lastwhisper.leetcode.array.删除排序数组中的重复项_II_80_中等; + +import org.junit.Assert; + +public class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array-ii/ + * 编号:80 + * ------------------------------------------------------------------- + * 思考: + * 数据特征:从小到大有序 + * ------------------------------------------------------------------- + * 思路: + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(1) + */ + public int removeDuplicates(int[] nums) { + if (nums == null || nums.length == 0) { + return 0; + } + // 区间[0,...,pos]每个元素最多出现两次 + int pos = 0; + // 数字可出现的次数 + int frequency = 2; + for (int num : nums) { + if (pos < frequency || num > nums[pos - frequency]) { + nums[pos++] = num; + } + } + return pos; + } + + //以下为测试代码 + public static void main(String[] args) { + int[] nums = {0, 0, 1, 1, 1, 1, 2, 3, 3}; + Assert.assertEquals(7, new Solution1().removeDuplicates(nums)); + } + +} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271_II_80_\344\270\255\347\255\211/Solution2.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271_II_80_\344\270\255\347\255\211/Solution2.java" new file mode 100644 index 00000000..0d8258b5 --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271_II_80_\344\270\255\347\255\211/Solution2.java" @@ -0,0 +1,49 @@ +package cn.lastwhisper.leetcode.array.删除排序数组中的重复项_II_80_中等; + +import org.junit.Assert; + +public class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array-ii/ + * 编号:80 + * ------------------------------------------------------------------- + * 思考: + * 数据特征:从小到大有序 + * ------------------------------------------------------------------- + * 思路: + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(1) + */ + public int removeDuplicates(int[] nums) { + // Initialize the counter and the second pointer. + int j = 1, count = 1; + + // Start from the second element of the array and process + // elements one by one. + for (int i = 1; i < nums.length; i++) { + + // If the current element is a duplicate, increment the count. + if (nums[i] == nums[i - 1]) { + count++; + } else { + // Reset the count since we encountered a different element + // than the previous one. + count = 1; + } + // For a count <= 2, we copy the element over thus + // overwriting the element at index "j" in the array + if (count <= 2) { + nums[j++] = nums[i]; + } + } + return j; + } + + //以下为测试代码 + public static void main(String[] args) { + int[] nums = {0, 0, 1, 1, 1, 1, 2, 3, 3}; + Assert.assertEquals(7, new Solution2().removeDuplicates(nums)); + } + +} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\214\272\351\227\264\345\220\210\345\271\266/\347\237\251\345\275\242\351\207\215\345\217\240_836_\347\256\200\345\215\225/Solution1.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\214\272\351\227\264\345\220\210\345\271\266/\347\237\251\345\275\242\351\207\215\345\217\240_836_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..3a74c52d --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\214\272\351\227\264\345\220\210\345\271\266/\347\237\251\345\275\242\351\207\215\345\217\240_836_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,30 @@ +package cn.lastwhisper.leetcode.array.区间合并.矩形重叠_836_简单; + +import org.junit.Assert; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/rectangle-overlap/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * 两个矩阵的重叠是无限的,但是不重叠是有限的 + * 检查位置 + * ------------------------------------------------------------------- + * 时间复杂度:O(1) + * 空间复杂度:O(1) + */ + public boolean isRectangleOverlap(int[] rec1, int[] rec2) { + // 矩阵投影X轴,矩阵1在矩阵2左侧 或 矩阵1在矩阵2右侧 + boolean x_overlap = !(rec1[2] <= rec2[0] || rec2[2] <= rec1[0]); + // 矩阵投影y轴,矩阵1在矩阵2上侧 或 矩阵1在矩阵2下侧 + boolean y_overlap = !(rec1[3] <= rec2[1] || rec2[3] <= rec1[1]); + return x_overlap && y_overlap; + } + + public static void main(String[] args) { + int[] rec1 = {0, 0, 2, 2}, rec2 = {1, 1, 3, 3}; + Assert.assertTrue(new Solution1().isRectangleOverlap(rec1, rec2)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\214\272\351\227\264\345\220\210\345\271\266/\347\237\251\345\275\242\351\207\215\345\217\240_836_\347\256\200\345\215\225/Solution2.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\214\272\351\227\264\345\220\210\345\271\266/\347\237\251\345\275\242\351\207\215\345\217\240_836_\347\256\200\345\215\225/Solution2.java" new file mode 100644 index 00000000..8107d63e --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\214\272\351\227\264\345\220\210\345\271\266/\347\237\251\345\275\242\351\207\215\345\217\240_836_\347\256\200\345\215\225/Solution2.java" @@ -0,0 +1,28 @@ +package cn.lastwhisper.leetcode.array.区间合并.矩形重叠_836_简单; + +import org.junit.Assert; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/rectangle-overlap/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * 检查重叠的矩阵区域 + * ------------------------------------------------------------------- + * 时间复杂度:O(1) + * 空间复杂度:O(1) + */ + public boolean isRectangleOverlap(int[] rec1, int[] rec2) { + //相交矩阵的水平边 + return (Math.min(rec1[2], rec2[2]) > Math.max(rec1[0], rec2[0]) && + //相交矩阵的垂直边 + Math.min(rec1[3], rec2[3]) > Math.max(rec1[1], rec2[1])); + } + + public static void main(String[] args) { + int[] rec1 = {0, 0, 2, 2}, rec2 = {1, 1, 3, 3}; + Assert.assertTrue(new Solution2().isRectangleOverlap(rec1, rec2)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\215\241\347\211\214\345\210\206\347\273\204_914_\347\256\200\345\215\225/Solution1.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\215\241\347\211\214\345\210\206\347\273\204_914_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..26542e85 --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\215\241\347\211\214\345\210\206\347\273\204_914_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,56 @@ +package cn.lastwhisper.leetcode.array.卡牌分组_914_简单; + +import org.junit.Assert; + +import java.util.Arrays; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/x-of-a-kind-in-a-deck-of-cards/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:先将数组排序,对数组进行步长为2~len/2进行分组 + * ------------------------------------------------------------------- + * 时间复杂度:O(n^2) + * 空间复杂度:O(1) + */ + public boolean hasGroupsSizeX(int[] deck) { + // 特判 + if (deck == null || deck.length <= 1) { + return false; + } + if (deck.length == 2) { + return true; + } + Arrays.sort(deck); + for (int i = 2; i <= deck.length / 2; i++) { + if (deck.length % i != 0) {//deck不能整分为i组 + continue; + } + boolean flag = true; + //步长为2~len/2进行分组 + for (int len = 0, start = 0, end = i - 1; len < deck.length; end += i, start += i, len += i) { + for (int j = start; j < end; j++) { + if (deck[j] != deck[j + 1]) { + flag = false; + break; + } + } + if (!flag) { + break; + } + } + if (flag) return true; + } + return false; + } + + public static void main(String[] args) { + Assert.assertTrue(new Solution1().hasGroupsSizeX(new int[]{0, 0, 0, 0, 0, 1, 1, 1, 1, 1})); + Assert.assertTrue(new Solution1().hasGroupsSizeX(new int[]{1, 1})); + Assert.assertFalse(new Solution1().hasGroupsSizeX(new int[]{1, 1, 1, 2, 2, 2, 3, 3})); + //Assert.assertTrue(new Solution1().hasGroupsSizeX(new int[]{0, 0, 0, 1, 1, 1, 2, 2, 2})); + //Assert.assertTrue(new Solution1().hasGroupsSizeX(new int[]{1, 2, 3, 4, 4, 3, 2, 1})); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\215\241\347\211\214\345\210\206\347\273\204_914_\347\256\200\345\215\225/Solution2.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\215\241\347\211\214\345\210\206\347\273\204_914_\347\256\200\345\215\225/Solution2.java" new file mode 100644 index 00000000..8338cd8c --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\215\241\347\211\214\345\210\206\347\273\204_914_\347\256\200\345\215\225/Solution2.java" @@ -0,0 +1,57 @@ +package cn.lastwhisper.leetcode.array.卡牌分组_914_简单; + +import org.junit.Assert; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/x-of-a-kind-in-a-deck-of-cards/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:统计每个数出现的次数,次数的最大公约数大于1即可 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(1) + */ + public boolean hasGroupsSizeX(int[] deck) { + // 特判 + if (deck == null || deck.length <= 1) { + return false; + } + int[] freq = new int[10000]; + for (int num : deck) { + freq[num]++; + } + + int x = freq[deck[0]]; + for (int num : freq) { + // 1个数不能分组 + if (num == 1) { + return false; + } + if (num > 1) { + x = gcd(x, num); + // 最小公倍数是1说明也不能按同样的值分组 + if (x == 1) { + return false; + } + } + } + return true; + } + + private int gcd(int a, int b) { + if (b == 0) { + return a; + } + return gcd(b, a % b); + } + + public static void main(String[] args) { + Assert.assertTrue(new Solution2().hasGroupsSizeX(new int[]{0, 0, 0, 0, 0, 1, 1, 1, 1, 1})); + Assert.assertTrue(new Solution2().hasGroupsSizeX(new int[]{1, 1})); + Assert.assertFalse(new Solution2().hasGroupsSizeX(new int[]{1, 1, 1, 2, 2, 2, 3, 3})); + //Assert.assertTrue(new Solution2().hasGroupsSizeX(new int[]{0, 0, 0, 1, 1, 1, 2, 2, 2})); + //Assert.assertTrue(new Solution2().hasGroupsSizeX(new int[]{1, 2, 3, 4, 4, 3, 2, 1})); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262_344_\347\256\200\345\215\225/Solution1.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262_344_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..ff909dd9 --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262_344_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,32 @@ +package cn.lastwhisper.leetcode.array.反转字符串_344_简单; + +import org.junit.Assert; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/reverse-string/ + * 编号:344 + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:对撞指针交换元素 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(1) + */ + public void reverseString(char[] s) { + int l = 0, r = s.length - 1; + while (l < r) { + char c = s[l]; + s[l] = s[r]; + s[r] = c; + l++; r--; + } + } + + public static void main(String[] args) { + char[] s = {'h', 'e', 'l', 'l', 'o'}; + new Solution1().reverseString(s); + Assert.assertArrayEquals(new char[]{'o', 'l', 'l', 'e', 'h'}, s); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262\344\270\255\347\232\204\345\205\203\351\237\263\345\255\227\346\257\215_345_\347\256\200\345\215\225/Solution1.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262\344\270\255\347\232\204\345\205\203\351\237\263\345\255\227\346\257\215_345_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..7c26f183 --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262\344\270\255\347\232\204\345\205\203\351\237\263\345\255\227\346\257\215_345_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,48 @@ +package cn.lastwhisper.leetcode.array.反转字符串中的元音字母_345_简单; + +import org.junit.Assert; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/reverse-vowels-of-a-string/ + * 编号:345 + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:对撞指针条件交换元素 + * 元音字母:a,e,i,o,u 大小写 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(n) + */ + public String reverseVowels(String s) { + int l = 0, r = s.length() - 1; + char[] chars = s.toCharArray(); + while (l < r) { + while (l < r && !valid(s.charAt(l))) { + l++; + } + while (l < r && !valid(s.charAt(r))) { + r--; + } + if (l < r) {// 需要判断 + char c = chars[l]; + chars[l] = chars[r]; + chars[r] = c; + l++; + r--; + } + } + return new String(chars); + } + + private boolean valid(char c) { + return c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u' || + c == 'A' || c == 'E' || c == 'I' || c == 'O' || c == 'U'; + } + + public static void main(String[] args) { + Assert.assertEquals("holle", new Solution1().reverseVowels("hello")); + Assert.assertEquals("leotcede", new Solution1().reverseVowels("leetcode")); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\346\225\260\347\273\204_88_\347\256\200\345\215\225/Solution1.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\346\225\260\347\273\204_88_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..bdba81f3 --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\346\225\260\347\273\204_88_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,53 @@ +package cn.lastwhisper.leetcode.array.合并两个有序数组_88_简单; + +import org.junit.Assert; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/merge-sorted-array/ + * 编号:88 + * ------------------------------------------------------------------- + * 思考: + * 数据特征:数组有序 + * ------------------------------------------------------------------- + * 思路: + * 归并排序,归的过程。 + * (1)从前到后比较(找小)复制只用 nums1,需要移动 nums1 中的元素,不如创建中间数据 + * (2)从后到前比较(找大)复制只用 nums1,无需移动 nums1 中的元素 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(n) + */ + public void merge(int[] nums1, int m, int[] nums2, int n) { + // 暂存 nums1 和 nums2 的数据 + int[] temp = new int[m + n]; + int p1 = 0, p2 = 0, t = 0; + // 将 nums1 和 nums2 有序复制到 temp,直到某个数组复制完 + while (p1 < m && p2 < n) { + if (nums1[p1] > nums2[p2]) { + temp[t] = nums2[p2++]; + } else { + temp[t] = nums1[p1++]; + } + t++; + } + // 将 nums1 剩余元素复制到 temp + while (p1 < m) { + temp[t++] = nums1[p1++]; + } + // 将 nums2 剩余元素复制到 temp + while (p2 < n) { + temp[t++] = nums2[p2++]; + } + // 将 temp 所有元素复制到 nums1 + System.arraycopy(temp, 0, nums1, 0, temp.length); + } + + public static void main(String[] args) { + int[] nums1 = {1, 2, 3, 0, 0, 0}, nums2 = {2, 5, 6}; + int m = 3, n = 3; + new Solution1().merge(nums1, m, nums2, n); + + Assert.assertArrayEquals(new int[]{1, 2, 2, 3, 5, 6}, nums1); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\346\225\260\347\273\204_88_\347\256\200\345\215\225/Solution2.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\346\225\260\347\273\204_88_\347\256\200\345\215\225/Solution2.java" new file mode 100644 index 00000000..72a5f842 --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\346\225\260\347\273\204_88_\347\256\200\345\215\225/Solution2.java" @@ -0,0 +1,39 @@ +package cn.lastwhisper.leetcode.array.合并两个有序数组_88_简单; + +import org.junit.Assert; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/merge-sorted-array/ + * 编号:88 + * ------------------------------------------------------------------- + * 思考: + * 数据特征:数组有序 + * ------------------------------------------------------------------- + * 思路: + * 从后向前复制 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(1) + */ + public void merge(int[] nums1, int m, int[] nums2, int n) { + int p1 = m - 1, p2 = n - 1, total = m + n - 1; + // 将 num1 和 num2 中最大的复制到 nums1的最后面 + while (p1 >= 0 && p2 >= 0) { + nums1[total--] = nums1[p1] > nums2[p2] ? nums1[p1--] : nums2[p2--]; + } + // 如果 num1 还没复制完,不用管,因为num1自身就是有序的 + // 如果 num2 还没复制完,把剩余复制进去 + while (p2 >= 0) { + nums1[total--] = nums2[p2--]; + } + } + + public static void main(String[] args) { + int[] nums1 = {1, 2, 3, 0, 0, 0}, nums2 = {2, 5, 6}; + int m = 3, n = 3; + new Solution2().merge(nums1, m, nums2, n); + + Assert.assertArrayEquals(new int[]{1, 2, 2, 3, 5, 6}, nums1); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\244\232\346\225\260\345\205\203\347\264\240_169_\347\256\200\345\215\225/Solution1.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\244\232\346\225\260\345\205\203\347\264\240_169_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..11993f9d --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\244\232\346\225\260\345\205\203\347\264\240_169_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,38 @@ +package cn.lastwhisper.leetcode.array.多数元素_169_简单; + +import org.junit.Assert; + +import java.util.HashMap; +import java.util.Map; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/majority-element/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:hash表 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(n) + */ + public int majorityElement(int[] nums) { + int half = nums.length / 2; + Map map = new HashMap<>(); + for (int num : nums) { + Integer count = map.get(num); + count = count == null ? 1 : ++count; + map.put(num, count); + if (count > half) { + return num; + } + } + return 0; + } + + public static void main(String[] args) { + //Assert.assertEquals(3, new Solution1().majorityElement(new int[]{3, 2, 3})); + Assert.assertEquals(2, new Solution1().majorityElement(new int[]{2, 2, 1, 1, 1, 2, 2})); + + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\244\232\346\225\260\345\205\203\347\264\240_169_\347\256\200\345\215\225/Solution2.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\244\232\346\225\260\345\205\203\347\264\240_169_\347\256\200\345\215\225/Solution2.java" new file mode 100644 index 00000000..791be615 --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\244\232\346\225\260\345\205\203\347\264\240_169_\347\256\200\345\215\225/Solution2.java" @@ -0,0 +1,32 @@ +package cn.lastwhisper.leetcode.array.多数元素_169_简单; + +import org.junit.Assert; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/majority-element/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:摩尔投票法 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(1) + */ + public int majorityElement(int[] nums) { + int candidate = 0; + int count = 0; + for (int num : nums) { + if (count == 0) { + candidate = num; + } + count += candidate == num ? 1 : -1; + } + return candidate; + } + + public static void main(String[] args) { + Assert.assertEquals(3, new Solution2().majorityElement(new int[]{3, 2, 3})); + Assert.assertEquals(2, new Solution2().majorityElement(new int[]{2, 2, 1, 1, 1, 2, 2})); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\257\271\346\222\236\346\214\207\351\222\210/\344\270\244\346\225\260\344\271\213\345\222\214_II_\350\276\223\345\205\245\346\234\211\345\272\217\346\225\260\347\273\204_167_Easy/Solution1.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\257\271\346\222\236\346\214\207\351\222\210/\344\270\244\346\225\260\344\271\213\345\222\214_II_\350\276\223\345\205\245\346\234\211\345\272\217\346\225\260\347\273\204_167_Easy/Solution1.java" deleted file mode 100644 index 64322f6c..00000000 --- "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\257\271\346\222\236\346\214\207\351\222\210/\344\270\244\346\225\260\344\271\213\345\222\214_II_\350\276\223\345\205\245\346\234\211\345\272\217\346\225\260\347\273\204_167_Easy/Solution1.java" +++ /dev/null @@ -1,34 +0,0 @@ -package cn.lastwhisper.leetcode.array.对撞指针.两数之和_II_输入有序数组_167_Easy; - -/** - * https://leetcode-cn.com/problems/two-sum-ii-input-array-is-sorted/ - * @author lastwhisper - */ -public class Solution1 { - /** - * https://leetcode-cn.com/problems/two-sum-ii-input-array-is-sorted/ - * 暴力解法 - * 时间复杂度:O(n^2) - * 空间复杂度:O(1) - */ - public int[] twoSum(int[] numbers, int target) { - if (numbers == null || numbers.length < 2) { - return null; - } - int len = numbers.length; - for (int i = 0; i < len; i++) { - for (int j = 1; j < len; j++) { - if ((i != j) && (numbers[i] + numbers[j]) == target) { - return new int[]{i + 1, j + 1}; - } - } - } - return null; - } - - public static void main(String[] args) { - int[] arr = {0, 0, 3, 4}; - int[] index = new Solution1().twoSum(arr, 0); - System.out.printf("[%s,%s]", index[0], index[1]); - } -} diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\257\271\346\222\236\346\214\207\351\222\210/\344\270\244\346\225\260\344\271\213\345\222\214_II_\350\276\223\345\205\245\346\234\211\345\272\217\346\225\260\347\273\204_167_Easy/Solution2.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\257\271\346\222\236\346\214\207\351\222\210/\344\270\244\346\225\260\344\271\213\345\222\214_II_\350\276\223\345\205\245\346\234\211\345\272\217\346\225\260\347\273\204_167_Easy/Solution2.java" deleted file mode 100644 index 9095a772..00000000 --- "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\257\271\346\222\236\346\214\207\351\222\210/\344\270\244\346\225\260\344\271\213\345\222\214_II_\350\276\223\345\205\245\346\234\211\345\272\217\346\225\260\347\273\204_167_Easy/Solution2.java" +++ /dev/null @@ -1,46 +0,0 @@ -package cn.lastwhisper.leetcode.array.对撞指针.两数之和_II_输入有序数组_167_Easy; - -/** - * @author lastwhisper - */ -public class Solution2 { - - /** - * https://leetcode-cn.com/problems/two-sum-ii-input-array-is-sorted/ - * 将差值放入二分查找剩余数组 - * 时间复杂度:O(nlogn) - * 空间复杂度:O(1) - */ - public int[] twoSum(int[] numbers, int target) { - if (numbers == null || numbers.length < 2) { - return null; - } - for (int index1 = 0; index1 < numbers.length; index1++) { - int differ = target - numbers[index1]; - int index2 = binarySearch(numbers, index1 + 1, numbers.length - 1, differ); - if (index2 != -1) { - return new int[]{index1 + 1, index2 + 1}; - } - } - throw new IllegalStateException("The input has no solution"); - } - - public int binarySearch(int[] arr, int l, int r, int target) { - while (l <= r) { - int mid = l + (r - l) / 2; - if (arr[mid] == target) - return mid; - if (target > arr[mid]) - l = mid + 1; - else - r = mid - 1; - } - return -1; - } - - public static void main(String[] args) { - int[] arr = {1, 2, 3, 4, 4, 9, 56, 90}; - int[] index = new Solution2().twoSum(arr, 8); - System.out.printf("[%s,%s]", index[0], index[1]); - } -} diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\257\271\346\222\236\346\214\207\351\222\210/\344\270\244\346\225\260\344\271\213\345\222\214_II_\350\276\223\345\205\245\346\234\211\345\272\217\346\225\260\347\273\204_167_Easy/Solution3.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\257\271\346\222\236\346\214\207\351\222\210/\344\270\244\346\225\260\344\271\213\345\222\214_II_\350\276\223\345\205\245\346\234\211\345\272\217\346\225\260\347\273\204_167_Easy/Solution3.java" deleted file mode 100644 index ba9f2825..00000000 --- "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\257\271\346\222\236\346\214\207\351\222\210/\344\270\244\346\225\260\344\271\213\345\222\214_II_\350\276\223\345\205\245\346\234\211\345\272\217\346\225\260\347\273\204_167_Easy/Solution3.java" +++ /dev/null @@ -1,38 +0,0 @@ -package cn.lastwhisper.leetcode.array.对撞指针.两数之和_II_输入有序数组_167_Easy; - -import java.util.Arrays; - -/** - * @author lastwhisper - */ -public class Solution3 { - /** - * https://leetcode-cn.com/problems/two-sum-ii-input-array-is-sorted/ - * 对撞指针(前提数组有序) - * 时间复杂度:O(n) - * 空间复杂度:O(1) - */ - public int[] twoSum(int[] numbers, int target) { - if (numbers == null || numbers.length < 2) { - return null; - } - int l = 0, r = numbers.length - 1; - while (l < r) { - int left = numbers[l]; - int right = numbers[r]; - if ((left + right) == target) { - return new int[]{l + 1, r + 1}; - } else if ((left + right) > target) { - r--; - } else { - l++; - } - } - return null; - } - - public static void main(String[] args) { - System.out.println(Arrays.toString(new Solution3().twoSum(new int[]{0, 0, 3, 4}, 0))); - System.out.println(Arrays.toString(new Solution3().twoSum(new int[]{1, 7, 17, 2, 6, 3, 14}, 20))); - } -} diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\257\271\346\222\236\346\214\207\351\222\210/\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262_344_Easy/Solution1.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\257\271\346\222\236\346\214\207\351\222\210/\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262_344_Easy/Solution1.java" deleted file mode 100644 index f0b8f06a..00000000 --- "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\257\271\346\222\236\346\214\207\351\222\210/\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262_344_Easy/Solution1.java" +++ /dev/null @@ -1,31 +0,0 @@ -package cn.lastwhisper.leetcode.array.对撞指针.反转字符串_344_Easy; - -/** - * @author lastwhisper - */ -public class Solution1 { - /** - * https://leetcode-cn.com/problems/reverse-string/ - * 指针对撞 - * 时间复杂度:O(n) - * 空间复杂度:O(1) - */ - public void reverseString(char[] s) { - int l = 0, r = s.length - 1; - while (l < r) { - char temp = s[l]; - s[l] = s[r]; - s[r] = temp; - l++; - r--; - } - } - - public static void main(String[] args) { - char[] reverses = new char[]{'H','a','n','n','a','h'}; - new Solution1().reverseString(reverses); - for (char c : reverses) { - System.out.printf("\"%s\",",c); - } - } -} diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\257\271\346\222\236\346\214\207\351\222\210/\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262\344\270\255\347\232\204\345\205\203\351\237\263\345\255\227\346\257\215_345_Easy/Solution1.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\257\271\346\222\236\346\214\207\351\222\210/\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262\344\270\255\347\232\204\345\205\203\351\237\263\345\255\227\346\257\215_345_Easy/Solution1.java" deleted file mode 100644 index 59dfaf84..00000000 --- "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\257\271\346\222\236\346\214\207\351\222\210/\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262\344\270\255\347\232\204\345\205\203\351\237\263\345\255\227\346\257\215_345_Easy/Solution1.java" +++ /dev/null @@ -1,43 +0,0 @@ -package cn.lastwhisper.leetcode.array.对撞指针.反转字符串中的元音字母_345_Easy; - -class Solution1 { - /** - * 指针对撞 - * 时间复杂度:O(n) - * 空间复杂度:O(1) - */ - public String reverseVowels(String s) { - char[] chars = s.toCharArray(); - int l = 0, r = chars.length - 1; - while (l < r) { - while (l < r && !isVowel(chars[l])) l++; //找到左边的元音 - while (l < r && !isVowel(chars[r])) r--; //找到右边的元音 - if (l < r) { - // 找到了交换 - char temp = chars[l]; - chars[l] = chars[r]; - chars[r] = temp; - l++; - r--; - } - } - return new String(chars); - } - - public boolean isVowel(char c) { - if (c == 'a' || c == 'A') return true; - else if (c == 'e' || c == 'E') return true; - else if (c == 'i' || c == 'I') return true; - else if (c == 'o' || c == 'O') return true; - else if (c == 'u' || c == 'U') return true; - return false; - } - - - public static void main(String[] args) { - String s = "leetcode"; - //String s = "aA"; - System.out.println(new Solution1().reverseVowels(s)); - ; - } -} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\257\271\346\222\236\346\214\207\351\222\210/\347\233\233\346\234\200\345\244\232\346\260\264\347\232\204\345\256\271\345\231\250_11_Medium/Solution1.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\257\271\346\222\236\346\214\207\351\222\210/\347\233\233\346\234\200\345\244\232\346\260\264\347\232\204\345\256\271\345\231\250_11_Medium/Solution1.java" deleted file mode 100644 index 79304785..00000000 --- "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\257\271\346\222\236\346\214\207\351\222\210/\347\233\233\346\234\200\345\244\232\346\260\264\347\232\204\345\256\271\345\231\250_11_Medium/Solution1.java" +++ /dev/null @@ -1,21 +0,0 @@ -package cn.lastwhisper.leetcode.array.对撞指针.盛最多水的容器_11_Medium; - -/** - * @author lastwhisper - */ -public class Solution1 { - public int maxArea(int[] height) { - int maxArea = 0; - for (int i = 0; i < height.length; i++) { - for (int j = i + 1; j < height.length; j++) { - maxArea = Math.max(maxArea, Math.min(height[i], height[j]) * (j - i)); - } - } - return maxArea; - } - - public static void main(String[] args) { - int[] arr = {1, 8, 6, 2, 5, 4, 8, 3, 7}; - System.out.println(new Solution1().maxArea(arr)); - } -} diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\257\271\346\222\236\346\214\207\351\222\210/\347\233\233\346\234\200\345\244\232\346\260\264\347\232\204\345\256\271\345\231\250_11_Medium/Solution2.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\257\271\346\222\236\346\214\207\351\222\210/\347\233\233\346\234\200\345\244\232\346\260\264\347\232\204\345\256\271\345\231\250_11_Medium/Solution2.java" deleted file mode 100644 index 18880fca..00000000 --- "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\257\271\346\222\236\346\214\207\351\222\210/\347\233\233\346\234\200\345\244\232\346\260\264\347\232\204\345\256\271\345\231\250_11_Medium/Solution2.java" +++ /dev/null @@ -1,24 +0,0 @@ -package cn.lastwhisper.leetcode.array.对撞指针.盛最多水的容器_11_Medium; - -/** - * @author lastwhisper - */ -public class Solution2 { - - public int maxArea(int[] height) { - int maxarea = 0, l = 0, r = height.length - 1; - while (l < r) { - maxarea = Math.max(maxarea, Math.min(height[l], height[r]) * (r - l)); - if (height[l] < height[r]) - l++; - else - r--; - } - return maxarea; - } - - public static void main(String[] args) { - int[] arr = {1, 8, 6, 2, 5, 4, 8, 3, 7}; - System.out.println(new Solution2().maxArea(arr)); - } -} diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\257\271\346\222\236\346\214\207\351\222\210/\351\252\214\350\257\201\345\233\236\346\226\207\344\270\262_125_Easy/Solution1.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\257\271\346\222\236\346\214\207\351\222\210/\351\252\214\350\257\201\345\233\236\346\226\207\344\270\262_125_Easy/Solution1.java" deleted file mode 100644 index c89b5506..00000000 --- "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\257\271\346\222\236\346\214\207\351\222\210/\351\252\214\350\257\201\345\233\236\346\226\207\344\270\262_125_Easy/Solution1.java" +++ /dev/null @@ -1,38 +0,0 @@ -package cn.lastwhisper.leetcode.array.对撞指针.验证回文串_125_Easy; - - -class Solution1 { - /** - * https://leetcode-cn.com/problems/valid-palindrome/ - * 指针对撞 - * 时间复杂度:O(n) - * 空间复杂度:O(1) - */ - public boolean isPalindrome(String s) { - String tempStr = s.toUpperCase(); - char[] chars = tempStr.toCharArray(); - int l = 0, r = tempStr.length() - 1; - while (l < r) { - while (l < r && !isWordOrNum(chars[l])) l++; - while (l < r && !isWordOrNum(chars[r])) r--; - if (chars[l] != chars[r]) { - return false; - } - l++; - r--; - } - return true; - } - - // 是否是字母和数字字符 - public boolean isWordOrNum(char c) { - return ((c >= 48 && c <= 57) || (c >= 65 && c <= 90) || (c >= 97 && c <= 122)); - } - - public static void main(String[] args) { - String s = "A man, a plan, a canal: Panama"; - //String s = "race a car"; - System.out.println(new Solution1().isPalindrome(s)); - //System.out.println(s.toUpperCase()); - } -} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\260\206\346\225\260\347\273\204\345\210\206\346\210\220\345\222\214\347\233\270\347\255\211\347\232\204\344\270\211\344\270\252\351\203\250_1013_\347\256\200\345\215\225/Solution1.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\260\206\346\225\260\347\273\204\345\210\206\346\210\220\345\222\214\347\233\270\347\255\211\347\232\204\344\270\211\344\270\252\351\203\250_1013_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..2a96a74a --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\260\206\346\225\260\347\273\204\345\210\206\346\210\220\345\222\214\347\233\270\347\255\211\347\232\204\344\270\211\344\270\252\351\203\250_1013_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,56 @@ +package cn.lastwhisper.leetcode.array.将数组分成和相等的三个部_1013_简单; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/partition-array-into-three-parts-with-equal-sum/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:三个和相等的非空部分,0~i == i+1~j == j-1~length-1。 + * 观察规律: + * 1.分成三等分,说明sum%3==0。 + * 2.sum%3==0有没有可能不能划分成三等分? + * 有可能,比如[6,7,8],必须把8拆一份给6才行,这是不允许的。 + * 坑: + * 非空部分!!!不一定要把数组里面值全部都使用 + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public boolean canThreePartsEqualSum(int[] A) { + int sum = 0; + for (int a : A) { + sum += a; + } + if (sum % 3 != 0) { + return false; + } + // 双指针 + int left = 0, right = A.length - 1; + int peer = sum / 3, leftSum = A[left], rightSum = A[right]; + // 使用left + 1 < right 的原因,防止只能将数组分成两个部分 + // 例如:[1,-1,1,-1],使用left < right作为判断条件就会出错 + while (left + 1 < right) { + if (leftSum == peer && rightSum == peer) { + return true; + } + while (left + 1 < right && leftSum != peer) { + left++; + leftSum += A[left]; + } + while (left + 1 < right && rightSum != peer) { + right--; + rightSum += A[right]; + } + } + return false; + } + + public static void main(String[] args) { + //int[] nums = new int[]{0,2,1,-6,6,-7,9,1,2,0,1}; + //int[] nums = new int[]{0, 2, 1, -6, 6, 7, 9, -1, 2, 0, 1}; + //int[] nums = new int[]{3,3,6,5,-2,2,5,1,-9,4}; + int[] nums = new int[]{3, 3, 6, 5, -2, 2, 5, 1, -9, 4}; + System.out.println(new Solution1().canThreePartsEqualSum(nums)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\260\206\346\225\260\347\273\204\345\210\206\346\210\220\345\222\214\347\233\270\347\255\211\347\232\204\344\270\211\344\270\252\351\203\250_1013_\347\256\200\345\215\225/Solution2.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\260\206\346\225\260\347\273\204\345\210\206\346\210\220\345\222\214\347\233\270\347\255\211\347\232\204\344\270\211\344\270\252\351\203\250_1013_\347\256\200\345\215\225/Solution2.java" new file mode 100644 index 00000000..35b02ccb --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\345\260\206\346\225\260\347\273\204\345\210\206\346\210\220\345\222\214\347\233\270\347\255\211\347\232\204\344\270\211\344\270\252\351\203\250_1013_\347\256\200\345\215\225/Solution2.java" @@ -0,0 +1,43 @@ +package cn.lastwhisper.leetcode.array.将数组分成和相等的三个部_1013_简单; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/partition-array-into-three-parts-with-equal-sum/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public boolean canThreePartsEqualSum(int[] A) { + int sum = 0; + for (int a : A) { + sum += a; + } + if (sum % 3 != 0) { + return false; + } + + int freq = 0; + int count = 0; + for (int a : A) { + count += a; + if (count == sum / 3) { + freq++; + count = 0; + } + } + // [10,-10,10,-10,10,-10,10,-10] + return freq >= 3; + } + + public static void main(String[] args) { + //int[] nums = new int[]{0,2,1,-6,6,-7,9,1,2,0,1}; + //int[] nums = new int[]{0, 2, 1, -6, 6, 7, 9, -1, 2, 0, 1}; + //int[] nums = new int[]{3,3,6,5,-2,2,5,1,-9,4}; + int[] nums = new int[]{3, 3, 6, 5, -2, 2, 5, 1, -9, 4}; + System.out.println(new Solution2().canThreePartsEqualSum(nums)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\211\276\345\210\260\345\255\227\347\254\246\344\270\262\344\270\255\346\211\200\346\234\211\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215_438_\344\270\255\347\255\211/Solution1.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\211\276\345\210\260\345\255\227\347\254\246\344\270\262\344\270\255\346\211\200\346\234\211\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215_438_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..72bd4c28 --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\211\276\345\210\260\345\255\227\347\254\246\344\270\262\344\270\255\346\211\200\346\234\211\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215_438_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,65 @@ +package cn.lastwhisper.leetcode.array.找到字符串中所有字母异位词_438_中等; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/find-all-anagrams-in-a-string/ + * 编号:438 + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:双指针(滑动窗口) + * (1)双指针 l、r 维护一个滑动窗口,初始窗口扩容至模式串 p 的长度 + * (2)判断当前 [l,r] 是否满足 异位词,如果满足,记录当前 l 的下标, + * (3)窗口整体右移 + * (4)循环2、3,条件 r 未越界,r 未越界,l 肯定未越界 + * ------------------------------------------------------------------- + * 时间复杂度:O(n^2) //n 是 s 的长度、m 是 p 的长度 + * 空间复杂度:O(1) + */ + public List findAnagrams(String s, String p) { + List result = new ArrayList<>(); + // 特判 + if (s == null || s.length() < p.length()) { + return result; + } + // 直接让 [l,r] 满足模式串长度 + int l = 0, r = p.length() - 1; + int[] visited = new int[26]; + + while (r < s.length()) { + // 检查是否是异位词 + if (anagram(s, l, r, p, visited)) { + result.add(l); + } + l++; + r++; + } + return result; + } + + public boolean anagram(String s, int l, int r, String p, int[] visited) { + Arrays.fill(visited, 0); + + for (int i = l; i <= r; i++) { + visited[s.charAt(i) - 'a']++; + visited[p.charAt(i - l) - 'a']--; + } + + for (int count : visited) { + if (count != 0) { + return false; + } + } + return true; + } + + public static void main(String[] args) { + String s = "cbaebabacd", p = "abc"; + //String s = "abab", p = "ab"; + System.out.println(new Solution1().findAnagrams(s, p)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\211\276\345\210\260\345\255\227\347\254\246\344\270\262\344\270\255\346\211\200\346\234\211\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215_438_\344\270\255\347\255\211/Solution2.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\211\276\345\210\260\345\255\227\347\254\246\344\270\262\344\270\255\346\211\200\346\234\211\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215_438_\344\270\255\347\255\211/Solution2.java" new file mode 100644 index 00000000..c3aaa4dd --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\211\276\345\210\260\345\255\227\347\254\246\344\270\262\344\270\255\346\211\200\346\234\211\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215_438_\344\270\255\347\255\211/Solution2.java" @@ -0,0 +1,73 @@ +package cn.lastwhisper.leetcode.array.找到字符串中所有字母异位词_438_中等; + +import java.util.ArrayList; +import java.util.List; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/find-all-anagrams-in-a-string/ + * 编号:438 + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:双指针(滑动窗口) + * (1)双指针 l、r 维护一个滑动窗口进行遍历主串 s, + * window[] hash 表用于记录 [l,r] 窗口中某字符次数,是否满足模式串 s 中字符次数, + * total 用于记录 [l,r] 窗口各个字符数量,是否满足模式串 s 中字符数量, + * need[] hash 表用于记录模式串 s 中各个字符数量, + * (2) + * (3) + * (4) + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(1) + */ + public List findAnagrams(String s, String p) { + if (s == null || p == null || s.length() < p.length()) { + return new ArrayList<>(); + } + List result = new ArrayList<>(); + int l = 0, r = 0, total = p.length(); + int[] window = new int[26]; + int[] need = new int[26]; + for (int i = 0; i < p.length(); i++) { + need[p.charAt(i) - 'a']++; + } + while (r < s.length()) { + int cr = s.charAt(r) - 'a'; + // s 中的字符,是否存在 p 中 + // 如果存在,window 记录该字符出现次数,该字符出现次数小于等于 p 中该字符数,total-- + if (need[cr] > 0) { + window[cr]++; + if (window[cr] <= need[cr]) { + total--; + } + } + // [l,r] 中包含了 p 中所有字符 + while (total == 0) { + // 必须是和 p 的长度相同才可以算字母异位词 + // 比如 s=ceba p=abc 也满足 total==0 ,但是并不是异位词 + if (r - l == p.length() - 1) { + result.add(l); + } + // 缩小窗口,剔除 l 所指向的字符次数,total++ + int cl = s.charAt(l) - 'a'; + if (need[cl] > 0) { + window[cl]--; + if (window[cl] < need[cl]) { + total++; + } + } + l++; + } + r++; + } + return result; + } + + public static void main(String[] args) { + String s = "cbaebabacd", p = "abc"; + //String s = "abab", p = "ab"; + System.out.println(new Solution2().findAnagrams(s, p)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\211\276\345\210\260\345\255\227\347\254\246\344\270\262\344\270\255\346\211\200\346\234\211\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215_438_\344\270\255\347\255\211/backup.md" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\211\276\345\210\260\345\255\227\347\254\246\344\270\262\344\270\255\346\211\200\346\234\211\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215_438_\344\270\255\347\255\211/backup.md" new file mode 100644 index 00000000..90baddd1 --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\211\276\345\210\260\345\255\227\347\254\246\344\270\262\344\270\255\346\211\200\346\234\211\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215_438_\344\270\255\347\255\211/backup.md" @@ -0,0 +1,139 @@ +第一步: +```java + +int l = 0, r = 0; + int[] visit = new int[26]; +while (l < s.length()) { + if (r < s.length() && r - l < p.length() && !anagram(s, l, r, p, visit)) { + r++; + } else { + if (anagram(s, l, r, p, visit)) { + result.add(l); + } + l++; + } + } + + +public boolean anagram(String s, int l, int r, String p, int[] visit) { + if (r - l != p.length()) { + return false; + } +... +} +``` + +第二步: + +思路:双指针(滑动窗口) +(1)双指针 l、r 维护一个滑动窗口,窗口的长度不大于模式串 p 的长度 +(2)判断当前 [l,r] 满足 异位词 +(3)如果不满足,窗口向右扩容 +(4)如果满足,记录当前 l 的下标,窗口向右缩小 +(5)循环2、3、4,条件 l 未越界 + +```java +int l = 0, r = 0; + int[] visit = new int[26]; +if (!anagram(s, l, r, p, visit)) { + // [l,r]不满足异位词且窗口大小不满足,扩展右边界 + if ((r - l+1) != p.length()) { + r++; + } else { + // [l,r]不满足异位词且窗口大小满足,扩展左边界 + l++; + } + } else { + result.add(l); + l++; + } +``` + +第三步: + + +```java + +int l = 0, r = 0; + int[] visit = new int[26]; +while (l < s.length() && r < s.length()) { + // [l,r]不满足窗口大小,扩展右边界 + if ((r - l + 1) != p.length()) { + r++; + } else { + // [l,r]满足窗口大小,检查是否是异位词 + if (anagram(s, l, r, p, visit)) { + result.add(l); + } + l++; + } + } + +``` + +第四步: + +```java +int l = 0, r = 0; + int[] visit = new int[26]; +while (l < s.length() && r < s.length()) { + // [l,r]不满足模式串长度,扩展右边界 + while ((r - l + 1) != p.length()) { + r++; + } + // 此时窗口肯定满足,模式串的长度了,但是有可能越界了 + if (r < s.length()) { + // 检查是否是异位词 + if (anagram(s, l, r, p, visit)) { + result.add(l); + } + l++; + } + } + +``` +第五步: + +```java + +int l = 0, r = 0; + int[] visit = new int[26]; + while (l < s.length() && r < s.length()) { + // [l,r]不满足模式串长度,扩展右边界到窗口最大长度 + // (r - l + 1) != p.length() ==》 推导 r = p.length() + l - 1; + r = p.length() + l - 1; + // 此时窗口肯定满足,模式串的长度了,但是有可能越界了 + if (r < s.length()) { + // 检查是否是异位词 + if (anagram(s, l, r, p, visit)) { + result.add(l); + } + l++; + } + } + +``` +第六步: + +```java +public List findAnagrams(String s, String p) { + List result = new ArrayList<>(); + // 过滤肯定不符合规则的数据 + if (s == null || s.length() < p.length()) { + return result; + } + // 直接让 [l,r] 满足模式串长度 + int l = 0, r = p.length() - 1; + int[] visit = new int[26]; + + while (r < s.length()) { + // 检查是否是异位词 + if (anagram(s, l, r, p, visit)) { + result.add(l); + } + l++; + r++; + } + return result; + } +``` diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\216\222\345\272\217\346\225\260\347\273\204_912_\344\270\255\347\255\211/README.md" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\216\222\345\272\217\346\225\260\347\273\204_912_\344\270\255\347\255\211/README.md" new file mode 100644 index 00000000..bfb64b8d --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\216\222\345\272\217\346\225\260\347\273\204_912_\344\270\255\347\255\211/README.md" @@ -0,0 +1,24 @@ +分类:稳定性、排序原则、存储器不同 + +按稳定性: + +1. 稳定:冒泡排序、插入排序、归并排序、基数排序、桶排序、计数排序 + +2. 不稳定:选择排序、希尔排序、堆排序、快速排序 + +按排序原则: +1. 插入排序:插入排序、希尔排序 +2. 交换排序:冒泡排序、快速排序 +3. 选择排序:选择排序、堆排序 +4. 归并排序:2-路归并排序 +5. 分配排序:基数排序 + + (1)插入类:将无序子序列中的一个或几个记录“插入”到有序序列中,从而增加记录的有序子序列的长度。 + (2)交换类:通过“交换”无序序列中的记录从而得到其中关键字最小或最大的记录,并将它加入到有序子序列中,以此方法增加记录的有序子序列的长度。 + (3)选择类:从记录的无序子序列中“选择”关键字最小或最大的记录,并将它加入到有序子序列中,以此方法增加记录的有序子序列的长度。 + (4)归并类:通过“归并”两个或两个以上的记录有序子序列,逐步增加记录有序序列的长度。 + (5)分配类:是唯一一类不需要进行关键字之间比较的排序方法,排序时主要利用分配和收集两种基本操作来完成。 + + + +​ \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\216\222\345\272\217\346\225\260\347\273\204_912_\344\270\255\347\255\211/\344\272\244\346\215\242/BubbleSort.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\216\222\345\272\217\346\225\260\347\273\204_912_\344\270\255\347\255\211/\344\272\244\346\215\242/BubbleSort.java" new file mode 100644 index 00000000..bab4a394 --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\216\222\345\272\217\346\225\260\347\273\204_912_\344\270\255\347\255\211/\344\272\244\346\215\242/BubbleSort.java" @@ -0,0 +1,40 @@ +package cn.lastwhisper.leetcode.array.排序数组_912_中等.交换; + +import org.junit.Assert; + +class BubbleSort { + /** + * 题目地址:https://leetcode-cn.com/problems/rectangle-overlap/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * 冒泡排序——稳定 + * https://zh.wikipedia.org/wiki/%E5%86%92%E6%B3%A1%E6%8E%92%E5%BA%8F + * ------------------------------------------------------------------- + * 时间复杂度:O(n^2) + * 空间复杂度:O(1) + */ + public int[] sortArray(int[] nums) { + // 标识数组是否无序 + boolean exchanged = true; + for (int i = 0; exchanged && i < nums.length; i++) { + exchanged = false; + // 每次将最大值交换到无序数组最后的位置 + for (int j = 0; j < nums.length - 1 - i; j++) { + if (nums[j] > nums[j + 1]) { + int temp = nums[j]; + nums[j] = nums[j + 1]; + nums[j + 1] = temp; + exchanged = true; + } + } + } + return nums; + } + + + public static void main(String[] args) { + Assert.assertArrayEquals(new int[]{1, 2, 3, 5}, new BubbleSort().sortArray(new int[]{5, 2, 3, 1})); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\216\222\345\272\217\346\225\260\347\273\204_912_\344\270\255\347\255\211/\344\272\244\346\215\242/Quick2Sort.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\216\222\345\272\217\346\225\260\347\273\204_912_\344\270\255\347\255\211/\344\272\244\346\215\242/Quick2Sort.java" new file mode 100644 index 00000000..341d33c9 --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\216\222\345\272\217\346\225\260\347\273\204_912_\344\270\255\347\255\211/\344\272\244\346\215\242/Quick2Sort.java" @@ -0,0 +1,73 @@ +package cn.lastwhisper.leetcode.array.排序数组_912_中等.交换; + +import org.junit.Assert; + +class Quick2Sort { + /** + * 题目地址:https://leetcode-cn.com/problems/rectangle-overlap/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * 快速排序——不稳定 + * https://zh.wikipedia.org/wiki/%E5%BF%AB%E9%80%9F%E6%8E%92%E5%BA%8F + * + * 快速排序(Quick Sort)是由冒泡排序改进而得的。在冒泡排序过程中,只对相邻的两个记录进行比较,因此每次交换两个相邻记录时只能消除一个逆序。 + * 如果能通过两个(不相邻)记录的一-次交换,消除多个逆序,则会大大加快排序的速度。快速排序方法中的一次交换可能消除多个逆序。 + * + * 基准值可以选择第一个值、中间值、最后一个值 + * ------------------------------------------------------------------- + * 时间复杂度:O(nlogn) + * 空间复杂度:O(nlogn) + */ + public int[] sortArray(int[] nums) { + quickSort(nums, 0, nums.length - 1); + return nums; + } + + public void quickSort(int[] nums, int left, int right) { + if (left < right) {// 长度大于1 + int pivotLoc = partition(nums, left, right);//中轴下标 + quickSort(nums, left, pivotLoc - 1); + quickSort(nums, pivotLoc + 1, right); + } + } + + /** + * 选择第一个值、中间值、最后一个值为中轴,这里选择第一个值 + * 在[low,high]范围内,中轴左边的值都小于中轴,中轴右边的值都大于中轴 + * + * @param nums 待排序数组 + * @param low 排序起始位置 + * @param high 排序终止位置 + * @return int 中轴下标 + */ + private int partition(int[] nums, int low, int high) { + int pivot = nums[low]; + while (low < high) { + while (low < high && nums[high] >= pivot) high--; + nums[low] = nums[high]; + while (low < high && nums[low] <= pivot) low++; + nums[high] = nums[low]; + } + nums[low] = pivot; + return low; + } + // 选最后一个值 + //private int partition(int[] nums, int low, int high) { + // int pivot = nums[high]; + // while (low < high) { + // while (low < high && nums[low] <= pivot) low++; + // nums[high] = nums[low]; + // while (low < high && nums[high] >= pivot) high--; + // nums[low] = nums[high]; + // } + // nums[high] = pivot; + // return high; + //} + + + public static void main(String[] args) { + Assert.assertArrayEquals(new int[]{1, 2, 3, 5}, new Quick2Sort().sortArray(new int[]{5, 2, 3, 1})); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\216\222\345\272\217\346\225\260\347\273\204_912_\344\270\255\347\255\211/\344\272\244\346\215\242/QuickSort.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\216\222\345\272\217\346\225\260\347\273\204_912_\344\270\255\347\255\211/\344\272\244\346\215\242/QuickSort.java" new file mode 100644 index 00000000..4968ccac --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\216\222\345\272\217\346\225\260\347\273\204_912_\344\270\255\347\255\211/\344\272\244\346\215\242/QuickSort.java" @@ -0,0 +1,69 @@ +package cn.lastwhisper.leetcode.array.排序数组_912_中等.交换; + +import org.junit.Assert; + +class QuickSort { + /** + * 题目地址:https://leetcode-cn.com/problems/rectangle-overlap/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * 快速排序——不稳定 + * https://zh.wikipedia.org/wiki/%E5%BF%AB%E9%80%9F%E6%8E%92%E5%BA%8F + * + * 快速排序(Quick Sort)是由冒泡排序改进而得的。在冒泡排序过程中,只对相邻的两个记录进行比较,因此每次交换两个相邻记录时只能消除一个逆序。 + * 如果能通过两个(不相邻)记录的一-次交换,消除多个逆序,则会大大加快排序的速度。快速排序方法中的一次交换可能消除多个逆序。 + * + * 基准值可以选择第一个值、中间值、最后一个值 + * ------------------------------------------------------------------- + * 时间复杂度:O(nlogn) + * 空间复杂度:O(nlogn) + */ + public int[] sortArray(int[] nums) { + quickSort(nums, 0, nums.length - 1); + return nums; + } + + public void quickSort(int[] nums, int left, int right) { + if (left < right) {// 长度大于1 + int pivotLoc = partition(nums, left, right);//中轴下标 + quickSort(nums, left, pivotLoc - 1); + quickSort(nums, pivotLoc + 1, right); + } + } + + /** + * 选择第一个值、中间值、最后一个值为中轴,这里选择最后一个值 + * 在[start,end]范围内,中轴左边的值都小于中轴,中轴右边的值都大于中轴 + * + * @param nums 待排序数组 + * @param leftBound 排序起始位置 + * @param rightBound 排序终止位置 + * @return int 中轴下标 + */ + // 分区 + private static int partition(int[] nums, int leftBound, int rightBound) { + int left = leftBound; + int pivot = nums[rightBound]; + int right = rightBound - 1; + while (left <= right) {// left <= right取等,[4,6]时进不去while + while (left <= right && nums[left] <= pivot) left++; + while (left <= right && nums[right] > pivot) right--; + if (left < right) swap(nums, left, right); + } + swap(nums, left, rightBound); + return left; + } + + private static void swap(int[] arr, int i, int j) { + int temp = arr[i]; + arr[i] = arr[j]; + arr[j] = temp; + } + + + public static void main(String[] args) { + Assert.assertArrayEquals(new int[]{1, 2, 3, 5}, new QuickSort().sortArray(new int[]{5, 2, 3, 1})); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\216\222\345\272\217\346\225\260\347\273\204_912_\344\270\255\347\255\211/\345\210\206\351\205\215/CountSort.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\216\222\345\272\217\346\225\260\347\273\204_912_\344\270\255\347\255\211/\345\210\206\351\205\215/CountSort.java" new file mode 100644 index 00000000..625e4898 --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\216\222\345\272\217\346\225\260\347\273\204_912_\344\270\255\347\255\211/\345\210\206\351\205\215/CountSort.java" @@ -0,0 +1,37 @@ +package cn.lastwhisper.leetcode.array.排序数组_912_中等.分配; + +class CountSort { + + /** + * 题目地址:https://leetcode-cn.com/problems/rectangle-overlap/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * 计数排序——稳定 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(n) + */ + public int[] sortArray(int[] nums) { + int max = -50001, min = 50001; + for (int num : nums) { + max = Math.max(num, max); + min = Math.min(num, min); + } + + int[] counter = new int[max - min + 1]; + for (int num : nums) { + counter[num - min]++; + } + + int idx = 0; + for (int num = min; num <= max; num++) { + int cnt = counter[num - min]; + while (cnt-- > 0) { + nums[idx++] = num; + } + } + return nums; + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\216\222\345\272\217\346\225\260\347\273\204_912_\344\270\255\347\255\211/\345\210\206\351\205\215/RadixSort.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\216\222\345\272\217\346\225\260\347\273\204_912_\344\270\255\347\255\211/\345\210\206\351\205\215/RadixSort.java" new file mode 100644 index 00000000..d9afe66d --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\216\222\345\272\217\346\225\260\347\273\204_912_\344\270\255\347\255\211/\345\210\206\351\205\215/RadixSort.java" @@ -0,0 +1,67 @@ +package cn.lastwhisper.leetcode.array.排序数组_912_中等.分配; + +import org.junit.Assert; + +class RadixSort { + /** + * 题目地址:https://leetcode-cn.com/problems/rectangle-overlap/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * 基数排序——稳定 + * ------------------------------------------------------------------- + * 时间复杂度:O(nlogn) + * 空间复杂度:O(1) + */ + public int[] sortArray(int[] nums) { + int[][] bucket = new int[10][nums.length]; + // 桶元素计数器,记录每个桶中存放了多少数据 + int[] bucketElementCount = new int[10]; + // 原arr下标 + int arrIndex; + // 除数 + int divisor = 1; + // 最大值 + int max = nums[0]; + // 由于基数排序次数由最大数值的位数决定,所以需要求最大值 + for (int i = 1; i < nums.length; i++) { + if (max < nums[i]) { + max = nums[i]; + } + } + + // 最大值得位数,即排序次数 + int maxLength = (max + "").length(); + for (int f = 0; f < maxLength; f++) { + for (int num : nums) { + // digitOfElement对应放在哪个bucket中 + int digitOfElement = num / divisor % 10; + // 放在第digitOfElement个bucket的第bucketElementCount[digitOfElement]下标位置 + bucket[digitOfElement][bucketElementCount[digitOfElement]] = num; + // 下次放在bucket的第bucketElementCount[digitOfElement]++下标位置 + bucketElementCount[digitOfElement]++; + } + + arrIndex = 0; + // 将桶中数据放回原数组 + for (int i = 0; i < bucketElementCount.length; i++) { + // 对应桶中有数据 + if (bucketElementCount[i] != 0) { + for (int j = 0; j < bucketElementCount[i]; j++) { + nums[arrIndex++] = bucket[i][j]; + } + } + // 将桶元素计数器清空 + bucketElementCount[i] = 0; + } + divisor *= 10; + } + return nums; + } + + public static void main(String[] args) { + Assert.assertArrayEquals(new int[]{1, 2, 3, 5}, new RadixSort().sortArray(new int[]{5, 2, 3, 1})); + Assert.assertArrayEquals(new int[]{0, 0, 1, 1, 2, 5}, new RadixSort().sortArray(new int[]{5, 1, 1, 2, 0, 0})); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\216\222\345\272\217\346\225\260\347\273\204_912_\344\270\255\347\255\211/\345\275\222\345\271\266/MergeSort.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\216\222\345\272\217\346\225\260\347\273\204_912_\344\270\255\347\255\211/\345\275\222\345\271\266/MergeSort.java" new file mode 100644 index 00000000..3b8bde6b --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\216\222\345\272\217\346\225\260\347\273\204_912_\344\270\255\347\255\211/\345\275\222\345\271\266/MergeSort.java" @@ -0,0 +1,89 @@ +package cn.lastwhisper.leetcode.array.排序数组_912_中等.归并; + +import org.junit.Assert; + +class MergeSort { + /** + * 题目地址:https://leetcode-cn.com/problems/rectangle-overlap/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * 归并排序——稳定 + * + * ------------------------------------------------------------------- + * 时间复杂度:O(nlogn) + * 空间复杂度:O(1) + */ + public int[] sortArray(int[] nums) { + mergeSort(nums, 0, nums.length - 1, new int[nums.length]); + return nums; + } + + /** + * 归并排序 + * 分 + * + * @param arr 排序的原始数组 + * @param left 左边有序序列的初始索引 + * @param right 右边索引 + * @param temp 中转数组 + */ + public void mergeSort(int[] arr, int left, int right, int[] temp) { + if (left < right) { + int mid = (left + right) / 2; + // 向左分 + mergeSort(arr, left, mid, temp); + // 向右分 + mergeSort(arr, mid + 1, right, temp); + // 治 + merge(arr, left, mid, right, temp); + } + } + + /** + * 治 + * @param arr 排序的原始数组 arr[left...mid] arr[mid+1...right] + * @param left 左边有序序列的初始索引 + * @param mid 中间索引 + * @param right 右边索引 + * @param temp 中转数组 + */ + public void merge(int[] arr, int left, int mid, int right, int[] temp) { + int i = left; //左边有序序列的初始索引 + int j = mid + 1; // 右边有序序列的初始化序索引 + int t = 0; // 指向temp数组的当前位置 + + // 1)、将左右两边(有序)的数据按照规则填充到temp数组,任意一边处理完毕为止 + while (i <= mid && j <= right) { + if (arr[i] < arr[j]) { + // 左小于右,将左数组第i个元素copy到temp数组的第t个位置 + temp[t++] = arr[i++]; + } else { + // 右小于或等于左,将右数组第j个元素copy到temp数组的第t个位置 + temp[t++] = arr[j++]; + } + } + + // 2)、把有剩余数据的一边的数据依次填充到temp + while (i <= mid) { + // 说明 左数组还有剩余元素 + temp[t++] = arr[i++]; + } + while (j <= right) { + // 说明 右数组还有剩余元素 + temp[t++] = arr[j++]; + } + + // 3)、将temp数组的数据copy到arr,[left,right]是每次copy的范围 + for (int k = left, l = 0; k <= right; k++, l++) { + arr[k] = temp[l]; + } + + } + + public static void main(String[] args) { + Assert.assertArrayEquals(new int[]{1, 2, 3, 5}, new MergeSort().sortArray(new int[]{5, 2, 3, 1})); + Assert.assertArrayEquals(new int[]{0, 0, 1, 1, 2, 5}, new MergeSort().sortArray(new int[]{5, 1, 1, 2, 0, 0})); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\216\222\345\272\217\346\225\260\347\273\204_912_\344\270\255\347\255\211/\346\217\222\345\205\245/InsertSort.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\216\222\345\272\217\346\225\260\347\273\204_912_\344\270\255\347\255\211/\346\217\222\345\205\245/InsertSort.java" new file mode 100644 index 00000000..13f03c56 --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\216\222\345\272\217\346\225\260\347\273\204_912_\344\270\255\347\255\211/\346\217\222\345\205\245/InsertSort.java" @@ -0,0 +1,36 @@ +package cn.lastwhisper.leetcode.array.排序数组_912_中等.插入; + +import org.junit.Assert; + +class InsertSort { + /** + * 题目地址:https://leetcode-cn.com/problems/rectangle-overlap/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * 插入排序——稳定 + * https://zh.wikipedia.org/wiki/%E6%8F%92%E5%85%A5%E6%8E%92%E5%BA%8F + * ------------------------------------------------------------------- + * 时间复杂度:O(n^2) + * 空间复杂度:O(1) + */ + public int[] sortArray(int[] nums) { + for (int i = 1; i < nums.length; i++) { + int num = nums[i];// 无序数组第一个值,待插入数据 + int idx = i - 1;// 有序数组最后一个值下标 + // 把待插入的位置腾出来 + while (idx >= 0 && nums[idx] > num) { + nums[idx + 1] = nums[idx]; + idx--; + } + nums[idx + 1] = num; + } + return nums; + } + + + public static void main(String[] args) { + Assert.assertArrayEquals(new int[]{1, 2, 3, 5}, new InsertSort().sortArray(new int[]{5, 2, 3, 1})); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\216\222\345\272\217\346\225\260\347\273\204_912_\344\270\255\347\255\211/\346\217\222\345\205\245/ShellSort.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\216\222\345\272\217\346\225\260\347\273\204_912_\344\270\255\347\255\211/\346\217\222\345\205\245/ShellSort.java" new file mode 100644 index 00000000..a0c870e9 --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\216\222\345\272\217\346\225\260\347\273\204_912_\344\270\255\347\255\211/\346\217\222\345\205\245/ShellSort.java" @@ -0,0 +1,46 @@ +package cn.lastwhisper.leetcode.array.排序数组_912_中等.插入; + +import org.junit.Assert; + +class ShellSort { + /** + * 题目地址:https://leetcode-cn.com/problems/rectangle-overlap/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * 希尔排序——不稳定 + * https://zh.wikipedia.org/wiki/%E6%8F%92%E5%85%A5%E6%8E%92%E5%BA%8F + * ------------------------------------------------------------------- + * 时间复杂度:O(nlogn) + * 空间复杂度:O(1) + */ + public int[] sortArray(int[] nums) { + int gap = nums.length / 2; + int j; + int temp; + while (gap > 0) { + // 对每个数组进行插入排序;由于每个数组并不是真的存在的数组,而是一个大数组 + // 所以通过gap进行取值 + for (int i = gap; i < nums.length; i++) { + j = i; // 缓存每个数组的起始下标 + temp = nums[i]; // 缓存每个数组的起始下标的数值 + if (temp < nums[j - gap]) { + while (j - gap >= 0 && temp < nums[j - gap]) { + // 从前往后移动 + nums[j] = nums[j - gap]; + j = j - gap; + } + nums[j] = temp; + } + } + gap = gap / 2; + } + return nums; + } + + + public static void main(String[] args) { + Assert.assertArrayEquals(new int[]{1, 2, 3, 5}, new ShellSort().sortArray(new int[]{5, 2, 3, 1})); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\216\222\345\272\217\346\225\260\347\273\204_912_\344\270\255\347\255\211/\351\200\211\346\213\251/HeapSort.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\216\222\345\272\217\346\225\260\347\273\204_912_\344\270\255\347\255\211/\351\200\211\346\213\251/HeapSort.java" new file mode 100644 index 00000000..39a9521a --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\216\222\345\272\217\346\225\260\347\273\204_912_\344\270\255\347\255\211/\351\200\211\346\213\251/HeapSort.java" @@ -0,0 +1,74 @@ +package cn.lastwhisper.leetcode.array.排序数组_912_中等.选择; + +import org.junit.Assert; + +class HeapSort { + /** + * 题目地址:https://leetcode-cn.com/problems/rectangle-overlap/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * 堆排序——不稳定 + * https://zh.wikipedia.org/wiki/%E5%A0%86%E6%8E%92%E5%BA%8F + * + * 大顶堆升序,小顶堆降序 + * ------------------------------------------------------------------- + * 时间复杂度:O(nlogn) + * 空间复杂度:O(1) + */ + public int[] sortArray(int[] nums) { + // 1. 满二叉树从右向左、从下往上构建大顶堆;完全二叉树从左向右、从下往上构建大顶堆; + // i--意味着,从下到上,每一次都是[i,arr.length]的数组(二叉树)进行重构大顶堆 + // 将整个数组构建成完整的大顶堆,此时nums[0]是数组最大值 + for (int i = nums.length / 2 - 1; i >= 0; i--) { + adjustHeap(nums, i, nums.length); + } + // 2. 交换堆顶元素与末尾元素,调整堆结构 + for (int j = nums.length - 1; j >= 0; j--) { + int temp = nums[j]; + nums[j] = nums[0]; + nums[0] = temp; + adjustHeap(nums, 0, j); + } + + return nums; + } + + + /** + * 将一个数组(二叉树), 调整成一个大顶堆 + * 功能: 将以i对应的非叶子节点的树调整成大顶堆 + * 举例: + * i = 1 => {4, 6, 8, 5, 9} => {4, 9, 8, 5, 6} + * i = 0 => {4, 9, 8, 5, 6} => {9, 6, 8, 5, 4} + * @param arr 待调整的数组 + * @param i 表示非叶子节点在数组中索引 + * @param length 表示对多少个元素继续调整, length 是在逐渐的减少 + */ + public void adjustHeap(int[] arr, int i, int length) { + // 当前非叶子节点值 + int temp = arr[i]; + // k = 2*i+1是i节点的左子节点,k+1是右子节点 + for (int k = 2 * i + 1; k < length; k = 2 * k + 1) { + // 找左右子节点最大的值 + if (k + 1 < length && arr[k] < arr[k + 1]) { + k++; + } + if (arr[k] > temp) {//子节点大于父节点 + arr[i] = arr[k];//将较大的子节点赋值到当前节点(父节点) + i = k;//记录子节点的下标,为了最后 arr[i] = temp; + } else { + break;//从下至上,下面已经是大顶堆 + } + } + //i = k; arr[i]此时已经是子节点的位置了,前面父节点已经拿到了子节点的值了,这里要将子节点的值赋为父节点的值 + // 当for循环结束后,我们已经将以i为父结点的树的最大值,放在了最顶(局部) + arr[i] = temp; + } + + public static void main(String[] args) { + Assert.assertArrayEquals(new int[]{1, 2, 3, 5}, new HeapSort().sortArray(new int[]{5, 2, 3, 1})); + Assert.assertArrayEquals(new int[]{0, 0, 1, 1, 2, 5}, new HeapSort().sortArray(new int[]{5, 1, 1, 2, 0, 0})); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\216\222\345\272\217\346\225\260\347\273\204_912_\344\270\255\347\255\211/\351\200\211\346\213\251/SelectSort.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\216\222\345\272\217\346\225\260\347\273\204_912_\344\270\255\347\255\211/\351\200\211\346\213\251/SelectSort.java" new file mode 100644 index 00000000..404b1e1a --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\216\222\345\272\217\346\225\260\347\273\204_912_\344\270\255\347\255\211/\351\200\211\346\213\251/SelectSort.java" @@ -0,0 +1,41 @@ +package cn.lastwhisper.leetcode.array.排序数组_912_中等.选择; + +import org.junit.Assert; + +class SelectSort { + /** + * 题目地址:https://leetcode-cn.com/problems/rectangle-overlap/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * 选择排序——不稳定 + * https://zh.wikipedia.org/wiki/%E9%80%89%E6%8B%A9%E6%8E%92%E5%BA%8F + * ------------------------------------------------------------------- + * 时间复杂度:O(n^2) + * 空间复杂度:O(1) + */ + public int[] sortArray(int[] nums) { + for (int i = 0; i < nums.length; i++) { + + int minIdx = i; + for (int j = i + 1; j < nums.length; j++) { + if (nums[j] < nums[minIdx]) { + minIdx = j; + } + } + // 每次找到无序数组最小值的下标,放到已排序序列的末尾 + if (nums[i] > nums[minIdx]) { + int temp = nums[i]; + nums[i] = nums[minIdx]; + nums[minIdx] = temp; + } + } + return nums; + } + + public static void main(String[] args) { + Assert.assertArrayEquals(new int[]{1, 2, 3, 5}, new SelectSort().sortArray(new int[]{5, 2, 3, 1})); + Assert.assertArrayEquals(new int[]{0, 0, 1, 1, 2, 5}, new SelectSort().sortArray(new int[]{5, 1, 1, 2, 0, 0})); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\225\260\347\273\204\344\270\255\347\232\204\347\254\254K\344\270\252\346\234\200\345\244\247\345\205\203\347\264\240_215_\344\270\255\347\255\211/Solution1.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\225\260\347\273\204\344\270\255\347\232\204\347\254\254K\344\270\252\346\234\200\345\244\247\345\205\203\347\264\240_215_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..7cebc5e1 --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\225\260\347\273\204\344\270\255\347\232\204\347\254\254K\344\270\252\346\234\200\345\244\247\345\205\203\347\264\240_215_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,28 @@ +package cn.lastwhisper.leetcode.array.数组中的第K个最大元素_215_中等; + +import org.junit.Assert; + +import java.util.Arrays; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/kth-largest-element-in-an-array/ + * 编号:215 + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * 升序排序,取n-k个元素 + * ------------------------------------------------------------------- + * 时间复杂度:O(n*logn) + * 空间复杂度:O(1) + */ + public int findKthLargest(int[] nums, int k) { + Arrays.sort(nums); + return nums[nums.length - k]; + } + + public static void main(String[] args) { + Assert.assertEquals(5, new Solution1().findKthLargest(new int[]{3, 2, 1, 5, 6, 4}, 2)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\225\260\347\273\204\344\270\255\347\232\204\347\254\254K\344\270\252\346\234\200\345\244\247\345\205\203\347\264\240_215_\344\270\255\347\255\211/Solution2.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\225\260\347\273\204\344\270\255\347\232\204\347\254\254K\344\270\252\346\234\200\345\244\247\345\205\203\347\264\240_215_\344\270\255\347\255\211/Solution2.java" new file mode 100644 index 00000000..fe03e634 --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\225\260\347\273\204\344\270\255\347\232\204\347\254\254K\344\270\252\346\234\200\345\244\247\345\205\203\347\264\240_215_\344\270\255\347\255\211/Solution2.java" @@ -0,0 +1,75 @@ +package cn.lastwhisper.leetcode.array.数组中的第K个最大元素_215_中等; + +import org.junit.Assert; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/kth-largest-element-in-an-array/ + * 编号:215 + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:小顶堆 + * 利用小顶堆的特性(堆顶元素最小),先对前K个数组元素进行"原地"建小顶堆,建完小顶堆后,堆顶的元素最小,正好是这K个元素的第K大元素。 + * 然后遍历剩下的元素 nums[k] ~ nums[len-1] + * 1、如果比堆顶元素小,跳过 + * 2、如果比堆顶元素大,和堆顶元素交换后重新堆化 + * 建堆 buildHeap 时间复杂度 O(K),遍历剩下元素并且堆化 时间复杂度(N-K)*O(logK),总体的时间复杂度 O(NlogK) + * ------------------------------------------------------------------- + * 时间复杂度:O(NlogK) + * 空间复杂度:O(1) + */ + public int findKthLargest(int[] nums, int k) { + //前K个元素原地建小顶堆 + buildHeap(nums, k); + //遍历剩下元素,比堆顶小,跳过;比堆顶大,交换后重新堆化 + for (int i = k; i < nums.length; i++) { + if (nums[i] < nums[0]) continue; + swap(nums, i, 0); + heapify(nums, k, 0); + } + //K个元素的小顶堆的堆顶即是第K大元素 + return nums[0]; + } + + /** + * 建堆函数 + * 从倒数第一个非叶子节点开始堆化,倒数第一个非叶子节点下标为 K/2-1 + */ + public void buildHeap(int[] a, int k) { + for (int i = k / 2 - 1; i >= 0; i--) { + heapify(a, k, i); + } + } + + /** + * 堆化函数 + * 父节点下标i,左右子节点的下标分别为 2*i+1 和 2*i+2 + */ + public void heapify(int[] a, int k, int i) { + //临时变量 minPos 用于存储最小值的下标,先假设父节点最小 + int minPos = i; + while (true) { + //和左子节点比较 + if (i * 2 + 1 < k && a[i * 2 + 1] < a[i]) minPos = i * 2 + 1; + //和右子节点比较 + if (i * 2 + 2 < k && a[i * 2 + 2] < a[minPos]) minPos = i * 2 + 2; + //如果minPos没有发生变化,说明父节点已经是最小了,直接跳出 + if (minPos == i) break; + //否则交换 + swap(a, i, minPos); + //父节点下标进行更新,继续堆化 + i = minPos; + } + } + + public void swap(int[] arr, int i, int j) { + int temp = arr[j]; + arr[j] = arr[i]; + arr[i] = temp; + } + + public static void main(String[] args) { + Assert.assertEquals(5, new Solution2().findKthLargest(new int[]{3, 2, 1, 5, 6, 4}, 2)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\227\240\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262_3_\344\270\255\347\255\211/Solution1.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\227\240\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262_3_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..2c0f8420 --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\227\240\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262_3_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,64 @@ +package cn.lastwhisper.leetcode.array.无重复字符的最长子串_3_中等; + +import java.util.HashSet; +import java.util.Set; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/ + * 编号:3 + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:双指针(滑动窗口) + * (1)左指针未超出边界,窗口继续扩容或缩小 + * (2)Hash表每次检查右指针指向的值是否存在 + * (3)存在则,移除该字符(移除标识),窗口长度减一 + * (4)不存在,标识该字符已经存在,窗口长度加一 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) // 字符串的长度 + * 空间复杂度:O(1) // 窗口长度 + */ + public int lengthOfLongestSubstring(String s) { + int[] freq = new int[256]; + // 窗口 [l,r] 内无重复元素 + int l = 0, r = 0; + int res = 0; + while (l < s.length()) { + if (r < s.length() && freq[s.charAt(r)] == 0) { + freq[s.charAt(r++)]++; + } else { + freq[s.charAt(l++)]--; + } + // 这里 r - l 不加一,因为 l、r 初始化值都是0,并且是先用在加的 + res = Math.max(res, (r - l)); + } + return res; + } + + //public int lengthOfLongestSubstring(String s) { + // Set hash = new HashSet<>(); + // // 窗口 [l,r] 内无重复元素 + // int l = 0, r = 0; + // int result = 0; + // while (l < s.length()) { + // if (r < s.length() && !hash.contains(s.charAt(r))) { + // hash.add(s.charAt(r)); + // r++; + // } else { + // hash.remove(s.charAt(l)); + // l++; + // } + // // 这里 r - l 不加一,因为 l、r 初始化值都是0,并且是先用在加的 + // result = Math.max(result, r - l); + // } + // return result; + //} + + public static void main(String[] args) { + System.out.println(new Solution1().lengthOfLongestSubstring("abcabcbb")); + System.out.println(new Solution1().lengthOfLongestSubstring("bbbbb")); + System.out.println(new Solution1().lengthOfLongestSubstring("pwwkew")); + System.out.println(new Solution1().lengthOfLongestSubstring(" ")); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\227\240\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262_3_\344\270\255\347\255\211/Solution2.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\227\240\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262_3_\344\270\255\347\255\211/Solution2.java" new file mode 100644 index 00000000..ff9f77a7 --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\227\240\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262_3_\344\270\255\347\255\211/Solution2.java" @@ -0,0 +1,36 @@ +package cn.lastwhisper.leetcode.array.无重复字符的最长子串_3_中等; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/ + * 编号:3 + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:双指针(滑动窗口) + * 优化 Solution1 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) // 字符串的长度 + * 空间复杂度:O(1) // 窗口长度 + */ + public int lengthOfLongestSubstring(String s) { + byte[] freq = new byte[256]; + int l = 0, r = 0; + int res = 0; + while (l < s.length()) { + while (r < s.length() && freq[s.charAt(r)] == 0) { + freq[s.charAt(r++)]++; + } + res = Math.max(res, (r - l)); + freq[s.charAt(l++)]--; + } + return res; + } + + public static void main(String[] args) { + System.out.println(new Solution2().lengthOfLongestSubstring("abcabcbb")); + System.out.println(new Solution2().lengthOfLongestSubstring("bbbbb")); + System.out.println(new Solution2().lengthOfLongestSubstring("pwwkew")); + System.out.println(new Solution2().lengthOfLongestSubstring(" ")); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262_76_hard/Solution1.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262_76_hard/Solution1.java" new file mode 100644 index 00000000..8026aeef --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262_76_hard/Solution1.java" @@ -0,0 +1,81 @@ +package cn.lastwhisper.leetcode.array.最小覆盖子串_76_hard; + +class Solution1 { + /** + * https://leetcode-cn.com/problems/minimum-window-substring/ + * 核心思想:滑动窗口 + * 超时 + */ + public String minWindow(String s, String t) { + if (s.length() < t.length()) return "";//"a", "aa" + if (s.equals(t)) return s;//"a", "a" + // 用于判断s子串是否包含t + int[] map = new int[128]; + String target = "";//"abc", "ac";"a", "b" + int l = 0, r = 0; + while (l <= s.length() && r <= s.length()) { + if (!isSub(s.substring(l, r), t, map)) { + // 不断增加 r 指针扩大窗口 [l, r],直到窗口中的字符串符合要求 + r++; + } else { + // 不断增加 l 指针缩小窗口 [l, r],直到窗口中的字符串不再符合要求 + if ("".equals(target)) { + target = s.substring(l, r); + } else { + target = target.length() > s.substring(l, r).length() ? s.substring(l, r) : target; + } + l++; + } + + } + return target; + } + + /** + * sub是否包含t + */ + public boolean isSub(String sub, String t, int[] map) { + if (sub.length() < t.length()) return false;//过滤肯定不包含 + boolean flag = true; + for (int i = 0; i < sub.length(); i++) { + map[sub.charAt(i)] += 1; + } + // 检验t在sub是否完全出现过 + for (int i = 0; i < t.length(); i++) { + if (map[t.charAt(i)] > 0) { + //t在sub出现过 + map[t.charAt(i)] -= 1; + } else { + //t在sub没出现过 + flag = false; + } + } + // 检验sub是否完全包含t + for (int i = 0; i < t.length(); i++) { + if (map[t.charAt(i)] < 0) { + flag = false; + } + } + // 清空 + for (int i = 0; i < sub.length(); i++) { + map[sub.charAt(i)] = 0; + } + return flag; + } + + public static void main(String[] args) { + System.out.println("target:" + new Solution1().minWindow("ADOBECODEBANC", "ABC")); + System.out.println("target:" + new Solution1().minWindow("a", "a")); + System.out.println("target:" + new Solution1().minWindow("a", "aa")); + System.out.println("target:" + new Solution1().minWindow("a", "b")); + System.out.println("target:" + new Solution1().minWindow("abc", "ac")); + System.out.println("target:" + new Solution1().minWindow("bbaa", "aba")); + System.out.println("target:" + new Solution1().minWindow("abbc", "abc")); + //int[] arr = new int[128]; + //System.out.println(new Solution1().isSub("ADCB", "ABC", arr)); + //System.out.println(new Solution1().isSub("ADQCB", "ABC", arr)); + //System.out.println(new Solution1().isSub("ADeB", "ABC", arr)); + //System.out.println(new Solution1().isSub("abbc", "abc", arr)); + //System.out.println(new Solution1().isSub("bbaa", "aba", arr)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262_76_hard/Solution2.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262_76_hard/Solution2.java" new file mode 100644 index 00000000..91ff8787 --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262_76_hard/Solution2.java" @@ -0,0 +1,82 @@ +package cn.lastwhisper.leetcode.array.最小覆盖子串_76_hard; + +class Solution2 { + /** + * https://leetcode-cn.com/problems/minimum-window-substring/ + * 核心思想:滑动窗口 + * 超时 + */ + public String minWindow(String s, String t) { + if (s.length() < t.length()) return "";//"a", "aa" + if (s.equals(t)) return s;//"a", "a" + char[] ss = s.toCharArray(); + // 用于判断s子串是否包含t + int[] map = new int[128]; + String target = "";//"abc", "ac";"a", "b" + int l = 0, r = 0; + while (l <= ss.length && r <= ss.length) { + if (!isSub(ss, l, r, t, map)) { + // 不断增加 r 指针扩大窗口 [l, r],直到窗口中的字符串符合要求 + r++; + } else { + // 不断增加 l 指针缩小窗口 [l, r],直到窗口中的字符串不再符合要求 + if ("".equals(target)) { + target = s.substring(l, r); + } else { + target = target.length() > s.substring(l, r).length() ? s.substring(l, r) : target; + } + l++; + } + + } + return target; + } + + /** + * sub是否包含t + */ + public boolean isSub(char[] sub, int start, int end, String t, int[] map) { + if (sub.length < t.length()) return false;//过滤肯定不包含 + boolean flag = true; + for (int i = start; i < end; i++) { + map[sub[i]] += 1; + } + // 检验t在sub是否完全出现过 + for (int i = 0; i < t.length(); i++) { + if (map[t.charAt(i)] > 0) { + //t在sub出现过 + map[t.charAt(i)] -= 1; + } else { + //t在sub没出现过 + flag = false; + } + } + // 检验sub是否完全包含t + for (int i = 0; i < t.length(); i++) { + if (map[t.charAt(i)] < 0) { + flag = false; + } + } + // 清空 + for (int i = start; i < end; i++) { + map[sub[i]] = 0; + } + return flag; + } + + public static void main(String[] args) { + System.out.println("target:" + new Solution2().minWindow("ADOBECODEBANC", "ABC")); + System.out.println("target:" + new Solution2().minWindow("a", "a")); + System.out.println("target:" + new Solution2().minWindow("a", "aa")); + System.out.println("target:" + new Solution2().minWindow("a", "b")); + System.out.println("target:" + new Solution2().minWindow("abc", "ac")); + System.out.println("target:" + new Solution2().minWindow("bbaa", "aba")); + System.out.println("target:" + new Solution2().minWindow("abbc", "abc")); + //int[] arr = new int[128]; + //System.out.println(new Solution2().isSub("ADCB", "ABC", arr)); + //System.out.println(new Solution2().isSub("ADQCB", "ABC", arr)); + //System.out.println(new Solution2().isSub("ADeB", "ABC", arr)); + //System.out.println(new Solution2().isSub("abbc", "abc", arr)); + //System.out.println(new Solution2().isSub("bbaa", "aba", arr)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262_76_hard/Solution3.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262_76_hard/Solution3.java" new file mode 100644 index 00000000..5d61574b --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262_76_hard/Solution3.java" @@ -0,0 +1,87 @@ +package cn.lastwhisper.leetcode.array.最小覆盖子串_76_hard; + +import java.util.HashMap; +import java.util.Map; + +class Solution3 { + public String minWindow(String s, String t) { + + if (s.length() == 0 || t.length() == 0) { + return ""; + } + + // Dictionary which keeps a count of all the unique characters in t. + Map dictT = new HashMap(); + for (int i = 0; i < t.length(); i++) { + int count = dictT.getOrDefault(t.charAt(i), 0); + dictT.put(t.charAt(i), count + 1); + } + + // Number of unique characters in t, which need to be present in the desired window. + int required = dictT.size(); + + // Left and Right pointer + int l = 0, r = 0; + + // formed is used to keep track of how many unique characters in t + // are present in the current window in its desired frequency. + // e.g. if t is "AABC" then the window must have two A's, one B and one C. + // Thus formed would be = 3 when all these conditions are met. + int formed = 0; + + // Dictionary which keeps a count of all the unique characters in the current window. + Map windowCounts = new HashMap(); + + // ans list of the form (window length, left, right) + int[] ans = {-1, 0, 0}; + + while (r < s.length()) { + // Add one character from the right to the window + char c = s.charAt(r); + int count = windowCounts.getOrDefault(c, 0); + windowCounts.put(c, count + 1); + + // If the frequency of the current character added equals to the + // desired count in t then increment the formed count by 1. + if (dictT.containsKey(c) && windowCounts.get(c).intValue() == dictT.get(c).intValue()) { + formed++; + } + + // Try and co***act the window till the point where it ceases to be 'desirable'. + while (l <= r && formed == required) { + c = s.charAt(l); + // Save the smallest window until now. + if (ans[0] == -1 || r - l + 1 < ans[0]) { + ans[0] = r - l + 1; + ans[1] = l; + ans[2] = r; + } + + // The character at the position pointed by the + // `Left` pointer is no longer a part of the window. + windowCounts.put(c, windowCounts.get(c) - 1); + if (dictT.containsKey(c) && windowCounts.get(c).intValue() < dictT.get(c).intValue()) { + formed--; + } + + // Move the left pointer ahead, this would help to look for a new window. + l++; + } + + // Keep expanding the window once we are done co***acting. + r++; + } + + return ans[0] == -1 ? "" : s.substring(ans[1], ans[2] + 1); + } + + public static void main(String[] args) { + System.out.println("target:" + new Solution3().minWindow("ADOBECODEBANC", "ABC")); + System.out.println("target:" + new Solution3().minWindow("a", "a")); + System.out.println("target:" + new Solution3().minWindow("a", "aa")); + System.out.println("target:" + new Solution3().minWindow("a", "b")); + System.out.println("target:" + new Solution3().minWindow("abc", "ac")); + System.out.println("target:" + new Solution3().minWindow("bbaa", "aba")); + System.out.println("target:" + new Solution3().minWindow("abbc", "abc")); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262_76_hard/Solution4.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262_76_hard/Solution4.java" new file mode 100644 index 00000000..2c81b182 --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262_76_hard/Solution4.java" @@ -0,0 +1,49 @@ +package cn.lastwhisper.leetcode.array.最小覆盖子串_76_hard; + +class Solution4 { + public String minWindow(String s, String t) { + //把字符串转换为字符数组 + char[] sChars = s.toCharArray(); + char[] pChars = t.toCharArray(); + // + int[] pMap = new int[128]; + //左指针,右指针 + int i = 0, j = 0; // 考察窗口[i,j-1] + //还没有覆盖的字符数量 + int count = pChars.length; + + //初始化记录答案的变量 + int minLen = s.length() + 1, l = 0, r = 0; + + //记录t串中每种字符出现的次数 + for (char pChar : pChars) + pMap[pChar]++; + + while (j < sChars.length) { + + //减小计数 + if (pMap[sChars[j]] > 0) + count--; + pMap[sChars[j]]--; + j++; + + //计数为 0说明区间[i,j-1] 包含 p + while (count == 0) { + + //更新答案 + if (j - i < minLen) { + minLen = j - i; + l = i; + r = j; + } + + pMap[sChars[i]]++; + // 增加计数 + if (pMap[sChars[i]] > 0) + count++; + i++; + } + } + return minLen == s.length() + 1 ? "" : s.substring(l, r); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\234\211\346\225\210\347\232\204\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215_242_\347\256\200\345\215\225/Solution1.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\234\211\346\225\210\347\232\204\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215_242_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..9c95a7c8 --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\234\211\346\225\210\347\232\204\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215_242_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,43 @@ +package cn.lastwhisper.leetcode.array.有效的字母异位词_242_简单; + +import java.util.HashMap; +import java.util.Map; + +class Solution1 { + public boolean isAnagram(String s, String t) { + char[] sChar = s.toCharArray(); + char[] tChar = t.toCharArray(); + HashMap map = new HashMap<>(); + for (int i = 0; i < sChar.length; i++) { + Integer num = map.get(sChar[i]); + if (num == null) { + map.put(sChar[i], 1); + } else { + map.put(sChar[i], ++num); + } + } + + for (int i = 0; i < tChar.length; i++) { + Integer num = map.get(tChar[i]); + if (num == null) { + return false; + } else { + map.put(tChar[i], --num); + } + } + for (Map.Entry entry : map.entrySet()) { + if (entry.getValue() != 0) { + return false; + } + } + return true; + } + + public static void main(String[] args) { + //String s = "anagram", t = "nagaram"; + String s = "rat", t = "car"; + + System.out.println(new Solution1().isAnagram(s, t)); + } + +} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\234\211\346\225\210\347\232\204\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215_242_\347\256\200\345\215\225/Solution2.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\234\211\346\225\210\347\232\204\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215_242_\347\256\200\345\215\225/Solution2.java" new file mode 100644 index 00000000..6c53f39c --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\234\211\346\225\210\347\232\204\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215_242_\347\256\200\345\215\225/Solution2.java" @@ -0,0 +1,39 @@ +package cn.lastwhisper.leetcode.array.有效的字母异位词_242_简单; + +class Solution2 { + /** + * https://leetcode-cn.com/problems/valid-anagram/submissions/ + * hash + * 时间复杂度:O(n) + * 空间复杂度:O(1) + */ + public boolean isAnagram(String s, String t) { + if (s.length() != t.length()) { + return false; + } + char[] sChar = s.toCharArray(); + char[] tChar = t.toCharArray(); + byte[] freq = new byte[256]; + for (int i = 0; i < sChar.length; i++) { + freq[sChar[i]]++; + } + + for (int i = 0; i < tChar.length; i++) { + freq[tChar[i]]--; + } + for (int i = 0; i < freq.length; i++) { + if (freq[i] != 0) { + return false; + } + } + return true; + } + + public static void main(String[] args) { + String s = "anagram", t = "nagaram"; + //String s = "rat", t = "car"; + + System.out.println(new Solution2().isAnagram(s, t)); + } + +} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\273\221\345\212\250\347\252\227\345\217\243/\346\211\276\345\210\260\345\255\227\347\254\246\344\270\262\344\270\255\346\211\200\346\234\211\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215_438_Medium/Solution1.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\273\221\345\212\250\347\252\227\345\217\243/\346\211\276\345\210\260\345\255\227\347\254\246\344\270\262\344\270\255\346\211\200\346\234\211\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215_438_Medium/Solution1.java" deleted file mode 100644 index 5f603473..00000000 --- "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\273\221\345\212\250\347\252\227\345\217\243/\346\211\276\345\210\260\345\255\227\347\254\246\344\270\262\344\270\255\346\211\200\346\234\211\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215_438_Medium/Solution1.java" +++ /dev/null @@ -1,72 +0,0 @@ -package cn.lastwhisper.leetcode.array.滑动窗口.找到字符串中所有字母异位词_438_Medium; - -import java.util.ArrayList; -import java.util.List; - -class Solution1 { - /** - * https://leetcode-cn.com/problems/find-all-anagrams-in-a-string/ - * 核心思想:滑动窗口 - * 时间复杂度:O(n^2) - */ - public List findAnagrams(String s, String p) { - List list = new ArrayList<>(); - // 过滤肯定不符合规则的数据 - if (s == null || s.length() < p.length()) { - return list; - } - int l = 0, r = 0; - char[] sChar = s.toCharArray(); - char[] pChar = p.toCharArray(); - while (l < sChar.length && r < sChar.length) { - // [l,r]不满足异位词 - if (!isAnagram(sChar, l, r, pChar)) { - // [l,r]不满足异位词且窗口大小不满足,扩展右边界 - if ((r - l) != pChar.length) { - r++; - } else { - // [l,r]不满足异位词且窗口大小满足,扩展左边界 - l++; - } - } else { - // [l,r]满足异位词,扩展左边界 - list.add(l); - l++; - } - } - return list; - } - - public boolean isAnagram(char[] sChar, int start, int end, char[] pChar) { - if ((end - start + 1) != pChar.length) { - return false; - } - byte[] freq = new byte[26]; - for (int i = start; i <= end; i++) { - freq[sChar[i] - 'a']++; - } - - for (int i = 0; i < pChar.length; i++) { - freq[pChar[i] - 'a']--; - } - for (int i = 0; i < freq.length; i++) { - if (freq[i] != 0) { - return false; - } - } - return true; - } - - - public static void main(String[] args) { - new Solution1().findAnagrams("cbaebabacd", "abc").forEach(System.out::print); - System.out.println(); - new Solution1().findAnagrams("abab", "ab").forEach(System.out::print); - System.out.println(); - new Solution1().findAnagrams("", "a").forEach(System.out::print);//错误数据 - - //System.out.println(new Solution1().isAnagram(new char[]{'c','b','a'}, new char[]{'a','b','c'})); - - } - -} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\273\221\345\212\250\347\252\227\345\217\243/\346\211\276\345\210\260\345\255\227\347\254\246\344\270\262\344\270\255\346\211\200\346\234\211\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215_438_Medium/Solution2.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\273\221\345\212\250\347\252\227\345\217\243/\346\211\276\345\210\260\345\255\227\347\254\246\344\270\262\344\270\255\346\211\200\346\234\211\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215_438_Medium/Solution2.java" deleted file mode 100644 index e8480290..00000000 --- "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\273\221\345\212\250\347\252\227\345\217\243/\346\211\276\345\210\260\345\255\227\347\254\246\344\270\262\344\270\255\346\211\200\346\234\211\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215_438_Medium/Solution2.java" +++ /dev/null @@ -1,46 +0,0 @@ -package cn.lastwhisper.leetcode.array.滑动窗口.找到字符串中所有字母异位词_438_Medium; - -import java.util.ArrayList; -import java.util.List; - -class Solution2 { - /** - * https://leetcode-cn.com/problems/find-all-anagrams-in-a-string/ - * 核心思想:滑动窗口 - * 时间复杂度:O(n) - */ - public List findAnagrams(String s, String p) { - if (s == null || s.length() == 0) return new ArrayList<>(); - List res = new ArrayList<>(); - int[] needs = new int[26]; //由于都是小写字母,因此直接用26个长度的数组代替原来的HashMap - int[] window = new int[26]; - int left = 0, right = 0, total = p.length(); //用total检测窗口中是否已经涵盖了p中的字符 - for (char ch : p.toCharArray()) { - needs[ch - 'a']++; - } - while (right < s.length()) { - char chr = s.charAt(right); - if (needs[chr - 'a'] > 0) { - window[chr - 'a']++; - if (window[chr - 'a'] <= needs[chr - 'a']) { - total--; - } - } - while (total == 0) { - if (right - left + 1 == p.length()) { - res.add(left); - } - char chl = s.charAt(left); - if (needs[chl - 'a'] > 0) { - window[chl - 'a']--; - if (window[chl - 'a'] < needs[chl - 'a']) { - total++; - } - } - left++; - } - right++; - } - return res; - } -} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\273\221\345\212\250\347\252\227\345\217\243/\346\211\276\345\210\260\345\255\227\347\254\246\344\270\262\344\270\255\346\211\200\346\234\211\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215_438_Medium/Solution3.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\273\221\345\212\250\347\252\227\345\217\243/\346\211\276\345\210\260\345\255\227\347\254\246\344\270\262\344\270\255\346\211\200\346\234\211\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215_438_Medium/Solution3.java" deleted file mode 100644 index f42488b3..00000000 --- "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\273\221\345\212\250\347\252\227\345\217\243/\346\211\276\345\210\260\345\255\227\347\254\246\344\270\262\344\270\255\346\211\200\346\234\211\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215_438_Medium/Solution3.java" +++ /dev/null @@ -1,50 +0,0 @@ -package cn.lastwhisper.leetcode.array.滑动窗口.找到字符串中所有字母异位词_438_Medium; - -import java.util.ArrayList; -import java.util.List; - -class Solution3 { - - public List findAnagrams(String s, String p) { - int sl = s.length(); - int pl = p.length(); - char[] sArr = s.toCharArray(); - char[] pArr = p.toCharArray(); - // 保存当前窗口的字符出现次数的哈希表 - char[] sLetters = new char[26]; - // 保存目标字符串字符出现次数的哈希表 - char[] pLetters = new char[26]; - ArrayList ans = new ArrayList<>(sl / pl); - // 填充目标字符串的哈希表 - for (int i = 0; i < pl; i++) { - pLetters[pArr[i] - 'a']++; - } - // 滑动窗口 - int left = 0; - int right = 0; - while (right < sl) { - // 当前字符在数组中的索引 - int cur = sArr[right++] - 'a'; - // 记录窗口中字符的出现次数 - sLetters[cur]++; - // 如果在窗口中的当前字符的出现次数大于目标字符串中该字符的出现次数,即不符合条件,则右移窗口。 - // 无论是字符出现次数多余目标字符串还是字符不在目标字符串数组中,右移窗口后都可以解决。 - while (pLetters[cur] < sLetters[cur]) { - // 这里将位于left上的字符(滑动窗口最左边的字符)从sLetters(记录窗口中字符出现次数的哈希表)中减去(值减一,抽象上等同于把该字符移出滑动窗口),同时left++,完成窗口右移。 - sLetters[sArr[left++] - 'a']--; - } - // 窗口调整完成后,判断当前窗口是否满足条件,即窗口长度和目标字符串长度是否相等。 - if (right - left == pl) ans.add(left); - } - - return ans; - } - - public static void main(String[] args) { - //new Solution2().findAnagrams("cbaebabacd", "abc").forEach(System.out::print); - //System.out.println(); - new Solution3().findAnagrams("abab", "ab").forEach(System.out::print); - System.out.println(); - //new Solution2().findAnagrams("", "a").forEach(System.out::print);//错误数据 - } -} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\273\221\345\212\250\347\252\227\345\217\243/\346\227\240\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262_3_Medium/Performance.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\273\221\345\212\250\347\252\227\345\217\243/\346\227\240\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262_3_Medium/Performance.java" deleted file mode 100644 index d9e6b3c0..00000000 --- "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\273\221\345\212\250\347\252\227\345\217\243/\346\227\240\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262_3_Medium/Performance.java" +++ /dev/null @@ -1,49 +0,0 @@ -package cn.lastwhisper.leetcode.array.滑动窗口.无重复字符的最长子串_3_Medium; - -import java.lang.reflect.Method; -import java.lang.Class; - -// 比较这个工程中 Solution1, Solution5, Solution6, Solution4 和 Solution3 的算法运行效率 -public class Performance { - - public static void testPerformance(String algoClassName, String algoName, String s){ - - try{ - Class algoClass = Class.forName(algoClassName); - Object solution = algoClass.newInstance(); - - // 通过排序函数的Class对象获得排序方法 - Method algoMethod = algoClass.getMethod(algoName, String.class); - - long startTime = System.currentTimeMillis(); - // 调用算法 - Object resObj = algoMethod.invoke(solution, s); - long endTime = System.currentTimeMillis(); - - int res = (Integer)resObj; - System.out.print(algoClassName + " : res = " + res + " "); - System.out.println("Time = " + (endTime-startTime) + " ms" ); - } - catch(Exception e){ - e.printStackTrace(); - } - } - - public static void main(String[] args) { - - int n = 10000000; - - StringBuilder s = new StringBuilder(n); - for(int i = 0 ; i < n ; i ++) - s.append((char)(Math.random()*95 + 32)); - - System.out.println("Test: 10,000,000 length of completely random string:"); - testPerformance("cn.lastwhisper.leetcode.array.滑动窗口.无重复字符的最长子串_3_Medium.Solution1", "lengthOfLongestSubstring", s.toString()); - testPerformance("cn.lastwhisper.leetcode.array.滑动窗口.无重复字符的最长子串_3_Medium.Solution2", "lengthOfLongestSubstring", s.toString()); - testPerformance("cn.lastwhisper.leetcode.array.滑动窗口.无重复字符的最长子串_3_Medium.Solution3", "lengthOfLongestSubstring", s.toString()); - testPerformance("cn.lastwhisper.leetcode.array.滑动窗口.无重复字符的最长子串_3_Medium.Solution4", "lengthOfLongestSubstring", s.toString()); - testPerformance("cn.lastwhisper.leetcode.array.滑动窗口.无重复字符的最长子串_3_Medium.Solution5", "lengthOfLongestSubstring", s.toString()); - testPerformance("cn.lastwhisper.leetcode.array.滑动窗口.无重复字符的最长子串_3_Medium.Solution6", "lengthOfLongestSubstring", s.toString()); - - } -} diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\273\221\345\212\250\347\252\227\345\217\243/\346\227\240\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262_3_Medium/Solution1.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\273\221\345\212\250\347\252\227\345\217\243/\346\227\240\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262_3_Medium/Solution1.java" deleted file mode 100644 index d7c5d7eb..00000000 --- "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\273\221\345\212\250\347\252\227\345\217\243/\346\227\240\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262_3_Medium/Solution1.java" +++ /dev/null @@ -1,47 +0,0 @@ -package cn.lastwhisper.leetcode.array.滑动窗口.无重复字符的最长子串_3_Medium; - -class Solution1 { - /** - * https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/submissions/ - * 核心思想:滑动窗口 - * 时间复杂度: O(len(s)) - * 空间复杂度: O(len(charset)) - */ - public int lengthOfLongestSubstring(String s) { - int[] freq = new int[256]; - int l = 0, r = 0; - int res = 0; - char[] chars = s.toCharArray(); - while (l < chars.length) { - if (r < chars.length && freq[chars[r]] == 0) { - freq[chars[r++]]++; - } else { - freq[chars[l++]]--; - } - res = Math.max(res, (r - l)); - } - return res; - } - - //public int lengthOfLongestSubstring(String s) { - // int[] freq = new int[256]; - // int l = 0, r = 0; - // int res = 0; - // while (l < s.length()) { - // if (r < s.length() && freq[s.charAt(r)] == 0) { - // freq[s.charAt(r++)]++; - // } else { - // freq[s.charAt(l++)]--; - // } - // res = Math.max(res, (r - l)); - // } - // return res; - //} - - public static void main(String[] args) { - System.out.println(new Solution1().lengthOfLongestSubstring("abcabcbb")); - System.out.println(new Solution1().lengthOfLongestSubstring("bbbbb")); - System.out.println(new Solution1().lengthOfLongestSubstring("pwwkew")); - System.out.println(new Solution1().lengthOfLongestSubstring(" ")); - } -} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\273\221\345\212\250\347\252\227\345\217\243/\346\227\240\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262_3_Medium/Solution2.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\273\221\345\212\250\347\252\227\345\217\243/\346\227\240\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262_3_Medium/Solution2.java" deleted file mode 100644 index 06470611..00000000 --- "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\273\221\345\212\250\347\252\227\345\217\243/\346\227\240\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262_3_Medium/Solution2.java" +++ /dev/null @@ -1,45 +0,0 @@ -package cn.lastwhisper.leetcode.array.滑动窗口.无重复字符的最长子串_3_Medium; - -class Solution2 { - /** - * https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/submissions/ - * 核心思想:滑动窗口,在Solution1的基础上优化 - * 时间复杂度: O(len(s)) - * 空间复杂度: O(len(charset)) - */ - public int lengthOfLongestSubstring(String s) { - byte[] freq = new byte[256]; - int l = 0, r = 0; - int res = 0; - char[] chars = s.toCharArray(); - while (l < chars.length) { - while (r < chars.length && freq[chars[r]] == 0) { - freq[chars[r++]]++; - } - res = Math.max(res, (r - l)); - freq[chars[l++]]--; - } - return res; - } - - //public int lengthOfLongestSubstring(String s) { - // byte[] freq = new byte[256]; - // int l = 0, r = 0; - // int res = 0; - // while (l < s.length()) { - // while (r < s.length() && freq[s.charAt(r)] == 0) { - // freq[s.charAt(r++)]++; - // } - // res = Math.max(res, (r - l)); - // freq[s.charAt(l++)]--; - // } - // return res; - //} - - public static void main(String[] args) { - System.out.println(new Solution2().lengthOfLongestSubstring("abcabcbb")); - System.out.println(new Solution2().lengthOfLongestSubstring("bbbbb")); - System.out.println(new Solution2().lengthOfLongestSubstring("pwwkew")); - System.out.println(new Solution2().lengthOfLongestSubstring(" ")); - } -} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\273\221\345\212\250\347\252\227\345\217\243/\346\227\240\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262_3_Medium/Solution3.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\273\221\345\212\250\347\252\227\345\217\243/\346\227\240\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262_3_Medium/Solution3.java" deleted file mode 100644 index 2aa5abb1..00000000 --- "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\273\221\345\212\250\347\252\227\345\217\243/\346\227\240\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262_3_Medium/Solution3.java" +++ /dev/null @@ -1,40 +0,0 @@ -package cn.lastwhisper.leetcode.array.滑动窗口.无重复字符的最长子串_3_Medium;// 3. Longest Substring Without Repeating Characters -// https://leetcode.com/problems/longest-substring-without-repeating-characters/description/ -// -// 滑动窗口 -// 其中使用last[c]保存字符c上一次出现的位置, 用于在右边界发现重复字符时, 快速移动左边界 -// 使用这种方法, 时间复杂度依然为O(n), 但是只需要动r指针, 实际上对整个s只遍历了一次 -// 相较而言, 之前的方法, 需要移动l和r两个指针, 相对于对s遍历了两次 - -import java.util.Arrays; - -// 时间复杂度: O(len(s)) -// 空间复杂度: O(len(charset)) -public class Solution3 { - - public int lengthOfLongestSubstring(String s) { - - int[] last = new int[256]; - Arrays.fill(last, -1); - int l = 0, r = -1; //滑动窗口为s[l...r] - int res = 0; - while (r + 1 < s.length()) { - r++; - if (last[s.charAt(r)] != -1) - l = Math.max(l, last[s.charAt(r)] + 1); - res = Math.max(res, r - l + 1); - last[s.charAt(r)] = r; - } - - return res; - } - - public static void main(String[] args) { - - System.out.println((new Solution3()).lengthOfLongestSubstring("abcabcbb")); - System.out.println((new Solution3()).lengthOfLongestSubstring("bbbbb")); - System.out.println((new Solution3()).lengthOfLongestSubstring("pwwkew")); - System.out.println((new Solution3()).lengthOfLongestSubstring("")); - System.out.println((new Solution3()).lengthOfLongestSubstring(" ")); - } -} diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\273\221\345\212\250\347\252\227\345\217\243/\346\227\240\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262_3_Medium/Solution4.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\273\221\345\212\250\347\252\227\345\217\243/\346\227\240\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262_3_Medium/Solution4.java" deleted file mode 100644 index ce8e8179..00000000 --- "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\273\221\345\212\250\347\252\227\345\217\243/\346\227\240\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262_3_Medium/Solution4.java" +++ /dev/null @@ -1,51 +0,0 @@ -package cn.lastwhisper.leetcode.array.滑动窗口.无重复字符的最长子串_3_Medium; - -// 3. Longest Substring Without Repeating Characters -// https://leetcode.com/problems/longest-substring-without-repeating-characters/description/ -// -// 课程问答区 @yatkun 提出的方法, -// l每次可以向前跳跃, 而不仅仅是+1 -// 但代价是, 为了获得这个跳跃的位置, 每次需要遍历整个窗口的字符串 -// -// 时间复杂度: O(len(s)*len(charset)) -// 空间复杂度: O(1) -public class Solution4{ - - public int lengthOfLongestSubstring(String s) { - - int l = 0, r = 0; //滑动窗口为s[l...r] - int res = 0; - - while(r < s.length()){ - - int index = isDuplicateChar(s, l, r); - - // 如果s[r]之前出现过 - // l可以直接跳到s[r+1]之前出现的位置 + 1的地方 - if(index != -1) - l = index + 1; - - res = Math.max(res, r-l+1); - r ++; - } - - return res; - } - - // 查看s[l...r-1]之间是否存在s[r] - // 若存在,返回相应的索引, 否则返回-1 - private int isDuplicateChar(String s, int l, int r){ - for(int i = l ; i < r ; i ++) - if(s.charAt(i) == s.charAt(r)) - return i; - return -1; - } - - public static void main(String[] args) { - - System.out.println((new Solution4()).lengthOfLongestSubstring( "abcabcbb" )); - System.out.println((new Solution4()).lengthOfLongestSubstring( "bbbbb" )); - System.out.println((new Solution4()).lengthOfLongestSubstring( "pwwkew" )); - System.out.println((new Solution4()).lengthOfLongestSubstring( "" )); - } -} diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\273\221\345\212\250\347\252\227\345\217\243/\346\227\240\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262_3_Medium/Solution5.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\273\221\345\212\250\347\252\227\345\217\243/\346\227\240\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262_3_Medium/Solution5.java" deleted file mode 100644 index 41abf904..00000000 --- "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\273\221\345\212\250\347\252\227\345\217\243/\346\227\240\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262_3_Medium/Solution5.java" +++ /dev/null @@ -1,38 +0,0 @@ -package cn.lastwhisper.leetcode.array.滑动窗口.无重复字符的最长子串_3_Medium; - -// 3. Longest Substring Without Repeating Characters -// https://leetcode.com/problems/longest-substring-without-repeating-characters/description/ -// -// 滑动窗口 -// 时间复杂度: O(len(s)) -// 空间复杂度: O(len(charset)) -public class Solution5 { - public int lengthOfLongestSubstring(String s) { - - int[] freq = new int[256]; - - int l = 0, r = -1; //滑动窗口为s[l...r] - int res = 0; - - // 在这里, 循环中止的条件可以是 r + 1 < s.length(), 想想看为什么? - // 感谢课程QQ群 @千千 指出 :) - while( r + 1 < s.length() ){ - - if( r + 1 < s.length() && freq[s.charAt(r+1)] == 0 ) - freq[s.charAt(++r)] ++; - else //freq[s[r+1]] == 1 - freq[s.charAt(l++)] --; - - res = Math.max(res, r-l+1); - } - - return res; - } - - public static void main(String[] args) { - System.out.println((new Solution5()).lengthOfLongestSubstring( "abcabcbb" )); - System.out.println((new Solution5()).lengthOfLongestSubstring( "bbbbb" )); - System.out.println((new Solution5()).lengthOfLongestSubstring( "pwwkew" )); - System.out.println((new Solution5()).lengthOfLongestSubstring( "" )); - } -} diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\273\221\345\212\250\347\252\227\345\217\243/\346\227\240\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262_3_Medium/Solution6.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\273\221\345\212\250\347\252\227\345\217\243/\346\227\240\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262_3_Medium/Solution6.java" deleted file mode 100644 index 9ae65b79..00000000 --- "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\273\221\345\212\250\347\252\227\345\217\243/\346\227\240\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262_3_Medium/Solution6.java" +++ /dev/null @@ -1,42 +0,0 @@ -package cn.lastwhisper.leetcode.array.滑动窗口.无重复字符的最长子串_3_Medium; - -// 3. Longest Substring Without Repeating Characters -// https://leetcode.com/problems/longest-substring-without-repeating-characters/description/ -// -// 滑动窗口的另一个实现, 仅做参考 -// 时间复杂度: O(len(s)) -// 空间复杂度: O(len(charset)) -public class Solution6 { - public int lengthOfLongestSubstring(String s) { - - int[] freq = new int[256]; - - int l = 0, r = -1; //滑动窗口为s[l...r] - int res = 0; - - while(r + 1 < s.length()){ - - while(r + 1 < s.length() && freq[s.charAt(r+1)] == 0) - freq[s.charAt(++r)] ++; - - res = Math.max(res, r - l + 1); - - if(r + 1 < s.length()){ - freq[s.charAt(++r)] ++; - assert(freq[s.charAt(r)] == 2); - while(l <= r && freq[s.charAt(r)] == 2) - freq[s.charAt(l++)] --; - } - } - - return res; - } - - public static void main(String[] args) { - - System.out.println((new Solution6()).lengthOfLongestSubstring( "abcabcbb" )); - System.out.println((new Solution6()).lengthOfLongestSubstring( "bbbbb" )); - System.out.println((new Solution6()).lengthOfLongestSubstring( "pwwkew" )); - System.out.println((new Solution6()).lengthOfLongestSubstring( "" )); - } -} diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\273\221\345\212\250\347\252\227\345\217\243/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262_76_hard/Solution1.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\273\221\345\212\250\347\252\227\345\217\243/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262_76_hard/Solution1.java" deleted file mode 100644 index b3891057..00000000 --- "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\273\221\345\212\250\347\252\227\345\217\243/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262_76_hard/Solution1.java" +++ /dev/null @@ -1,81 +0,0 @@ -package cn.lastwhisper.leetcode.array.滑动窗口.最小覆盖子串_76_hard; - -class Solution1 { - /** - * https://leetcode-cn.com/problems/minimum-window-substring/ - * 核心思想:滑动窗口 - * 超时 - */ - public String minWindow(String s, String t) { - if (s.length() < t.length()) return "";//"a", "aa" - if (s.equals(t)) return s;//"a", "a" - // 用于判断s子串是否包含t - int[] map = new int[128]; - String target = "";//"abc", "ac";"a", "b" - int l = 0, r = 0; - while (l <= s.length() && r <= s.length()) { - if (!isSub(s.substring(l, r), t, map)) { - // 不断增加 r 指针扩大窗口 [l, r],直到窗口中的字符串符合要求 - r++; - } else { - // 不断增加 l 指针缩小窗口 [l, r],直到窗口中的字符串不再符合要求 - if ("".equals(target)) { - target = s.substring(l, r); - } else { - target = target.length() > s.substring(l, r).length() ? s.substring(l, r) : target; - } - l++; - } - - } - return target; - } - - /** - * sub是否包含t - */ - public boolean isSub(String sub, String t, int[] map) { - if (sub.length() < t.length()) return false;//过滤肯定不包含 - boolean flag = true; - for (int i = 0; i < sub.length(); i++) { - map[sub.charAt(i)] += 1; - } - // 检验t在sub是否完全出现过 - for (int i = 0; i < t.length(); i++) { - if (map[t.charAt(i)] > 0) { - //t在sub出现过 - map[t.charAt(i)] -= 1; - } else { - //t在sub没出现过 - flag = false; - } - } - // 检验sub是否完全包含t - for (int i = 0; i < t.length(); i++) { - if (map[t.charAt(i)] < 0) { - flag = false; - } - } - // 清空 - for (int i = 0; i < sub.length(); i++) { - map[sub.charAt(i)] = 0; - } - return flag; - } - - public static void main(String[] args) { - System.out.println("target:" + new Solution1().minWindow("ADOBECODEBANC", "ABC")); - System.out.println("target:" + new Solution1().minWindow("a", "a")); - System.out.println("target:" + new Solution1().minWindow("a", "aa")); - System.out.println("target:" + new Solution1().minWindow("a", "b")); - System.out.println("target:" + new Solution1().minWindow("abc", "ac")); - System.out.println("target:" + new Solution1().minWindow("bbaa", "aba")); - System.out.println("target:" + new Solution1().minWindow("abbc", "abc")); - //int[] arr = new int[128]; - //System.out.println(new Solution1().isSub("ADCB", "ABC", arr)); - //System.out.println(new Solution1().isSub("ADQCB", "ABC", arr)); - //System.out.println(new Solution1().isSub("ADeB", "ABC", arr)); - //System.out.println(new Solution1().isSub("abbc", "abc", arr)); - //System.out.println(new Solution1().isSub("bbaa", "aba", arr)); - } -} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\273\221\345\212\250\347\252\227\345\217\243/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262_76_hard/Solution2.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\273\221\345\212\250\347\252\227\345\217\243/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262_76_hard/Solution2.java" deleted file mode 100644 index acc9e6ec..00000000 --- "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\273\221\345\212\250\347\252\227\345\217\243/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262_76_hard/Solution2.java" +++ /dev/null @@ -1,82 +0,0 @@ -package cn.lastwhisper.leetcode.array.滑动窗口.最小覆盖子串_76_hard; - -class Solution2 { - /** - * https://leetcode-cn.com/problems/minimum-window-substring/ - * 核心思想:滑动窗口 - * 超时 - */ - public String minWindow(String s, String t) { - if (s.length() < t.length()) return "";//"a", "aa" - if (s.equals(t)) return s;//"a", "a" - char[] ss = s.toCharArray(); - // 用于判断s子串是否包含t - int[] map = new int[128]; - String target = "";//"abc", "ac";"a", "b" - int l = 0, r = 0; - while (l <= ss.length && r <= ss.length) { - if (!isSub(ss, l, r, t, map)) { - // 不断增加 r 指针扩大窗口 [l, r],直到窗口中的字符串符合要求 - r++; - } else { - // 不断增加 l 指针缩小窗口 [l, r],直到窗口中的字符串不再符合要求 - if ("".equals(target)) { - target = s.substring(l, r); - } else { - target = target.length() > s.substring(l, r).length() ? s.substring(l, r) : target; - } - l++; - } - - } - return target; - } - - /** - * sub是否包含t - */ - public boolean isSub(char[] sub, int start, int end, String t, int[] map) { - if (sub.length < t.length()) return false;//过滤肯定不包含 - boolean flag = true; - for (int i = start; i < end; i++) { - map[sub[i]] += 1; - } - // 检验t在sub是否完全出现过 - for (int i = 0; i < t.length(); i++) { - if (map[t.charAt(i)] > 0) { - //t在sub出现过 - map[t.charAt(i)] -= 1; - } else { - //t在sub没出现过 - flag = false; - } - } - // 检验sub是否完全包含t - for (int i = 0; i < t.length(); i++) { - if (map[t.charAt(i)] < 0) { - flag = false; - } - } - // 清空 - for (int i = start; i < end; i++) { - map[sub[i]] = 0; - } - return flag; - } - - public static void main(String[] args) { - System.out.println("target:" + new Solution2().minWindow("ADOBECODEBANC", "ABC")); - System.out.println("target:" + new Solution2().minWindow("a", "a")); - System.out.println("target:" + new Solution2().minWindow("a", "aa")); - System.out.println("target:" + new Solution2().minWindow("a", "b")); - System.out.println("target:" + new Solution2().minWindow("abc", "ac")); - System.out.println("target:" + new Solution2().minWindow("bbaa", "aba")); - System.out.println("target:" + new Solution2().minWindow("abbc", "abc")); - //int[] arr = new int[128]; - //System.out.println(new Solution2().isSub("ADCB", "ABC", arr)); - //System.out.println(new Solution2().isSub("ADQCB", "ABC", arr)); - //System.out.println(new Solution2().isSub("ADeB", "ABC", arr)); - //System.out.println(new Solution2().isSub("abbc", "abc", arr)); - //System.out.println(new Solution2().isSub("bbaa", "aba", arr)); - } -} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\273\221\345\212\250\347\252\227\345\217\243/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262_76_hard/Solution3.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\273\221\345\212\250\347\252\227\345\217\243/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262_76_hard/Solution3.java" deleted file mode 100644 index c7521ecb..00000000 --- "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\273\221\345\212\250\347\252\227\345\217\243/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262_76_hard/Solution3.java" +++ /dev/null @@ -1,87 +0,0 @@ -package cn.lastwhisper.leetcode.array.滑动窗口.最小覆盖子串_76_hard; - -import java.util.HashMap; -import java.util.Map; - -class Solution3 { - public String minWindow(String s, String t) { - - if (s.length() == 0 || t.length() == 0) { - return ""; - } - - // Dictionary which keeps a count of all the unique characters in t. - Map dictT = new HashMap(); - for (int i = 0; i < t.length(); i++) { - int count = dictT.getOrDefault(t.charAt(i), 0); - dictT.put(t.charAt(i), count + 1); - } - - // Number of unique characters in t, which need to be present in the desired window. - int required = dictT.size(); - - // Left and Right pointer - int l = 0, r = 0; - - // formed is used to keep track of how many unique characters in t - // are present in the current window in its desired frequency. - // e.g. if t is "AABC" then the window must have two A's, one B and one C. - // Thus formed would be = 3 when all these conditions are met. - int formed = 0; - - // Dictionary which keeps a count of all the unique characters in the current window. - Map windowCounts = new HashMap(); - - // ans list of the form (window length, left, right) - int[] ans = {-1, 0, 0}; - - while (r < s.length()) { - // Add one character from the right to the window - char c = s.charAt(r); - int count = windowCounts.getOrDefault(c, 0); - windowCounts.put(c, count + 1); - - // If the frequency of the current character added equals to the - // desired count in t then increment the formed count by 1. - if (dictT.containsKey(c) && windowCounts.get(c).intValue() == dictT.get(c).intValue()) { - formed++; - } - - // Try and co***act the window till the point where it ceases to be 'desirable'. - while (l <= r && formed == required) { - c = s.charAt(l); - // Save the smallest window until now. - if (ans[0] == -1 || r - l + 1 < ans[0]) { - ans[0] = r - l + 1; - ans[1] = l; - ans[2] = r; - } - - // The character at the position pointed by the - // `Left` pointer is no longer a part of the window. - windowCounts.put(c, windowCounts.get(c) - 1); - if (dictT.containsKey(c) && windowCounts.get(c).intValue() < dictT.get(c).intValue()) { - formed--; - } - - // Move the left pointer ahead, this would help to look for a new window. - l++; - } - - // Keep expanding the window once we are done co***acting. - r++; - } - - return ans[0] == -1 ? "" : s.substring(ans[1], ans[2] + 1); - } - - public static void main(String[] args) { - System.out.println("target:" + new Solution3().minWindow("ADOBECODEBANC", "ABC")); - System.out.println("target:" + new Solution3().minWindow("a", "a")); - System.out.println("target:" + new Solution3().minWindow("a", "aa")); - System.out.println("target:" + new Solution3().minWindow("a", "b")); - System.out.println("target:" + new Solution3().minWindow("abc", "ac")); - System.out.println("target:" + new Solution3().minWindow("bbaa", "aba")); - System.out.println("target:" + new Solution3().minWindow("abbc", "abc")); - } -} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\273\221\345\212\250\347\252\227\345\217\243/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262_76_hard/Solution4.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\273\221\345\212\250\347\252\227\345\217\243/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262_76_hard/Solution4.java" deleted file mode 100644 index fce81bdb..00000000 --- "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\273\221\345\212\250\347\252\227\345\217\243/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262_76_hard/Solution4.java" +++ /dev/null @@ -1,49 +0,0 @@ -package cn.lastwhisper.leetcode.array.滑动窗口.最小覆盖子串_76_hard; - -class Solution4 { - public String minWindow(String s, String t) { - //把字符串转换为字符数组 - char[] sChars = s.toCharArray(); - char[] pChars = t.toCharArray(); - // - int[] pMap = new int[128]; - //左指针,右指针 - int i = 0, j = 0; // 考察窗口[i,j-1] - //还没有覆盖的字符数量 - int count = pChars.length; - - //初始化记录答案的变量 - int minLen = s.length() + 1, l = 0, r = 0; - - //记录t串中每种字符出现的次数 - for (char pChar : pChars) - pMap[pChar]++; - - while (j < sChars.length) { - - //减小计数 - if (pMap[sChars[j]] > 0) - count--; - pMap[sChars[j]]--; - j++; - - //计数为 0说明区间[i,j-1] 包含 p - while (count == 0) { - - //更新答案 - if (j - i < minLen) { - minLen = j - i; - l = i; - r = j; - } - - pMap[sChars[i]]++; - // 增加计数 - if (pMap[sChars[i]] > 0) - count++; - i++; - } - } - return minLen == s.length() + 1 ? "" : s.substring(l, r); - } -} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\273\221\345\212\250\347\252\227\345\217\243/\351\225\277\345\272\246\346\234\200\345\260\217\347\232\204\345\255\220\346\225\260\347\273\204_209_Medium/Solution1.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\273\221\345\212\250\347\252\227\345\217\243/\351\225\277\345\272\246\346\234\200\345\260\217\347\232\204\345\255\220\346\225\260\347\273\204_209_Medium/Solution1.java" deleted file mode 100644 index 898b86b7..00000000 --- "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\273\221\345\212\250\347\252\227\345\217\243/\351\225\277\345\272\246\346\234\200\345\260\217\347\232\204\345\255\220\346\225\260\347\273\204_209_Medium/Solution1.java" +++ /dev/null @@ -1,41 +0,0 @@ -package cn.lastwhisper.leetcode.array.滑动窗口.长度最小的子数组_209_Medium; - -/** - * @author lastwhisper - */ -public class Solution1 { - /** - * https://leetcode-cn.com/problems/minimum-size-subarray-sum/ - * 暴力解法 - * 时间复杂度:O(n^3) - * 空间复杂度:O(1) - */ - public int minSubArrayLen(int s, int[] nums) { - if (s <= 0 || nums == null) { - throw new IllegalArgumentException("Illegal Argument"); - } - int res = nums.length + 1; - for (int l = 0; l < nums.length; l++) { - for (int r = l; r < nums.length; r++) { - int sum = 0; - // 求[l...r]子数组之和 - for (int i = l; i < r; i++) { - sum += nums[i]; - } - if (sum >= s) { - res = Math.min(res, r - l + 1); - } - } - } - if (res == nums.length + 1) { - return 0; - } - return res; - } - - public static void main(String[] args) { - int[] nums = {2, 3, 1, 2, 4, 3}; - int s = 7; - System.out.println((new Solution1()).minSubArrayLen(s, nums)); - } -} diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\273\221\345\212\250\347\252\227\345\217\243/\351\225\277\345\272\246\346\234\200\345\260\217\347\232\204\345\255\220\346\225\260\347\273\204_209_Medium/Solution2.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\273\221\345\212\250\347\252\227\345\217\243/\351\225\277\345\272\246\346\234\200\345\260\217\347\232\204\345\255\220\346\225\260\347\273\204_209_Medium/Solution2.java" deleted file mode 100644 index 85d3de20..00000000 --- "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\273\221\345\212\250\347\252\227\345\217\243/\351\225\277\345\272\246\346\234\200\345\260\217\347\232\204\345\255\220\346\225\260\347\273\204_209_Medium/Solution2.java" +++ /dev/null @@ -1,46 +0,0 @@ -package cn.lastwhisper.leetcode.array.滑动窗口.长度最小的子数组_209_Medium; - -/** - * 209. 长度最小的子数组 - * https://leetcode-cn.com/problems/minimum-size-subarray-sum/ - * @author lastwhisper - */ -public class Solution2 { - // 优化暴力解法 - - public int minSubArrayLen(int s, int[] nums) { - if (s <= 0 || nums == null) { - throw new IllegalArgumentException("Illegal Argument"); - } - - int[] sum = new int[nums.length + 1]; - sum[0] = 0; - // nums=> 2, 3, 1, 2, 4, 3 - // sum=>0, 2, 5, 6, 8, 12,7 - // sums[i]存放nums[0...i-1]的和 - for (int i = 1; i <= nums.length; i++) { - sum[i] = sum[i - 1] + nums[i - 1]; - } - - int res = nums.length + 1; - for (int l = 0; l < nums.length; l++) { - for (int r = l; r < nums.length; r++) { - // sum[r + 1] - sum[l]快速求出nums[l...r]之和 - if (sum[r + 1] - sum[l] >= s) { - res = Math.min(res, r - l + 1); - } - } - } - - if (res == nums.length + 1) { - res = 0; - } - return res; - } - - public static void main(String[] args) { - int[] nums = {2, 3, 1, 2, 4, 3}; - int s = 7; - System.out.println((new Solution2()).minSubArrayLen(s, nums)); - } -} diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\273\221\345\212\250\347\252\227\345\217\243/\351\225\277\345\272\246\346\234\200\345\260\217\347\232\204\345\255\220\346\225\260\347\273\204_209_Medium/Solution3.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\273\221\345\212\250\347\252\227\345\217\243/\351\225\277\345\272\246\346\234\200\345\260\217\347\232\204\345\255\220\346\225\260\347\273\204_209_Medium/Solution3.java" deleted file mode 100644 index e3d5ced6..00000000 --- "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\273\221\345\212\250\347\252\227\345\217\243/\351\225\277\345\272\246\346\234\200\345\260\217\347\232\204\345\255\220\346\225\260\347\273\204_209_Medium/Solution3.java" +++ /dev/null @@ -1,48 +0,0 @@ -package cn.lastwhisper.leetcode.array.滑动窗口.长度最小的子数组_209_Medium; - -/** - * @author lastwhisper - */ -public class Solution3 { - /** - * https://leetcode-cn.com/problems/minimum-size-subarray-sum/ - * 核心思想:滑动窗口,两个指针从起始点向前推进,维护一个窗口 - * 时间复杂度:O(n) - * 空间复杂度:O(1) - */ - public int minSubArrayLen(int s, int[] nums) { - if (s <= 0 || nums == null) { - throw new IllegalArgumentException("Illegal Argument"); - } - // nums[l...r]是一个滑动窗口 - int l = 0, r = -1; - int sum = 0; - int res = nums.length + 1; - // 窗口的左边界在数组范围内,则循环继续 - while (l < nums.length) { - if (r < nums.length - 1 && sum < s) { - //r未到头且sums,需要动态缩小窗口左边界 - sum -= nums[l]; - l++; - } - if (sum >= s) { - res = Math.min(res, r - l + 1); - } - } - - if (res == nums.length + 1) { - res = 0; - } - return res; - } - - public static void main(String[] args) { - int[] nums = {2, 3, 1, 2, 4, 3}; - int s = 7; - System.out.println((new Solution3()).minSubArrayLen(s, nums)); - } -} diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\273\221\345\212\250\347\252\227\345\217\243/\351\225\277\345\272\246\346\234\200\345\260\217\347\232\204\345\255\220\346\225\260\347\273\204_209_Medium/Solution4.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\273\221\345\212\250\347\252\227\345\217\243/\351\225\277\345\272\246\346\234\200\345\260\217\347\232\204\345\255\220\346\225\260\347\273\204_209_Medium/Solution4.java" deleted file mode 100644 index 0e014fc2..00000000 --- "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\273\221\345\212\250\347\252\227\345\217\243/\351\225\277\345\272\246\346\234\200\345\260\217\347\232\204\345\255\220\346\225\260\347\273\204_209_Medium/Solution4.java" +++ /dev/null @@ -1,51 +0,0 @@ -package cn.lastwhisper.leetcode.array.滑动窗口.长度最小的子数组_209_Medium; - -/** - * 209. 长度最小的子数组 - * https://leetcode-cn.com/problems/minimum-size-subarray-sum/ - * @author lastwhisper - */ -public class Solution4 { - // 滑动窗口 - // 时间复杂度:O(n) - // 空间复杂度:O(1) - public int minSubArrayLen(int s, int[] nums) { - if (s <= 0 || nums == null) { - throw new IllegalArgumentException("Illegal Argument"); - } - - // nums[l...r]是一个滑动窗口 - int l = 0, r = -1; - int sum = 0; - int res = nums.length + 1; - // 窗口的右边界在数组范围内,则循环继续 - while (r < nums.length - 1) { - while (r < nums.length - 1 && sum < s) { - r++; - sum += nums[r]; - } - if (sum >= s) { - res = Math.min(res, r - l + 1); - } - while (l < nums.length && sum >= s) { - sum -= nums[l]; - l++; - if (sum >= s) { - res = Math.min(res, r - l + 1); - } - } - } - - if (res == nums.length + 1) { - res = 0; - } - return res; - } - - public static void main(String[] args) { - int[] nums = {2, 3, 1, 2, 4, 3}; - int s = 7; - System.out.println((new Solution4()).minSubArrayLen(s, nums)); - } - -} diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\273\221\345\212\250\347\252\227\345\217\243/\351\225\277\345\272\246\346\234\200\345\260\217\347\232\204\345\255\220\346\225\260\347\273\204_209_Medium/Solution5.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\273\221\345\212\250\347\252\227\345\217\243/\351\225\277\345\272\246\346\234\200\345\260\217\347\232\204\345\255\220\346\225\260\347\273\204_209_Medium/Solution5.java" deleted file mode 100644 index 3143d09b..00000000 --- "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\346\273\221\345\212\250\347\252\227\345\217\243/\351\225\277\345\272\246\346\234\200\345\260\217\347\232\204\345\255\220\346\225\260\347\273\204_209_Medium/Solution5.java" +++ /dev/null @@ -1,71 +0,0 @@ -package cn.lastwhisper.leetcode.array.滑动窗口.长度最小的子数组_209_Medium; - -/** - * 209. 长度最小的子数组 - * https://leetcode-cn.com/problems/minimum-size-subarray-sum/ - * @author lastwhisper - */ -public class Solution5 { - // 二分搜索 - // 扩展 Solution5 的方法。对于每一个l, 可以使用二分搜索法搜索r - // 时间复杂度: O(nlogn) - // 空间复杂度: O(n) - public int minSubArrayLen(int s, int[] nums) { - - if(s <= 0 || nums == null) - throw new IllegalArgumentException("Illigal Arguments"); - - // sums[i]存放nums[0...i-1]的和 - int[] sums = new int[nums.length + 1]; - sums[0] = 0; - for(int i = 1 ; i <= nums.length ; i ++) - sums[i] = sums[i-1] + nums[i-1]; - - int res = nums.length + 1; - for(int l = 0 ; l < nums.length - 1 ; l ++){ - // Java类库中没有内置的lowerBound方法, - // 我们需要自己实现一个基于二分搜索的lowerBound:) - int r = lowerBound(sums, sums[l] + s); - if(r != sums.length){ - res = Math.min(res, r - l); - } - } - - if(res == nums.length + 1) - return 0; - return res; - } - - // 在有序数组nums中寻找大于等于target的最小值 - // 如果没有(nums数组中所有值都小于target),则返回nums.length - private int lowerBound(int[] nums, int target){ - - if(nums == null /*|| !isSorted(nums)*/) - throw new IllegalArgumentException("Illegal argument nums in lowerBound."); - - int l = 0, r = nums.length; // 在nums[l...r)的范围里寻找解 - while(l != r){ - int mid = l + (r - l) / 2; - if(nums[mid] >= target) - r = mid; - else - l = mid + 1; - } - - return l; - } - - private boolean isSorted(int[] nums){ - for(int i = 1 ; i < nums.length ; i ++) - if(nums[i] < nums[i-1]) - return false; - return true; - } - - public static void main(String[] args) { - - int[] nums = {2, 3, 1, 2, 4, 3}; - int s = 7; - System.out.println((new Solution5()).minSubArrayLen(s, nums)); - } -} diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\347\233\233\346\234\200\345\244\232\346\260\264\347\232\204\345\256\271\345\231\250_11_\344\270\255\347\255\211/Solution1.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\347\233\233\346\234\200\345\244\232\346\260\264\347\232\204\345\256\271\345\231\250_11_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..5b285110 --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\347\233\233\346\234\200\345\244\232\346\260\264\347\232\204\345\256\271\345\231\250_11_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,31 @@ +package cn.lastwhisper.leetcode.array.盛最多水的容器_11_中等; + +import org.junit.Assert; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/container-with-most-water/ + * 编号:11 + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:暴力组合高和底 + * ------------------------------------------------------------------- + * 时间复杂度:O(n^2) + * 空间复杂度:O(1) + */ + public int maxArea(int[] height) { + int max = Integer.MIN_VALUE, h; + for (int i = 0; i < height.length; i++) { + for (int j = i + 1; j < height.length; j++) { + h = Math.min(height[i], height[j]);// 最小高度 + max = Math.max(max, h * (j - i)); + } + } + return max; + } + + public static void main(String[] args) { + Assert.assertEquals(49, new Solution1().maxArea(new int[]{1, 8, 6, 2, 5, 4, 8, 3, 7})); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\347\233\233\346\234\200\345\244\232\346\260\264\347\232\204\345\256\271\345\231\250_11_\344\270\255\347\255\211/Solution2.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\347\233\233\346\234\200\345\244\232\346\260\264\347\232\204\345\256\271\345\231\250_11_\344\270\255\347\255\211/Solution2.java" new file mode 100644 index 00000000..2c7c9213 --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\347\233\233\346\234\200\345\244\232\346\260\264\347\232\204\345\256\271\345\231\250_11_\344\270\255\347\255\211/Solution2.java" @@ -0,0 +1,34 @@ +package cn.lastwhisper.leetcode.array.盛最多水的容器_11_中等; + +import org.junit.Assert; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/container-with-most-water/ + * 编号:11 + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:双指针(对撞指针) + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(1) + */ + public int maxArea(int[] height) { + int l = 0, r = height.length - 1, max = Integer.MIN_VALUE; + while (l < r) { + if (height[l] < height[r]) { + max = Math.max(max, height[l] * (r - l)); + l++; + } else { + max = Math.max(max, height[r] * (r - l)); + r--; + } + } + return max; + } + + public static void main(String[] args) { + Assert.assertEquals(49, new Solution2().maxArea(new int[]{1, 8, 6, 2, 5, 4, 8, 3, 7})); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\347\247\273\345\212\250\351\233\266_283_\347\256\200\345\215\225/Solution1.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\347\247\273\345\212\250\351\233\266_283_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..08cf49e7 --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\347\247\273\345\212\250\351\233\266_283_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,44 @@ +package cn.lastwhisper.leetcode.array.移动零_283_简单; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class Solution1 { + /** + * 题目地址:https://leetcode.cn/problems/move-zeroes/ + * 编号:283 + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(n) + */ + public void moveZeroes(int[] nums) { + // 缓存非0元素 + List nonZeroElements = new ArrayList<>(); + // 找出非0元素并将它缓存进nonZeroElements + for (int i = 0; i < nums.length; i++) { + if (nums[i] != 0) { + nonZeroElements.add(nums[i]); + } + } + // 将非0元素放入原数组中 + for (int i = 0; i < nonZeroElements.size(); i++) { + nums[i] = nonZeroElements.get(i); + } + // 将原数组剩余的位置放置为0 + for (int i = nonZeroElements.size(); i < nums.length; i++) { + nums[i] = 0; + } + } + + //以下为测试代码 + public static void main(String[] args) { + int[] arr = {0, 1, 0, 3, 12}; + new Solution1().moveZeroes(arr); + System.out.println(Arrays.toString(arr)); + } +} diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\347\247\273\345\212\250\351\233\266_283_\347\256\200\345\215\225/Solution2.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\347\247\273\345\212\250\351\233\266_283_\347\256\200\345\215\225/Solution2.java" new file mode 100644 index 00000000..b55ff636 --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\347\247\273\345\212\250\351\233\266_283_\347\256\200\345\215\225/Solution2.java" @@ -0,0 +1,41 @@ +package cn.lastwhisper.leetcode.array.移动零_283_简单; + + +import java.util.Arrays; + +public class Solution2 { + /** + * 题目地址:https://leetcode.cn/problems/move-zeroes/ + * 编号:283 + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(1) + */ + public void moveZeroes(int[] nums) { + // k保证从[0,...,k)均为非零元素 + int k = 0; + // 遍历到第i个元素后,保证[0,...,i]中所有非零元素, + // 都按顺序排列在[0,...,k)中 + for (int i = 0; i < nums.length; i++) { + if (nums[i] != 0) { + nums[k] = nums[i]; + k++; + } + } + // 同时保证[k,...,nums.length]中均为零元素 + for (int i = k; i < nums.length; i++) { + nums[i] = 0; + } + } + + //以下为测试代码 + public static void main(String[] args) { + int[] arr = {0, 1, 0, 3, 12}; + new Solution2().moveZeroes(arr); + System.out.println(Arrays.toString(arr)); + } +} diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\347\247\273\345\212\250\351\233\266_283_\347\256\200\345\215\225/Solution3.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\347\247\273\345\212\250\351\233\266_283_\347\256\200\345\215\225/Solution3.java" new file mode 100644 index 00000000..b96bbb3c --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\347\247\273\345\212\250\351\233\266_283_\347\256\200\345\215\225/Solution3.java" @@ -0,0 +1,44 @@ +package cn.lastwhisper.leetcode.array.移动零_283_简单; + + +import java.util.Arrays; + +public class Solution3 { + /** + * 题目地址:https://leetcode.cn/problems/move-zeroes/ + * 编号:283 + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:快慢指针 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(1) + */ + public void moveZeroes(int[] nums) { + // k保证从[0,...,k)均为非零元素,k 表示0的索引 + int k = 0; + // temp用于交换时暂存数据 + int temp; + // 遍历到第i个元素后,保证[0,...,i]中所有非零元素,都按顺序排列在[0,...,k)中 + // 同时保证[k,...,i]中均为零元素 + for (int i = 0; i < nums.length; i++) { + if (nums[i] != 0) { + if (i != k) { // 防止数组本身就是“有序”,这里的有序指 + temp = nums[k]; + nums[k] = nums[i]; + nums[i] = temp; + } + k++; + } + } + } + + //以下为测试代码 + public static void main(String[] args) { + //int[] arr = {0, 1, 0, 3, 12}; + int[] arr = {0, 0, 0, 0, 0}; + new Solution3().moveZeroes(arr); + System.out.println(Arrays.toString(arr)); + } +} diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\347\247\273\351\231\244\345\205\203\347\264\240_27_\347\256\200\345\215\225/Solution1.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\347\247\273\351\231\244\345\205\203\347\264\240_27_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..e5be0ff3 --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\347\247\273\351\231\244\345\205\203\347\264\240_27_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,45 @@ +package cn.lastwhisper.leetcode.array.移除元素_27_简单; + +import org.junit.Assert; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/min-stack/ + * 编号:27 + * ------------------------------------------------------------------- + * 思考: + * 特殊场景1:数组本身“有序” + * num=[1,1,1,1,1],Val=1 + * ------------------------------------------------------------------- + * 思路: + * 快慢指针 + * 1、记录val的索引slow + * 2、遍历,找到非val的索引i后,交换i和pos位置的值 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(1) + */ + public int removeElement(int[] nums, int val) { + // 特判 + if (nums == null || nums.length == 0) { + return 0; + } + // 区间[0,...,slow)均为不等于val的元素,slow为val的索引 + int slow = 0; + for (int i = 0; i < nums.length; i++) { + if (nums[i] != val) { + if (slow != i) { // 防止数组本身就是“有序” + nums[slow] = nums[i]; + } + slow++; + } + } + return slow; + } + + public static void main(String[] args) { + //Assert.assertEquals(2, new Solution1().removeElement(new int[]{3, 2, 2, 3}, 3)); + Assert.assertEquals(2, new Solution1().removeElement(new int[]{2, 2, 3, 3}, 3)); + + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\347\247\273\351\231\244\345\205\203\347\264\240_27_\347\256\200\345\215\225/Solution2.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\347\247\273\351\231\244\345\205\203\347\264\240_27_\347\256\200\345\215\225/Solution2.java" new file mode 100644 index 00000000..62da8322 --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\347\247\273\351\231\244\345\205\203\347\264\240_27_\347\256\200\345\215\225/Solution2.java" @@ -0,0 +1,46 @@ +package cn.lastwhisper.leetcode.array.移除元素_27_简单; + +import org.junit.Assert; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/min-stack/ + * 编号:27 + * ------------------------------------------------------------------- + * 思考: + * 特殊场景2:数组中只有少量待删除数据 + * num=[1,2,3,5,4],Val=4 + * num=[4,1,2,3,5],Val=4 + * ------------------------------------------------------------------- + * 思路: + * 快慢指针 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(1) + */ + public int removeElement(int[] nums, int val) { + // 特判 + if (nums == null || nums.length == 0) { + return 0; + } + // 区间[0,...,slow)均为不等于val的元素,slow为val的索引 + int i = 0; + int n = nums.length - 1; + while (i < n) { + if (nums[i] == val) { + nums[i] = nums[n]; + n--; + } else { + i++; + } + } + + return i; + } + + public static void main(String[] args) { + //Assert.assertEquals(2, new Solution1().removeElement(new int[]{3, 2, 2, 3}, 3)); + Assert.assertEquals(2, new Solution2().removeElement(new int[]{2, 2, 3, 3}, 3)); + + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\347\274\272\345\244\261\347\232\204\347\254\254\344\270\200\344\270\252\346\255\243\346\225\260_41_\345\233\260\351\232\276/Solution1.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\347\274\272\345\244\261\347\232\204\347\254\254\344\270\200\344\270\252\346\255\243\346\225\260_41_\345\233\260\351\232\276/Solution1.java" new file mode 100644 index 00000000..c5426aee --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\347\274\272\345\244\261\347\232\204\347\254\254\344\270\200\344\270\252\346\255\243\346\225\260_41_\345\233\260\351\232\276/Solution1.java" @@ -0,0 +1,61 @@ +package cn.lastwhisper.leetcode.array.缺失的第一个正数_41_困难; + +class Solution1 { + + /** + * https://leetcode-cn.com/problems/first-missing-positive/ + * 核心思路:输入数组值映射到数组下标,修改下标对应的值标识该数组值出现过, + * 最后统计数组第一个未标识的下标即为结果 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(n) + * ------------------------------------------------------------------- + * 此思路无法应对输入数组中存在一个很大的值 + */ + public int firstMissingPositive(int[] nums) { + //特殊情况三:输入数组为空 + if (nums.length <= 0) { + return 1; + } + int max = nums[0]; + for (int i = 0; i < nums.length; i++) { + // 特殊情况一:数组中有负数 + if (nums[i] < 0) { + nums[i] = 0; + } + if (nums[i] > max) { + max = nums[i]; + } + } + int[] arr = new int[max + 2]; + for (int num : nums) { + arr[num]++; + } + + for (int i = 0; i < arr.length; i++) { + // 特殊情况二:输入数组第一个数值大于1 + if (i == 0 && arr[i] == 0) { + continue; + } + if (arr[i] == 0) { + return i; + } + } + + return -1; + } + + /** + * 题目: 给定一个未排序的整数数组,找出其中没有出现的最小的正整数 + * 说明: 你的算法的时间复杂度应为O(n),并且只能使用常数级别的空间。 + */ + public static void main(String[] args) { + //int[] arr = new int[]{1, 2, 0};//3 + //int[] arr = new int[]{3, 4, -1, 1};//2 //特殊情况一:输入数组中有负数 + //int[] arr = new int[]{7, 8, 9, 11, 12};//1 //特殊情况二:输入数组第一个数值大于1 + //int[] arr = new int[]{};//1 //特殊情况三:输入数组为空 + int[] arr = new int[]{1, 2, 3, 10, 2147483647, 9};//1 //特殊情况四:输入数组值过大 + System.out.println(new Solution1().firstMissingPositive(arr)); + //System.out.println(Integer.MAX_VALUE==2147483647); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\347\274\272\345\244\261\347\232\204\347\254\254\344\270\200\344\270\252\346\255\243\346\225\260_41_\345\233\260\351\232\276/Solution2.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\347\274\272\345\244\261\347\232\204\347\254\254\344\270\200\344\270\252\346\255\243\346\225\260_41_\345\233\260\351\232\276/Solution2.java" new file mode 100644 index 00000000..4748e957 --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\347\274\272\345\244\261\347\232\204\347\254\254\344\270\200\344\270\252\346\255\243\346\225\260_41_\345\233\260\351\232\276/Solution2.java" @@ -0,0 +1,80 @@ +package cn.lastwhisper.leetcode.array.缺失的第一个正数_41_困难; + +class Solution2 { + + /** + * https://leetcode-cn.com/problems/first-missing-positive/ + * 核心思路:使用数组值当做下标 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(1) + * ------------------------------------------------------------------- + * + */ + public int firstMissingPositive(int[] nums) { + + // 处理负数和0,置为大于输入数组长度的一个整数即可 + for (int i = 0; i < nums.length; i++) { + if (nums[i] <= 0) { + nums[i] = Integer.MAX_VALUE; + } + } + + // 将所有出现的正整数,且值在数组长度内,置为负数 + for (int i = 0; i < nums.length; i++) { + int absNum = Math.abs(nums[i]); + /* + * 将[数组值-1]的值当做下标,并将该下标的值置为负, + * 没有被置为负数的数组值,说明它没有后一位数 + * + * absNum>nums.length,有三种情况 + * 1.负数 + * 2.0 + * 3.输入数组中本身就有一个很大的值(此时数组肯定不连续) + */ + if (absNum <= nums.length) { + /* + * 这个负数不能随便写,一定是-nums[absNum - 1] + * 比如nums={2,2} + * 情况一:nums[absNum - 1] = -Math.abs(nums[absNum - 1]) + * 第一次循环nums={2,-2},第二次循环还是nums={2,-2} + * 情况二:随便写一个负数,nums[absNum - 1] = -1 + * 第一次循环nums={2,-1},第二次循环还是nums={-1,-1} + * + */ + nums[absNum - 1] = -Math.abs(nums[absNum - 1]); + } + } + /* + * 处理不连续的数组和连续的数组 + * (1)长度为5的数组里面有一个100——此时缺失的数一定小于100, + * 且为一个没有帮它置为负数的值 + * (2)长度为100的连续数组,最大值100——此时缺失的数一定为100+1 + */ + for (int i = 0; i < nums.length; i++) { + if (nums[i] > 0) { + return i + 1; + } + } + + // 处理空数组 + return nums.length + 1; + } + + /** + * 题目: 给定一个未排序的整数数组,找出其中没有出现的最小的正整数 + * 说明: 你的算法的时间复杂度应为O(n),并且只能使用常数级别的空间。 + */ + public static void main(String[] args) { + //int[] arr = new int[]{1, 2, 0};//3 + //int[] arr = new int[]{3, 4, -1, 1};//2 //特殊情况一:输入数组中有负数 + //int[] arr = new int[]{7, 8, 9, 11, 12};//1 //特殊情况二:输入数组第一个数值大于1 + //int[] arr = new int[]{};//1 //特殊情况三:输入数组为空 + //int[] arr = new int[]{1, 2, 3, 10, 2147483647, 9};//1 //特殊情况四:输入数组值过大 + //int[] arr = new int[]{1};//2 + //int[] arr = new int[]{0};//1 + //int[] arr = new int[]{2,2};//1 + int[] arr = new int[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};//10 + System.out.println(new Solution2().firstMissingPositive(arr)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\347\274\272\345\244\261\347\232\204\347\254\254\344\270\200\344\270\252\346\255\243\346\225\260_41_\345\233\260\351\232\276/YourVersion1.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\347\274\272\345\244\261\347\232\204\347\254\254\344\270\200\344\270\252\346\255\243\346\225\260_41_\345\233\260\351\232\276/YourVersion1.java" new file mode 100644 index 00000000..84f9bdd0 --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\347\274\272\345\244\261\347\232\204\347\254\254\344\270\200\344\270\252\346\255\243\346\225\260_41_\345\233\260\351\232\276/YourVersion1.java" @@ -0,0 +1,45 @@ +package cn.lastwhisper.leetcode.array.缺失的第一个正数_41_困难; + +class YourVersion1 { + + public int firstMissingPositive(int[] nums) { + + // 处理负数和0 + for (int i = 0; i < nums.length; i++) { + if (nums[i] <= 0) { + nums[i] = Integer.MAX_VALUE; + } + } + + for (int i = 0; i < nums.length; i++) { + int absNum = Math.abs(nums[i]); + if (absNum <= nums.length) { + nums[absNum - 1] = -Math.abs(nums[absNum - 1]); + } + } + + for (int i = 0; i < nums.length; i++) { + if (nums[i] > 0) { + return i + 1; + } + } + + return nums.length + 1; + } + + /** + * 题目: 给定一个未排序的整数数组,找出其中没有出现的最小的正整数 + * 说明: 你的算法的时间复杂度应为O(n),并且只能使用常数级别的空间。 + */ + public static void main(String[] args) { + //int[] arr = new int[]{1, 2, 0};//3 + //int[] arr = new int[]{3, 4, -1, 1};//2 //特殊情况一:输入数组中有负数 + //int[] arr = new int[]{7, 8, 9, 11, 12};//1 //特殊情况二:输入数组第一个数值大于1 + //int[] arr = new int[]{};//1 //特殊情况三:输入数组为空 + //int[] arr = new int[]{1, 2, 3, 10, 2147483647, 9};//1 //特殊情况四:输入数组值过大 + //int[] arr = new int[]{1};//2 + //int[] arr = new int[]{0};//1 + int[] arr = new int[]{2, 2};//1 + System.out.println(new YourVersion1().firstMissingPositive(arr)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\350\236\272\346\227\213\347\237\251\351\230\265_54_\344\270\255\347\255\211/Solution1.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\350\236\272\346\227\213\347\237\251\351\230\265_54_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..494ce3ce --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\350\236\272\346\227\213\347\237\251\351\230\265_54_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,54 @@ +package cn.lastwhisper.leetcode.array.螺旋矩阵_54_中等; + +import java.util.ArrayList; +import java.util.List; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/spiral-matrix/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * ------------------------------------------------------------------- + * 时间复杂度:O(n^2) + * 空间复杂度:O(n^2) + */ + public List spiralOrder(int[][] matrix) { + if (matrix == null || matrix.length == 0) return new ArrayList<>(); + List result = new ArrayList<>(matrix.length * matrix[0].length); + // nowColumn当前所在列、totalColumn总列数、nowRow当前所在行、totalRow总行数 + int nowColumn = 0, totalColumn = matrix[0].length - 1, nowRow = 0, totalRow = matrix.length - 1; + // 顺时针遍历 + while (nowColumn <= totalColumn && nowRow <= totalRow) { + //只有一列,不需要从左到右 + for (int i = nowColumn; i <= totalColumn; i++) {//第一步 从左到右 + result.add(matrix[nowRow][i]); + } + //只有一行,不需要从上到下 + for (int i = nowRow + 1; i <= totalRow; i++) {//第二步 从上到下 + result.add(matrix[i][totalColumn]); + } + if (nowRow != totalRow) {//同行,不需要从右向左遍历 + for (int i = totalColumn - 1; i >= nowColumn; i--) {//第三步 从右向左 + result.add(matrix[totalRow][i]); + } + } + if (nowColumn != totalColumn) {//同列,不需要从下到上遍历 + for (int i = totalRow - 1; i > nowRow; i--) {// 第四步 从下到上 + result.add(matrix[i][nowColumn]); + } + } + nowColumn++; + nowRow++; + totalColumn--; + totalRow--; + } + return result; + } + + public static void main(String[] args) { + int[][] matrix = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}; + System.out.println(new Solution1().spiralOrder(matrix)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\351\224\231\350\257\257\347\232\204\351\233\206\345\220\210_645_\347\256\200\345\215\225/Solution1.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\351\224\231\350\257\257\347\232\204\351\233\206\345\220\210_645_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..e37115a5 --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\351\224\231\350\257\257\347\232\204\351\233\206\345\220\210_645_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,62 @@ +package cn.lastwhisper.leetcode.array.错误的集合_645_简单; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +class Solution1 { + /** + * https://leetcode-cn.com/problems/set-mismatch/ + * ------------------------------------------------------------------- + * 数据特征: + * 输入:数组、1~n整数、无序、存在重复数据、不一定包含丢失数据 + * 输出:数组[重复数据,丢失数据]、1~n+1整数、 + * ------------------------------------------------------------------- + * 思路: + * 使用两个set集合,set1找出重复数据,set2记录1~length+1, + * set2.removeAll(set1)得到丢失数据。 + * 特殊情况:[1,1] + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(n) + */ + public int[] findErrorNums(int[] nums) { + if (nums.length == 2) { + if (nums[0] == 1 && nums[1] == 1) return new int[]{1, 2}; + } + + Set allSet = new HashSet<>(); + Set numsSet = new HashSet<>(); + int duplicate = -1, miss = -1; + for (Integer num : nums) { + // 找到重复,并将所有元素放到numsSet + if (numsSet.contains(num)) { + duplicate = num; + } else { + numsSet.add(num); + } + + } + for (int i = 1; i <= nums.length + 1; i++) { + allSet.add(i); + } + allSet.removeAll(numsSet); + for (Integer num : allSet) { + miss = num; + break; + } + + return new int[]{duplicate, miss}; + } + + public static void main(String[] args) { + // example + //int[] arr = {1, 2, 2, 4};//2,3 + //int[] arr = {2, 2};//2,1 + // error example + //int[] arr = {3, 2, 2};//2,1 + //int[] arr = {1, 1};//1,2 + int[] arr = {1, 5, 3, 2, 2, 7, 6, 4, 8, 9}; + System.out.println(Arrays.toString(new Solution1().findErrorNums(arr))); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\351\224\231\350\257\257\347\232\204\351\233\206\345\220\210_645_\347\256\200\345\215\225/Solution2.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\351\224\231\350\257\257\347\232\204\351\233\206\345\220\210_645_\347\256\200\345\215\225/Solution2.java" new file mode 100644 index 00000000..b604915c --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\351\224\231\350\257\257\347\232\204\351\233\206\345\220\210_645_\347\256\200\345\215\225/Solution2.java" @@ -0,0 +1,54 @@ +package cn.lastwhisper.leetcode.array.错误的集合_645_简单; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +class Solution2 { + /** + * https://leetcode-cn.com/problems/set-mismatch/ + * ------------------------------------------------------------------- + * 数据特征: + * 输入:数组、1~n整数、无序、存在重复数据、不一定包含丢失数据 + * 输出:数组[重复数据,丢失数据]、1~n+1整数、 + * ------------------------------------------------------------------- + * 思路: + * 遍历输入数组,使用map存储数组值出现的频率 + * 正常数据1~length每一个出现的频率都为1,将1~length每一个值当做key查询map, + * frequency=2的为重复数据,frequency=null为丢失数据 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(n) + * ------------------------------------------------------------------- + * 改进: + * 将数组值当做数据下标,统计该值出现的频率 + * map需要使用2n的额外空间,使用额外数组当做map,只需要使用n的额外空间 + */ + public int[] findErrorNums(int[] nums) { + Map numFreMap = new HashMap<>(); + int duplicate = -1, miss = -1; + for (int num : nums) { + numFreMap.put(num, numFreMap.getOrDefault(num, 0) + 1); + } + for (int i = 1; i <= nums.length; i++) { + Integer frequency = numFreMap.get(i); + if (frequency == null) { + miss = i; + } else if (frequency == 2) { + duplicate = i; + } + } + return new int[]{duplicate, miss}; + } + + public static void main(String[] args) { + // example + //int[] arr = {1, 2, 2, 4};//2,3 + //int[] arr = {2, 2};//2,1 + // error example + //int[] arr = {3, 2, 2};//2,1 + //int[] arr = {1, 1};//1,2 + int[] arr = {1, 5, 3, 2, 2, 7, 6, 4, 8, 9}; + System.out.println(Arrays.toString(new Solution2().findErrorNums(arr))); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\351\224\231\350\257\257\347\232\204\351\233\206\345\220\210_645_\347\256\200\345\215\225/Solution3.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\351\224\231\350\257\257\347\232\204\351\233\206\345\220\210_645_\347\256\200\345\215\225/Solution3.java" new file mode 100644 index 00000000..277ee841 --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\351\224\231\350\257\257\347\232\204\351\233\206\345\220\210_645_\347\256\200\345\215\225/Solution3.java" @@ -0,0 +1,19 @@ +package cn.lastwhisper.leetcode.array.错误的集合_645_简单; + +class Solution3 { + public int[] findErrorNums(int[] nums) { + int[] copy = new int[nums.length + 1]; + for (int n : nums) { + copy[n]++; + } + + int[] res = new int[2]; + for (int i = 1; i < copy.length; i++) { + if (copy[i] == 0) + res[1] = i; + if (copy[i] >= 2) + res[0] = i; + } + return res; + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\351\224\231\350\257\257\347\232\204\351\233\206\345\220\210_645_\347\256\200\345\215\225/Solution4.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\351\224\231\350\257\257\347\232\204\351\233\206\345\220\210_645_\347\256\200\345\215\225/Solution4.java" new file mode 100644 index 00000000..da9c2807 --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\351\224\231\350\257\257\347\232\204\351\233\206\345\220\210_645_\347\256\200\345\215\225/Solution4.java" @@ -0,0 +1,52 @@ +package cn.lastwhisper.leetcode.array.错误的集合_645_简单; + +import java.util.Arrays; + +class Solution4 { + /** + * https://leetcode-cn.com/problems/set-mismatch/ + * ------------------------------------------------------------------- + * 数据特征: + * 输入:数组、1~n整数、无序、存在重复数据、不一定包含丢失数据 + * 输出:数组[重复数据,丢失数据]、1~n+1整数、 + * ------------------------------------------------------------------- + * 思路:将数组中的每一个值当做下标,按下标-1找到数组对应的值,并更新为负数, + * 在更新之前检查这个值是否已经是负数,如果已经是负数,说明这个值是重复数据。 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(1) + * ------------------------------------------------------------------- + * 相似题目:https://leetcode-cn.com/problems/first-missing-positive/ + */ + public int[] findErrorNums(int[] nums) { + // 丢失数据初始值为1, + int duplicate = -1, miss = 1; + for (int num : nums) { + if (nums[Math.abs(num) - 1] < 0) { + // 重复出现的下标 + duplicate = Math.abs(num); + } else { + nums[Math.abs(num) - 1] *= -1; + } + } + for (int i = 0; i < nums.length; i++) { + if (nums[i] > 0) { + miss = i + 1; + } + } + return new int[]{duplicate, miss}; + } + + public static void main(String[] args) { + // example + //int[] arr = {1, 2, 2, 4};//2,3 + //int[] arr = {2, 2};//2,1 + // error example + //int[] arr = {3, 2, 2};//2,1 + //int[] arr = {1, 1};//1,2 + //int[] arr = {1, 5, 3, 2, 2, 7, 6, 4, 8, 9};//10 + //int[] arr = {2, 3, 2}; + int[] arr = {3,3,1}; + System.out.println(Arrays.toString(new Solution4().findErrorNums(arr))); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\351\225\277\345\272\246\346\234\200\345\260\217\347\232\204\345\255\220\346\225\260\347\273\204_209_\344\270\255\347\255\211/Solution1.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\351\225\277\345\272\246\346\234\200\345\260\217\347\232\204\345\255\220\346\225\260\347\273\204_209_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..1c23fde0 --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\351\225\277\345\272\246\346\234\200\345\260\217\347\232\204\345\255\220\346\225\260\347\273\204_209_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,45 @@ +package cn.lastwhisper.leetcode.array.长度最小的子数组_209_中等; + +import org.junit.Assert; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/minimum-size-subarray-sum/ + * 编号:209 + * ------------------------------------------------------------------- + * 思考:边界值一定要考虑取还是不取,为什么? + * ------------------------------------------------------------------- + * 思路:二层循环暴力组合,一层循环计算组合范围值 + * ------------------------------------------------------------------- + * 时间复杂度:O(n^3) + * 空间复杂度:O(1) + */ + public int minSubArrayLen(int s, int[] nums) { + if (s <= 0 || nums == null) { + throw new IllegalArgumentException("Illegal Argument"); + } + // 子数组长度有可能等于 nums.length + int ans = Integer.MAX_VALUE; + for (int i = 0; i < nums.length; i++) { + for (int j = i; j < nums.length; j++) { + int sum = 0; + // 计算 [i,j] 子数组的和 + for (int k = i; k <= j; k++) { + sum += nums[k]; + } + if (sum >= s) { + ans = Math.min(ans, j - i + 1);// i=0,j=1 ————> ans=2 + j = nums.length;// 退出内循环 + } + } + } + // 子数组长度等于 nums.length+1,说明无解 + if (ans == Integer.MAX_VALUE) + return 0; + return ans; + } + + public static void main(String[] args) { + Assert.assertEquals(2, new Solution1().minSubArrayLen(7, new int[]{2, 3, 1, 2, 4, 3})); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\351\225\277\345\272\246\346\234\200\345\260\217\347\232\204\345\255\220\346\225\260\347\273\204_209_\344\270\255\347\255\211/Solution2.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\351\225\277\345\272\246\346\234\200\345\260\217\347\232\204\345\255\220\346\225\260\347\273\204_209_\344\270\255\347\255\211/Solution2.java" new file mode 100644 index 00000000..e9082877 --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\351\225\277\345\272\246\346\234\200\345\260\217\347\232\204\345\255\220\346\225\260\347\273\204_209_\344\270\255\347\255\211/Solution2.java" @@ -0,0 +1,54 @@ +package cn.lastwhisper.leetcode.array.长度最小的子数组_209_中等; + +import org.junit.Assert; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/minimum-size-subarray-sum/ + * 编号:209 + * ------------------------------------------------------------------- + * 思考:边界值一定要考虑取还是不取,为什么? + * ------------------------------------------------------------------- + * 思路:二层循环暴力组合 + * 组合的和提前计算 + * (1)提前将 sum[0...n] 计算出来, sum[0] = 0; sum[i] = sum[i-1] + num[i-1] + * (2)nums[i...j] 的和 = sum[j+1]-sum[i] + * ------------------------------------------------------------------- + * 时间复杂度:O(n^2) + * 空间复杂度:O(n) + */ + public int minSubArrayLen(int s, int[] nums) { + if (s <= 0 || nums == null) { + throw new IllegalArgumentException("Illegal Argument"); + } + // nums=> 2, 3, 1, 2, 4, 3 + // sum=>0, 2, 5, 6, 8, 12, 15 + // sums[i] 存放 nums[0...i-1] 的和 + int[] sum = new int[nums.length + 1]; + sum[0] = 0; + for (int i = 1; i <= nums.length; i++) { + sum[i] = sum[i - 1] + nums[i - 1]; + } + // 子数组长度有可能等于 nums.length + int ans = Integer.MAX_VALUE; + for (int i = 0; i < nums.length; i++) { + for (int j = i; j < nums.length; j++) { + // sum[j+1] - sum[0] = num[0,j]的和,sum[0]==0 + // sum[j+1] - sum[i] = num[i,j]的和 + if (sum[j + 1] - sum[i] >= s) { + ans = Math.min(ans, j - i + 1); + //j = nums.length;// 退出内循环 + break; + } + } + } + // 子数组长度等于 nums.length+1,说明无解 + if (ans == Integer.MAX_VALUE) + return 0; + return ans; + } + + public static void main(String[] args) { + Assert.assertEquals(2, new Solution2().minSubArrayLen(7, new int[]{2, 3, 1, 2, 4, 3})); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\351\225\277\345\272\246\346\234\200\345\260\217\347\232\204\345\255\220\346\225\260\347\273\204_209_\344\270\255\347\255\211/Solution3.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\351\225\277\345\272\246\346\234\200\345\260\217\347\232\204\345\255\220\346\225\260\347\273\204_209_\344\270\255\347\255\211/Solution3.java" new file mode 100644 index 00000000..f34de047 --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\351\225\277\345\272\246\346\234\200\345\260\217\347\232\204\345\255\220\346\225\260\347\273\204_209_\344\270\255\347\255\211/Solution3.java" @@ -0,0 +1,51 @@ +package cn.lastwhisper.leetcode.array.长度最小的子数组_209_中等; + +import org.junit.Assert; + +class Solution3 { + /** + * 题目地址:https://leetcode-cn.com/problems/minimum-size-subarray-sum/ + * 编号:209 + * ------------------------------------------------------------------- + * 思考:边界值一定要考虑取还是不取,为什么? + * ------------------------------------------------------------------- + * 思路:滑动窗口 + * (1)双指针 l、r 维护一个滑动窗口 + * (2)窗口的左边界在数组范围内,则循环继续 + * (3)r未到数组尾且 sums 需要动态缩小窗口左边界 + * (5)循环内每次找 sum >= s 时的最小长度 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) // l 和 r 指针同时遍历了一遍数组 O(2n) + * 空间复杂度:O(1) + */ + public int minSubArrayLen(int s, int[] nums) { + if (s <= 0 || nums == null) { + throw new IllegalArgumentException("Illegal Argument"); + } + // 初始窗口 [l,r] 是一个空集,所以 r 初值为 -1,后面需要先加才能使用 + int l = 0, r = -1; + int ans = Integer.MAX_VALUE, sum = 0; + // 维护窗口,通过窗口内 sum 与 s 的关系,触发窗口的扩容或缩小 + // 窗口的左边界在数组范围内,说明窗口还能继续扩容或者缩小 + while (l < nums.length) { + // 因为 r 先加再用所以要保证 r + 1 < nums.length + if (r + 1 < nums.length && sum < s) { + sum += nums[++r]; + } else { + sum -= nums[l++]; + } + if (sum >= s) { + ans = Math.min(ans, (r - l + 1)); + } + } + if (ans == Integer.MAX_VALUE) { + ans = 0; + } + return ans; + } + + public static void main(String[] args) { + Assert.assertEquals(2, new Solution3().minSubArrayLen(7, new int[]{2, 3, 1, 2, 4, 3})); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\351\225\277\345\272\246\346\234\200\345\260\217\347\232\204\345\255\220\346\225\260\347\273\204_209_\344\270\255\347\255\211/Solution4.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\351\225\277\345\272\246\346\234\200\345\260\217\347\232\204\345\255\220\346\225\260\347\273\204_209_\344\270\255\347\255\211/Solution4.java" new file mode 100644 index 00000000..32800e20 --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\351\225\277\345\272\246\346\234\200\345\260\217\347\232\204\345\255\220\346\225\260\347\273\204_209_\344\270\255\347\255\211/Solution4.java" @@ -0,0 +1,32 @@ +package cn.lastwhisper.leetcode.array.长度最小的子数组_209_中等; + +import org.junit.Assert; + +class Solution4 { + /** + * 题目地址:https://leetcode-cn.com/problems/minimum-size-subarray-sum/ + * 编号:209 + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:滑动窗口 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) // l 和 r 指针同时遍历了一遍数组 O(2n) + * 空间复杂度:O(1) + */ + public int minSubArrayLen(int s, int[] nums) { + int l = 0, sum = 0, ans = Integer.MAX_VALUE; + for (int r = 0; r < nums.length; r++) { + sum += nums[r]; + while (sum >= s) { + ans = Math.min(ans, r - l + 1); + sum -= nums[l++]; + } + } + return ans == Integer.MAX_VALUE ? 0 : ans; + } + + public static void main(String[] args) { + Assert.assertEquals(2, new Solution4().minSubArrayLen(7, new int[]{2, 3, 1, 2, 4, 3})); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\351\225\277\345\272\246\346\234\200\345\260\217\347\232\204\345\255\220\346\225\260\347\273\204_209_\344\270\255\347\255\211/Solution5.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\351\225\277\345\272\246\346\234\200\345\260\217\347\232\204\345\255\220\346\225\260\347\273\204_209_\344\270\255\347\255\211/Solution5.java" new file mode 100644 index 00000000..95b5835d --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\351\225\277\345\272\246\346\234\200\345\260\217\347\232\204\345\255\220\346\225\260\347\273\204_209_\344\270\255\347\255\211/Solution5.java" @@ -0,0 +1,69 @@ +package cn.lastwhisper.leetcode.array.长度最小的子数组_209_中等; + +/** + * 209. 长度最小的子数组 + * https://leetcode-cn.com/problems/minimum-size-subarray-sum/ + * @author lastwhisper + */ +public class Solution5 { + // 二分搜索 + // 扩展 Solution5 的方法。对于每一个l, 可以使用二分搜索法搜索r + // 时间复杂度: O(nlogn) + // 空间复杂度: O(n) + public int minSubArrayLen(int s, int[] nums) { + if(s <= 0 || nums == null) + throw new IllegalArgumentException("Illegal Arguments"); + + // sums[i]存放nums[0...i-1]的和 + int[] sums = new int[nums.length + 1]; + sums[0] = 0; + for(int i = 1 ; i <= nums.length ; i ++) + sums[i] = sums[i-1] + nums[i-1]; + + int res = Integer.MAX_VALUE; + for(int l = 0 ; l < nums.length - 1 ; l ++){ + // Java类库中没有内置的lowerBound方法, + // 我们需要自己实现一个基于二分搜索的lowerBound:) + int r = lowerBound(sums, sums[l] + s); + if(r != sums.length){ + res = Math.min(res, r - l); + } + } + + if(res == Integer.MAX_VALUE) + return 0; + return res; + } + + // 在有序数组nums中寻找大于等于target的最小值 + // 如果没有(nums数组中所有值都小于target),则返回nums.length + private int lowerBound(int[] nums, int target){ + if(nums == null /*|| !isSorted(nums)*/) + throw new IllegalArgumentException("Illegal argument nums in lowerBound."); + + int l = 0, r = nums.length; // 在nums[l...r)的范围里寻找解 + while(l != r){ + int mid = l + (r - l) / 2; + if(nums[mid] >= target) + r = mid; + else + l = mid + 1; + } + + return l; + } + + private boolean isSorted(int[] nums){ + for(int i = 1 ; i < nums.length ; i ++) + if(nums[i] < nums[i-1]) + return false; + return true; + } + + public static void main(String[] args) { + + int[] nums = {2, 3, 1, 2, 4, 3}; + int s = 7; + System.out.println((new Solution5()).minSubArrayLen(s, nums)); + } +} diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\351\225\277\345\272\246\346\234\200\345\260\217\347\232\204\345\255\220\346\225\260\347\273\204_209_\344\270\255\347\255\211/Solution6.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\351\225\277\345\272\246\346\234\200\345\260\217\347\232\204\345\255\220\346\225\260\347\273\204_209_\344\270\255\347\255\211/Solution6.java" new file mode 100644 index 00000000..ffb08944 --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\351\225\277\345\272\246\346\234\200\345\260\217\347\232\204\345\255\220\346\225\260\347\273\204_209_\344\270\255\347\255\211/Solution6.java" @@ -0,0 +1,52 @@ +package cn.lastwhisper.leetcode.array.长度最小的子数组_209_中等; + +import org.junit.Assert; + +class Solution6 { + /** + * 题目地址:https://leetcode-cn.com/problems/minimum-size-subarray-sum/ + * 编号:209 + * ------------------------------------------------------------------- + * 思考:边界值一定要考虑取还是不取,为什么? + * ------------------------------------------------------------------- + * 思路:滑动窗口 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(1) + */ + public int minSubArrayLen(int s, int[] nums) { + if (s <= 0 || nums == null) { + throw new IllegalArgumentException("Illegal Argument"); + } + // 初始窗口 [l,r] 是一个空集,所以 r 初值为 -1,后面需要先加才能使用 + int l = 0, r = -1; + int ans = Integer.MAX_VALUE, sum = 0; + // 维护窗口,通过窗口内 sum 与 s 的关系,触发窗口的扩容或缩小 + // 窗口的右边界在数组范围内,说明窗口还能继续扩容或者缩小 + while (r + 1 < nums.length) { + // 因为 r 先加再用所以 r < nums.length - 1 + while (r + 1 < nums.length && sum < s) { + r++; + sum += nums[r]; + } + if (sum >= s) { + ans = Math.min(ans, (r + 1 - l)); + } + while (l < nums.length && sum >= s) { + sum -= nums[l]; + l++; + if (sum >= s) { + ans = Math.min(ans, (r + 1 - l)); + } + } + } + if (ans == Integer.MAX_VALUE) { + ans = 0; + } + return ans; + } + + public static void main(String[] args) { + Assert.assertEquals(2, new Solution6().minSubArrayLen(7, new int[]{2, 3, 1, 2, 4, 3})); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\351\242\234\350\211\262\345\210\206\347\261\273_75_\344\270\255\347\255\211/Solution1.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\351\242\234\350\211\262\345\210\206\347\261\273_75_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..17a33f1c --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\351\242\234\350\211\262\345\210\206\347\261\273_75_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,39 @@ +package cn.lastwhisper.leetcode.array.颜色分类_75_中等; + +import org.junit.Assert; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/sort-colors/ + * 编号:75 + * ------------------------------------------------------------------- + * 思考: + * 数据特征:只有0,1,2 + * ------------------------------------------------------------------- + * 思路: + * 计数排序,统计每一个数出现的频率 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(1) + */ + public void sortColors(int[] nums) { + // freq 统计0、1、2的频率 + int[] freq = new int[3]; + for (int num : nums) { + freq[num]++; + } + int idx = 0; + for (int i = 0; i < freq.length; i++) { + while (freq[i]-- > 0) { + nums[idx++] = i; + } + } + } + + public static void main(String[] args) { + int[] arr = new int[]{2, 0, 2, 1, 1, 0}; + new Solution1().sortColors(arr); + Assert.assertArrayEquals(new int[]{0, 0, 1, 1, 2, 2}, arr); + } + +} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\351\242\234\350\211\262\345\210\206\347\261\273_75_\344\270\255\347\255\211/Solution2.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\351\242\234\350\211\262\345\210\206\347\261\273_75_\344\270\255\347\255\211/Solution2.java" new file mode 100644 index 00000000..d169835d --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\351\242\234\350\211\262\345\210\206\347\261\273_75_\344\270\255\347\255\211/Solution2.java" @@ -0,0 +1,51 @@ +package cn.lastwhisper.leetcode.array.颜色分类_75_中等; + +import org.junit.Assert; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/sort-colors/ + * 编号:75 + * ------------------------------------------------------------------- + * 思考: + * 数据特征:只有0,1,2 + * ------------------------------------------------------------------- + * 思路: + * 三路快速排序的思想,对整个数组只遍历了一遍 + * (1)双指针 left=-1,right=n + * (2)下标 i 遍历数组,num[i]==1,i++ + * (3)num[i]==0,将 0 移动到数组最前位置,swap(num,++left,i++) + * i++,即使 num[++left]==0,这次的交换和位移也是正确的 + * (4)num[i]==2,将 2 移动到数组最后位置,swap(num,--right,i) + * i不变,因为有可能num[--right]==2 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(1) + */ + public void sortColors(int[] nums) { + int left = -1, right = nums.length; + for (int i = 0; i < right; ) { + if (nums[i] == 1) { + i++; + } else if (nums[i] == 0) { + swap(nums, ++left, i++); + } else if (nums[i] == 2) { + swap(nums, --right, i); + } + } + } + + public void swap(int[] num, int i, int j) { + if (i != j) { + int temp = num[j]; + num[j] = num[i]; + num[i] = temp; + } + } + + public static void main(String[] args) { + int[] arr = new int[]{2, 0, 2, 1, 1, 0}; + new Solution2().sortColors(arr); + Assert.assertArrayEquals(new int[]{0, 0, 1, 1, 2, 2}, arr); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\351\252\214\350\257\201\345\233\236\346\226\207\344\270\262_125_\347\256\200\345\215\225/Solution1.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\351\252\214\350\257\201\345\233\236\346\226\207\344\270\262_125_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..1db21830 --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\351\252\214\350\257\201\345\233\236\346\226\207\344\270\262_125_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,48 @@ +package cn.lastwhisper.leetcode.array.验证回文串_125_简单; + +import org.junit.Assert; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/valid-palindrome/ + * 编号:125 + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * 对撞指针遍历比较 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(n) + */ + public boolean isPalindrome(String s) { + String upperS = s.toUpperCase(); + int l = 0, r = upperS.length() - 1; + // 这里不能等于 + while (l < r) { + while (l < r && !valid(upperS.charAt(l))) { + l++; + } + while (l < r && !valid(upperS.charAt(r))) { + r--; + } + if (upperS.charAt(l) != upperS.charAt(r)) { + return false; + } + l++; + r--; + } + return true; + } + // 只考虑字母和数字字符 + private boolean valid(char c) { + return ((c >= 48 && c <= 57) || (c >= 65 && c <= 90) || (c >= 97 && c <= 122)); + } + + public static void main(String[] args) { + //String s = "A man, a plan, a canal: Panama"; + //String s = "race a car"; + String s = "a"; + Assert.assertTrue(new Solution1().isPalindrome(s)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\351\252\214\350\257\201\345\233\236\346\226\207\344\270\262_125_\347\256\200\345\215\225/Solution2.java" "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\351\252\214\350\257\201\345\233\236\346\226\207\344\270\262_125_\347\256\200\345\215\225/Solution2.java" new file mode 100644 index 00000000..2720acde --- /dev/null +++ "b/algorithms/leetcode/array/src/main/java/cn/lastwhisper/leetcode/array/\351\252\214\350\257\201\345\233\236\346\226\207\344\270\262_125_\347\256\200\345\215\225/Solution2.java" @@ -0,0 +1,41 @@ +package cn.lastwhisper.leetcode.array.验证回文串_125_简单; + +import org.junit.Assert; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/valid-palindrome/ + * 编号:125 + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * 对撞指针遍历比较 + * 统一转成大写:ch & 0b11011111 简写:ch & 0xDF + * 统一转成小写:ch | 0b00100000 简写:ch | 0x20 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(1) + */ + public boolean isPalindrome(String s) { + int l = 0, r = s.length() - 1; + while (l < r) {// 这里不能等于 + while (l < r && !valid(s.charAt(l))) l++; + while (l < r && !valid(s.charAt(r))) r--; + if ((s.charAt(l++) & 0xDF) != (s.charAt(r--) & 0xDF)) return false; + } + return true; + } + + // 只考虑字母和数字字符 + private boolean valid(char c) { + return ((c >= 48 && c <= 57) || (c >= 65 && c <= 90) || (c >= 97 && c <= 122)); + } + + public static void main(String[] args) { + String s = "A man, a plan, a canal: Panama"; + //String s = "race a car"; + //String s = "a"; + Assert.assertTrue(new Solution2().isPalindrome(s)); + } +} \ No newline at end of file diff --git a/algorithms/leetcode/binarysearch/pom.xml b/algorithms/leetcode/binarysearch/pom.xml new file mode 100644 index 00000000..2427d876 --- /dev/null +++ b/algorithms/leetcode/binarysearch/pom.xml @@ -0,0 +1,15 @@ + + + + leetcode + cn.lastwhisper + 1.0-SNAPSHOT + + 4.0.0 + + binarysearch + + + \ No newline at end of file diff --git "a/algorithms/leetcode/binarysearch/src/main/java/cn/lastwhisper/leetcode/binarysearch/pow_50_\344\270\255\347\255\211/Solution1.java" "b/algorithms/leetcode/binarysearch/src/main/java/cn/lastwhisper/leetcode/binarysearch/pow_50_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..355ab5b7 --- /dev/null +++ "b/algorithms/leetcode/binarysearch/src/main/java/cn/lastwhisper/leetcode/binarysearch/pow_50_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,51 @@ +package cn.lastwhisper.leetcode.binarysearch.pow_50_中等; + + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/shu-zhi-de-zheng-shu-ci-fang-lcof/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * 一、n=-2147483648无法处理 + * 二、二分优化n^8=n^4^2=n^2^2^2 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(n) + */ + public double myPow(double x, int n) { + if (x == 0) { + return 0; + } + // x底数 n指数 + double result; + + int absExponent = n; + if (n < 0) absExponent = -n; + result = pow(x, absExponent); + + if (n < 0) { + result = 1.0 / result; + } + + return result; + } + + public double pow(double base, int exponent) { + double result = 1.0; + for (int i = 0; i < exponent; i++) { + result *= base; + } + return result; + } + + public static void main(String[] args) { + //System.err.println(new Solution1().myPow(2.00000, 2)); + //System.err.println(new Solution1().myPow(2.00000, -2)); + //System.err.println(new Solution1().myPow(2.00000, 0)); + System.err.println(new Solution1().myPow(0, 0)); + System.err.println(new Solution1().myPow(-1, 0)); + System.err.println(new Solution1().myPow(2.00000, 10)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/binarysearch/src/main/java/cn/lastwhisper/leetcode/binarysearch/pow_50_\344\270\255\347\255\211/Solution2.java" "b/algorithms/leetcode/binarysearch/src/main/java/cn/lastwhisper/leetcode/binarysearch/pow_50_\344\270\255\347\255\211/Solution2.java" new file mode 100644 index 00000000..46b08d04 --- /dev/null +++ "b/algorithms/leetcode/binarysearch/src/main/java/cn/lastwhisper/leetcode/binarysearch/pow_50_\344\270\255\347\255\211/Solution2.java" @@ -0,0 +1,34 @@ +package cn.lastwhisper.leetcode.binarysearch.pow_50_中等; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/shu-zhi-de-zheng-shu-ci-fang-lcof/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(n) + */ + public double myPow(double x, int n) { + double res = 1.0; + for (int i = n; i != 0; i /= 2) { + if (i % 2 != 0) { + res *= x; + } + x *= x; + } + return n < 0 ? 1 / res : res; + } + + public static void main(String[] args) { + //System.err.println(new Solution2().myPow(2.00000, 2)); + //System.err.println(new Solution2().myPow(2.00000, -2)); + //System.err.println(new Solution2().myPow(2.00000, 0)); + //System.err.println(new Solution2().myPow(0, 0)); + //System.err.println(new Solution2().myPow(-1, 0)); + //System.err.println(new Solution2().myPow(2.00000, 10)); + System.err.println(new Solution2().myPow(2.00000, -2147483648)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/binarysearch/src/main/java/cn/lastwhisper/leetcode/binarysearch/pow_50_\344\270\255\347\255\211/Solution3.java" "b/algorithms/leetcode/binarysearch/src/main/java/cn/lastwhisper/leetcode/binarysearch/pow_50_\344\270\255\347\255\211/Solution3.java" new file mode 100644 index 00000000..f78d0303 --- /dev/null +++ "b/algorithms/leetcode/binarysearch/src/main/java/cn/lastwhisper/leetcode/binarysearch/pow_50_\344\270\255\347\255\211/Solution3.java" @@ -0,0 +1,25 @@ +package cn.lastwhisper.leetcode.binarysearch.pow_50_中等; + +class Solution3 { + public double myPow(double x, int n) { + // 指数-偶数 + if (n == 0) { + return 1; + } + // 指数-奇数 + if (n == 1) { + return x; + } + // 指数-负数 + if (n == -1) { + return 1 / x; + } + double half = myPow(x, n / 2);//n>>1 + double base = myPow(x, n % 2); + return half * half * base; + } + + public static void main(String[] args){ + System.err.println(new Solution3().myPow(34.00515,-3)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/binarysearch/src/main/java/cn/lastwhisper/leetcode/binarysearch/\344\272\214\345\210\206\346\237\245\346\211\276_704_\347\256\200\345\215\225/Solution1.java" "b/algorithms/leetcode/binarysearch/src/main/java/cn/lastwhisper/leetcode/binarysearch/\344\272\214\345\210\206\346\237\245\346\211\276_704_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..74a71577 --- /dev/null +++ "b/algorithms/leetcode/binarysearch/src/main/java/cn/lastwhisper/leetcode/binarysearch/\344\272\214\345\210\206\346\237\245\346\211\276_704_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,53 @@ +package cn.lastwhisper.leetcode.binarysearch.二分查找_704_简单; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/binary-search/ + * ------------------------------------------------------------------- + * 思考: + * 二分搜索防加法溢出,遍历和递归两种写法 + * ------------------------------------------------------------------- + * 思路: + * 遍历 + * ------------------------------------------------------------------- + * 时间复杂度:O(logn) + * 空间复杂度:O(1) + */ + public int search(int[] nums, int target) { + /* + * 为什么是[0,nums.length - 1]? + * 仅仅是数组范围 + */ + int start = 0, end = nums.length - 1, middle; + /* + * 为什么是end >= start? + * 由于middle+1和middle-1的存在,所以合法的[start,end]范围内肯定是待搜索的 + */ + while (end >= start) { + /* + * 如何避免middle = (end + start) / 2;加法溢出? + */ + middle = (end - start) / 2 + start; + if (nums[middle] == target) { + return middle; + } else if (nums[middle] > target) { + /* + * 为什么middle - 1?(两个方面) + * 1.为了跳出while循环 + * 2.nums[middle] > target时,middle本身不在搜索范围 + */ + end = middle - 1; + } else { + start = middle + 1; + } + } + return -1; + } + + public static void main(String[] args) { + int[] nums = {-1, 0, 3, 5, 9, 12}; + //int target = 9; + int target = 2; + System.out.println(new Solution1().search(nums, target)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/binarysearch/src/main/java/cn/lastwhisper/leetcode/binarysearch/\344\272\214\345\210\206\346\237\245\346\211\276_704_\347\256\200\345\215\225/Solution2.java" "b/algorithms/leetcode/binarysearch/src/main/java/cn/lastwhisper/leetcode/binarysearch/\344\272\214\345\210\206\346\237\245\346\211\276_704_\347\256\200\345\215\225/Solution2.java" new file mode 100644 index 00000000..62789934 --- /dev/null +++ "b/algorithms/leetcode/binarysearch/src/main/java/cn/lastwhisper/leetcode/binarysearch/\344\272\214\345\210\206\346\237\245\346\211\276_704_\347\256\200\345\215\225/Solution2.java" @@ -0,0 +1,41 @@ +package cn.lastwhisper.leetcode.binarysearch.二分查找_704_简单; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/binary-search/ + * ------------------------------------------------------------------- + * 思考: + * 二分搜索防加法溢出,遍历和递归两种写法 + * ------------------------------------------------------------------- + * 思路: + * 递归写法 + * ------------------------------------------------------------------- + * 时间复杂度:O(logn) + * 空间复杂度:O(logn) + */ + public int search(int[] nums, int target) { + return binarySearch(nums, target, 0, nums.length - 1); + } + + public int binarySearch(int[] nums, int target, int start, int end) { + if (end < start) { + return -1; + } + int middle = (end - start) / 2 + start; + if (nums[middle] == target) { + return middle; + } else if (nums[middle] > target) { + end = middle - 1; + } else { + start = middle + 1; + } + return binarySearch(nums, target, start, end); + } + + public static void main(String[] args) { + int[] nums = {-1, 0, 3, 5, 9, 12}; + int target = 9; + //int target = 2; + System.out.println(new Solution2().search(nums, target)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/binarysearch/src/main/java/cn/lastwhisper/leetcode/binarysearch/\345\257\273\346\211\276\346\227\213\350\275\254\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\346\234\200\345\260\217\345\200\274II_154_\345\233\260\351\232\276/Solution1.java" "b/algorithms/leetcode/binarysearch/src/main/java/cn/lastwhisper/leetcode/binarysearch/\345\257\273\346\211\276\346\227\213\350\275\254\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\346\234\200\345\260\217\345\200\274II_154_\345\233\260\351\232\276/Solution1.java" new file mode 100644 index 00000000..a54fd952 --- /dev/null +++ "b/algorithms/leetcode/binarysearch/src/main/java/cn/lastwhisper/leetcode/binarysearch/\345\257\273\346\211\276\346\227\213\350\275\254\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\346\234\200\345\260\217\345\200\274II_154_\345\233\260\351\232\276/Solution1.java" @@ -0,0 +1,57 @@ +package cn.lastwhisper.leetcode.binarysearch.寻找旋转排序数组中的最小值II_154_困难; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array-ii/ + * ------------------------------------------------------------------- + * 思考: + * 输入特征: + * 1、两个连续有序部分 + * 2、nums[0]>=num[n] + * 3、数组内无重复 + * ------------------------------------------------------------------- + * 思路: + * 一、遍历 + * 二、二分 + * ------------------------------------------------------------------- + * 时间复杂度:O(logn) + * 空间复杂度:O(n) + */ + public int findMin(int[] nums) { + int left = 0, right = nums.length - 1, middle = left; + + while (nums[left] >= nums[right]) { + // 找到最小值 + if (right - left == 1) { + middle = right; + break; + } + middle = (right - left) / 2 + left; + + // 无法界定middle属于前数组还是后数组 {1, 0, 1, 1, 1};//01111 + if (nums[left] == nums[middle] && nums[right] == nums[middle]) { + return sequenceSearch(left, right, nums); + } + + if (nums[middle] >= nums[left]) { + left = middle; + } else if (nums[middle] <= nums[right]) { + right = middle; + } + } + return nums[middle]; + } + + // 顺序查找 + public int sequenceSearch(int left, int right, int[] nums) { + int min = nums[left]; + for (int i = left + 1; i <= right; i++) { + if (nums[i] < min) { + min = nums[i]; + } + } + return min; + } + + +} \ No newline at end of file diff --git "a/algorithms/leetcode/binarysearch/src/main/java/cn/lastwhisper/leetcode/binarysearch/\345\257\273\346\211\276\346\227\213\350\275\254\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\346\234\200\345\260\217\345\200\274II_154_\345\233\260\351\232\276/Solution2.java" "b/algorithms/leetcode/binarysearch/src/main/java/cn/lastwhisper/leetcode/binarysearch/\345\257\273\346\211\276\346\227\213\350\275\254\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\346\234\200\345\260\217\345\200\274II_154_\345\233\260\351\232\276/Solution2.java" new file mode 100644 index 00000000..fa277246 --- /dev/null +++ "b/algorithms/leetcode/binarysearch/src/main/java/cn/lastwhisper/leetcode/binarysearch/\345\257\273\346\211\276\346\227\213\350\275\254\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\346\234\200\345\260\217\345\200\274II_154_\345\233\260\351\232\276/Solution2.java" @@ -0,0 +1,23 @@ +package cn.lastwhisper.leetcode.binarysearch.寻找旋转排序数组中的最小值II_154_困难; + +class Solution2 { + public int findMin(int[] nums) { + int left = 0, right = nums.length - 1; + while (left < right) { + int mid = (left + right) / 2; + if (nums[mid] > nums[right]) left = mid + 1; + else if (nums[mid] < nums[right]) right = mid; + else right = right - 1; + } + return nums[left]; + } + + public static void main(String[] args) { + //int[] nums = new int[]{3, 4, 5, 1, 2}; + //int[] nums = new int[]{0,0,0,0}; + int[] nums = new int[]{1, 0, 1, 1, 1};//01111 + //int[] nums = new int[]{1,1,1,0,1};//01111 + //int[] nums = new int[]{0, 1, 1, 1, 1};//01111 + System.err.println(new Solution2().findMin(nums)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/binarysearch/src/main/java/cn/lastwhisper/leetcode/binarysearch/\345\257\273\346\211\276\346\227\213\350\275\254\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\346\234\200\345\260\217\345\200\274_153_\344\270\255\347\255\211/Solution1.java" "b/algorithms/leetcode/binarysearch/src/main/java/cn/lastwhisper/leetcode/binarysearch/\345\257\273\346\211\276\346\227\213\350\275\254\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\346\234\200\345\260\217\345\200\274_153_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..0bf96aa3 --- /dev/null +++ "b/algorithms/leetcode/binarysearch/src/main/java/cn/lastwhisper/leetcode/binarysearch/\345\257\273\346\211\276\346\227\213\350\275\254\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\346\234\200\345\260\217\345\200\274_153_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,47 @@ +package cn.lastwhisper.leetcode.binarysearch.寻找旋转排序数组中的最小值_153_中等; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array/ + * ------------------------------------------------------------------- + * 思考: + * 输入特征: + * 1、两个连续有序部分 + * 2、nums[0]>num[n] + * 3、数组内无重复 + * ------------------------------------------------------------------- + * 思路: + * 一、遍历 + * 二、二分 + * ------------------------------------------------------------------- + * 时间复杂度:O(logn) + * 空间复杂度:O(n) + */ + public int findMin(int[] nums) { + int left = 0, right = nums.length - 1, middle = left; + + while (nums[left] > nums[right]) { + // 找到最小值 + if (right - left == 1) { + middle = right; + break; + } + middle = (right - left) / 2 + left; + + if (nums[middle] > nums[left]) { + // middle在左数组 + left = middle; + } else if (nums[middle] < nums[right]) { + // middle在右数组 + right = middle; + } + } + return nums[middle]; + } + + public static void main(String[] args) { + int[] nums = new int[]{3,4,5,1,2}; + + System.err.println(new Solution1().findMin(nums)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/binarysearch/src/main/java/cn/lastwhisper/leetcode/binarysearch/\346\220\234\347\264\242\346\217\222\345\205\245\344\275\215\347\275\256_35_\347\256\200\345\215\225/Solution1.java" "b/algorithms/leetcode/binarysearch/src/main/java/cn/lastwhisper/leetcode/binarysearch/\346\220\234\347\264\242\346\217\222\345\205\245\344\275\215\347\275\256_35_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..aaa8dfcb --- /dev/null +++ "b/algorithms/leetcode/binarysearch/src/main/java/cn/lastwhisper/leetcode/binarysearch/\346\220\234\347\264\242\346\217\222\345\205\245\344\275\215\347\275\256_35_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,30 @@ +package cn.lastwhisper.leetcode.binarysearch.搜索插入位置_35_简单; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/search-insert-position/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:线性遍历 + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public int searchInsert(int[] nums, int target) { + for (int i = 0; i < nums.length; i++) { + // 起始,中间 + if (nums[i] >= target) { + return i; + } + } + // 最后 + return nums.length; + } + + public static void main(String[] args) { + int[] nums = {1, 3, 5, 6}; + int target = 5; + System.out.println(new Solution1().searchInsert(nums, target)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/binarysearch/src/main/java/cn/lastwhisper/leetcode/binarysearch/\346\220\234\347\264\242\346\217\222\345\205\245\344\275\215\347\275\256_35_\347\256\200\345\215\225/Solution2.java" "b/algorithms/leetcode/binarysearch/src/main/java/cn/lastwhisper/leetcode/binarysearch/\346\220\234\347\264\242\346\217\222\345\205\245\344\275\215\347\275\256_35_\347\256\200\345\215\225/Solution2.java" new file mode 100644 index 00000000..5f51047c --- /dev/null +++ "b/algorithms/leetcode/binarysearch/src/main/java/cn/lastwhisper/leetcode/binarysearch/\346\220\234\347\264\242\346\217\222\345\205\245\344\275\215\347\275\256_35_\347\256\200\345\215\225/Solution2.java" @@ -0,0 +1,34 @@ +package cn.lastwhisper.leetcode.binarysearch.搜索插入位置_35_简单; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/search-insert-position/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:二分查找 + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public int searchInsert(int[] nums, int target) { + int left = 0, right = nums.length - 1; + while (left <= right) { + int mid = (left + right) / 2; + if (nums[mid] == target) { + // 中间 + return mid; + } else if (nums[mid] < target) { + left = mid + 1; + } else { + right = mid - 1; + } + } + //起始和最后 + return left; + } + + public static void main(String[] args) { + + } +} \ No newline at end of file diff --git a/algorithms/leetcode/binarytree/pom.xml b/algorithms/leetcode/binarytree/pom.xml index b2f47839..0d0a8aab 100644 --- a/algorithms/leetcode/binarytree/pom.xml +++ b/algorithms/leetcode/binarytree/pom.xml @@ -12,5 +12,11 @@ cn.lastwhisper.leetcode binarytree - + + + cn.lastwhisper + leetcode-common + 1.0-SNAPSHOT + + \ No newline at end of file diff --git "a/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210_235_\347\256\200\345\215\225/Solution1.java" "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210_235_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..09897e63 --- /dev/null +++ "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210_235_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,45 @@ +package cn.lastwhisper.leetcode.binarytree.二叉搜索树的最近公共祖先_235_简单; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; + +import static cn.lastwhisper.leetcode.common.tree.TreeUtil.createTree; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-search-tree/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:递归 + * 二叉树排序树:根大于左子树小于右子树 + * 情况一:pq同时大于root,说明pq的最近公共祖先在右子树 + * 情况一:pq同时小于root,说明pq的最近公共祖先在左子树 + * 情况一:pq不同时大于或小于root,说明root为最近公共祖先 + * pq分别在左右子树,root为最近公共祖先 + * p在root上,q在左或右子树,p=root为最近公共祖先 + * q在root上,p在左或右子树,q=root为最近公共祖先 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(n) + */ + public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { + + if (p.val > root.val && q.val > root.val) { + return lowestCommonAncestor(root.right, p, q); + } + if (p.val < root.val && q.val < root.val) { + return lowestCommonAncestor(root.left, p, q); + } + + return root; + } + + public static void main(String[] args) { + System.out.println(new Solution1().lowestCommonAncestor( + createTree(6, 2, 8, 0, 4, 7, 9, null, null, 3, 5), new TreeNode(2), new TreeNode(8)).val); + System.out.println(new Solution1().lowestCommonAncestor( + createTree(6, 2, 8, 0, 4, 7, 9, null, null, 3, 5), new TreeNode(2), new TreeNode(4)).val); + + + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210_235_\347\256\200\345\215\225/Solution2.java" "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210_235_\347\256\200\345\215\225/Solution2.java" new file mode 100644 index 00000000..e12d84ce --- /dev/null +++ "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210_235_\347\256\200\345\215\225/Solution2.java" @@ -0,0 +1,45 @@ +package cn.lastwhisper.leetcode.binarytree.二叉搜索树的最近公共祖先_235_简单; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; + +import static cn.lastwhisper.leetcode.common.tree.TreeUtil.createTree; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-search-tree/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:迭代-找到分隔点 + * 二叉树排序树:根大于左子树小于右子树 + * 情况一:pq同时大于root,说明pq的最近公共祖先在右子树 + * 情况一:pq同时小于root,说明pq的最近公共祖先在左子树 + * 情况一:pq不同时大于或小于root,说明root为最近公共祖先 + * pq分别在左右子树,root为最近公共祖先 + * p在root上,q在左或右子树,p=root为最近公共祖先 + * q在root上,p在左或右子树,q=root为最近公共祖先 + * ------------------------------------------------------------------- + * 时间复杂度:O(N) + * 空间复杂度:O(1) + */ + public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { + while (root!=null){ + if (p.val > root.val && q.val > root.val) { + root=root.right; + } else if (p.val < root.val && q.val < root.val) { + root=root.left; + }else { + return root; + } + } + return null; + } + + + public static void main(String[] args) { + System.out.println(new Solution2().lowestCommonAncestor( + createTree(6, 2, 8, 0, 4, 7, 9, null, null, 3, 5), new TreeNode(2), new TreeNode(8)).val); + System.out.println(new Solution2().lowestCommonAncestor( + createTree(6, 2, 8, 0, 4, 7, 9, null, null, 3, 5), new TreeNode(2), new TreeNode(4)).val); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\347\273\223\347\202\271\346\234\200\345\260\217\350\267\235\347\246\273_783_\347\256\200\345\215\225/Solution1.java" "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\347\273\223\347\202\271\346\234\200\345\260\217\350\267\235\347\246\273_783_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..0de79d03 --- /dev/null +++ "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\347\273\223\347\202\271\346\234\200\345\260\217\350\267\235\347\246\273_783_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,60 @@ +package cn.lastwhisper.leetcode.binarytree.二叉搜索树结点最小距离_783_简单; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +import static cn.lastwhisper.leetcode.common.tree.TreeUtil.createTree; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/minimum-distance-between-bst-nodes/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:bst中序遍历就是从小到大 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(n) + */ + public int minDiffInBST(TreeNode root) { + List list = new ArrayList<>(); + middleDfs(root, list); + + int min = Integer.MAX_VALUE; + for (int i = 0; i < list.size() - 1; i++) { + min = Math.min(min, list.get(i + 1) - list.get(i)); + } + return min; + } + + public void middleDfs(TreeNode root, List list) { + if (root == null) { + return; + } + LinkedList stack = new LinkedList<>(); + while (root != null || !stack.isEmpty()) { + while (root != null) { + stack.push(root); + root = root.left; + } + root = stack.pop(); + list.add(root.val); + root = root.right; + } + } + + //public void middleDfs(TreeNode root, List list) { + // if (root != null) { + // middleDfs(root.left, list); + // list.add(root.val); + // middleDfs(root.right, list); + // } + //} + + public static void main(String[] args) { + System.out.println(new Solution1().minDiffInBST(createTree(4, 2, 6, 1, 3, null, null))); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\344\272\214\345\217\211\346\240\221\347\232\204\346\211\200\346\234\211\350\267\257\345\276\204_257_\347\256\200\345\215\225/Solution1.java" "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\344\272\214\345\217\211\346\240\221\347\232\204\346\211\200\346\234\211\350\267\257\345\276\204_257_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..ce85bab8 --- /dev/null +++ "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\344\272\214\345\217\211\346\240\221\347\232\204\346\211\200\346\234\211\350\267\257\345\276\204_257_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,47 @@ +package cn.lastwhisper.leetcode.binarytree.二叉树的所有路径_257_简单; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; + +import java.util.ArrayList; +import java.util.List; + +import static cn.lastwhisper.leetcode.common.print.PrintUtil.printList; +import static cn.lastwhisper.leetcode.common.tree.TreeUtil.createTree; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/binary-tree-paths/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:先序遍历-递归 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(n) + */ + public List binaryTreePaths(TreeNode root) { + List result = new ArrayList<>(); + if (root == null) { + return result; + } + binaryTreePathsHelper(root, result, String.valueOf(root.val)); + return result; + } + + public void binaryTreePathsHelper(TreeNode root, List result, String path) { + if (root.left == null && root.right == null) { + result.add(path); + } + if (root.left != null) { + binaryTreePathsHelper(root.left, result, path + "->" + root.left.val); + } + if (root.right != null) { + binaryTreePathsHelper(root.right, result, path + "->" + root.right.val); + } + } + + + public static void main(String[] args) { + printList(new Solution1().binaryTreePaths(createTree(1, 2, 3, null, 5))); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\344\272\214\345\217\211\346\240\221\347\232\204\346\211\200\346\234\211\350\267\257\345\276\204_257_\347\256\200\345\215\225/Solution2.java" "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\344\272\214\345\217\211\346\240\221\347\232\204\346\211\200\346\234\211\350\267\257\345\276\204_257_\347\256\200\345\215\225/Solution2.java" new file mode 100644 index 00000000..b5aa12b8 --- /dev/null +++ "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\344\272\214\345\217\211\346\240\221\347\232\204\346\211\200\346\234\211\350\267\257\345\276\204_257_\347\256\200\345\215\225/Solution2.java" @@ -0,0 +1,52 @@ +package cn.lastwhisper.leetcode.binarytree.二叉树的所有路径_257_简单; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; +import javafx.util.Pair; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +import static cn.lastwhisper.leetcode.common.print.PrintUtil.printList; +import static cn.lastwhisper.leetcode.common.tree.TreeUtil.createTree; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/binary-tree-paths/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:先序遍历-迭代 + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public List binaryTreePaths(TreeNode root) { + List result = new ArrayList<>(); + if (root == null) { + return result; + } + LinkedList> stack = new LinkedList<>(); + stack.push(new Pair<>(root, String.valueOf(root.val))); + + while (!stack.isEmpty()) { + Pair pair = stack.pop(); + root = pair.getKey(); + String path = pair.getValue(); + if (root.left == null && root.right == null) { + result.add(path); + } + if (root.left != null) { + stack.push(new Pair<>(root.left, path + "->" + root.left.val)); + } + if (root.right != null) { + stack.push(new Pair<>(root.right, path + "->" + root.right.val)); + } + } + return result; + } + + public static void main(String[] args) { + printList(new Solution2().binaryTreePaths(createTree(1, 2, 3, null, 5))); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\244\247\346\267\261\345\272\246_104_\347\256\200\345\215\225/Solution1.java" "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\244\247\346\267\261\345\272\246_104_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..a64d7d02 --- /dev/null +++ "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\244\247\346\267\261\345\272\246_104_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,33 @@ +package cn.lastwhisper.leetcode.binarytree.二叉树的最大深度_104_简单; + + +import cn.lastwhisper.leetcode.common.tree.TreeNode; +import cn.lastwhisper.leetcode.common.tree.TreeUtil; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/maximum-depth-of-binary-tree/ + * ------------------------------------------------------------------- + * 思考: + * Q:递归结束条件? + * A:当前TreeNode为null + * ------------------------------------------------------------------- + * 思路:先序遍历-递归 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:不平衡O(n)、平衡O(logn) + */ + public int maxDepth(TreeNode root) { + // 递归结束条件 + if (root == null) { + return 0; + } + // 递归过程 + return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1; + } + + public static void main(String[] args) { + System.out.println(new Solution1().maxDepth(TreeUtil.createTree())); + } + +} \ No newline at end of file diff --git "a/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\244\247\346\267\261\345\272\246_104_\347\256\200\345\215\225/Solution2.java" "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\244\247\346\267\261\345\272\246_104_\347\256\200\345\215\225/Solution2.java" new file mode 100644 index 00000000..9f1c06d8 --- /dev/null +++ "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\244\247\346\267\261\345\272\246_104_\347\256\200\345\215\225/Solution2.java" @@ -0,0 +1,47 @@ +package cn.lastwhisper.leetcode.binarytree.二叉树的最大深度_104_简单; + + +import cn.lastwhisper.leetcode.common.tree.TreeNode; +import cn.lastwhisper.leetcode.common.tree.TreeUtil; +import javafx.util.Pair; + +import java.util.LinkedList; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/maximum-depth-of-binary-tree/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:先序遍历-迭代 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:不平衡O(n)、平衡O(logn) + */ + public int maxDepth(TreeNode root) { + LinkedList> stack = new LinkedList<>(); + if (root != null) { + stack.push(new Pair<>(root, 0)); + } + int maxDepth = 0; + // stack模拟递归系统栈 + while (!stack.isEmpty()) { + Pair pair = stack.poll(); + root = pair.getKey(); + Integer height = pair.getValue(); + // dfs过程中更新最大深度 + maxDepth = Math.max(maxDepth, height); + if (root != null) { + stack.push(new Pair<>(root.right, height + 1)); + stack.push(new Pair<>(root.left, height + 1)); + } + } + + return maxDepth; + } + + public static void main(String[] args) { + System.out.println(new Solution2().maxDepth(TreeUtil.createTree())); + } + +} \ No newline at end of file diff --git "a/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\260\217\346\267\261\345\272\246_111_\347\256\200\345\215\225/Solution1.java" "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\260\217\346\267\261\345\272\246_111_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..71dd7713 --- /dev/null +++ "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\260\217\346\267\261\345\272\246_111_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,40 @@ +package cn.lastwhisper.leetcode.binarytree.二叉树的最小深度_111_简单; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; +import cn.lastwhisper.leetcode.common.tree.TreeUtil; +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/maximum-depth-of-binary-tree/ + * ------------------------------------------------------------------- + * 思考: + * Q:何为二叉树的深度? + * A:从根节点到叶子节点的路径上的节点数量 + * ------------------------------------------------------------------- + * 思路:先序遍历-递归 + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public int minDepth(TreeNode root) { + if (root == null) { + return 0; + } + // 叶子节点 + if ((root.left == null) && (root.right == null)) { + return 1; + } + + int min_depth = Integer.MAX_VALUE; + if (root.left != null) { + min_depth = Math.min(minDepth(root.left), min_depth); + } + if (root.right != null) { + min_depth = Math.min(minDepth(root.right), min_depth); + } + return min_depth + 1; + } + + public static void main(String[] args) { + System.out.println(new Solution1().minDepth(TreeUtil.createTree())); + } +} diff --git "a/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\260\217\346\267\261\345\272\246_111_\347\256\200\345\215\225/Solution2.java" "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\260\217\346\267\261\345\272\246_111_\347\256\200\345\215\225/Solution2.java" new file mode 100644 index 00000000..ccba9434 --- /dev/null +++ "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\260\217\346\267\261\345\272\246_111_\347\256\200\345\215\225/Solution2.java" @@ -0,0 +1,57 @@ +package cn.lastwhisper.leetcode.binarytree.二叉树的最小深度_111_简单; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; +import cn.lastwhisper.leetcode.common.tree.TreeUtil; +import javafx.util.Pair; + +import java.util.LinkedList; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/maximum-depth-of-binary-tree/ + * ------------------------------------------------------------------- + * 思考: + * Q:何为二叉树的深度? + * A:从根节点到叶子节点的路径上的节点数量 + * ------------------------------------------------------------------- + * 思路:先序遍历-迭代 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:最坏O(n),可能保存整颗树 + */ + public int minDepth(TreeNode root) { + if (root == null) { + return 0; + } + LinkedList> stack = new LinkedList<>(); + stack.push(new Pair<>(root, 1)); + + int minDepth = Integer.MAX_VALUE; + while (!stack.isEmpty()) { + Pair pair = stack.pop(); + root = pair.getKey(); + Integer depth = pair.getValue(); + if (root.left == null && root.right == null) { + minDepth = Math.min(minDepth, depth); + } + if (root.left != null) { + stack.push(new Pair<>(root.left, depth + 1)); + } + if (root.right != null) { + stack.push(new Pair<>(root.right, depth + 1)); + } + } + return minDepth; + } + + public static void main(String[] args) { + /* + * 3 + * / \ + * 9 20 + * / \ + * 15 7 + */ + System.out.println(new Solution2().minDepth(TreeUtil.createTree(3,9,20,null,null,15,7))); + } +} diff --git "a/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\260\217\346\267\261\345\272\246_111_\347\256\200\345\215\225/Solution3.java" "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\260\217\346\267\261\345\272\246_111_\347\256\200\345\215\225/Solution3.java" new file mode 100644 index 00000000..27c4da84 --- /dev/null +++ "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\260\217\346\267\261\345\272\246_111_\347\256\200\345\215\225/Solution3.java" @@ -0,0 +1,60 @@ +package cn.lastwhisper.leetcode.binarytree.二叉树的最小深度_111_简单; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; +import cn.lastwhisper.leetcode.common.tree.TreeUtil; +import javafx.util.Pair; + +import java.util.LinkedList; + +class Solution3 { + /** + * 题目地址:https://leetcode-cn.com/problems/maximum-depth-of-binary-tree/ + * ------------------------------------------------------------------- + * 思考:从根节点到叶子节点的路径上的节点数量。BFS按照树的层次去迭代, + * 第一个访问到的叶子就是最小深度的节点,这样就不要遍历所有的节点了。 + * ------------------------------------------------------------------- + * 思路:BFS迭代 + * ------------------------------------------------------------------- + * 时间复杂度:最多访问n/2个节点,O(n) + * 空间复杂度:最多队列中保存n/2个节点,O(n) + */ + public int minDepth(TreeNode root) { + if (root == null) { + return 0; + } + LinkedList> queue = new LinkedList<>(); + queue.add(new Pair<>(root, 1)); + + // 当前深度 + int currentDepth = 0; + Pair pair = null; + while (!queue.isEmpty()) { + pair = queue.poll(); + root = pair.getKey(); + currentDepth = pair.getValue(); + // 找到层中第一个叶子节点 + if (root.left == null && root.right == null) { + break; + } + if (root.left != null) { + queue.add(new Pair<>(root.left, currentDepth + 1)); + } + if (root.right != null) { + queue.add(new Pair<>(root.right, currentDepth + 1)); + } + + } + return currentDepth; + } + + public static void main(String[] args) { + /* + * 3 + * / \ + * 9 20 + * / \ + * 15 7 + */ + System.out.println(new Solution2().minDepth(TreeUtil.createTree(3,9,20,null,null,15,7))); + } +} diff --git "a/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\344\272\214\345\217\211\346\240\221\347\232\204\347\233\264\345\276\204_543_\347\256\200\345\215\225/Solution1.java" "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\344\272\214\345\217\211\346\240\221\347\232\204\347\233\264\345\276\204_543_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..99d1d4aa --- /dev/null +++ "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\344\272\214\345\217\211\346\240\221\347\232\204\347\233\264\345\276\204_543_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,51 @@ +package cn.lastwhisper.leetcode.binarytree.二叉树的直径_543_简单; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; +import cn.lastwhisper.leetcode.common.tree.TreeUtil; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/diameter-of-binary-tree/ + * ------------------------------------------------------------------- + * 思考: + * + * ------------------------------------------------------------------- + * 思路: + * 1.普通情况,找左子树和右子树最大高度和 + * 2.特殊情况,不一定经过根节点 + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public int diameterOfBinaryTree(TreeNode root) { + int max = 0; + if (root != null) { + max = Math.max(max, sumHeight(root)); + max = Math.max(max, diameterOfBinaryTree(root.left)); + max = Math.max(max, diameterOfBinaryTree(root.right)); + } + return max; + } + + // node结点左右子树最大高度和 + private int sumHeight(TreeNode node) { + if (node == null) { + return 0; + } + return height(node.left) + height(node.right); + } + + // node结点最大高度 + private int height(TreeNode node) { + if (node == null) { + return 0; + } + return Math.max(height(node.left), height(node.right)) + 1; + } + + public static void main(String[] args) { + Integer[] nums = new Integer[]{4, -7, -3, null, null, -9, -3, 9, -7, -4, null, 6, null, -6, -6, null, null, 0, 6, 5, null, 9, null, null, -1, -4, null, null, null, -2}; + TreeNode tree = TreeUtil.createTree(nums); + System.out.println(new Solution1().diameterOfBinaryTree(tree)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\345\215\225\350\257\215\347\232\204\345\216\213\347\274\251\347\274\226\347\240\201_820_\344\270\255\347\255\211/Solution1.java" "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\345\215\225\350\257\215\347\232\204\345\216\213\347\274\251\347\274\226\347\240\201_820_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..691c0a9d --- /dev/null +++ "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\345\215\225\350\257\215\347\232\204\345\216\213\347\274\251\347\274\226\347\240\201_820_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,66 @@ +package cn.lastwhisper.leetcode.binarytree.单词的压缩编码_820_中等; + +import org.junit.Assert; + +import java.util.Arrays; +import java.util.Comparator; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/short-encoding-of-words/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * 按长度排序,逆序插入字典树, + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public int minimumLengthEncoding(String[] words) { + int len = 0; + // 先对单词列表根据单词长度由长到短排序 + Arrays.sort(words, (s1, s2) -> s2.length() - s1.length()); + Trie trie = new Trie(); + // 单词插入trie,返回该单词增加的编码长度 + for (String word : words) { + len += trie.insert(word); + } + return len; + } + + static class TrieNode { + TrieNode[] children = new TrieNode[26]; + public TrieNode() {} + } + + static class Trie { + + private TrieNode root; + + public Trie() { + root = new TrieNode(); + } + + public int insert(String word) { + TrieNode cur = root; + boolean isNew = false; + // 倒着插入单词 + for (int i = word.length() - 1; i >= 0; i--) { + int c = word.charAt(i) - 'a'; + if (cur.children[c] == null) { + isNew = true; + cur.children[c] = new TrieNode(); + } + cur = cur.children[c]; + } + // +1是# + return isNew ? word.length() + 1 : 0; + } + } + + public static void main(String[] args) { + + Assert.assertEquals(10,new Solution1().minimumLengthEncoding(new String[]{"time", "me", "bell"})); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\345\256\214\345\205\250\344\272\214\345\217\211\346\240\221\347\232\204\350\212\202\347\202\271\344\270\252\346\225\260_222_\344\270\255\347\255\211/Solution1.java" "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\345\256\214\345\205\250\344\272\214\345\217\211\346\240\221\347\232\204\350\212\202\347\202\271\344\270\252\346\225\260_222_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..a3f262df --- /dev/null +++ "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\345\256\214\345\205\250\344\272\214\345\217\211\346\240\221\347\232\204\350\212\202\347\202\271\344\270\252\346\225\260_222_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,28 @@ +package cn.lastwhisper.leetcode.binarytree.完全二叉树的节点个数_222_中等; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; + +import static cn.lastwhisper.leetcode.common.tree.TreeUtil.createTree; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/count-complete-tree-nodes/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:遍历时计数-递归 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:最坏O(n) + */ + public int countNodes(TreeNode root) { + if (root == null) { + return 0; + } + return countNodes(root.left) + countNodes(root.right) + 1; + } + + public static void main(String[] args) { + System.out.println(new Solution1().countNodes(createTree(1, 2, 3, 4, 5, 6, null))); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\345\256\214\345\205\250\344\272\214\345\217\211\346\240\221\347\232\204\350\212\202\347\202\271\344\270\252\346\225\260_222_\344\270\255\347\255\211/Solution2.java" "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\345\256\214\345\205\250\344\272\214\345\217\211\346\240\221\347\232\204\350\212\202\347\202\271\344\270\252\346\225\260_222_\344\270\255\347\255\211/Solution2.java" new file mode 100644 index 00000000..06775da1 --- /dev/null +++ "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\345\256\214\345\205\250\344\272\214\345\217\211\346\240\221\347\232\204\350\212\202\347\202\271\344\270\252\346\225\260_222_\344\270\255\347\255\211/Solution2.java" @@ -0,0 +1,40 @@ +package cn.lastwhisper.leetcode.binarytree.完全二叉树的节点个数_222_中等; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; + +import java.util.LinkedList; + +import static cn.lastwhisper.leetcode.common.tree.TreeUtil.createTree; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/count-complete-tree-nodes/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:遍历时计数-迭代 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:最坏O(n) + */ + public int countNodes(TreeNode root) { + if (root == null) { + return 0; + } + LinkedList stack = new LinkedList<>(); + stack.push(root); + int count = 0; + // 根-左-右 + while (!stack.isEmpty()) { + root = stack.pop(); + count++; + if (root.right != null) stack.push(root.right); + if (root.left != null) stack.push(root.left); + } + return count; + } + + public static void main(String[] args) { + System.out.println(new Solution2().countNodes(createTree(1, 2, 3, 4, 5, 6, null))); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\345\256\214\345\205\250\344\272\214\345\217\211\346\240\221\347\232\204\350\212\202\347\202\271\344\270\252\346\225\260_222_\344\270\255\347\255\211/Solution3.java" "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\345\256\214\345\205\250\344\272\214\345\217\211\346\240\221\347\232\204\350\212\202\347\202\271\344\270\252\346\225\260_222_\344\270\255\347\255\211/Solution3.java" new file mode 100644 index 00000000..a529f89c --- /dev/null +++ "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\345\256\214\345\205\250\344\272\214\345\217\211\346\240\221\347\232\204\350\212\202\347\202\271\344\270\252\346\225\260_222_\344\270\255\347\255\211/Solution3.java" @@ -0,0 +1,51 @@ +package cn.lastwhisper.leetcode.binarytree.完全二叉树的节点个数_222_中等; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; + +import static cn.lastwhisper.leetcode.common.tree.TreeUtil.createTree; + +class Solution3 { + /** + * 题目地址:https://leetcode-cn.com/problems/count-complete-tree-nodes/ + * ------------------------------------------------------------------- + * 思考:完全二叉树,左右子树肯定存在一颗满二叉树 + * ------------------------------------------------------------------- + * 思路:利用二叉树的特点 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:最坏O(n) + */ + public int countNodes(TreeNode root) { + if (root == null) { + return 0; + } + int left = maxDepth(root.left); + int right = maxDepth(root.right); + if (left == right) { + /* + * 左子树肯定是满二叉树,左子树节点总数=2^left-1,加上root,正好是2^left + * 再对右子树进行递归统计。 + */ + return (1 << left) + countNodes(root.right);//2^left + } else { + /* + * 右子树肯定是满二叉树,右子树节点总数=2^right-1,加上root,正好是2^right + * 再对左子树进行递归统计。 + */ + return (1 << right) + countNodes(root.left); + } + } + + private int maxDepth(TreeNode root) { + int level = 0; + while (root != null) { + level++; + root = root.left; + } + return level; + } + + public static void main(String[] args) { + System.out.println(new Solution3().countNodes(createTree(1, 2, 3, 4, 5, 6, null))); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\345\256\236\347\216\260Trie\345\211\215\347\274\200\346\240\221_208_\344\270\255\347\255\211/Trie.java" "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\345\256\236\347\216\260Trie\345\211\215\347\274\200\346\240\221_208_\344\270\255\347\255\211/Trie.java" new file mode 100644 index 00000000..f21bad54 --- /dev/null +++ "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\345\256\236\347\216\260Trie\345\211\215\347\274\200\346\240\221_208_\344\270\255\347\255\211/Trie.java" @@ -0,0 +1,101 @@ +package cn.lastwhisper.leetcode.binarytree.实现Trie前缀树_208_中等; + +import cn.lastwhisper.leetcode.common.tree.TrieNode; +import org.junit.Assert; + +class Trie { + + private TrieNode root; + + /** + * 功能: + * 找到具有同一前缀的全部键值。 + * 按词典序枚举字符串的数据集。 + * + * 与哈希表相比,Trie 树在存储多个具有相同前缀的键时可以使用较少的空间。 + * 此时 Trie 树只需要 O(m) 的时间复杂度,其中 m 为键长。而在平衡树中查找键值需要 O(mlogn) 时间复杂度。 + * + * https://leetcode-cn.com/problems/implement-trie-prefix-tree/solution/shi-xian-trie-qian-zhui-shu-by-leetcode/ + */ + public Trie() { + root = new TrieNode(); + } + + /** + * 通过搜索 Trie 树来插入一个键。我们从根开始搜索它对应于第一个键字符的链接。有两种情况: + * 链接存在。沿着链接移动到树的下一个子层。算法继续搜索下一个键字符。 + * 链接不存在。创建一个新的节点,并将它与父节点的链接相连,该链接与当前的键字符相匹配。 + * 重复以上步骤,直到到达键的最后一个字符,然后将当前节点标记为结束节点,算法完成。 + * + * 时间复杂度:O(m),其中 m 为键长。在算法的每次迭代中,我们要么检查要么创建一个节点,直到到达键尾。只需要 m 次操作。 + * 空间复杂度:O(m)。最坏的情况下,新插入的键和 Trie 树中已有的键没有公共前缀。此时需要添加 m 个结点,使用 O(m) 空间。 + */ + public void insert(String word) { + TrieNode node = root; + for (int i = 0; i < word.length(); i++) { + char currentChar = word.charAt(i); + if (!node.containsKey(currentChar)) { + node.put(currentChar, new TrieNode()); + } + node = node.get(currentChar); + } + node.setEnd(); + } + + /** + * 功能:查找word在是否在前缀树中 + * + * 每个键在trie中表示为从根到内部节点或叶的路径。我们用第一个键字符从根开始,检查当前节点中与键字符对应的链接。 + * 有两种情况: + * 1.存在链接。我们移动到该链接后面路径中的下一个节点,并继续搜索下一个键字符。 + * 2.不存在链接。若已无键字符,且当前结点标记为 isEnd,则返回 true。否则有两种可能,均返回 false : + * 还有键字符剩余,但无法跟随 Trie 树的键路径,找不到键。 + * 没有键字符剩余,但当前结点没有标记为 isEnd。也就是说,待查找键只是Trie树中另一个键的前缀。 + */ + public boolean search(String word) { + TrieNode node = searchPrefix(word); + return node != null && node.isEnd(); + } + + // search a prefix or whole key in trie and + // returns the node where search ends + /** + * + * 时间复杂度 : O(m) + * 空间复杂度 : O(1) + */ + private TrieNode searchPrefix(String word) { + TrieNode node = root; + for (int i = 0; i < word.length(); i++) { + char curLetter = word.charAt(i); + if (node.containsKey(curLetter)) { + node = node.get(curLetter); + } else { + return null; + } + } + return node; + } + + /** + * 功能:查找prefix在是否在前缀树中 + * + * 时间复杂度 : O(m) + * 空间复杂度 : O(1) + */ + public boolean startsWith(String prefix) { + TrieNode node = searchPrefix(prefix); + return node != null; + } + + public static void main(String[] args) { + Trie trie = new Trie(); + + trie.insert("apple"); + Assert.assertTrue(trie.search("apple")); // 返回 true + Assert.assertFalse(trie.search("app")); // 返回 false + Assert.assertTrue(trie.startsWith("app")); // 返回 true + trie.insert("app"); + Assert.assertTrue(trie.search("app")); // 返回 true + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\345\257\271\347\247\260\344\272\214\345\217\211\346\240\221_101_\347\256\200\345\215\225/Solution1.java" "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\345\257\271\347\247\260\344\272\214\345\217\211\346\240\221_101_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..5f3468c6 --- /dev/null +++ "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\345\257\271\347\247\260\344\272\214\345\217\211\346\240\221_101_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,45 @@ +package cn.lastwhisper.leetcode.binarytree.对称二叉树_101_简单; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; + +import static cn.lastwhisper.leetcode.common.tree.TreeUtil.createTree; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/symmetric-tree/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:先序遍历-递归 + * ------------------------------------------------------------------- + * 时间复杂度:O(n),因为我们遍历整个输入树一次,所以总的运行时间为 O(n),其中 nn 是树中节点的总数。 + * 空间复杂度:递归调用的次数受树的高度限制。在最糟糕情况下,树是线性的,其高度为 O(n)。 + * 因此,在最糟糕的情况下,由栈上的递归调用造成的空间复杂度为 O(n)。 + */ + public boolean isSymmetric(TreeNode root) { + if (root == null) { + return true; + } + return isMirror(root.left, root.right); + } + + public boolean isMirror(TreeNode p, TreeNode q) { + if (p == null && q == null) { + return true; + } + if (p == null || q == null) { + return false; + } + if (p.val != q.val) { + return false; + } + return isMirror(p.left, q.right) && isMirror(p.right, q.left); + } + + + public static void main(String[] args) { + System.out.println(new Solution1().isSymmetric(createTree(1, 2, 2, 3, 4, 4, 3))); // true + System.out.println(new Solution1().isSymmetric(createTree(1, 2, 2, null, 3, null, 3))); //false + System.out.println(new Solution1().isSymmetric(createTree(2, 3, 3, 4, 5, 5))); //false + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\345\257\271\347\247\260\344\272\214\345\217\211\346\240\221_101_\347\256\200\345\215\225/Solution2.java" "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\345\257\271\347\247\260\344\272\214\345\217\211\346\240\221_101_\347\256\200\345\215\225/Solution2.java" new file mode 100644 index 00000000..b4e7dd56 --- /dev/null +++ "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\345\257\271\347\247\260\344\272\214\345\217\211\346\240\221_101_\347\256\200\345\215\225/Solution2.java" @@ -0,0 +1,46 @@ +package cn.lastwhisper.leetcode.binarytree.对称二叉树_101_简单; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; + +import java.util.LinkedList; + +import static cn.lastwhisper.leetcode.common.tree.TreeUtil.createTree; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/symmetric-tree/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:先序遍历-迭代 + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public boolean isSymmetric(TreeNode root) { + LinkedList stack = new LinkedList<>(); + stack.push(root); + stack.push(root); + + while (!stack.isEmpty()) { + TreeNode p = stack.pop(); + TreeNode q = stack.pop(); + + if (p == null && q == null) continue; + if (p == null || q == null) return false; + if (p.val != q.val) return false; + + stack.push(p.left); + stack.push(q.right); + stack.push(q.left); + stack.push(p.right); + } + return true; + } + + public static void main(String[] args) { + System.out.println(new Solution2().isSymmetric(createTree(1, 2, 2, 3, 4, 4, 3))); // true + System.out.println(new Solution2().isSymmetric(createTree(1, 2, 2, null, 3, null, 3))); //false + System.out.println(new Solution2().isSymmetric(createTree(2, 3, 3, 4, 5, 5))); //false + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\345\257\271\347\247\260\344\272\214\345\217\211\346\240\221_101_\347\256\200\345\215\225/Solution3.java" "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\345\257\271\347\247\260\344\272\214\345\217\211\346\240\221_101_\347\256\200\345\215\225/Solution3.java" new file mode 100644 index 00000000..5e5b322d --- /dev/null +++ "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\345\257\271\347\247\260\344\272\214\345\217\211\346\240\221_101_\347\256\200\345\215\225/Solution3.java" @@ -0,0 +1,45 @@ +package cn.lastwhisper.leetcode.binarytree.对称二叉树_101_简单; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; + +import java.util.LinkedList; +import java.util.Queue; + +import static cn.lastwhisper.leetcode.common.tree.TreeUtil.createTree; + +class Solution3 { + /** + * 题目地址:https://leetcode-cn.com/problems/symmetric-tree/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:层次遍历(BFS) + * ------------------------------------------------------------------- + * 时间复杂度:O(n),因为我们遍历整个输入树一次,所以总的运行时间为 O(n),其中 nn 是树中节点的总数。 + * 空间复杂度:递归调用的次数受树的高度限制。在最糟糕情况下,树是线性的,其高度为 O(n)。 + * 因此,在最糟糕的情况下,由栈上的递归调用造成的空间复杂度为 O(n)。 + */ + public boolean isSymmetric(TreeNode root) { + Queue q = new LinkedList<>(); + q.add(root); + q.add(root); + while (!q.isEmpty()) { + TreeNode t1 = q.poll(); + TreeNode t2 = q.poll(); + if (t1 == null && t2 == null) continue; + if (t1 == null || t2 == null) return false; + if (t1.val != t2.val) return false; + q.add(t1.left); + q.add(t2.right); + q.add(t1.right); + q.add(t2.left); + } + return true; + } + + public static void main(String[] args) { + System.out.println(new Solution3().isSymmetric(createTree(1, 2, 2, 3, 4, 4, 3))); // true + System.out.println(new Solution3().isSymmetric(createTree(1, 2, 2, null, 3, null, 3))); //false + System.out.println(new Solution3().isSymmetric(createTree(2, 3, 3, 4, 5, 5))); //false + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\345\257\271\347\247\260\344\272\214\345\217\211\346\240\221_101_\347\256\200\345\215\225/Solution6.java" "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\345\257\271\347\247\260\344\272\214\345\217\211\346\240\221_101_\347\256\200\345\215\225/Solution6.java" new file mode 100644 index 00000000..42322e65 --- /dev/null +++ "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\345\257\271\347\247\260\344\272\214\345\217\211\346\240\221_101_\347\256\200\345\215\225/Solution6.java" @@ -0,0 +1,58 @@ +package cn.lastwhisper.leetcode.binarytree.对称二叉树_101_简单; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; + +import static cn.lastwhisper.leetcode.common.tree.TreeUtil.createTree; + +class Solution6 { + /** + * 题目地址:https://leetcode-cn.com/problems/symmetric-tree/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * 1.将二叉树的左子节点或者右子节点左右翻转 + * 2.比较左右子节点是否相同 + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public boolean isSymmetric(TreeNode root) { + if (root == null) { + return true; + } + TreeNode right = invertTree(root.right); + return isSameTree(root.left, right); + } + + public boolean isSameTree(TreeNode p, TreeNode q) { + // 递归结束条件 + if (p == null && q == null) { + return true; + } + if (p == null || q == null) { + return false; + } + if (p.val != q.val) { + return false; + } + // 递归体 + return isSameTree(p.left, q.left) && isSameTree(p.right, q.right); + } + + public TreeNode invertTree(TreeNode root) { + if (root == null) + return null; + // 翻转当前节点的左右子节点 + TreeNode tempNode = root.left; + + root.left = invertTree(root.right); + root.right = invertTree(tempNode); + return root; + } + + + public static void main(String[] args) { + System.out.println(new Solution6().isSymmetric(createTree())); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\345\267\246\345\217\266\345\255\220\344\271\213\345\222\214_404_\347\256\200\345\215\225/Solution.java" "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\345\267\246\345\217\266\345\255\220\344\271\213\345\222\214_404_\347\256\200\345\215\225/Solution.java" new file mode 100644 index 00000000..795ff180 --- /dev/null +++ "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\345\267\246\345\217\266\345\255\220\344\271\213\345\222\214_404_\347\256\200\345\215\225/Solution.java" @@ -0,0 +1,29 @@ +package cn.lastwhisper.leetcode.binarytree.左叶子之和_404_简单; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; + +import static cn.lastwhisper.leetcode.common.tree.TreeUtil.createTree; + +class Solution { + public int sumOfLeftLeaves(TreeNode root) { + return helper(root); + } + + public int helper(TreeNode node) { + int sum = 0; + if (node == null) { + return 0; + } + if (node.left != null && (node.left.left == null && node.left.right == null)) { + sum += node.left.val; + } + sum += helper(node.left) + helper(node.right); + return sum; + } + + public static void main(String[] args) { + //System.out.println(new Solution().sumOfLeftLeaves(createTree(1, 2, 3, 4, 5))); + //System.out.println(new Solution().sumOfLeftLeaves(createTree(1, null, 2))); + System.out.println(new Solution().sumOfLeftLeaves(createTree(3, 9, 20, null, null, 15, 7))); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\345\267\246\345\217\266\345\255\220\344\271\213\345\222\214_404_\347\256\200\345\215\225/Solution1.java" "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\345\267\246\345\217\266\345\255\220\344\271\213\345\222\214_404_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..ecc08b4f --- /dev/null +++ "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\345\267\246\345\217\266\345\255\220\344\271\213\345\222\214_404_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,69 @@ +package cn.lastwhisper.leetcode.binarytree.左叶子之和_404_简单; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; + +import static cn.lastwhisper.leetcode.common.tree.TreeUtil.createTree; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/sum-of-left-leaves/ + * ------------------------------------------------------------------- + * 思考:左叶子之和 + * 注意:叶子之和 + * ------------------------------------------------------------------- + * 思路: + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public int sumOfLeftLeaves(TreeNode root) { + return sumOfLeftLeavesHelper(root, false); + } + + // 先序遍历求所有左叶子节点值之和 + public int sumOfLeftLeavesHelper(TreeNode root, boolean flag) { + if (root == null) { + return 0; + } + int leave = 0; + // 左叶子节点 + if (flag && root.left == null && root.right == null) { + leave = root.val; + } + int left = sumOfLeftLeavesHelper(root.left, true); + int right = sumOfLeftLeavesHelper(root.right, false); + return left + right + leave; + } + + // 先序遍历求所有叶子节点值之和 + public int sumOfLeaves(TreeNode root) { + if (root == null) { + return 0; + } + int leave = 0; + // 叶子节点 + if (root.left == null && root.right == null) { + leave = root.val; + } + int left = sumOfLeaves(root.left); + int right = sumOfLeaves(root.right); + return left + right + leave; + } + + // 先序遍历求所有节点值之和 + public int sumOfTrees(TreeNode root) { + if (root == null) { + return 0; + } + int leave = root.val; + int left = sumOfTrees(root.left); + int right = sumOfTrees(root.right); + return left + right + leave; + } + + public static void main(String[] args) { + System.out.println(new Solution1().sumOfLeftLeaves(createTree(1, 2, 3, 4, 5))); + //System.out.println(new Solution1().sumOfLeftLeaves(createTree(1, null, 2))); + //System.out.println(new Solution1().sumOfLeftLeaves(createTree(3, 9, 20, null, null, 15, 7))); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\345\267\246\345\217\266\345\255\220\344\271\213\345\222\214_404_\347\256\200\345\215\225/Solution2.java" "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\345\267\246\345\217\266\345\255\220\344\271\213\345\222\214_404_\347\256\200\345\215\225/Solution2.java" new file mode 100644 index 00000000..188e1cf6 --- /dev/null +++ "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\345\267\246\345\217\266\345\255\220\344\271\213\345\222\214_404_\347\256\200\345\215\225/Solution2.java" @@ -0,0 +1,52 @@ +package cn.lastwhisper.leetcode.binarytree.左叶子之和_404_简单; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; +import javafx.util.Pair; + +import java.util.LinkedList; + +import static cn.lastwhisper.leetcode.common.tree.TreeUtil.createTree; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/sum-of-left-leaves/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:将递归改成迭代 + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public int sumOfLeftLeaves(TreeNode root) { + if (root == null) { + return 0; + } + LinkedList> stack = new LinkedList<>(); + stack.push(new Pair<>(root, false)); + + int sum = 0; + Boolean flag; + while (!stack.isEmpty()) { + Pair pair = stack.pop(); + root = pair.getKey(); + flag = pair.getValue(); + if (flag && root.left == null && root.right == null) { + sum += root.val; + } + if (root.left != null) { + stack.push(new Pair<>(root.left, true)); + } + if (root.right != null) { + stack.push(new Pair<>(root.right, false)); + } + } + return sum; + } + + public static void main(String[] args) { + System.out.println(new Solution2().sumOfLeftLeaves(createTree(1, 2, 3, 4, 5))); + //System.out.println(new Solution1().sumOfLeftLeaves(createTree(1, null, 2))); + //System.out.println(new Solution1().sumOfLeftLeaves(createTree(3, 9, 20, null, null, 15, 7))); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\345\271\263\350\241\241\344\272\214\345\217\211\346\240\221_110_\347\256\200\345\215\225/Solution1.java" "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\345\271\263\350\241\241\344\272\214\345\217\211\346\240\221_110_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..24674fc9 --- /dev/null +++ "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\345\271\263\350\241\241\344\272\214\345\217\211\346\240\221_110_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,81 @@ +package cn.lastwhisper.leetcode.binarytree.平衡二叉树_110_简单; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; + +import static cn.lastwhisper.leetcode.common.tree.TreeUtil.createTree; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/balanced-binary-tree/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public boolean isBalanced(TreeNode root) { + //它是一棵空树 + if (root == null) { + return true; + } + //它的左右两个子树的高度差的绝对值不超过1 + int leftDepth = getTreeDepth(root.left); + int rightDepth = getTreeDepth(root.right); + if (Math.abs(leftDepth - rightDepth) > 1) { + return false; + } + //左右两个子树都是一棵平衡二叉树 + return isBalanced(root.left) && isBalanced(root.right); + + } + + private int getTreeDepth(TreeNode root) { + if (root == null) { + return 0; + } + int leftDepth = getTreeDepth(root.left); + int rightDepth = getTreeDepth(root.right); + return Math.max(leftDepth, rightDepth) + 1; + } + + public static void main(String[] args) { + /* + * 1 + * \ + * 2 + * / + * 3 + */ + //System.out.println(new Solution1().isBalanced(createTree(1, null, 2, null, 3)));//false + /* + * 3 + * / \ + * 9 20 + * / \ + * 15 7 + */ + //System.out.println(new Solution1().isBalanced(createTree(3, 9, 20, null, null, 15, 7)));//true + /* + * 1 + * / \ + * 2 2 + * / \ + * 3 3 + * / \ + * 4 4 + */ + //System.out.println(new Solution1().isBalanced(createTree(1, 2, 2, 3, null, null, 3, 4, null, null, 4)));//false + /* + * 1 + * / \ + * 2 2 + * / \ + * 3 3 + * / \ + * 4 4 + */ + System.out.println(new Solution1().isBalanced(createTree(1, 2, 2, 3, 3, null, null, 4, 4)));//false + } +} diff --git "a/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\345\271\263\350\241\241\344\272\214\345\217\211\346\240\221_110_\347\256\200\345\215\225/Solution2.java" "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\345\271\263\350\241\241\344\272\214\345\217\211\346\240\221_110_\347\256\200\345\215\225/Solution2.java" new file mode 100644 index 00000000..9788109f --- /dev/null +++ "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\345\271\263\350\241\241\344\272\214\345\217\211\346\240\221_110_\347\256\200\345\215\225/Solution2.java" @@ -0,0 +1,79 @@ +package cn.lastwhisper.leetcode.binarytree.平衡二叉树_110_简单; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; + +import static cn.lastwhisper.leetcode.common.tree.TreeUtil.createTree; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/balanced-binary-tree/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public boolean isBalanced(TreeNode root) { + return getTreeDepth(root) != -1; + } + + private int getTreeDepth(TreeNode root) { + if (root == null) { + return 0; + } + int leftDepth = getTreeDepth(root.left); + if (leftDepth == -1) { + return -1; + } + int rightDepth = getTreeDepth(root.right); + if (rightDepth == -1) { + return -1; + } + if (Math.abs(leftDepth - rightDepth) > 1) { + return -1; + } + return Math.max(leftDepth, rightDepth) + 1; + } + + + public static void main(String[] args) { + /* + * 1 + * \ + * 2 + * / + * 3 + */ + //System.out.println(new Solution2().isBalanced(createTree(1, null, 2, null, 3)));//false + /* + * 3 + * / \ + * 9 20 + * / \ + * 15 7 + */ + //System.out.println(new Solution2().isBalanced(createTree(3, 9, 20, null, null, 15, 7)));//true + /* + * 1 + * / \ + * 2 2 + * / \ + * 3 3 + * / \ + * 4 4 + */ + //System.out.println(new Solution2().isBalanced(createTree(1, 2, 2, 3, null, null, 3, 4, null, null, 4)));//false + /* + * 1 + * / \ + * 2 2 + * / \ + * 3 3 + * / \ + * 4 4 + */ + System.out.println(new Solution2().isBalanced(createTree(1, 2, 2, 3, 3, null, null, 4, 4)));//false + } +} diff --git "a/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\346\261\202\346\240\271\345\210\260\345\217\266\345\255\220\350\212\202\347\202\271\346\225\260\345\255\227\344\271\213\345\222\214_129_\344\270\255\347\255\211/Solution1.java" "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\346\261\202\346\240\271\345\210\260\345\217\266\345\255\220\350\212\202\347\202\271\346\225\260\345\255\227\344\271\213\345\222\214_129_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..38996df2 --- /dev/null +++ "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\346\261\202\346\240\271\345\210\260\345\217\266\345\255\220\350\212\202\347\202\271\346\225\260\345\255\227\344\271\213\345\222\214_129_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,51 @@ +package cn.lastwhisper.leetcode.binarytree.求根到叶子节点数字之和_129_中等; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; + +import java.util.ArrayList; +import java.util.List; + +import static cn.lastwhisper.leetcode.common.tree.TreeUtil.createTree; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/binary-tree-paths/ + * ------------------------------------------------------------------- + * 思考:二叉树的所有路径_257 + * ------------------------------------------------------------------- + * 思路:先序遍历-递归 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(n) + */ + public int sumNumbers(TreeNode root) { + if (root == null) { + return 0; + } + List result = new ArrayList<>(); + binaryTreePathsHelper(root, result, String.valueOf(root.val)); + int sum = 0; + for (String s : result) { + sum += Integer.parseInt(s); + } + return sum; + } + + public void binaryTreePathsHelper(TreeNode root, List result, String path) { + if (root.left == null && root.right == null) { + result.add(path); + } + if (root.left != null) { + binaryTreePathsHelper(root.left, result, path + root.left.val); + } + if (root.right != null) { + binaryTreePathsHelper(root.right, result, path + root.right.val); + } + } + + + public static void main(String[] args) { + System.out.println(new Solution1().sumNumbers(createTree(1, 2, 3))); + System.out.println(new Solution1().sumNumbers(createTree(4,9,0,5,1))); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\346\261\202\346\240\271\345\210\260\345\217\266\345\255\220\350\212\202\347\202\271\346\225\260\345\255\227\344\271\213\345\222\214_129_\344\270\255\347\255\211/Solution2.java" "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\346\261\202\346\240\271\345\210\260\345\217\266\345\255\220\350\212\202\347\202\271\346\225\260\345\255\227\344\271\213\345\222\214_129_\344\270\255\347\255\211/Solution2.java" new file mode 100644 index 00000000..a4070533 --- /dev/null +++ "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\346\261\202\346\240\271\345\210\260\345\217\266\345\255\220\350\212\202\347\202\271\346\225\260\345\255\227\344\271\213\345\222\214_129_\344\270\255\347\255\211/Solution2.java" @@ -0,0 +1,58 @@ +package cn.lastwhisper.leetcode.binarytree.求根到叶子节点数字之和_129_中等; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; +import javafx.util.Pair; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +import static cn.lastwhisper.leetcode.common.tree.TreeUtil.createTree; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/sum-root-to-leaf-numbers/ + * ------------------------------------------------------------------- + * 思考:二叉树的所有路径_257 + * ------------------------------------------------------------------- + * 思路:先序遍历-迭代 + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public int sumNumbers(TreeNode root) { + if (root == null) { + return 0; + } + + List result = new ArrayList<>(); + LinkedList> stack = new LinkedList<>(); + stack.push(new Pair<>(root, String.valueOf(root.val))); + + while (!stack.isEmpty()) { + Pair pair = stack.pop(); + root = pair.getKey(); + String path = pair.getValue(); + if (root.left == null && root.right == null) { + result.add(path); + } + if (root.left != null) { + stack.push(new Pair<>(root.left, path + root.left.val)); + } + if (root.right != null) { + stack.push(new Pair<>(root.right, path + root.right.val)); + } + } + + int sum = 0; + for (String s : result) { + sum += Integer.parseInt(s); + } + return sum; + } + + public static void main(String[] args) { + System.out.println(new Solution2().sumNumbers(createTree(1, 2, 3))); + System.out.println(new Solution2().sumNumbers(createTree(4,9,0,5,1))); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\347\233\270\345\220\214\347\232\204\346\240\221_100_\347\256\200\345\215\225/Solution1.java" "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\347\233\270\345\220\214\347\232\204\346\240\221_100_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..55cb44d5 --- /dev/null +++ "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\347\233\270\345\220\214\347\232\204\346\240\221_100_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,40 @@ +package cn.lastwhisper.leetcode.binarytree.相同的树_100_简单; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; + +import static cn.lastwhisper.leetcode.common.tree.TreeUtil.*; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/same-tree/ + * ------------------------------------------------------------------- + * 思考: + * Q:递归结束条件? + * 1.两个节点都为null,返回true + * 2.两个节点有一个不为null,返回false + * 3.两个节点值不同,返回false + * ------------------------------------------------------------------- + * 思路:先序遍历 + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public boolean isSameTree(TreeNode p, TreeNode q) { + // 递归结束条件 + if (p == null && q == null) { + return true; + } + if (p == null || q == null) { + return false; + } + if (p.val != q.val) { + return false; + } + // 递归体 + return isSameTree(p.left, q.left) && isSameTree(p.right, q.right); + } + + public static void main(String[] args) { + System.out.println(new Solution1().isSameTree(createTree(), createTree())); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\347\233\270\345\220\214\347\232\204\346\240\221_100_\347\256\200\345\215\225/Solution2.java" "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\347\233\270\345\220\214\347\232\204\346\240\221_100_\347\256\200\345\215\225/Solution2.java" new file mode 100644 index 00000000..17868463 --- /dev/null +++ "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\347\233\270\345\220\214\347\232\204\346\240\221_100_\347\256\200\345\215\225/Solution2.java" @@ -0,0 +1,75 @@ +package cn.lastwhisper.leetcode.binarytree.相同的树_100_简单; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; + +import java.util.LinkedList; + +import static cn.lastwhisper.leetcode.common.tree.TreeUtil.createTree; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/same-tree/ + * ------------------------------------------------------------------- + * 思考:思路三对条件进行优化 + * ------------------------------------------------------------------- + * 思路:先序遍历-迭代 + * 情况一:q或p为null false + * 情况二:q与p为null true + * 情况二:q!=p true + * 情况三:q左子树或p左子树为null false + * 情况四:q右子树或p右子树为null false + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public boolean isSameTree(TreeNode p, TreeNode q) { + + if (p == null && q == null) { + return true; + } + if (p == null || q == null) { + return false; + } + + LinkedList pStaCK = new LinkedList<>(); + LinkedList qStaCK = new LinkedList<>(); + pStaCK.push(p); + qStaCK.push(q); + while (!pStaCK.isEmpty() && !qStaCK.isEmpty()) { + p = pStaCK.pop(); + q = qStaCK.pop(); + if (p.val != q.val) { + return false; + } + + //p、q左子树有一个为null + if ((p.left == null && q.left != null) || (p.left != null && q.left == null)) { + return false; + } + //p、q右子树有一个为null + if ((p.right == null && q.right != null) || (p.right != null && q.right == null)) { + return false; + } + + if (p.left != null) { + pStaCK.push(p.left); + } + if (p.right != null) { + pStaCK.push(p.right); + } + if (q.left != null) { + qStaCK.push(q.left); + } + if (q.right != null) { + qStaCK.push(q.right); + } + } + return true; + } + + public static void main(String[] args) { + System.out.println(new Solution2().isSameTree(createTree(1, 2, 3), createTree(1, 2, 3))); + System.out.println(new Solution2().isSameTree(createTree(1, 2), createTree(1, null, 2))); + System.out.println(new Solution2().isSameTree(createTree(1, 2, 1), createTree(1, 1, 2))); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\347\233\270\345\220\214\347\232\204\346\240\221_100_\347\256\200\345\215\225/Solution3.java" "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\347\233\270\345\220\214\347\232\204\346\240\221_100_\347\256\200\345\215\225/Solution3.java" new file mode 100644 index 00000000..6bc50c58 --- /dev/null +++ "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\347\233\270\345\220\214\347\232\204\346\240\221_100_\347\256\200\345\215\225/Solution3.java" @@ -0,0 +1,46 @@ +package cn.lastwhisper.leetcode.binarytree.相同的树_100_简单; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; + +import java.util.LinkedList; + +import static cn.lastwhisper.leetcode.common.tree.TreeUtil.createTree; + +class Solution3 { + /** + * 题目地址:https://leetcode-cn.com/problems/same-tree/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:先序遍历-迭代 + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public boolean isSameTree(TreeNode p, TreeNode q) { + LinkedList pStack = new LinkedList<>(); + LinkedList qStack = new LinkedList<>(); + pStack.push(p); + qStack.push(q); + while (!pStack.isEmpty() && !qStack.isEmpty()) { + p = pStack.pop(); + q = qStack.pop(); + + if (p == null && q == null) continue; + if (p == null || q == null) return false; + if (p.val != q.val) return false; + + pStack.push(p.left); + pStack.push(p.right); + qStack.push(q.left); + qStack.push(q.right); + } + return true; + } + + public static void main(String[] args) { + System.out.println(new Solution3().isSameTree(createTree(1, 2, 3), createTree(1, 2, 3))); + System.out.println(new Solution3().isSameTree(createTree(1, 2), createTree(1, null, 2))); + System.out.println(new Solution3().isSameTree(createTree(1, 2, 1), createTree(1, 1, 2))); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\347\233\270\345\220\214\347\232\204\346\240\221_100_\347\256\200\345\215\225/Solution4.java" "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\347\233\270\345\220\214\347\232\204\346\240\221_100_\347\256\200\345\215\225/Solution4.java" new file mode 100644 index 00000000..bbf69363 --- /dev/null +++ "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\347\233\270\345\220\214\347\232\204\346\240\221_100_\347\256\200\345\215\225/Solution4.java" @@ -0,0 +1,45 @@ +package cn.lastwhisper.leetcode.binarytree.相同的树_100_简单; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; + +import java.util.LinkedList; + +import static cn.lastwhisper.leetcode.common.tree.TreeUtil.createTree; + +class Solution4 { + /** + * 题目地址:https://leetcode-cn.com/problems/same-tree/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:先序遍历-迭代 + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public boolean isSameTree(TreeNode p, TreeNode q) { + LinkedList stack = new LinkedList<>(); + stack.push(p); + stack.push(q); + while (!stack.isEmpty()) { + p = stack.pop(); + q = stack.pop(); + + if (p == null && q == null) continue; + if (p == null || q == null) return false; + if (p.val != q.val) return false; + + stack.push(p.left); + stack.push(q.left); + stack.push(p.right); + stack.push(q.right); + } + return true; + } + + public static void main(String[] args) { + System.out.println(new Solution4().isSameTree(createTree(1, 2, 3), createTree(1, 2, 3))); + System.out.println(new Solution4().isSameTree(createTree(1, 2), createTree(1, null, 2))); + System.out.println(new Solution4().isSameTree(createTree(1, 2, 1), createTree(1, 1, 2))); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\347\233\270\345\220\214\347\232\204\346\240\221_100_\347\256\200\345\215\225/Solution5.java" "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\347\233\270\345\220\214\347\232\204\346\240\221_100_\347\256\200\345\215\225/Solution5.java" new file mode 100644 index 00000000..5e70cdcd --- /dev/null +++ "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\347\233\270\345\220\214\347\232\204\346\240\221_100_\347\256\200\345\215\225/Solution5.java" @@ -0,0 +1,49 @@ +package cn.lastwhisper.leetcode.binarytree.相同的树_100_简单; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; + +import java.util.LinkedList; + +import static cn.lastwhisper.leetcode.common.tree.TreeUtil.createTree; + +class Solution5 { + /** + * 题目地址:https://leetcode-cn.com/problems/same-tree/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:层次遍历-迭代 + * 使用两个队列分别遍历两颗树 + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + + public boolean isSameTree(TreeNode p, TreeNode q) { + LinkedList pQueue = new LinkedList<>(); + LinkedList qQueue = new LinkedList<>(); + pQueue.add(p); + qQueue.add(q); + while (!pQueue.isEmpty() && !qQueue.isEmpty()) { + p = pQueue.poll(); + q = qQueue.poll(); + + if (p == null && q == null) continue; + if (p == null || q == null) return false; + if (p.val != q.val) return false; + + pQueue.add(p.left); + pQueue.add(p.right); + qQueue.add(q.left); + qQueue.add(q.right); + } + return true; + } + + + public static void main(String[] args) { + System.out.println(new Solution5().isSameTree(createTree(1, 2, 3), createTree(1, 2, 3)));//true + System.out.println(new Solution5().isSameTree(createTree(1, 2), createTree(1, null, 2)));//false + System.out.println(new Solution5().isSameTree(createTree(1, 2, 1), createTree(1, 1, 2)));//false + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\347\233\270\345\220\214\347\232\204\346\240\221_100_\347\256\200\345\215\225/Solution6.java" "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\347\233\270\345\220\214\347\232\204\346\240\221_100_\347\256\200\345\215\225/Solution6.java" new file mode 100644 index 00000000..cfe0f756 --- /dev/null +++ "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\347\233\270\345\220\214\347\232\204\346\240\221_100_\347\256\200\345\215\225/Solution6.java" @@ -0,0 +1,48 @@ +package cn.lastwhisper.leetcode.binarytree.相同的树_100_简单; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; + +import java.util.LinkedList; + +import static cn.lastwhisper.leetcode.common.tree.TreeUtil.createTree; + +class Solution6 { + /** + * 题目地址:https://leetcode-cn.com/problems/same-tree/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:层次遍历-迭代 + * 使用1个队列同时遍历两颗树 + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + + public boolean isSameTree(TreeNode p, TreeNode q) { + LinkedList queue = new LinkedList<>(); + queue.add(p); + queue.add(q); + while (!queue.isEmpty()) { + p = queue.poll(); + q = queue.poll(); + + if (p == null && q == null) continue; + if (p == null || q == null) return false; + if (p.val != q.val) return false; + + queue.add(p.left); + queue.add(q.left); + queue.add(p.right); + queue.add(q.right); + } + return true; + } + + + public static void main(String[] args) { + System.out.println(new Solution6().isSameTree(createTree(1, 2, 3), createTree(1, 2, 3)));//true + System.out.println(new Solution6().isSameTree(createTree(1, 2), createTree(1, null, 2)));//false + System.out.println(new Solution6().isSameTree(createTree(1, 2, 1), createTree(1, 1, 2)));//false + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\347\277\273\350\275\254\344\272\214\345\217\211\346\240\221_226_\347\256\200\345\215\225/Solution1.java" "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\347\277\273\350\275\254\344\272\214\345\217\211\346\240\221_226_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..d1cefea3 --- /dev/null +++ "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\347\277\273\350\275\254\344\272\214\345\217\211\346\240\221_226_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,46 @@ +package cn.lastwhisper.leetcode.binarytree.翻转二叉树_226_简单; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; + +import static cn.lastwhisper.leetcode.common.tree.TreeUtil.*; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/invert-binary-tree/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:先序遍历,递归DFS + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:最坏O(n)、最好O(logn) + */ + public TreeNode invertTree(TreeNode root) { + if (root == null) + return null; + // 翻转当前节点的左右子节点 + TreeNode tempNode = root.left; + root.left = root.right; + root.right = tempNode; + // left与right已经交换,所以right写前面 + invertTree(root.right); + invertTree(root.left); + return root; + } + + public TreeNode invertTree1(TreeNode root) { + if (root == null) + return null; + // 翻转当前节点的左右子节点 + TreeNode tempNode = root.left; + root.left = invertTree1(root.right); + root.right = invertTree1(tempNode); + return root; + } + + public static void main(String[] args) { + printLevelOrder(createTree(4,2,7,1,3,6,9)); + System.out.println("-------------------------------------"); + printLevelOrder(new Solution1().invertTree(createTree(4,2,7,1,3,6,9))); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\347\277\273\350\275\254\344\272\214\345\217\211\346\240\221_226_\347\256\200\345\215\225/Solution2.java" "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\347\277\273\350\275\254\344\272\214\345\217\211\346\240\221_226_\347\256\200\345\215\225/Solution2.java" new file mode 100644 index 00000000..14367309 --- /dev/null +++ "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\347\277\273\350\275\254\344\272\214\345\217\211\346\240\221_226_\347\256\200\345\215\225/Solution2.java" @@ -0,0 +1,44 @@ +package cn.lastwhisper.leetcode.binarytree.翻转二叉树_226_简单; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; + +import java.util.LinkedList; + +import static cn.lastwhisper.leetcode.common.tree.TreeUtil.*; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/invert-binary-tree/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:将先序遍历(递归)利用Stack改成迭代。使用Stack模拟系统递归栈 + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public TreeNode invertTree(TreeNode root) { + LinkedList stack = new LinkedList<>(); + if (root != null) { + stack.push(root); + } + TreeNode current = null; + while (!stack.isEmpty()) { + current = stack.poll(); + // 翻转当前节点的左右子节点 + TreeNode tempNode = current.left; + current.left = current.right; + current.right = tempNode; + // 此时left与right已经交换,栈先进先出,所以入栈顺序left->right + if (current.left != null) stack.push(current.left); + if (current.right != null) stack.push(current.right); + } + return root; + } + + public static void main(String[] args) { + printLevelOrder(createTree(4,2,7,1,3,6,9)); + System.out.println("-------------------------------------"); + printLevelOrder(new Solution2().invertTree(createTree(4,2,7,1,3,6,9))); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\347\277\273\350\275\254\344\272\214\345\217\211\346\240\221_226_\347\256\200\345\215\225/Solution3.java" "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\347\277\273\350\275\254\344\272\214\345\217\211\346\240\221_226_\347\256\200\345\215\225/Solution3.java" new file mode 100644 index 00000000..5fc5055d --- /dev/null +++ "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\347\277\273\350\275\254\344\272\214\345\217\211\346\240\221_226_\347\256\200\345\215\225/Solution3.java" @@ -0,0 +1,48 @@ +package cn.lastwhisper.leetcode.binarytree.翻转二叉树_226_简单; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; + +import java.util.LinkedList; +import java.util.Queue; + +import static cn.lastwhisper.leetcode.common.tree.TreeUtil.*; + +class Solution3 { + /** + * 题目地址:https://leetcode-cn.com/problems/invert-binary-tree/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:迭代BFS,层级遍历翻转(二叉树的层次遍历_102) + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public TreeNode invertTree(TreeNode root) { + Queue queue = new LinkedList<>(); + if (root != null) { + queue.add(root); + } + TreeNode current = null; + while (!queue.isEmpty()) { + //int size = queue.size(); + //for (int i = 0; i < size; i++) { + current = queue.poll(); + // 翻转当前节点的左右子节点 + TreeNode tempNode = current.left; + current.left = current.right; + current.right = tempNode; + + if (current.right != null) queue.add(current.right); + if (current.left != null) queue.add(current.left); + //} + } + return root; + } + + public static void main(String[] args) { + printLevelOrder(createTree(4,2,7,1,3,6,9)); + System.out.println("-------------------------------------"); + printLevelOrder(new Solution3().invertTree(createTree(4,2,7,1,3,6,9))); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\347\277\273\350\275\254\344\272\214\345\217\211\346\240\221_226_\347\256\200\345\215\225/Solution4.java" "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\347\277\273\350\275\254\344\272\214\345\217\211\346\240\221_226_\347\256\200\345\215\225/Solution4.java" new file mode 100644 index 00000000..2697a199 --- /dev/null +++ "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\347\277\273\350\275\254\344\272\214\345\217\211\346\240\221_226_\347\256\200\345\215\225/Solution4.java" @@ -0,0 +1,35 @@ +package cn.lastwhisper.leetcode.binarytree.翻转二叉树_226_简单; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; + +import static cn.lastwhisper.leetcode.common.tree.TreeUtil.createTree; +import static cn.lastwhisper.leetcode.common.tree.TreeUtil.printLevelOrder; + +class Solution4 { + /** + * 题目地址:https://leetcode-cn.com/problems/invert-binary-tree/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:中序遍历-递归 + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public TreeNode invertTree(TreeNode root) { + if (root == null) return null; + invertTree(root.left); // 递归找到左节点 + TreeNode rightNode = root.right; // 保存右节点 + root.right = root.left; + root.left = rightNode; + // 递归找到右节点 继续交换 : 因为此时左右节点已经交换了,所以此时的右节点为root.left + invertTree(root.left); + return root; + } + + public static void main(String[] args) { + printLevelOrder(createTree(4, 2, 7, 1, 3, 6, 9)); + System.out.println("-------------------------------------"); + printLevelOrder(new Solution4().invertTree(createTree(4, 2, 7, 1, 3, 6, 9))); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\347\277\273\350\275\254\344\272\214\345\217\211\346\240\221_226_\347\256\200\345\215\225/Solution5.java" "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\347\277\273\350\275\254\344\272\214\345\217\211\346\240\221_226_\347\256\200\345\215\225/Solution5.java" new file mode 100644 index 00000000..60e8195f --- /dev/null +++ "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\347\277\273\350\275\254\344\272\214\345\217\211\346\240\221_226_\347\256\200\345\215\225/Solution5.java" @@ -0,0 +1,34 @@ +package cn.lastwhisper.leetcode.binarytree.翻转二叉树_226_简单; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; + +import static cn.lastwhisper.leetcode.common.tree.TreeUtil.createTree; +import static cn.lastwhisper.leetcode.common.tree.TreeUtil.printLevelOrder; + +class Solution5 { + /** + * 题目地址:https://leetcode-cn.com/problems/invert-binary-tree/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:后序遍历-递归 + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public TreeNode invertTree(TreeNode root) { + // 后序遍历-- 从下向上交换 + if (root == null) return null; + TreeNode leftNode = invertTree(root.left); + TreeNode rightNode = invertTree(root.right); + root.right = leftNode; + root.left = rightNode; + return root; + } + + public static void main(String[] args) { + printLevelOrder(createTree(4, 2, 7, 1, 3, 6, 9)); + System.out.println("-------------------------------------"); + printLevelOrder(new Solution5().invertTree(createTree(4, 2, 7, 1, 3, 6, 9))); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\350\267\257\345\276\204\346\200\273\345\222\214_112_\347\256\200\345\215\225/Solution1.java" "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\350\267\257\345\276\204\346\200\273\345\222\214_112_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..8d057a72 --- /dev/null +++ "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\350\267\257\345\276\204\346\200\273\345\222\214_112_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,37 @@ +package cn.lastwhisper.leetcode.binarytree.路径总和_112_简单; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; + +import static cn.lastwhisper.leetcode.common.tree.TreeUtil.createTree; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/path-sum/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:递归先序遍历递归 + * 先序遍历,sum-路径上节点的值,减到叶子节点,返回结果是否等于0 + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public boolean hasPathSum(TreeNode root, int sum) { + // 当前节点不为空 + if (root == null) { + return false; + } + // 根节点到叶子节点中间路径和等于sum不行,叶子节点为终结才行 + if (root.left == null && root.right == null) { + return sum - root.val == 0; + } + return hasPathSum(root.left, sum - root.val) || hasPathSum(root.right, sum - root.val); + } + + public static void main(String[] args) { + TreeNode tree = createTree(5, 4, 8, 11, null, 13, 4, 7, 2, null, null, null, 1); + //TreeNode tree = createTree(5, null, 8, null, null, 13, 4); + int sum = 22; + System.out.println(new Solution1().hasPathSum(tree, sum)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\350\267\257\345\276\204\346\200\273\345\222\214_112_\347\256\200\345\215\225/Solution4.java" "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\350\267\257\345\276\204\346\200\273\345\222\214_112_\347\256\200\345\215\225/Solution4.java" new file mode 100644 index 00000000..5e2a58c6 --- /dev/null +++ "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\350\267\257\345\276\204\346\200\273\345\222\214_112_\347\256\200\345\215\225/Solution4.java" @@ -0,0 +1,52 @@ +package cn.lastwhisper.leetcode.binarytree.路径总和_112_简单; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; +import javafx.util.Pair; + +import java.util.LinkedList; + +class Solution4 { + /** + * 题目地址:https://leetcode-cn.com/problems/path-sum/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:先序遍历-迭代; + * 在根节点到叶子节点的路径总和=sum即可 + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public boolean hasPathSum(TreeNode root, int sum) { + if (root == null) { + return false; + } + // 节点 + LinkedList> stack = new LinkedList<>(); + stack.push(new Pair<>(root, 0)); + + Pair pair; + Integer parentVal; + while (!stack.isEmpty()) { + pair = stack.pop(); + root = pair.getKey(); + parentVal = pair.getValue(); + if (root.left == null && root.right == null) { + if (root.val + parentVal == sum) { + return true; + } + } + if (root.left != null) { + stack.push(new Pair<>(root.left, root.val + parentVal)); + } + if (root.right != null) { + stack.push(new Pair<>(root.right, root.val + parentVal)); + } + } + return false; + } + + public static void main(String[] args) { + + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\350\267\257\345\276\204\346\200\273\345\222\214_112_\347\256\200\345\215\225/Solution5.java" "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\350\267\257\345\276\204\346\200\273\345\222\214_112_\347\256\200\345\215\225/Solution5.java" new file mode 100644 index 00000000..b8b5f2b4 --- /dev/null +++ "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\350\267\257\345\276\204\346\200\273\345\222\214_112_\347\256\200\345\215\225/Solution5.java" @@ -0,0 +1,56 @@ +package cn.lastwhisper.leetcode.binarytree.路径总和_112_简单; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; +import javafx.util.Pair; + +import java.util.LinkedList; + +import static cn.lastwhisper.leetcode.common.tree.TreeUtil.createTree; + +class Solution5 { + /** + * 题目地址:https://leetcode-cn.com/problems/path-sum/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:先序遍历-迭代; + * 在根节点到叶子节点的路径总和=sum即可 + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public boolean hasPathSum(TreeNode root, int sum) { + if (root == null) { + return false; + } + // 节点 + LinkedList> stack = new LinkedList<>(); + stack.push(new Pair<>(root, sum)); + Pair pair; + // 暂存当前位置sum还剩下的值 + Integer parentSum; + while (!stack.isEmpty()) { + pair = stack.pop(); + root = pair.getKey(); + parentSum = pair.getValue(); + if (root.left == null && root.right == null) { + if (parentSum - root.val == 0) { + return true; + } + } + if (root.left != null) { + stack.push(new Pair<>(root.left, parentSum - root.val)); + } + if (root.right != null) { + stack.push(new Pair<>(root.right, parentSum - root.val)); + } + } + return false; + } + + public static void main(String[] args) { + TreeNode tree = createTree(5, 4, 8, 11, null, 13, 4, 7, 2, null, null, null, 1); + int sum = 22; + System.out.println(new Solution5().hasPathSum(tree, sum)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\350\267\257\345\276\204\346\200\273\345\222\214_III_437_\347\256\200\345\215\225/Solution1.java" "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\350\267\257\345\276\204\346\200\273\345\222\214_III_437_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..b786a6bc --- /dev/null +++ "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\350\267\257\345\276\204\346\200\273\345\222\214_III_437_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,48 @@ +package cn.lastwhisper.leetcode.binarytree.路径总和_III_437_简单; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; + +import static cn.lastwhisper.leetcode.common.tree.TreeUtil.createTree; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/path-sum-iii/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:先序遍历-递归 + * 找每一个节点的pathSum + * ------------------------------------------------------------------- + * 时间复杂度:O(n^2) + * 空间复杂度:O(n^2) + */ + // 从root找到路径和等于sum的数量 + public int pathSum(TreeNode root, int sum) { + if(root==null){ + return 0; + } + int res = findPathSum(root, sum); + res+=pathSum(root.left,sum); + res+=pathSum(root.right,sum); + return res; + } + + // 从node找到路径和等于sum的数量 + public int findPathSum(TreeNode node, int sum) { + if (node == null) { + return 0; + } + int res = 0; + if (node.val == sum) { + res++; + } + res += findPathSum(node.left, sum - node.val); + res += findPathSum(node.right, sum - node.val); + + return res; + } + + public static void main(String[] args) { + System.out.println(new Solution1().pathSum(createTree(10, 5, -3, 3, 2, null, 11, 3, -2, null, 1), 8)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\350\267\257\345\276\204\346\200\273\345\222\214_II_113_\344\270\255\347\255\211/Solution1.java" "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\350\267\257\345\276\204\346\200\273\345\222\214_II_113_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..704f3ab1 --- /dev/null +++ "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\350\267\257\345\276\204\346\200\273\345\222\214_II_113_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,51 @@ +package cn.lastwhisper.leetcode.binarytree.路径总和_II_113_中等; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; + +import java.util.ArrayList; +import java.util.List; + +import static cn.lastwhisper.leetcode.common.tree.TreeUtil.createTree; +import static cn.lastwhisper.leetcode.common.print.PrintUtil.printLists; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/path-sum-ii/ + * ------------------------------------------------------------------- + * 思考:路径总和(112)+二叉树的所有路劲(257) + * ------------------------------------------------------------------- + * 思路:先序遍历-递归 + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public List> pathSum(TreeNode root, int sum) { + List> result = new ArrayList<>(); + if (root == null) { + return result; + } + pathSumHelper(root, String.valueOf(root.val), root.val, result, sum); + return result; + } + + public void pathSumHelper(TreeNode root, String path, int partSum, List> result, int sum) { + if (root.left == null && root.right == null && partSum == sum) { + String[] arr = path.split(","); + List list = new ArrayList<>(arr.length); + for (String a : arr) { + list.add(Integer.parseInt(a)); + } + result.add(list); + } + if (root.left != null) { + pathSumHelper(root.left, path + "," + root.left.val, partSum + root.left.val, result, sum); + } + if (root.right != null) { + pathSumHelper(root.right, path + "," + root.right.val, partSum + root.right.val, result, sum); + } + } + + public static void main(String[] args) { + printLists(new Solution1().pathSum(createTree(5, 4, 8, 11, null, 13, 4, 7, 2, null, null, 5, 1), 22)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\350\267\257\345\276\204\346\200\273\345\222\214_II_113_\344\270\255\347\255\211/Solution2.java" "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\350\267\257\345\276\204\346\200\273\345\222\214_II_113_\344\270\255\347\255\211/Solution2.java" new file mode 100644 index 00000000..c9a5f6ff --- /dev/null +++ "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\350\267\257\345\276\204\346\200\273\345\222\214_II_113_\344\270\255\347\255\211/Solution2.java" @@ -0,0 +1,71 @@ +package cn.lastwhisper.leetcode.binarytree.路径总和_II_113_中等; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +import static cn.lastwhisper.leetcode.common.tree.TreeUtil.createTree; +import static cn.lastwhisper.leetcode.common.print.PrintUtil.printLists; + +class Solution2 { + static class DTO { + public TreeNode treeNode; + public String path; + public Integer sum; + + public DTO(TreeNode treeNode, String path, Integer sum) { + this.treeNode = treeNode; + this.path = path; + this.sum = sum; + } + } + + /** + * 题目地址:https://leetcode-cn.com/problems/path-sum-ii/ + * ------------------------------------------------------------------- + * 思考:路径总和(112)+二叉树的所有路劲(257) + * ------------------------------------------------------------------- + * 思路:先序遍历-迭代 + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public List> pathSum(TreeNode root, int sum) { + List> result = new ArrayList<>(); + if (root == null) { + return result; + } + LinkedList stack = new LinkedList<>(); + stack.push(new DTO(root, String.valueOf(root.val), root.val)); + + while (!stack.isEmpty()) { + DTO dto = stack.pop(); + root = dto.treeNode; + String path = dto.path; + Integer partSum = dto.sum; + + if (root.left == null && root.right == null && partSum == sum) { + String[] arr = path.split(","); + List list = new ArrayList<>(arr.length); + for (String a : arr) { + list.add(Integer.parseInt(a)); + } + result.add(list); + } + + if (root.left != null) { + stack.push(new DTO(root.left, path + "," + root.left.val, partSum + root.left.val)); + } + if (root.right != null) { + stack.push(new DTO(root.right, path + "," + root.right.val, partSum + root.right.val)); + } + } + return result; + } + + public static void main(String[] args) { + printLists(new Solution2().pathSum(createTree(5, 4, 8, 11, null, 13, 4, 7, 2, null, null, 5, 1), 22)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\351\252\214\350\257\201\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221_98_\344\270\255\347\255\211/Solution1.java" "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\351\252\214\350\257\201\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221_98_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..5722bed9 --- /dev/null +++ "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\351\252\214\350\257\201\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221_98_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,41 @@ +package cn.lastwhisper.leetcode.binarytree.验证二叉搜索树_98_中等; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; + +import java.util.LinkedList; + +import static cn.lastwhisper.leetcode.common.tree.TreeUtil.createTree; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/validate-binary-search-tree/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:bst中序遍历就是从小到大 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(n) + */ + public boolean isValidBST(TreeNode root) { + double inorder = -Double.MAX_VALUE; + LinkedList stack = new LinkedList<>(); + while (root != null || !stack.isEmpty()) { + while (root != null) { + stack.push(root); + root = root.left; + } + root = stack.pop(); + // 每一个节点值都应该比前一个值大 + if (root.val <= inorder) return false; + inorder = root.val; + root = root.right; + } + return true; + } + + public static void main(String[] args) { + System.out.println(new Solution1().isValidBST(createTree(5, 1, 4, null, null, 3, 6))); + System.out.println(new Solution1().isValidBST(createTree(1, 1))); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\351\252\214\350\257\201\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221_98_\344\270\255\347\255\211/Solution2.java" "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\351\252\214\350\257\201\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221_98_\344\270\255\347\255\211/Solution2.java" new file mode 100644 index 00000000..dbd6dc14 --- /dev/null +++ "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\351\252\214\350\257\201\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221_98_\344\270\255\347\255\211/Solution2.java" @@ -0,0 +1,35 @@ +package cn.lastwhisper.leetcode.binarytree.验证二叉搜索树_98_中等; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; + +import static cn.lastwhisper.leetcode.common.tree.TreeUtil.createTree; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/validate-binary-search-tree/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(n) + */ + public boolean isValidBST(TreeNode root) { + return isValidBST(root, null, null); + } + + private boolean isValidBST(TreeNode root, TreeNode min, TreeNode max) { + if (root == null) return true; + // 右子树>root + if (min != null && root.val <= min.val) return false; + // 左子树= max.val) return false; + return isValidBST(root.left, min, root) && isValidBST(root.right, root, max); + } + + public static void main(String[] args) { + System.out.println(new Solution2().isValidBST(createTree(5, 1, 4, null, null, 3, 6))); + System.out.println(new Solution2().isValidBST(createTree(1, 1))); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\351\252\214\350\257\201\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221_98_\344\270\255\347\255\211/Solution3.java" "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\351\252\214\350\257\201\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221_98_\344\270\255\347\255\211/Solution3.java" new file mode 100644 index 00000000..8eb75135 --- /dev/null +++ "b/algorithms/leetcode/binarytree/src/main/java/cn/lastwhisper/leetcode/binarytree/\351\252\214\350\257\201\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221_98_\344\270\255\347\255\211/Solution3.java" @@ -0,0 +1,36 @@ +package cn.lastwhisper.leetcode.binarytree.验证二叉搜索树_98_中等; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; + +import java.util.LinkedList; + +class Solution3 { + private LinkedList stack = new LinkedList<>(); + private LinkedList uppers = new LinkedList<>(); + private LinkedList lowers = new LinkedList<>(); + + private void update(TreeNode node, Integer lower, Integer upper) { + stack.add(node); + lowers.add(lower); + uppers.add(upper); + } + + public boolean isValidBST(TreeNode root) { + Integer lower = null, upper = null, val; + update(root, lower, upper); + + while (!stack.isEmpty()) { + root = stack.poll(); + lower = lowers.poll(); + upper = uppers.poll(); + + if (root == null) continue; + val = root.val; + if (lower != null && val <= lower) return false; + if (upper != null && val >= upper) return false; + update(root.right, val, upper); + update(root.left, lower, val); + } + return true; + } +} \ No newline at end of file diff --git a/algorithms/leetcode/bitoperation/pom.xml b/algorithms/leetcode/bitoperation/pom.xml new file mode 100644 index 00000000..dc6566c3 --- /dev/null +++ b/algorithms/leetcode/bitoperation/pom.xml @@ -0,0 +1,15 @@ + + + + leetcode + cn.lastwhisper + 1.0-SNAPSHOT + + 4.0.0 + + bitoperation + + + \ No newline at end of file diff --git "a/algorithms/leetcode/bitoperation/src/main/java/cn/lastwhisper/leetcode/bitoperation/\344\275\2151\347\232\204\344\270\252\346\225\260_191_\347\256\200\345\215\225/Solution.java" "b/algorithms/leetcode/bitoperation/src/main/java/cn/lastwhisper/leetcode/bitoperation/\344\275\2151\347\232\204\344\270\252\346\225\260_191_\347\256\200\345\215\225/Solution.java" new file mode 100644 index 00000000..4980b5ec --- /dev/null +++ "b/algorithms/leetcode/bitoperation/src/main/java/cn/lastwhisper/leetcode/bitoperation/\344\275\2151\347\232\204\344\270\252\346\225\260_191_\347\256\200\345\215\225/Solution.java" @@ -0,0 +1,17 @@ +package cn.lastwhisper.leetcode.bitoperation.位1的个数_191_简单; + +class Solution { + // you need to treat n as an unsigned value + public int hammingWeight(int n) { + int count = 0; + while (n != 0) { + // n=10011101,n-1=10011100 + // &全1则1,否则0 + // n & (n - 1)=10011101&10011100=10011100 + // n=10011100 + n = n & (n - 1); + count++; + } + return count; + } +} \ No newline at end of file diff --git a/algorithms/leetcode/dfsbfs/pom.xml b/algorithms/leetcode/dfsbfs/pom.xml new file mode 100644 index 00000000..7390dea6 --- /dev/null +++ b/algorithms/leetcode/dfsbfs/pom.xml @@ -0,0 +1,21 @@ + + + + leetcode + cn.lastwhisper + 1.0-SNAPSHOT + + 4.0.0 + + dfsbfs + + + + leetcode-common + cn.lastwhisper + 1.0-SNAPSHOT + + + \ No newline at end of file diff --git "a/algorithms/leetcode/dfsbfs/src/main/java/cn/lastwhisper/leetcode/dfsbfs/\345\234\260\345\233\276\345\210\206\346\236\220_1162_\344\270\255\347\255\211/Solution1.java" "b/algorithms/leetcode/dfsbfs/src/main/java/cn/lastwhisper/leetcode/dfsbfs/\345\234\260\345\233\276\345\210\206\346\236\220_1162_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..4a36d1f8 --- /dev/null +++ "b/algorithms/leetcode/dfsbfs/src/main/java/cn/lastwhisper/leetcode/dfsbfs/\345\234\260\345\233\276\345\210\206\346\236\220_1162_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,55 @@ +package cn.lastwhisper.leetcode.dfsbfs.地图分析_1162_中等; + +import org.junit.Assert; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/as-far-from-land-as-possible/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:广度优先搜索 + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public int maxDistance(int[][] grid) { + int max = 0; + + //boolean[][] visited = new boolean[grid.length][grid[0].length]; + for (int i = 0; i < grid.length; i++) { + for (int j = 0; j < grid[0].length; j++) { + if (grid[i][j] == 1) { + max = Math.max(dfs(grid, i, j), max); + } + } + } + return max; + } + + public int dfs(int[][] grid, int i, int j) { + int max = 0; + for (int k = 0; k < grid.length; k++) { + for (int l = 0; l < grid[0].length; l++) { + //if (k == i && l == j) { + // continue; + //} + if (grid[k][l] == 0) { + max = Math.max(manhattanDistance(i, k, j, l), max); + } + } + } + return max; + } + + /** + * 曼哈顿距离 + */ + public int manhattanDistance(int x0, int x1, int y0, int y1) { + return Math.abs(x0 - x1) + Math.abs(y0 - y1); + } + + public static void main(String[] args) { + Assert.assertEquals(2, new Solution1().maxDistance(new int[][]{{1, 0, 1}, {0, 0, 0}, {1, 0, 1}})); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/dfsbfs/src/main/java/cn/lastwhisper/leetcode/dfsbfs/\345\262\233\345\261\277\347\232\204\346\234\200\345\244\247\351\235\242\347\247\257_695_\344\270\255\347\255\211/Solution1.java" "b/algorithms/leetcode/dfsbfs/src/main/java/cn/lastwhisper/leetcode/dfsbfs/\345\262\233\345\261\277\347\232\204\346\234\200\345\244\247\351\235\242\347\247\257_695_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..48665435 --- /dev/null +++ "b/algorithms/leetcode/dfsbfs/src/main/java/cn/lastwhisper/leetcode/dfsbfs/\345\262\233\345\261\277\347\232\204\346\234\200\345\244\247\351\235\242\347\247\257_695_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,64 @@ +package cn.lastwhisper.leetcode.dfsbfs.岛屿的最大面积_695_中等; + +import org.junit.Assert; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/max-area-of-island/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:深度优先搜索 + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public int maxAreaOfIsland(int[][] grid) { + int max = 0; + boolean[][] visited = new boolean[grid.length][grid[0].length]; + for (int i = 0; i < grid.length; i++) { + for (int j = 0; j < grid[0].length; j++) { + if (grid[i][j] == 1) { + max = Math.max(dfs(grid, i, j, visited), max); + } + } + } + return max; + } + + /** + * @param grid 岛屿 + * @param x 当前所处的x + * @param y 当前所处的y + * @param visited 已经被访问的 + */ + public int dfs(int[][] grid, int x, int y, boolean[][] visited) { + if (x < 0 || x > grid.length - 1 || y < 0 || y > grid[0].length - 1 || visited[x][y] || grid[x][y] == 0) { + return 0; + } + int count = 1; + visited[x][y] = true;// 不需要回溯,因为到过的地方下次不会再去 + count += dfs(grid, x - 1, y, visited);//上 + count += dfs(grid, x, y + 1, visited);//右 + count += dfs(grid, x + 1, y, visited);//下 + count += dfs(grid, x, y - 1, visited);//左 + return count; + } + + public static void main(String[] args) { + //int[][] grid = {{0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0}, + // {0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0}, + // {0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, + // {0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0}, + // {0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0}, + // {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, + // {0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0}, + // {0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0} + //}; + int[][] grid = {{1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {0, 0, 0, 1, 1}, + {0, 0, 0, 1, 1}}; + Assert.assertEquals(4, new Solution1().maxAreaOfIsland(grid)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/dfsbfs/src/main/java/cn/lastwhisper/leetcode/dfsbfs/\350\205\220\347\203\202\347\232\204\346\251\230\345\255\220_994_\347\256\200\345\215\225/Solution1.java" "b/algorithms/leetcode/dfsbfs/src/main/java/cn/lastwhisper/leetcode/dfsbfs/\350\205\220\347\203\202\347\232\204\346\251\230\345\255\220_994_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..f70e4922 --- /dev/null +++ "b/algorithms/leetcode/dfsbfs/src/main/java/cn/lastwhisper/leetcode/dfsbfs/\350\205\220\347\203\202\347\232\204\346\251\230\345\255\220_994_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,80 @@ +package cn.lastwhisper.leetcode.dfsbfs.腐烂的橘子_994_简单; + +import java.util.LinkedList; +import java.util.Queue; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/rotting-oranges/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:广度优先搜索 + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public int orangesRotting(int[][] grid) { + int m = grid.length; + int n = grid[0].length; + Queue queue = new LinkedList<>(); + + int count = 0; // count 表示新鲜橘子的数量 + for (int r = 0; r < m; r++) { + for (int c = 0; c < n; c++) { + if (grid[r][c] == 1) {//新鲜 + count++; + } else if (grid[r][c] == 2) {//腐烂 + queue.add(new int[]{r, c}); + } + } + } + + int round = 0; // round 表示腐烂的轮数,或者分钟数 + while (count > 0 && !queue.isEmpty()) { + round++; + int size = queue.size(); + for (int i = 0; i < size; i++) { + int[] orange = queue.poll(); + // 腐烂橘子的坐标 + int r = orange[0]; + int c = orange[1]; + // 上下左右查看,是新鲜的就给它腐烂 + // 腐烂橘子上面的橘子 + if (r - 1 >= 0 && grid[r - 1][c] == 1) { + grid[r - 1][c] = 2; + count--; + queue.add(new int[]{r - 1, c}); + } + // 腐烂橘子下面的橘子 + if (r + 1 < m && grid[r + 1][c] == 1) { + grid[r + 1][c] = 2; + count--; + queue.add(new int[]{r + 1, c}); + } + // 腐烂橘子左面的橘子 + if (c - 1 >= 0 && grid[r][c - 1] == 1) { + grid[r][c - 1] = 2; + count--; + queue.add(new int[]{r, c - 1}); + } + // 腐烂橘子右面的橘子 + if (c + 1 < n && grid[r][c + 1] == 1) { + grid[r][c + 1] = 2; + count--; + queue.add(new int[]{r, c + 1}); + } + } + } + + if (count > 0) { + return -1; + } else { + return round; + } + } + + public static void main(String[] args) { + + } +} \ No newline at end of file diff --git a/algorithms/leetcode/divide/pom.xml b/algorithms/leetcode/divide/pom.xml new file mode 100644 index 00000000..4fe344f5 --- /dev/null +++ b/algorithms/leetcode/divide/pom.xml @@ -0,0 +1,21 @@ + + + + leetcode + cn.lastwhisper + 1.0-SNAPSHOT + + 4.0.0 + + divide + + + + cn.lastwhisper + leetcode-common + 1.0-SNAPSHOT + + + \ No newline at end of file diff --git a/algorithms/leetcode/dynamic/README.md b/algorithms/leetcode/dynamic/README.md new file mode 100644 index 00000000..93d3aba6 --- /dev/null +++ b/algorithms/leetcode/dynamic/README.md @@ -0,0 +1,156 @@ +### 动态规划题目特点 + +##### 1. 计数 + +- 有多少种方式走到右下角 +- 有多少种方法选出k个数使得和是sum + +##### 2.求最大最小值 + +- 从左上角走到右下角路径的最大数字和 +- 最长上升子序列长度 + +##### 3.求存在性 + +- 取石子游戏,先手是否必胜 +- 能不能选出k个数使得和是sum + +### 动态规划四个组成部分: + +- 确定状态 + - 研究最优策略的最后一步 + - 化为子问题 +- 转移方程 + - 根据子问题定义直接得到 +- **初始条件和边界情况** +- 计算顺序 + - 利用之前的计算结果 + +### 最值型动态规划 + +> Coin Change +> 假设你有三种硬币,分别面值2元,5元和7元,每种硬币都有足够多,买一本书需要27元,如何用最少的硬币组合正好付清,不需要对方找钱。 + +#### 动态规划组成部分一:确定状态 + +- 状态是动态规划的核心 +- 解动态规划时需要定义一个数组,数组的每一个元素`f[i]`或者`f[j][j]`代表什么 +- 确定状态需要两个意识: + - 最后一步 + - 子问题 + +> **最后一步** +> 1-不知道最优策略,但最优策略肯定是K枚硬币![a_1,a_2,...,a_k](https://math.jianshu.com/math?formula=a_1%2Ca_2%2C...%2Ca_k)面值加起来是27 +> 2-所以肯定有一枚最后的硬币:![a_k](https://math.jianshu.com/math?formula=a_k) +>  **关键点1:**不关心前面`k-1`枚硬币如何拼出![27-a_k](https://math.jianshu.com/math?formula=27-a_k),甚至不知道![a_k和K](https://math.jianshu.com/math?formula=a_k%E5%92%8CK),但是确定了前面的硬币拼出了![27-a_k](https://math.jianshu.com/math?formula=27-a_k) +>  **关键点2:**因为是最优策略,所以拼出![27-a_k](https://math.jianshu.com/math?formula=27-a_k)的硬币数一定要最少,否则矛盾。 +> **子问题** +> 1 - 需要求出最少用多少枚硬币可以拼出![27-a_k](https://math.jianshu.com/math?formula=27-a_k) +> 2 - 原问题是最少用多少枚硬币拼出27 +> 3 - 原问题转化成了一个规模更小的子问题:![27-a_k](https://math.jianshu.com/math?formula=27-a_k) +> 4 - 设状态![f(X) = 最少用多少枚硬币拼出X](https://math.jianshu.com/math?formula=f(X)%20%3D%20%E6%9C%80%E5%B0%91%E7%94%A8%E5%A4%9A%E5%B0%91%E6%9E%9A%E7%A1%AC%E5%B8%81%E6%8B%BC%E5%87%BAX) +> 最后一枚硬币只可能是2,5或7 +> 若![a_k == 2](https://math.jianshu.com/math?formula=a_k%20%3D%3D%202),![f(27)](https://math.jianshu.com/math?formula=f(27))应该是![f(27 - 2) + 1](https://math.jianshu.com/math?formula=f(27%20-%202)%20%2B%201)(加上最后的一枚硬币2) +> 若![a_k == 5](https://math.jianshu.com/math?formula=a_k%20%3D%3D%205),![f(27)](https://math.jianshu.com/math?formula=f(27))应该是![f(27 - 5) + 1](https://math.jianshu.com/math?formula=f(27%20-%205)%20%2B%201)(加上最后的一枚硬币5) +> 若![a_k == 7](https://math.jianshu.com/math?formula=a_k%20%3D%3D%207),![f(27)](https://math.jianshu.com/math?formula=f(27))应该是![f(27 - 7) + 1](https://math.jianshu.com/math?formula=f(27%20-%207)%20%2B%201)(加上最后的一枚硬币7) +> 要求最少的硬币数: +> ![f(27) = min{f(27 - 2), f(27 - 5), f(27 - 7)} + 1](https://math.jianshu.com/math?formula=f(27)%20%3D%20min%7Bf(27%20-%202)%2C%20f(27%20-%205)%2C%20f(27%20-%207)%7D%20%2B%201) + +#### 动态规划组成部分二:转移方程 + +- 设状态![f(X) =](https://math.jianshu.com/math?formula=f(X)%20%3D) 最少用多少枚硬币拼出![X](https://math.jianshu.com/math?formula=X) +- 对于任意![X](https://math.jianshu.com/math?formula=X),![f(27) = min{f(27 - 2), f(27 - 5), f(27 - 7)} + 1](https://math.jianshu.com/math?formula=f(27)%20%3D%20min%7Bf(27%20-%202)%2C%20f(27%20-%205)%2C%20f(27%20-%207)%7D%20%2B%201) + +#### 动态规划组成部分三:初始条件和边界情况 + +- ![X < 0](https://math.jianshu.com/math?formula=X%20%3C%200)时,![f(X) = +\infty](https://math.jianshu.com/math?formula=f(X)%20%3D%20%2B%5Cinfty) +- 初始条件:![f(0) = 0](https://math.jianshu.com/math?formula=f(0)%20%3D%200) + +#### 动态规划组成部分三:计算顺序 + +- 初始条件:![f(0) = 0](https://math.jianshu.com/math?formula=f(0)%20%3D%200) +- 然后计算![f(1),f(2),...,f(27)](https://math.jianshu.com/math?formula=f(1)%2Cf(2)%2C...%2Cf(27)) +- 大多数情况都是从小到大地算,这样当算![f(x)](https://math.jianshu.com/math?formula=f(x))时,前面的![f(x-2),f(x-5)和f(x-7)](https://math.jianshu.com/math?formula=f(x-2)%2Cf(x-5)%E5%92%8Cf(x-7))都已经算过了。 + +### 求最值型动态规划小结 + +- 1.确定状态 + - 最后一步(最优策略中使用的最后一枚硬币![a_k](https://math.jianshu.com/math?formula=a_k)) + - 化成子问题(最少的硬币拼出更小的面值![27-a_k](https://math.jianshu.com/math?formula=27-a_k) +- 2.转移方程 + - ![f(X) = min{f(X - 2), f(X - 5), f(X - 7)} + 1](https://math.jianshu.com/math?formula=f(X)%20%3D%20min%7Bf(X%20-%202)%2C%20f(X%20-%205)%2C%20f(X%20-%207)%7D%20%2B%201) +- 3.初始条件和边界情况 + - ![f(0) = 0](https://math.jianshu.com/math?formula=f(0)%20%3D%200),如果不能拼出![X](https://math.jianshu.com/math?formula=X),![f(X) = +\infty](https://math.jianshu.com/math?formula=f(X)%20%3D%20%2B%5Cinfty) +- 4.计算顺序 + - ![f(0),f(1),...](https://math.jianshu.com/math?formula=f(0)%2Cf(1)%2C...) + +### 计数型动态规划 + +> Unique Paths +> +> +> +> 给定m行n列的网格,有一个机器人从左上角(0, 0)出发,每一步可以向下或者向右走一步,问有多少种不同的方式走到右下角 +> +> ![img](https:////upload-images.jianshu.io/upload_images/17253929-90839d8817c3c9ad.png?imageMogr2/auto-orient/strip|imageView2/2/w/585/format/webp) + +#### 动态规划组成部分一:确定状态 + +- 最后一步:机器人走到右下角之前的最后一步: + + 向右或者向下 + + ![img](https:////upload-images.jianshu.io/upload_images/17253929-33fb59e5c5f32a8b.png?imageMogr2/auto-orient/strip|imageView2/2/w/578/format/webp) + +- 右下角坐标为(m - 1, n - 1),那么前一步机器人一定是在(m - 2, n - 1)或者(m - 1, n - 2) + +- 子问题 ——从左上角走到(m - 2, n - 1)和从左上角走到(m - 1, n - 2);假设从左上角走到(m - 2, n - 1)有![X](https://math.jianshu.com/math?formula=X)种方式,从左上角走到(m - 1, n - 2)有![Y](https://math.jianshu.com/math?formula=Y)种方式,那么走到(m - 1, n - 1)就有![X+Y](https://math.jianshu.com/math?formula=X%2BY)种方式。 + 问题转化为机器人有多少种方式从左上角走到(m - 2, n - 1)和(m - 1, n - 2) + +- 状态:设![f[i][j]](https://math.jianshu.com/math?formula=f%5Bi%5D%5Bj%5D)为机器人有多少种方式从左上角走到![(i,j)](https://math.jianshu.com/math?formula=(i%2Cj)) + +#### 动态规划组成部分二:转移方程 + +- 对于任意坐标![(i,j)](https://math.jianshu.com/math?formula=(i%2Cj)),![f[i][j] = f[i - 1][j] + f[i][j - 1]](https://math.jianshu.com/math?formula=f%5Bi%5D%5Bj%5D%20%3D%20f%5Bi%20-%201%5D%5Bj%5D%20%2B%20f%5Bi%5D%5Bj%20-%201%5D) + +#### 动态规划组成部分三:初始条件和边界情况 + +- 初始条件:![f[0][0] = 1](https://math.jianshu.com/math?formula=f%5B0%5D%5B0%5D%20%3D%201),机器人只有一种方式到左上角 +- 边界情况:![i = 0或j = 0](https://math.jianshu.com/math?formula=i%20%3D%200%E6%88%96j%20%3D%200),则前一步只能有一个方向过来 + +#### 动态规划组成部分四:计算顺序 + +- ![f[0][0] = 1](https://math.jianshu.com/math?formula=f%5B0%5D%5B0%5D%20%3D%201) +- 计算第0行:![f[0][0],f[0][1],...,f[0][n-1]](https://math.jianshu.com/math?formula=f%5B0%5D%5B0%5D%2Cf%5B0%5D%5B1%5D%2C...%2Cf%5B0%5D%5Bn-1%5D) +- 计算第1行:![f[1][0],f[1][1],...,f[1][n-1]](https://math.jianshu.com/math?formula=f%5B1%5D%5B0%5D%2Cf%5B1%5D%5B1%5D%2C...%2Cf%5B1%5D%5Bn-1%5D) +- ![...](https://math.jianshu.com/math?formula=...) +- 计算第m-1行:![f[m-1][0],f[m-1][1],...,f[m-1][n-1]](https://math.jianshu.com/math?formula=f%5Bm-1%5D%5B0%5D%2Cf%5Bm-1%5D%5B1%5D%2C...%2Cf%5Bm-1%5D%5Bn-1%5D) +- 答案是![f[m-1][n-1]](https://math.jianshu.com/math?formula=f%5Bm-1%5D%5Bn-1%5D) + 时间复杂度和空间复杂度都是![O(mn)](https://math.jianshu.com/math?formula=O(mn)) + +### 存在性型动态规划 + +> 有![n](https://math.jianshu.com/math?formula=n)块石头分别在x轴的![0,1,...,n-1](https://math.jianshu.com/math?formula=0%2C1%2C...%2Cn-1)位置,一只青蛙在石头![0](https://math.jianshu.com/math?formula=0),想跳到石头![n-1](https://math.jianshu.com/math?formula=n-1),如果青蛙在第![i](https://math.jianshu.com/math?formula=i)块石头上,它最多可以向右跳距离![a_i](https://math.jianshu.com/math?formula=a_i),问青蛙能否跳到石头![n-1](https://math.jianshu.com/math?formula=n-1)。 + +#### 动态规划组成部分一:确定状态 + +- 最后一步:如果青蛙能跳到最后一块石头![n-1](https://math.jianshu.com/math?formula=n-1),考虑它跳的最后一步是从石头![i](https://math.jianshu.com/math?formula=i)跳过来的,![i < n-1](https://math.jianshu.com/math?formula=i%20%3C%20n-1) +- 需要满足两个条件:1. 青蛙可以跳到石头![i](https://math.jianshu.com/math?formula=i) 2.最后一步不超过跳跃的最大距离:![n-1-i<=a_i](https://math.jianshu.com/math?formula=n-1-i%3C%3Da_i) +- 子问题——青蛙能不能跳到石头![i(i= j))](https://math.jianshu.com/math?formula=f%5Bj%5D%20%3D%20OR_%7B0%3C%3Di%3Cj%7D(f%5Bi%5D%20%5C%26%5C%26%20(i%20%2B%20a%5Bi%5D%20%3E%3D%20j))) + +#### 动态规划组成部分三:初始条件和边界情况 + +- 设![f[j]](https://math.jianshu.com/math?formula=f%5Bj%5D)表示青蛙能不能跳到石头![j](https://math.jianshu.com/math?formula=j) +- 初始条件:![f[0] = True](https://math.jianshu.com/math?formula=f%5B0%5D%20%3D%20True),青蛙一开始就在石头![0](https://math.jianshu.com/math?formula=0) + +#### 动态规划组成部分四:计算顺序 + +- 初始化![f[0] = True](https://math.jianshu.com/math?formula=f%5B0%5D%20%3D%20True) +- 计算![f[1],f[2],...,f[n-1]](https://math.jianshu.com/math?formula=f%5B1%5D%2Cf%5B2%5D%2C...%2Cf%5Bn-1%5D) +- 答案是![f[n-1]](https://math.jianshu.com/math?formula=f%5Bn-1%5D) + 时间复杂度:![O(n^2)](https://math.jianshu.com/math?formula=O(n%5E2)),空间复杂度:![O(n)](https://math.jianshu.com/math?formula=O(n)) \ No newline at end of file diff --git a/algorithms/leetcode/dynamic/pom.xml b/algorithms/leetcode/dynamic/pom.xml index e7c48bb8..6f55f76b 100644 --- a/algorithms/leetcode/dynamic/pom.xml +++ b/algorithms/leetcode/dynamic/pom.xml @@ -13,4 +13,13 @@ dynamic + + + + leetcode-common + cn.lastwhisper + 1.0-SNAPSHOT + + + \ No newline at end of file diff --git a/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/knapsack01/Solution1.java b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/knapsack01/Solution1.java new file mode 100644 index 00000000..a68c90c0 --- /dev/null +++ b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/knapsack01/Solution1.java @@ -0,0 +1,54 @@ +package cn.lastwhisper.leetcode.dynamic.knapsack01; + +/** + * 01背包 + * @author lastwhisper + * @date 2020/2/20 + */ +public class Solution1 { + + + private int bestValue(int[] w, int[] v, int index, int capacity) { + if (index < 0 || capacity <= 0) { + return 0; + } + // 尝试[0,index-1]的商品 + int res = bestValue(w, v, index - 1, capacity); + if (capacity >= w[index]) { + // 尝试index的商品和[0,index-1]时capacity等于减去w[index]的商品 + res = Math.max(res, v[index] + bestValue(w, v, index - 1, capacity - w[index])); + } + return res; + } + + /** + * 01背包 递归 + * + * F(n,c)考虑将n个物品放进容量为c的背包,使得价值最大 + * F(i,c) = max(F(i-1,c),v[i]+F(i-1,c-w[i])) + * + * @param w 每个商品对应的重量 + * @param v 每个商品对应的价值 + * @param capacity 背包容量 + * @return int 最大价值 + */ + public int knapsack01(int[] w, int[] v, int capacity) { + int n = w.length; + return bestValue(w, v, n - 1,capacity ); + } + + /** + * 容量为:5 + * 三个物品: + * w 1 2 3 + * v 6 10 12 + * + * 最大价值22 + */ + public static void main(String[] args) { + int[] w = new int[]{1, 2, 3}; + int[] v = new int[]{6, 10, 12}; + int capacity = 5; + System.out.println(new Solution1().knapsack01(w, v, capacity)); + } +} diff --git a/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/knapsack01/Solution2.java b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/knapsack01/Solution2.java new file mode 100644 index 00000000..9c4b23c2 --- /dev/null +++ b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/knapsack01/Solution2.java @@ -0,0 +1,57 @@ +package cn.lastwhisper.leetcode.dynamic.knapsack01; + +/** + * 01背包 + * @author lastwhisper + * @date 2020/2/20 + */ +public class Solution2 { + + + private int bestValue(int[] w, int[] v, int index, int capacity, int[][] memo) { + if (index < 0 || capacity <= 0) { + return 0; + } + if (memo[index][capacity] != 0) { + return memo[index][capacity]; + } + // 尝试[0,index-1]的商品 + int res = bestValue(w, v, index - 1, capacity, memo); + if (capacity >= w[index]) { + // 尝试index的商品和[0,index-1]时capacity等于减去w[index]的商品 + res = Math.max(res,v[index] + bestValue(w, v, index - 1, capacity - w[index], memo)); + } + memo[index][capacity] = res; + return res; + } + + /** + * 01背包 + * 递归+备忘录 + * + * @param w 每个商品对应的重量 + * @param v 每个商品对应的价值 + * @param capacity 背包容量 + * @return int 最大价值 + */ + public int knapsack01(int[] w, int[] v, int capacity) { + int n = w.length; + int[][] memo = new int[n][capacity + 1]; + return bestValue(w, v,n-1, capacity, memo); + } + + /** + * 容量为:5 + * 三个物品: + * w 1 2 3 + * v 6 10 12 + * + * 最大价值22 + */ + public static void main(String[] args) { + int[] w = new int[]{1, 2, 3}; + int[] v = new int[]{6, 10, 12}; + int capacity = 5; + System.out.println(new Solution2().knapsack01(w, v, capacity)); + } +} diff --git a/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/knapsack01/Solution3.java b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/knapsack01/Solution3.java new file mode 100644 index 00000000..5e60824d --- /dev/null +++ b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/knapsack01/Solution3.java @@ -0,0 +1,67 @@ +package cn.lastwhisper.leetcode.dynamic.knapsack01; + +/** + * 01背包 + * @author lastwhisper + * @date 2020/2/20 + */ +public class Solution3 { + + /** + * 01背包 动态规划 + * + * 时间复杂度:O(n*c) + * 空间复杂度:O(n*c) + * + * F(n,c)考虑将n个物品放进容量为c的背包,使得价值最大 + * F(i,c) = max(F(i-1,c),v[i]+F(i-1,c-w[i])) + * + * @param w 每个商品对应的重量 + * @param v 每个商品对应的价值 + * @param c 背包容量 + * @return int 最大价值 + */ + public int knapsack01(int[] w, int[] v, int c) { + int n = w.length; + if (n == 0) { + return 0; + } + + int[][] dp = new int[n][c + 1]; + + // 初始化第一行 + for (int i = 0; i <= c; i++) { + dp[0][i] = i >= w[0] ? v[0] : 0; + } + + // 外循环,当前可选商品 + for (int i = 1; i < n; i++) { + // 内循环,当前可用背包大小 + for (int j = 0; j <= c; j++) { + // 不考虑当前商品 + dp[i][j] = dp[i - 1][j]; + // 考虑当前商品+剩余容量时剩下商品 + if (j >= w[i]) { + dp[i][j] = Math.max(dp[i][j], v[i] + dp[i - 1][j - w[i]]); + } + } + } + + return dp[n - 1][c]; + } + + /** + * 容量为:5 + * 三个物品: + * w 1 2 3 + * v 6 10 12 + * + * 最大价值22 + */ + public static void main(String[] args) { + int[] w = new int[]{1, 2, 3}; + int[] v = new int[]{6, 10, 12}; + int capacity = 5; + System.out.println(new Solution3().knapsack01(w, v, capacity)); + } +} diff --git a/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/knapsack01/Solution4.java b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/knapsack01/Solution4.java new file mode 100644 index 00000000..82ec5b1c --- /dev/null +++ b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/knapsack01/Solution4.java @@ -0,0 +1,71 @@ +package cn.lastwhisper.leetcode.dynamic.knapsack01; + +/** + * 01背包 + * @author lastwhisper + * @date 2020/2/20 + */ +public class Solution4 { + + /** + * 01背包 动态规划 + * + * 时间复杂度:O(n*c) + * 空间复杂度:O(2*c) + * + * F(n,c)考虑将n个物品放进容量为c的背包,使得价值最大 + * F(i,c) = max(F(i-1,c),v[i]+F(i-1,c-w[i])) + * + * 空间优化: + * 第i行元素只依赖于第i-1行元素。理论上,只需要保持两行元素。 + * 空间复杂度:O( 2 * C ) = O(C) + * + * @param w 每个商品对应的重量 + * @param v 每个商品对应的价值 + * @param c 背包容量 + * @return int 最大价值 + */ + public int knapsack01(int[] w, int[] v, int c) { + int n = w.length; + if (n == 0) { + return 0; + } + + int[][] dp = new int[2][c + 1]; + + // 初始化第一行 + for (int i = 0; i <= c; i++) { + dp[0][i] = i >= w[0] ? v[0] : 0; + } + + // 外循环,当前可选商品 + for (int i = 1; i < n; i++) { + // 内循环,当前可用背包大小 + for (int j = 0; j <= c; j++) { + // 不考虑当前商品 + dp[i % 2][j] = dp[(i - 1) % 2][j]; + // 考虑当前商品+剩余容量时剩下商品 + if (j >= w[i % 2]) { + dp[i % 2][j] = Math.max(dp[i % 2][j], v[i% 2] + dp[(i - 1) % 2][j - w[i % 2]]); + } + } + } + + return dp[(n - 1) % 2][c]; + } + + /** + * 容量为:5 + * 三个物品: + * w 1 2 3 + * v 6 10 12 + * + * 最大价值22 + */ + public static void main(String[] args) { + int[] w = new int[]{1, 2, 3}; + int[] v = new int[]{6, 10, 12}; + int capacity = 5; + System.out.println(new Solution4().knapsack01(w, v, capacity)); + } +} diff --git a/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/knapsack01/Solution5.java b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/knapsack01/Solution5.java new file mode 100644 index 00000000..c335d37e --- /dev/null +++ b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/knapsack01/Solution5.java @@ -0,0 +1,66 @@ +package cn.lastwhisper.leetcode.dynamic.knapsack01; + +/** + * 01背包 + * @author lastwhisper + * @date 2020/2/20 + */ +public class Solution5 { + + /** + * 01背包 动态规划 + * + * 时间复杂度:O(n*c) + * 空间复杂度:O(c) + * + * F(n,c)考虑将n个物品放进容量为c的背包,使得价值最大 + * F(i,c) = max(F(i-1,c),v[i]+F(i-1,c-w[i])) + * + * 空间优化: + * + * + * @param w 每个商品对应的重量 + * @param v 每个商品对应的价值 + * @param c 背包容量 + * @return int 最大价值 + */ + public int knapsack01(int[] w, int[] v, int c) { + int n = w.length; + if (n == 0) { + return 0; + } + + int[] dp = new int[c + 1]; + + // 初始化第一行 + for (int i = 0; i <= c; i++) { + dp[i] = i >= w[0] ? v[0] : 0; + } + + // 外循环,当前可选商品 + for (int i = 1; i < n; i++) { + // 内循环,当前可用背包大小 + for (int j = c; j >= w[i]; j--) { + // 不考虑当前商品 vs 当前商品+剩余容量时剩下商品 + dp[j] = Math.max(dp[j], v[i] + dp[j - w[i]]); + } + } + + return dp[c]; + } + + /** + * 容量为:5 + * 三个物品: + * w 1 2 3 + * v 6 10 12 + * + * 最大价值22 + */ + public static void main(String[] args) { + int[] w = new int[]{1, 2, 3}; + int[] v = new int[]{6, 10, 12}; + int capacity = 5; + System.out.println(new Solution5().knapsack01(w, v, capacity)); + } +} diff --git a/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/knapsack01/knapsack01.md b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/knapsack01/knapsack01.md new file mode 100644 index 00000000..7431ee35 --- /dev/null +++ b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/knapsack01/knapsack01.md @@ -0,0 +1,15 @@ +| id | 0 | 1 | 2 | +| ------ | ---- | ---- | ---- | +| weight | 1 | 2 | 3 | +| value | 6 | 10 | 12 | + +​ + + + +| 物品编号\背包容量 | 0 | 1 | 2 | 3 | 4 | 5 | +|-----------| ---- | ---- | ---- | ---- | ---- | ---- | +| 0 | 0 | 6 | 6 | 6 | 6 | 6 | +| 1 | 0 | 6 | 10 | 16 | 16 | 16 | +| 2 | 0 | 6 | 10 | 16 | 18 | 22 | + diff --git "a/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\344\270\211\350\247\222\345\275\242\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214_120_\344\270\255\347\255\211/README.md" "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\344\270\211\350\247\222\345\275\242\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214_120_\344\270\255\347\255\211/README.md" new file mode 100644 index 00000000..68f2ea3d --- /dev/null +++ "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\344\270\211\350\247\222\345\275\242\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214_120_\344\270\255\347\255\211/README.md" @@ -0,0 +1 @@ +https://leetcode-cn.com/problems/triangle/solution/javadong-tai-gui-hua-si-lu-yi-ji-dai-ma-shi-xian-b/ \ No newline at end of file diff --git "a/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\344\270\211\350\247\222\345\275\242\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214_120_\344\270\255\347\255\211/Solution1.java" "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\344\270\211\350\247\222\345\275\242\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214_120_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..a2ac0362 --- /dev/null +++ "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\344\270\211\350\247\222\345\275\242\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214_120_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,82 @@ +package cn.lastwhisper.leetcode.dynamic.三角形最小路径和_120_中等; + +import java.util.List; + +import static cn.lastwhisper.leetcode.common.array.ArrayUtil.createList; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/triangle/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:动态规划——自顶向下 + * triangle={ + * [2], + * [3,4], + * [6,5,7], + * [4,1,8,3] + * } + * 1、状态定义:dp[i][j]表示包含第i行第j列元素的最小路径和 + * 2、状态分析 + * 初始化: + * dp[0][0]=triangle[0][0] + * 常规: + * triangle[i][j]一定会经过triangle[i-1][j]或者triangle[i-1][j-1] + * 所以状态dp[i][j]一定等于dp[i-1][j]或者dp[i-1][j-1]的最小值+triangle[i][j] + * 特殊: + * triangle[i][0]没有左上角 只能从triangle[i-1][j]经过 + * triangle[i][row[0].length]没有上面 只能从triangle[i-1][j-1]经过 + * 3、转换方程:dp[i][j]=min(dp[i-1][j],dp[i-1][j-1])+triangle[i][j] + * ------------------------------------------------------------------- + * 时间复杂度:O(n^2) + * 空间复杂度:O(n^2) + */ + public int minimumTotal(List> triangle) { + // 特判 + if (triangle == null || triangle.size() == 0) { + return 0; + } + + int row = triangle.size(); + int column = triangle.get(row - 1).size(); + + int[][] dp = new int[row][column]; + dp[0][0] = triangle.get(0).get(0); + + for (int i = 1; i < row; i++) { + //对每一行的元素进行最小路径和推导 + List rows = triangle.get(i); + for (int j = 0; j <= i; j++) { + if (j == 0) { + // 最左端特殊处理 + dp[i][j] = dp[i - 1][j] + rows.get(j); + } else if (j == i) { + // 最右端特殊处理 + dp[i][j] = dp[i - 1][j - 1] + rows.get(j); + } else { + dp[i][j] = Math.min(dp[i - 1][j], dp[i - 1][j - 1]) + rows.get(j); + } + } + } + + int res = Integer.MAX_VALUE; + // dp最后一行记录了最小路径 + for (int i = 0; i < column; i++) { + res = Math.min(res, dp[row - 1][i]); + } + return res; + } + + public static void main(String[] args) { + int[][] arrays = new int[][]{ + {2}, + {3, 4}, + {6, 5, 7}, + {4, 1, 8, 3} + }; + //int[][] arrays = new int[][]{{-10}}; + List> triangle = createList(arrays); + System.err.println(new Solution1().minimumTotal(triangle)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\344\270\211\350\247\222\345\275\242\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214_120_\344\270\255\347\255\211/Solution2.java" "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\344\270\211\350\247\222\345\275\242\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214_120_\344\270\255\347\255\211/Solution2.java" new file mode 100644 index 00000000..3a96c641 --- /dev/null +++ "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\344\270\211\350\247\222\345\275\242\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214_120_\344\270\255\347\255\211/Solution2.java" @@ -0,0 +1,69 @@ +package cn.lastwhisper.leetcode.dynamic.三角形最小路径和_120_中等; + +import java.util.List; + +import static cn.lastwhisper.leetcode.common.array.ArrayUtil.createList; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/triangle/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:动态规划——基于思路一 + * 空间优化: + * prev暂存dp[i-1][j-1],cur暂存dp[i-1][j] + * ------------------------------------------------------------------- + * 时间复杂度:O(n^2) + * 空间复杂度:O(n) + */ + public int minimumTotal(List> triangle) { + // 特判 + if (triangle == null || triangle.size() == 0) { + return 0; + } + // dp最大长度==triangle底边长度 + // 题意:只使用 O(n) 的额外空间(n 为三角形的总行数) + int[] dp = new int[triangle.size()]; + dp[0] = triangle.get(0).get(0); + + // prev暂存dp[i-1][j-1],cur暂存dp[i-1][j] + int prev = 0, cur; + for (int i = 1; i < triangle.size(); i++) { + //对每一行的元素进行推导 + List rows = triangle.get(i); + for (int j = 0; j <= i; j++) { + cur = dp[j]; + if (j == 0) { + // 最左端特殊处理 + dp[j] = cur + rows.get(j); + } else if (j == i) { + // 最右端特殊处理 + dp[j] = prev + rows.get(j); + } else { + dp[j] = Math.min(cur, prev) + rows.get(j); + } + prev = cur; + } + } + + int res = Integer.MAX_VALUE; + // dp最后一行记录了最小路径 + for (int i = 0; i < triangle.size(); i++) { + res = Math.min(res, dp[i]); + } + return res; + } + + public static void main(String[] args) { + int[][] arrays = new int[][]{ + {2}, + {3, 4}, + {6, 5, 7}, + {4, 1, 8, 3} + }; + //int[][] arrays = new int[][]{{-10}}; + List> triangle = createList(arrays); + System.err.println(new Solution2().minimumTotal(triangle)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\344\270\211\350\247\222\345\275\242\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214_120_\344\270\255\347\255\211/Solution3.java" "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\344\270\211\350\247\222\345\275\242\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214_120_\344\270\255\347\255\211/Solution3.java" new file mode 100644 index 00000000..912548cd --- /dev/null +++ "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\344\270\211\350\247\222\345\275\242\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214_120_\344\270\255\347\255\211/Solution3.java" @@ -0,0 +1,61 @@ +package cn.lastwhisper.leetcode.dynamic.三角形最小路径和_120_中等; + +import java.util.List; + +import static cn.lastwhisper.leetcode.common.array.ArrayUtil.createList; + +class Solution3 { + /** + * 题目地址:https://leetcode-cn.com/problems/triangle/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:动态规划——自底向上 + * triangle={ + * [2], + * [3,4], + * [6,5,7], + * [4,1,8,3] + * } + * 1、状态定义:dp[i][j]表示包含第i行第j列元素的最小路径和 + * 2、状态分析 + * 初始化: + * dp[n]=triangle[n] + * 常规: + * triangle[i][j]一定会到达triangle[i+1][j]或者triangle[i+1][j+1] + * 所以状态dp[i][j]一定等于dp[i+1][j]或者dp[i+1][j+1]的最小值+triangle[i][j] + * 3、转换方程:dp[i][j]=min(dp[i+1][j],dp[i+1][j+1])+triangle[i][j] + * ------------------------------------------------------------------- + * 时间复杂度:O(n^2) + * 空间复杂度:O(n^2) + */ + public int minimumTotal(List> triangle) { + // 特判 + if (triangle == null || triangle.size() == 0) { + return 0; + } + // 加1可以不用初始化最后一行 + // 根据题意,行列值相同 + int[][] dp = new int[triangle.size() + 1][triangle.size() + 1]; + + for (int i = triangle.size() - 1; i >= 0; i--) { + List rows = triangle.get(i); + for (int j = 0; j < rows.size(); j++) { + dp[i][j] = Math.min(dp[i + 1][j], dp[i + 1][j + 1]) + rows.get(j); + } + } + return dp[0][0]; + } + + public static void main(String[] args) { + int[][] arrays = new int[][]{ + {2}, + {3, 4}, + {6, 5, 7}, + {4, 1, 8, 3} + }; + //int[][] arrays = new int[][]{{-10}}; + List> triangle = createList(arrays); + System.err.println(new Solution3().minimumTotal(triangle)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\344\270\211\350\247\222\345\275\242\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214_120_\344\270\255\347\255\211/Solution4.java" "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\344\270\211\350\247\222\345\275\242\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214_120_\344\270\255\347\255\211/Solution4.java" new file mode 100644 index 00000000..d71d3786 --- /dev/null +++ "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\344\270\211\350\247\222\345\275\242\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214_120_\344\270\255\347\255\211/Solution4.java" @@ -0,0 +1,48 @@ +package cn.lastwhisper.leetcode.dynamic.三角形最小路径和_120_中等; + +import java.util.List; + +import static cn.lastwhisper.leetcode.common.array.ArrayUtil.createList; + +class Solution4 { + /** + * 题目地址:https://leetcode-cn.com/problems/triangle/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:动态规划——基于思路三 + * 空间优化: + * + * ------------------------------------------------------------------- + * 时间复杂度:O(n^2) + * 空间复杂度:O(n) + */ + public int minimumTotal(List> triangle) { + // 特判 + if (triangle == null || triangle.size() == 0) { + return 0; + } + // dp中记录了求第i行时,第i+1的最小路径和 + int[] dp = new int[triangle.size() + 1]; + + for (int i = triangle.size() - 1; i >= 0; i--) { + List rows = triangle.get(i); + for (int j = 0; j < rows.size(); j++) { + dp[j] = Math.min(dp[j], dp[j + 1]) + rows.get(j); + } + } + return dp[0]; + } + + public static void main(String[] args) { + int[][] arrays = new int[][]{ + {2}, + {3, 4}, + {6, 5, 7}, + {4, 1, 8, 3} + }; + //int[][] arrays = new int[][]{{-10}}; + List> triangle = createList(arrays); + System.err.println(new Solution4().minimumTotal(triangle)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\344\270\215\345\220\214\350\267\257\345\276\204II_63_\344\270\255\347\255\211/Solution1.java" "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\344\270\215\345\220\214\350\267\257\345\276\204II_63_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..6b1d84f6 --- /dev/null +++ "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\344\270\215\345\220\214\350\267\257\345\276\204II_63_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,56 @@ +package cn.lastwhisper.leetcode.dynamic.不同路径II_63_中等; + +class Solution1 { + + /** + * 题目地址:https://leetcode-cn.com/problems/unique-paths-ii/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:递归 + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + private int m, n; + private int[][] dir = {{0, 1}, {1, 0}}; + public int uniquePathsWithObstacles(int[][] obstacleGrid) { + if (obstacleGrid[0][0] == 1) { + return 0; + } + m = obstacleGrid.length; + n = obstacleGrid[0].length; + return findPath(obstacleGrid, 0, 0); + } + + private int findPath(int[][] grid, int startX, int startY) { + if (m - 1 == startX && n - 1 == startY) { + return 1; + } + int result = 0; + for (int i = 0; i < dir.length; i++) { + int newX = startX + dir[i][0]; + int newY = startY + dir[i][1]; + if (isValid(newX, newY, grid)) { + result += findPath(grid, newX, newY); + } + } + return result; + } + + private boolean isValid(int x, int y, int[][] grid) { + return x < m && y < n && grid[x][y] != 1; + } + + public static void main(String[] args) { + //int[][] obstacleGrid = { + // {0, 0, 0}, + // {0, 1, 0}, + // {0, 0, 0} + //}; + int[][] obstacleGrid = { + {1}, + }; + System.out.println(new Solution1().uniquePathsWithObstacles(obstacleGrid)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\344\270\215\345\220\214\350\267\257\345\276\204II_63_\344\270\255\347\255\211/Solution2.java" "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\344\270\215\345\220\214\350\267\257\345\276\204II_63_\344\270\255\347\255\211/Solution2.java" new file mode 100644 index 00000000..3f67aad1 --- /dev/null +++ "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\344\270\215\345\220\214\350\267\257\345\276\204II_63_\344\270\255\347\255\211/Solution2.java" @@ -0,0 +1,46 @@ +package cn.lastwhisper.leetcode.dynamic.不同路径II_63_中等; + +class Solution2 { + + /** + * 题目地址:https://leetcode-cn.com/problems/unique-paths-ii/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:动态规划 + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public int uniquePathsWithObstacles(int[][] obstacleGrid) { + if (obstacleGrid[0][0] == 1) { + return 0; + } + int m = obstacleGrid.length, n = obstacleGrid[0].length; + int[][] dp = new int[m][n]; + dp[0][0] = 1; + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + if (obstacleGrid[i][j] == 1) + continue; + if (i >= 1) + dp[i][j] = dp[i][j] + dp[i - 1][j]; + if (j >= 1) + dp[i][j] = dp[i][j] + dp[i][j - 1]; + } + } + return dp[m - 1][n - 1]; + } + + public static void main(String[] args) { + int[][] obstacleGrid = { + {0, 0, 0}, + {0, 1, 0}, + {0, 0, 0} + }; + //int[][] obstacleGrid = { + // {1}, + //}; + System.out.println(new Solution2().uniquePathsWithObstacles(obstacleGrid)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\344\270\215\345\220\214\350\267\257\345\276\204_62_\344\270\255\347\255\211/Solution1.java" "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\344\270\215\345\220\214\350\267\257\345\276\204_62_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..fd1374c2 --- /dev/null +++ "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\344\270\215\345\220\214\350\267\257\345\276\204_62_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,27 @@ +package cn.lastwhisper.leetcode.dynamic.不同路径_62_中等; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/fibonacci-number/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:递归(自顶向下) + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + + public int uniquePaths(int m, int n) { + // m==1||n==1时,只剩下一条路可走,直接返回1 + if (m == 1 || n == 1) { + return 1; + } + // 向右走+向下走 + return uniquePaths(m - 1, n) + uniquePaths(m, n - 1); + } + + public static void main(String[] args) { + System.out.println(new Solution1().uniquePaths(7, 3)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\344\270\215\345\220\214\350\267\257\345\276\204_62_\344\270\255\347\255\211/Solution2.java" "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\344\270\215\345\220\214\350\267\257\345\276\204_62_\344\270\255\347\255\211/Solution2.java" new file mode 100644 index 00000000..31e2a3a9 --- /dev/null +++ "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\344\270\215\345\220\214\350\267\257\345\276\204_62_\344\270\255\347\255\211/Solution2.java" @@ -0,0 +1,34 @@ +package cn.lastwhisper.leetcode.dynamic.不同路径_62_中等; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/fibonacci-number/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:动态规划 + * 每个位置的路径 = 该位置左边的路径 + 该位置上边的路径 + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public int uniquePaths(int m, int n) { + int[][] dp = new int[m][n]; + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + // 到达[0,1]、[1,0]只有一步 + if (i == 0 || j == 0) { + dp[i][j] = 1; + } else { + // 每个位置的路径 = 该位置左边的路径 + 该位置上边的路径 + dp[i][j] = dp[i][j - 1] + dp[i - 1][j]; + } + } + } + return dp[m - 1][n - 1]; + } + + public static void main(String[] args) { + System.out.println(new Solution2().uniquePaths(7, 3)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272_121_\347\256\200\345\215\225/Solution1.java" "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272_121_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..5e0b6bfa --- /dev/null +++ "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272_121_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,32 @@ +package cn.lastwhisper.leetcode.dynamic.买卖股票的最佳时机_121_简单; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:暴力 + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public int maxProfit(int[] prices) { + int max = 0; + for (int i = prices.length - 1; i > 0; i--) { + for (int j = i - 1; j >= 0; j--) { + int profit = prices[i] - prices[j]; + if (profit > max) { + max = profit; + } + } + } + return max; + } + + public static void main(String[] args) { + //int[] nums = new int[]{7, 1, 5, 3, 6, 4}; + int[] nums = new int[]{7, 6, 4, 3, 1}; + System.out.println(new Solution1().maxProfit(nums)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272_121_\347\256\200\345\215\225/Solution2.java" "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272_121_\347\256\200\345\215\225/Solution2.java" new file mode 100644 index 00000000..3e8bbf5d --- /dev/null +++ "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272_121_\347\256\200\345\215\225/Solution2.java" @@ -0,0 +1,33 @@ +package cn.lastwhisper.leetcode.dynamic.买卖股票的最佳时机_121_简单; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:动态规划 + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public int maxProfit(int[] prices) { + if (prices == null || prices.length <= 1) { + return 0; + } + // 前i天的最大收益 = max{前i-1天的最大收益,第i天的价格-前i-1天中的最小价格} + // min是前i-1天中的最小价格,前i-1天的最大收益 + int min = prices[0], max = 0; + for (int i = 1; i < prices.length; i++) { + max = Math.max(max, prices[i] - min); + min = Math.min(min, prices[i]); + } + return max; + } + + public static void main(String[] args) { + int[] nums = new int[]{7, 1, 5, 3, 6, 4}; + //int[] nums = new int[]{7, 6, 4, 3, 1}; + System.out.println(new Solution2().maxProfit(nums)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\345\210\206\345\211\262\347\255\211\345\222\214\345\255\220\351\233\206_416_\344\270\255\347\255\211/416.md" "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\345\210\206\345\211\262\347\255\211\345\222\214\345\255\220\351\233\206_416_\344\270\255\347\255\211/416.md" new file mode 100644 index 00000000..6661c76c --- /dev/null +++ "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\345\210\206\345\211\262\347\255\211\345\222\214\345\255\220\351\233\206_416_\344\270\255\347\255\211/416.md" @@ -0,0 +1,23 @@ +背包容量sum/2,数组中的值是物品的重量。 + +状态定义:`dp[i][j]`表示从数组的 `[0, i]` 这个子区间内挑选一些正整数,每个数只能用一次,使得这些数的和**恰好等于** `j`。 + +1. 不选择 `nums[i]`,如果在`[0, i - 1]` 这个子区间内已经有一部分元素,使得它们的和为 j ,那么 `dp[i][j] = true`; + +2. 选择 `nums[i]`,如果在 `[0, i - 1]` 这个子区间内就得找到一部分元素,使得它们的和为 `j - nums[i]`。 + +状态转移方程是: + +``` +dp[i][j]=dp[i-1][j] or dp[i][j-num[i]] +``` + + + +| | (i,j) | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | +| ---- | ------ | ----- | ----- | ---- | ---- | ---- | ----- | ----- | ---- | ---- | ---- | ----- | ----- | +| 1 | num[0] | **T** | **T** | F | F | F | F | F | F | F | F | F | F | +| 5 | num[1] | **T** | **T** | F | F | F | **T** | **T** | F | F | F | F | F | +| 11 | num[2] | **T** | **T** | F | F | F | **T** | **T** | F | F | F | F | **T** | +| 5 | num[3] | **T** | **T** | F | F | F | **T** | **T** | F | F | F | **T** | **T** | + diff --git "a/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\345\210\206\345\211\262\347\255\211\345\222\214\345\255\220\351\233\206_416_\344\270\255\347\255\211/Solution1.java" "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\345\210\206\345\211\262\347\255\211\345\222\214\345\255\220\351\233\206_416_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..14a445b7 --- /dev/null +++ "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\345\210\206\345\211\262\347\255\211\345\222\214\345\255\220\351\233\206_416_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,49 @@ +package cn.lastwhisper.leetcode.dynamic.分割等和子集_416_中等; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/partition-equal-subset-sum/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:动态规划 + * 背包问题,在n个物品中选出一定物品,填满sum/2的背包 + * 1、状态定义; + * 2、状态转移方程; + * 3、初始化; + * 4、输出; + * 5、思考状态压缩 + * F(n,c)考虑将n个物品填满容量为c的背包 + * F(i,c) = F(i-1,c)||F(i-1,c-w(i)) + * ------------------------------------------------------------------- + * 时间复杂度:O(n*sum/2) + * 空间复杂度:O(n*sum/2) + */ + public boolean canPartition(int[] nums) { + int sum = 0; + for (int num : nums) { + sum += num; + } + if (sum % 2 != 0) { + return false; + } + + return tryPartition(nums, nums.length - 1, sum / 2); + } + + // 使用nums[0,index],是否可以完全填充一个容量为sum的背包 + private boolean tryPartition(int[] nums, int index, int sum) { + if (sum == 0) { + return true; + } + if (index < 0 || sum < 0) { + return false; + } + + return tryPartition(nums, index - 1, sum) || tryPartition(nums, index - 1, sum - nums[index]); + } + + public static void main(String[] args) { + System.out.println(new Solution1().canPartition(new int[]{1, 5, 11, 5})); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\345\210\206\345\211\262\347\255\211\345\222\214\345\255\220\351\233\206_416_\344\270\255\347\255\211/Solution2.java" "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\345\210\206\345\211\262\347\255\211\345\222\214\345\255\220\351\233\206_416_\344\270\255\347\255\211/Solution2.java" new file mode 100644 index 00000000..1c7cb54b --- /dev/null +++ "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\345\210\206\345\211\262\347\255\211\345\222\214\345\255\220\351\233\206_416_\344\270\255\347\255\211/Solution2.java" @@ -0,0 +1,59 @@ +package cn.lastwhisper.leetcode.dynamic.分割等和子集_416_中等; + +import java.util.Arrays; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/partition-equal-subset-sum/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:动态规划 + * 背包问题,在n个物品中选出一定物品,填满sum/2的背包 + * 1、状态定义; + * 2、状态转移方程; + * 3、初始化; + * 4、输出; + * 5、思考状态压缩 + * F(n,c)考虑将n个物品填满容量为c的背包 + * F(i,c) = F(i-1,c)||F(i-1,c-w(i)) + * ------------------------------------------------------------------- + * 时间复杂度:O(n*sum/2) + * 空间复杂度: + */ + public boolean canPartition(int[] nums) { + int sum = 0; + for (int num : nums) { + sum += num; + } + if (sum % 2 != 0) { + return false; + } + // -1未存储;0 false;1 true + int[][] memo = new int[nums.length][sum / 2 + 1]; + for (int[] ints : memo) { + Arrays.fill(ints, -1); + } + return tryPartition(nums, nums.length - 1, sum / 2, memo); + } + + // 使用nums[0,index],是否可以完全填充一个容量为sum的背包 + private boolean tryPartition(int[] nums, int index, int sum, int[][] memo) { + if (sum == 0) { + return true; + } + if (index < 0 || sum < 0) { + return false; + } + if (memo[index][sum] != -1) { + return memo[index][sum] == 1; + } + memo[index][sum] = (tryPartition(nums, index - 1, sum, memo) || + tryPartition(nums, index - 1, sum - nums[index], memo)) ? 1 : 0; + return memo[index][sum] == 1; + } + + public static void main(String[] args) { + System.out.println(new Solution2().canPartition(new int[]{1, 5, 11, 5})); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\345\210\206\345\211\262\347\255\211\345\222\214\345\255\220\351\233\206_416_\344\270\255\347\255\211/Solution3.java" "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\345\210\206\345\211\262\347\255\211\345\222\214\345\255\220\351\233\206_416_\344\270\255\347\255\211/Solution3.java" new file mode 100644 index 00000000..3e7c3b95 --- /dev/null +++ "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\345\210\206\345\211\262\347\255\211\345\222\214\345\255\220\351\233\206_416_\344\270\255\347\255\211/Solution3.java" @@ -0,0 +1,62 @@ +package cn.lastwhisper.leetcode.dynamic.分割等和子集_416_中等; + +class Solution3 { + /** + * 题目地址:https://leetcode-cn.com/problems/partition-equal-subset-sum/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:动态规划 + * 背包问题,在n个物品中选出一定物品,填满sum/2的背包 + * dp[i][j]考虑将i个物品填满容量为j的背包 + * dp[i][j]=dp[i-1][j] or dp[i][j-num[i]] + * ------------------------------------------------------------------- + * 时间复杂度:O(NC):这里 N 是数组元素的个数,C 是数组元素的和的一半。 + * 空间复杂度:O(NC) + */ + public boolean canPartition(int[] nums) { + int len = nums.length; + if (len == 0) { + return false; + } + + int sum = 0; + for (int num : nums) { + sum += num; + } + // 特判:如果是奇数,就不符合要求 + if (sum % 2 != 0) { + return false; + } + int target = sum / 2; + + // 创建二维状态数组,行:物品索引,列:容量(包括 0) + boolean[][] dp = new boolean[len][target + 1]; + + // 先填表格第 0 行,第 1 个数只能让容积为它自己的背包恰好装满 + if (nums[0] <= target) { + dp[0][nums[0]] = true; + } + + // 外循环是物品 + for (int i = 1; i < len; i++) { + // 内循环是容量 + for (int j = 0; j <= target; j++) { + // 第i个物品重量num[i]刚好够,背包容量j + if (nums[i] == j) { + dp[i][j] = true; + } else if (nums[i] < j) { + dp[i][j] = dp[i - 1][j] || dp[i - 1][j - nums[i]]; + } else { + dp[i][j] = dp[i - 1][j]; + } + } + } + return dp[len - 1][target]; + } + + public static void main(String[] args) { + System.out.println(new Solution3().canPartition(new int[]{1, 2, 5})); + //System.out.println(new Solution3().canPartition(new int[]{1, 5, 11, 5})); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\345\210\206\345\211\262\347\255\211\345\222\214\345\255\220\351\233\206_416_\344\270\255\347\255\211/Solution4.java" "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\345\210\206\345\211\262\347\255\211\345\222\214\345\255\220\351\233\206_416_\344\270\255\347\255\211/Solution4.java" new file mode 100644 index 00000000..38c83b99 --- /dev/null +++ "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\345\210\206\345\211\262\347\255\211\345\222\214\345\255\220\351\233\206_416_\344\270\255\347\255\211/Solution4.java" @@ -0,0 +1,60 @@ +package cn.lastwhisper.leetcode.dynamic.分割等和子集_416_中等; + +class Solution4 { + /** + * 题目地址:https://leetcode-cn.com/problems/partition-equal-subset-sum/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * 动态规划: + * 背包问题,在n个物品中选出一定物品,填满sum/2的背包 + * dp[i][j]考虑将i个物品填满容量为j的背包 + * dp[i][j]=dp[i-1][j] or dp[i][j-num[i]] + * 时间优化: + * ------------------------------------------------------------------- + * 时间复杂度:O(NC):这里 N 是数组元素的个数,C 是数组元素的和的一半。 + * 空间复杂度:O(C) + */ + public boolean canPartition(int[] nums) { + int len = nums.length; + if (len == 0) { + return false; + } + + int sum = 0; + for (int num : nums) { + sum += num; + } + // 特判:如果是奇数,就不符合要求 + if (sum % 2 != 0) { + return false; + } + int target = sum / 2; + + // 创建二维状态数组,行:物品索引,列:容量(包括 0) + boolean[] dp = new boolean[target + 1]; + + // 先填表格第 0 行,第 1 个数只能让容积为它自己的背包恰好装满 + if (nums[0] <= target) { + dp[nums[0]] = true; + } + + // 外循环是物品 + for (int i = 1; i < len; i++) { + // 内循环是容量 + for (int j = target; j >= nums[i]; j--) { + if (dp[target]) { + return true; + } + dp[j] = dp[j] || dp[j - nums[i]]; + } + } + return dp[target]; + } + + public static void main(String[] args) { + System.out.println(new Solution4().canPartition(new int[]{1, 2, 5})); + //System.out.println(new Solution3().canPartition(new int[]{1, 5, 11, 5})); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\345\256\214\345\205\250\345\271\263\346\226\271\346\225\260_279_\344\270\255\347\255\211/Solution1.java" "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\345\256\214\345\205\250\345\271\263\346\226\271\346\225\260_279_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..4fb45d2c --- /dev/null +++ "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\345\256\214\345\205\250\345\271\263\346\226\271\346\225\260_279_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,53 @@ +package cn.lastwhisper.leetcode.dynamic.完全平方数_279_中等; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/perfect-squares/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * 四平方定理:每个正整数均可表为四个整数的平方和(其中有些整数可以为零),满足n=(4^a)*(8b+7) + * 1、任何正整数都可以拆分成不超过4个数的平方和 ---> 答案只可能是1,2,3,4 + * 2、如果一个数正好可以拆成4个数的平方和,则这个数还满足 n = (4^a)*(8b+7) ---> + * 因此可以先看这个数是否满足上述公式,如果不满足,答案就是1,2,3了 + * 3、如果这个数本来就是某个数的平方,那么答案就是1,否则答案就只剩2,3了 + * 4、如果答案是2,即n=a^2+b^2,那么我们可以枚举a,来验证,如果验证通过则答案是2 + * 5、只能是3 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(1) + */ + public int numSquares(int n) { + // 1、如果n可以拆成四个数的平方,n=(4^a)*(8b+7) + while (n % 4 == 0) { + n /= 4; + } + if (n % 8 == 7) { + return 4; + } + /* + * 2、如果n本来就是某个数的平方,那么答案就是1 + * 3、如果答案是2,即n=a^2+b^2,那么我们可以枚举a,来验证,如果验证通过则答案是2 + */ + int a = 0,b; + while ((a * a) < n) { + b = (int) Math.sqrt(n - (a * a)); + if ((a * a) + (b * b) == n) { + if (a != 0 && b != 0) { + return 2; + } else { + return 1; + } + } + a++; + } + // 4、否则为3 + return 3; + } + + public static void main(String[] args) { + System.out.println(new Solution1().numSquares(12)); + System.out.println(new Solution1().numSquares(13)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\345\256\214\345\205\250\345\271\263\346\226\271\346\225\260_279_\344\270\255\347\255\211/Solution2.java" "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\345\256\214\345\205\250\345\271\263\346\226\271\346\225\260_279_\344\270\255\347\255\211/Solution2.java" new file mode 100644 index 00000000..171df1c6 --- /dev/null +++ "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\345\256\214\345\205\250\345\271\263\346\226\271\346\225\260_279_\344\270\255\347\255\211/Solution2.java" @@ -0,0 +1,51 @@ +package cn.lastwhisper.leetcode.dynamic.完全平方数_279_中等; + +import javafx.util.Pair; + +import java.util.LinkedList; + +/** + * 题目地址:https://leetcode-cn.com/problems/perfect-squares/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * 图,使用visited数组,记录每一个入队元素 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(n) + */ +public class Solution2 { + + public int numSquares(int n) { + + LinkedList> queue = new LinkedList>(); + queue.addLast(new Pair(n, 0)); + + boolean[] visited = new boolean[n + 1]; + visited[n] = true; + + while (!queue.isEmpty()) { + Pair front = queue.removeFirst(); + int num = front.getKey(); + int step = front.getValue(); + + if (num == 0) + return step; + + for (int i = 1; num - i * i >= 0; i++) + if (!visited[num - i * i]) { + queue.addLast(new Pair<>(num - i * i, step + 1)); + visited[num - i * i] = true; + } + } + + throw new IllegalStateException("No Solution."); + } + + public static void main(String[] args) { + + System.out.println((new Solution2()).numSquares(12)); + System.out.println((new Solution2()).numSquares(13)); + } +} diff --git "a/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\345\256\214\345\205\250\345\271\263\346\226\271\346\225\260_279_\344\270\255\347\255\211/Solution3.java" "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\345\256\214\345\205\250\345\271\263\346\226\271\346\225\260_279_\344\270\255\347\255\211/Solution3.java" new file mode 100644 index 00000000..7b63b225 --- /dev/null +++ "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\345\256\214\345\205\250\345\271\263\346\226\271\346\225\260_279_\344\270\255\347\255\211/Solution3.java" @@ -0,0 +1,23 @@ +package cn.lastwhisper.leetcode.dynamic.完全平方数_279_中等; + +class Solution3 { + /** + * 题目地址:https://leetcode-cn.com/problems/perfect-squares/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:01背包 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(1) + */ + public int numSquares(int n) { + + return 3; + } + + public static void main(String[] args) { + System.out.println(new Solution3().numSquares(12)); + System.out.println(new Solution3().numSquares(13)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\210\263\346\260\224\347\220\203_312_\345\233\260\351\232\276/Solution1.java" "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\210\263\346\260\224\347\220\203_312_\345\233\260\351\232\276/Solution1.java" new file mode 100644 index 00000000..3b134cab --- /dev/null +++ "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\210\263\346\260\224\347\220\203_312_\345\233\260\351\232\276/Solution1.java" @@ -0,0 +1,51 @@ +package cn.lastwhisper.leetcode.dynamic.戳气球_312_困难; + +import org.junit.Assert; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +class Solution1 { + + /** + * 题目地址:https://leetcode-cn.com/problems/burst-balloons/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:递归回溯 + * ------------------------------------------------------------------- + * 时间复杂度:O(n!) + * 空间复杂度:O(n!) + */ + public int maxCoins(int[] nums) { + if (nums == null || nums.length == 0) { + return 0; + } + List arrayList = Arrays.stream(nums) + .boxed() + .collect(Collectors.toList()); + return helper(arrayList, 0); + } + + private int helper(List nums, int coins) { + if (nums.size() == 0) { + return coins; + } + int res = 0; + for (int i = 0; i < nums.size(); i++) { + int tmp = nums.get(i); + int delta = nums.get(i) + * (i - 1 < 0 ? 1 : nums.get(i - 1)) + * (i + 1 > nums.size() - 1 ? 1 : nums.get(i + 1)); + nums.remove(i); + res = Math.max(res, helper(nums, coins + delta)); + nums.add(i, tmp); + } + return res; + } + + public static void main(String[] args) { + Assert.assertEquals(167, new Solution1().maxCoins(new int[]{3, 1, 5, 8})); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\211\223\345\256\266\345\212\253\350\210\215_198_\347\256\200\345\215\225/Solution1.java" "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\211\223\345\256\266\345\212\253\350\210\215_198_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..2debb5d8 --- /dev/null +++ "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\211\223\345\256\266\345\212\253\350\210\215_198_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,50 @@ +package cn.lastwhisper.leetcode.dynamic.打家劫舍_198_简单; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/house-robber/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:动态规划 + * 1、状态定义:dp[i]表示偷到至第i个房子,所获取最大的利益 + * 2、状态分析 + * 初始: + * dp[0] = nums[0]; + * dp[1] = Math.max(nums[0], nums[1]) + * 方程: + * dp[i]=max(dp[i-2]+num[i],dp[i-1]) + * ------------------------------------------------------------------- + * 时间复杂度:O(n^2) + * 空间复杂度:O(n) + */ + public int rob(int[] nums) { + // 特判 + if (nums == null || nums.length == 0) { + return 0; + } + if (nums.length == 1) { + return nums[0]; + } + if (nums.length == 2) { + return Math.max(nums[0], nums[1]); + } + + int[] dp = new int[nums.length]; + dp[0] = nums[0]; + dp[1] = Math.max(nums[0], nums[1]); + + for (int i = 2; i < nums.length; i++) { + dp[i] = Math.max(dp[i - 2] + nums[i], dp[i - 1]); + } + + return dp[nums.length - 1]; + } + + public static void main(String[] args) { + int[] array = new int[]{2, 1, 1, 2}; + //int[] array = new int[]{2, 7, 9, 3, 1}; + //int[] array = new int[]{1, 2, 3, 1}; + System.out.println(new Solution1().rob(array)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\211\223\345\256\266\345\212\253\350\210\215_198_\347\256\200\345\215\225/Solution2.java" "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\211\223\345\256\266\345\212\253\350\210\215_198_\347\256\200\345\215\225/Solution2.java" new file mode 100644 index 00000000..0992ccf8 --- /dev/null +++ "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\211\223\345\256\266\345\212\253\350\210\215_198_\347\256\200\345\215\225/Solution2.java" @@ -0,0 +1,39 @@ +package cn.lastwhisper.leetcode.dynamic.打家劫舍_198_简单; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/house-robber/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:动态规划 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(n) + */ + public int rob(int[] nums) { + int n = nums.length; + if (n == 0) { + return 0; + } + // memo[i] 表示考虑抢劫 nums[i...n-1] 所能获得最大收益(不是说一定从 i 开始抢劫) + int[] memo = new int[n]; + // 先考虑最简单的情况 + memo[n - 1] = nums[n - 1]; + for (int i = n - 2; i >= 0; i--) { + // memo[i] 的取值在考虑抢劫 i 号房子和不考虑抢劫之间取最大值 + for (int j = i; j < n; j++) { + memo[i] = Math.max(memo[i], nums[j] + (j + 2 < n ? memo[j + 2] : 0)); + } + } + + return memo[0]; + } + + + public static void main(String[] args) { + System.out.println(new Solution2().rob(new int[]{2, 1, 1, 2})); + System.out.println(new Solution2().rob(new int[]{2, 7, 9, 3, 1})); + System.out.println(new Solution2().rob(new int[]{1, 2, 3, 1})); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\211\223\345\256\266\345\212\253\350\210\215_198_\347\256\200\345\215\225/recursion/Solution1.java" "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\211\223\345\256\266\345\212\253\350\210\215_198_\347\256\200\345\215\225/recursion/Solution1.java" new file mode 100644 index 00000000..9a0af284 --- /dev/null +++ "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\211\223\345\256\266\345\212\253\350\210\215_198_\347\256\200\345\215\225/recursion/Solution1.java" @@ -0,0 +1,37 @@ +package cn.lastwhisper.leetcode.dynamic.打家劫舍_198_简单.recursion; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/house-robber/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:递归 + * ------------------------------------------------------------------- + * 时间复杂度:O() + * 空间复杂度:O() + */ + public int rob(int[] nums) { + return tryRob(0, nums); + } + + public int tryRob(int index, int[] nums) { + if (index >= nums.length) { + return 0; + } + int max = 0, res; + for (int i = index; i < nums.length; i++) { + res = nums[i] + tryRob(i + 2, nums); + max = Math.max(max, res); + System.out.println("max:" + max + " res:" + res); + } + + return max; + } + + public static void main(String[] args) { + System.out.println(new Solution1().rob(new int[]{2, 1, 1, 2})); +// System.out.println(new Solution1().rob(new int[]{2, 7, 9, 3, 1})); + //System.out.println(new Solution1().rob(new int[]{1, 2, 3, 1})); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\211\223\345\256\266\345\212\253\350\210\215_198_\347\256\200\345\215\225/recursion/Solution2.java" "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\211\223\345\256\266\345\212\253\350\210\215_198_\347\256\200\345\215\225/recursion/Solution2.java" new file mode 100644 index 00000000..30025c16 --- /dev/null +++ "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\211\223\345\256\266\345\212\253\350\210\215_198_\347\256\200\345\215\225/recursion/Solution2.java" @@ -0,0 +1,45 @@ +package cn.lastwhisper.leetcode.dynamic.打家劫舍_198_简单.recursion; + +import java.util.Arrays; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/house-robber/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:递归+备忘录 + * 状态:考虑抢劫 nums[index...num.length) 这个范围内的所有房子 + * 状态转移:tryRob(n) = Max{rob(0) + tryRob(2), rob(1) + tryRob(3)... rob(n-3) + tryRob(n-1), rob(n-2), rob(n-1)} + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(n) + */ + public int rob(int[] nums) { + int[] memo = new int[nums.length]; + // 必须先初始化为-1,有特殊用例 + Arrays.fill(memo, -1); + return tryRob(0, nums, memo); + } + + public int tryRob(int index, int[] nums, int[] memo) { + if (index >= nums.length) { + return 0; + } + if (memo[index] != -1) { + return memo[index]; + } + int max = 0; + for (int i = index; i < nums.length; i++) { + max = Math.max(max, nums[i] + tryRob(i + 2, nums, memo)); + } + memo[index] = max; + return max; + } + + public static void main(String[] args) { + System.out.println(new Solution1().rob(new int[]{2, 1, 1, 2})); + System.out.println(new Solution1().rob(new int[]{2, 7, 9, 3, 1})); + System.out.println(new Solution2().rob(new int[]{1, 2, 3, 1})); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\225\264\346\225\260\346\213\206\345\210\206_343_\344\270\255\347\255\211/Solution1.java" "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\225\264\346\225\260\346\213\206\345\210\206_343_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..f8da2c87 --- /dev/null +++ "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\225\264\346\225\260\346\213\206\345\210\206_343_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,43 @@ +package cn.lastwhisper.leetcode.dynamic.整数拆分_343_中等; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/integer-break/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:树形递归+回溯(28超时) + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + private int max = 0; + + public int integerBreak(int n) { + dfs(n, n, 1); + return max; + } + + private void dfs(int n, int temp, int result) { + if (temp == 0) { + max = Math.max(max, result); + } + // 至少拆分出1,至多拆分出n-1 + // temp-i >= 0(剪枝)、i < n(剪枝) + for (int i = 1; temp - i >= 0 && i < n; i++) { + temp = temp - i; + result = result * i; + dfs(n, temp, result); + temp = temp + i; + result = result / i; + } + } + + public static void main(String[] args) { + System.out.println(new Solution1().integerBreak(2));//1 + System.out.println(new Solution1().integerBreak(3));//2 + //System.out.println(new Solution1().integerBreak(10));//36 + //System.out.println(new Solution1().integerBreak(27));//19683 + //System.out.println(new Solution1().integerBreak(28));//26244 + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\225\264\346\225\260\346\213\206\345\210\206_343_\344\270\255\347\255\211/Solution2.java" "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\225\264\346\225\260\346\213\206\345\210\206_343_\344\270\255\347\255\211/Solution2.java" new file mode 100644 index 00000000..2258f9c5 --- /dev/null +++ "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\225\264\346\225\260\346\213\206\345\210\206_343_\344\270\255\347\255\211/Solution2.java" @@ -0,0 +1,37 @@ +package cn.lastwhisper.leetcode.dynamic.整数拆分_343_中等; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/integer-break/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:树形递归 + * n拆分最大乘积 f(n)=max(1*(n-1),2*(n-2),...(n-1)*1) + * ------------------------------------------------------------------- + * 时间复杂度:O(n^n) + * 空间复杂度:O(n) + */ + public int integerBreak(int n) { + return dfs(n); + } + + private int dfs(int n) { + if (n == 1) { + return 1; + } + int result = -1; + for (int i = 1; i < n; i++) { + result = Math.max(result, Math.max(i * (n - i), i * dfs(n - i))); + } + return result; + } + + public static void main(String[] args) { + System.out.println(new Solution2().integerBreak(2));//1 + System.out.println(new Solution2().integerBreak(3));//2 + System.out.println(new Solution2().integerBreak(10));//36 + System.out.println(new Solution2().integerBreak(27));//19683 + System.out.println(new Solution2().integerBreak(28));//26244 + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\225\264\346\225\260\346\213\206\345\210\206_343_\344\270\255\347\255\211/Solution3.java" "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\225\264\346\225\260\346\213\206\345\210\206_343_\344\270\255\347\255\211/Solution3.java" new file mode 100644 index 00000000..e75e52ac --- /dev/null +++ "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\225\264\346\225\260\346\213\206\345\210\206_343_\344\270\255\347\255\211/Solution3.java" @@ -0,0 +1,43 @@ +package cn.lastwhisper.leetcode.dynamic.整数拆分_343_中等; + +class Solution3 { + /** + * 题目地址:https://leetcode-cn.com/problems/integer-break/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:树形递归——记忆化搜索 + * n拆分最大乘积 f(n)=max(1*(n-1),2*(n-2),...(n-1)*1) + * ------------------------------------------------------------------- + * 时间复杂度:O(n^2) + * 空间复杂度:O(n) + */ + public int integerBreak(int n) { + int[] memo = new int[n + 1]; + return dfs(n, memo); + } + + private int dfs(int n, int[] memo) { + if (n == 1) { + return 1; + } + if (memo[n] != 0) { + return memo[n]; + } + int result = -1; + for (int i = 1; i < n; i++) { + // 分解成i、n-i; + result = Math.max(result, Math.max(i * (n - i), i * dfs(n - i, memo))); + } + memo[n] = result; + return result; + } + + public static void main(String[] args) { + System.out.println(new Solution3().integerBreak(2));//1 + System.out.println(new Solution3().integerBreak(3));//2 + System.out.println(new Solution3().integerBreak(10));//36 + System.out.println(new Solution3().integerBreak(27));//19683 + System.out.println(new Solution3().integerBreak(28));//26244 + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\225\264\346\225\260\346\213\206\345\210\206_343_\344\270\255\347\255\211/Solution4.java" "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\225\264\346\225\260\346\213\206\345\210\206_343_\344\270\255\347\255\211/Solution4.java" new file mode 100644 index 00000000..516a254c --- /dev/null +++ "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\225\264\346\225\260\346\213\206\345\210\206_343_\344\270\255\347\255\211/Solution4.java" @@ -0,0 +1,32 @@ +package cn.lastwhisper.leetcode.dynamic.整数拆分_343_中等; + +class Solution4 { + /** + * 题目地址:https://leetcode-cn.com/problems/integer-break/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:动态规划 + * ------------------------------------------------------------------- + * 时间复杂度:O(n^2) + * 空间复杂度:O(n) + */ + public int integerBreak(int n) { + int[] memo = new int[n + 1]; + memo[1] = 1; + for (int i = 2; i <= n; i++) { + for (int j = 1; j < i; j++) { + memo[i] = Math.max(memo[i], Math.max(j * (i - j), j * memo[i - j])); + } + } + return memo[n]; + } + + public static void main(String[] args) { + System.out.println(new Solution4().integerBreak(2));//1 + System.out.println(new Solution4().integerBreak(3));//2 + System.out.println(new Solution4().integerBreak(10));//36 + System.out.println(new Solution4().integerBreak(27));//19683 + System.out.println(new Solution4().integerBreak(28));//26244 + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260_509_\347\256\200\345\215\225/Solution1.java" "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260_509_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..6099ecaf --- /dev/null +++ "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260_509_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,28 @@ +package cn.lastwhisper.leetcode.dynamic.斐波那契数_509_简单; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/fibonacci-number/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:递归(自顶向下) + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public int fib(int N) { + if (N == 0) { + return 0; + } + if (N == 1) { + return 1; + } + + return fib(N - 1) + fib(N - 2); + } + + public static void main(String[] args) { + System.out.println(new Solution1().fib(3)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260_509_\347\256\200\345\215\225/Solution2.java" "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260_509_\347\256\200\345\215\225/Solution2.java" new file mode 100644 index 00000000..f3f1d81a --- /dev/null +++ "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260_509_\347\256\200\345\215\225/Solution2.java" @@ -0,0 +1,38 @@ +package cn.lastwhisper.leetcode.dynamic.斐波那契数_509_简单; + +import java.util.HashMap; +import java.util.Map; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/fibonacci-number/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:递归+记忆化搜索(自顶向下) + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + private Map map = new HashMap<>(); + + public int fib(int N) { + if (N == 0) { + return 0; + } + if (N == 1) { + return 1; + } + + Integer result = map.getOrDefault(N, -1); + if (result == -1) { + result = fib(N - 1) + fib(N - 2); + map.put(N, result); + } + return result; + } + + public static void main(String[] args) { + System.out.println(new Solution2().fib(10)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260_509_\347\256\200\345\215\225/Solution3.java" "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260_509_\347\256\200\345\215\225/Solution3.java" new file mode 100644 index 00000000..da2b0339 --- /dev/null +++ "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260_509_\347\256\200\345\215\225/Solution3.java" @@ -0,0 +1,32 @@ +package cn.lastwhisper.leetcode.dynamic.斐波那契数_509_简单; + +class Solution3 { + /** + * 题目地址:https://leetcode-cn.com/problems/fibonacci-number/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:动态规划(自底向上) + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public int fib(int N) { + if (N < 2) { + return N; + } + int[] arr = new int[N + 1]; + arr[0] = 0; + arr[1] = 1; + + for (int i = 2; i <= N; i++) { + arr[i] = arr[i - 1] + arr[i - 2]; + } + return arr[N]; + } + + public static void main(String[] args) { + System.out.println(new Solution3().fib(2));//1 + System.out.println(new Solution3().fib(10));//55 + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260_509_\347\256\200\345\215\225/Solution4.java" "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260_509_\347\256\200\345\215\225/Solution4.java" new file mode 100644 index 00000000..ab5d3653 --- /dev/null +++ "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260_509_\347\256\200\345\215\225/Solution4.java" @@ -0,0 +1,31 @@ +package cn.lastwhisper.leetcode.dynamic.斐波那契数_509_简单; + +class Solution4 { + /** + * 题目地址:https://leetcode-cn.com/problems/fibonacci-number/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:动态规划(自底向上)的另一种写法 + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public int fib(int N) { + if (N < 2) return N; + int item1 = 0; + int item2 = 1; + int sum = 0; + for (int i = 2; i <= N; i++) { + sum = item1 + item2; + item1 = item2; + item2 = sum; + } + return sum; + } + + public static void main(String[] args) { + System.out.println(new Solution4().fib(2)); + System.out.println(new Solution4().fib(10)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260_509_\347\256\200\345\215\225/Solution5.java" "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260_509_\347\256\200\345\215\225/Solution5.java" new file mode 100644 index 00000000..a1a6692d --- /dev/null +++ "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260_509_\347\256\200\345\215\225/Solution5.java" @@ -0,0 +1,29 @@ +package cn.lastwhisper.leetcode.dynamic.斐波那契数_509_简单; + +class Solution5 { + /** + * 题目地址:https://leetcode-cn.com/problems/fibonacci-number/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:尾递归(自底向上) + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + + public int fib(int n) { + return fib(n, 0, 1); + } + + // 第n个斐波那契,初始两个值0、1 + private int fib(int n, int rt1, int rt2) { + return n == 0 ? rt1 : fib(n - 1, rt2, rt1 + rt2); + } + + + public static void main(String[] args) { + System.out.println(new Solution5().fib(2)); + System.out.println(new Solution5().fib(10)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\234\200\345\244\247\345\255\220\345\272\217\345\222\214_53_\347\256\200\345\215\225/README.md" "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\234\200\345\244\247\345\255\220\345\272\217\345\222\214_53_\347\256\200\345\215\225/README.md" new file mode 100644 index 00000000..3ab287da --- /dev/null +++ "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\234\200\345\244\247\345\255\220\345\272\217\345\222\214_53_\347\256\200\345\215\225/README.md" @@ -0,0 +1,15 @@ +# 53 + +**思路:**动态规划 + +**状态:**dp[i]表示以num[i]为结尾的连续子序列的最大和 + +**状态转换方程:**dp[i] = Math.max(dp[i - 1] + nums[i], nums[i]) + +**实例:** + +| nums | -2 | 1 | -3 | 4 | -1 | 2 | 1 | -5 | 4 | +| ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | +| dp | -2 | 1 | -2 | 4 | 3 | 5 | `6` | 1 | 5 | + + diff --git "a/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\234\200\345\244\247\345\255\220\345\272\217\345\222\214_53_\347\256\200\345\215\225/Solution1.java" "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\234\200\345\244\247\345\255\220\345\272\217\345\222\214_53_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..6270648f --- /dev/null +++ "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\234\200\345\244\247\345\255\220\345\272\217\345\222\214_53_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,32 @@ +package cn.lastwhisper.leetcode.dynamic.最大子序和_53_简单; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/maximum-subarray/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(1) + */ + public int maxSubArray(int[] nums) { + int res = nums[0]; + int sum = 0; + for (int num : nums) { + if (sum > 0) { + sum += num; + } else { + sum = num; + } + res = Math.max(res, sum); + } + return res; + } + + public static void main(String[] args) { + int[] nums = {-2, 1, -3, 4, -1, 2, 1, -5, 4}; + System.err.println(new Solution1().maxSubArray(nums)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\234\200\345\244\247\345\255\220\345\272\217\345\222\214_53_\347\256\200\345\215\225/Solution2.java" "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\234\200\345\244\247\345\255\220\345\272\217\345\222\214_53_\347\256\200\345\215\225/Solution2.java" new file mode 100644 index 00000000..36c8158e --- /dev/null +++ "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\234\200\345\244\247\345\255\220\345\272\217\345\222\214_53_\347\256\200\345\215\225/Solution2.java" @@ -0,0 +1,33 @@ +package cn.lastwhisper.leetcode.dynamic.最大子序和_53_简单; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/maximum-subarray/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:动态规划 + * 状态:dp[i]表示以num[i]为结尾的连续子序列的最大和 + * 状态转换方程:dp[i] = Math.max(dp[i - 1] + nums[i], nums[i]) + * + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(n) + */ + public int maxSubArray(int[] nums) { + // 初始值 + int res = nums[0]; + int[] dp = new int[nums.length]; + dp[0] = nums[0]; + for (int i = 1; i < nums.length; i++) { + dp[i] = Math.max(dp[i - 1] + nums[i], nums[i]); + res = Math.max(res, dp[i]); + } + return res; + } + + public static void main(String[] args) { + int[] nums = {-2, 1, -3, 4, -1, 2, 1, -5, 4}; + System.err.println(new Solution2().maxSubArray(nums)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\234\200\345\244\247\345\255\220\345\272\217\345\222\214_53_\347\256\200\345\215\225/Solution3.java" "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\234\200\345\244\247\345\255\220\345\272\217\345\222\214_53_\347\256\200\345\215\225/Solution3.java" new file mode 100644 index 00000000..e18c979f --- /dev/null +++ "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\234\200\345\244\247\345\255\220\345\272\217\345\222\214_53_\347\256\200\345\215\225/Solution3.java" @@ -0,0 +1,34 @@ +package cn.lastwhisper.leetcode.dynamic.最大子序和_53_简单; + +class Solution3 { + /** + * 题目地址:https://leetcode-cn.com/problems/maximum-subarray/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:动态规划 + * 状态:dp[i]表示以num[i]为结尾的连续子序列的最大和 + * 状态转换方程:dp[i] = Math.max(dp[i - 1] + nums[i], nums[i]) + * + * 优化空间:只需要两个变量就可以完成动态规划 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(1) + */ + public int maxSubArray(int[] nums) { + // 初始值 + int res = nums[0]; + int prev = nums[0], current; + for (int i = 1; i < nums.length; i++) { + current = Math.max(prev + nums[i], nums[i]); + res = Math.max(res, current); + prev = current; + } + return res; + } + + public static void main(String[] args) { + int[] nums = {-2, 1, -3, 4, -1, 2, 1, -5, 4}; + System.err.println(new Solution3().maxSubArray(nums)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214_64_\344\270\255\347\255\211/Solution1.java" "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214_64_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..238e1a17 --- /dev/null +++ "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214_64_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,66 @@ +package cn.lastwhisper.leetcode.dynamic.最小路径和_64_中等; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/minimum-path-sum/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:动态规划——自顶向下 + * 1、状态定义:dp[i][j]表示包含第i行第j列元素的最小路径和 + * 2、状态分析 + * 初始: + * dp[0][0]=grid[0][0] + * 常规: + * grid[i][j]一定会经过grid[i][j-1]或者grid[i-1][j] + * 所以状态dp[i][j]一定等于dp[i][j-1]或者dp[i-1][j]的最小值+grid[i][j] + * 状态转换方程: + * dp[i][j]=min(dp[i][j-1],dp[i-1][j])+grid[i][j] + * 特殊: + * grid[i][0]没有左边 只能从上边grid[i-1][0]经过 + * grid[0][j]没有上边 只能从左边grid[0][j-1]经过 + * 状态转换方程: + * dp[i][0]=dp[i-1][0]+grid[i][j] + * dp[0][j]=dp[0][j-1]+grid[i][j] + * ------------------------------------------------------------------- + * 时间复杂度:O(n^2) + * 空间复杂度:O(n^2) + */ + public int minPathSum(int[][] grid) { + // 特判 + if (grid == null || grid.length == 0) { + return 0; + } + int row = grid.length; + int column = grid[0].length; + + int[][] dp = new int[row][column]; + for (int i = 0; i < row; i++) { + for (int j = 0; j < column; j++) { + if (i == 0 && j == 0) { + // 起点 + dp[0][0] = grid[0][0]; + } else if (i == 0) { + // 从左边来 + dp[i][j] = dp[i][j - 1] + grid[i][j]; + } else if (j == 0) { + // 从上面来 + dp[i][j] = dp[i - 1][j] + grid[i][j]; + } else { + dp[i][j] = Math.min(dp[i][j - 1], dp[i - 1][j]) + grid[i][j]; + } + } + } + + return dp[row - 1][column - 1]; + } + + public static void main(String[] args) { + int[][] grid = { + {1, 3, 1}, + {1, 5, 1}, + {4, 2, 1} + }; + System.out.println(new Solution1().minPathSum(grid)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214_64_\344\270\255\347\255\211/Solution2.java" "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214_64_\344\270\255\347\255\211/Solution2.java" new file mode 100644 index 00000000..eb26a680 --- /dev/null +++ "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214_64_\344\270\255\347\255\211/Solution2.java" @@ -0,0 +1,53 @@ +package cn.lastwhisper.leetcode.dynamic.最小路径和_64_中等; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/minimum-path-sum/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:动态规划——基于思路二 + * 空间优化: + * 只需要左边和上边的值保存即可,一维数组dp[j]存储上边的值, + * dp[j-1]存储左边的值 + * ------------------------------------------------------------------- + * 时间复杂度:O(n^2) + * 空间复杂度:O(n) + */ + public int minPathSum(int[][] grid) { + // 特判 + if (grid == null || grid.length == 0) { + return 0; + } + int row = grid.length; + int column = grid[0].length; + + int[] dp = new int[column]; + for (int i = 0; i < row; i++) { + for (int j = 0; j < column; j++) { + if (i == 0 && j == 0) { + // 起点 + dp[0] = grid[0][0]; + } else if (i == 0) { + // 从左边来 + dp[j] = dp[j - 1] + grid[i][j]; + } else if (j == 0) { + // 从上面来 + dp[j] = dp[j] + grid[i][j]; + } else { + dp[j] = Math.min(dp[j - 1], dp[j]) + grid[i][j]; + } + } + } + return dp[column - 1]; + } + + public static void main(String[] args) { + int[][] grid = { + {1, 3, 1}, + {1, 5, 1}, + {4, 2, 1} + }; + System.out.println(new Solution2().minPathSum(grid)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214_64_\344\270\255\347\255\211/Solution3.java" "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214_64_\344\270\255\347\255\211/Solution3.java" new file mode 100644 index 00000000..fd10d4d6 --- /dev/null +++ "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214_64_\344\270\255\347\255\211/Solution3.java" @@ -0,0 +1,63 @@ +package cn.lastwhisper.leetcode.dynamic.最小路径和_64_中等; + +class Solution3 { + /** + * 题目地址:https://leetcode-cn.com/problems/minimum-path-sum/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:动态规划——自底向上 + * 1、状态定义:dp[i][j]表示包含第i行第j列元素的最小路径和 + * 2、状态分析 + * 初始: + * dp[m][n]=grid[m][n] + * 常规: + * grid[i][j]一定会经过grid[i][j+1]或者grid[i+1][j] + * 所以状态dp[i][j]一定等于dp[i][j+1]或者dp[i+1][j]的最小值+grid[i][j] + * 状态转换方程: + * dp[i][j]=min(dp[i][j+1],dp[i+1][j])+grid[i][j] + * 特殊: + * 矩阵m*n + * grid[i][n]没有右边 只能从下边grid[i+1][n]经过 + * grid[m][j]没有下边 只能从右边grid[m][j+1]经过 + * 状态转换方程: + * dp[i][n]=dp[i+1][n]+grid[i][j] + * dp[m][j]=dp[m][j+1]+grid[i][j] + * ------------------------------------------------------------------- + * 时间复杂度:O(n^2) + * 空间复杂度:O(n^2) + */ + public int minPathSum(int[][] grid) { + // 特判 + if (grid == null || grid.length == 0) { + return 0; + } + int row = grid.length; + int column = grid[0].length; + + int[][] dp = new int[row][column]; + for (int i = row - 1; i >= 0; i--) { + for (int j = column - 1; j >= 0; j--) { + if (i == row - 1 && j == column - 1) { + dp[i][j] = grid[i][j]; + } else if (j == column - 1) { + dp[i][j] = dp[i + 1][j] + grid[i][j]; + } else if (i == row - 1) { + dp[i][j] = dp[i][j + 1] + grid[i][j]; + } else { + dp[i][j] = Math.min(dp[i + 1][j], dp[i][j + 1]) + grid[i][j]; + } + } + } + return dp[0][0]; + } + + public static void main(String[] args) { + int[][] grid = { + {1, 3, 1}, + {1, 5, 1}, + {4, 2, 1} + }; + System.out.println(new Solution3().minPathSum(grid)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214_64_\344\270\255\347\255\211/Solution4.java" "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214_64_\344\270\255\347\255\211/Solution4.java" new file mode 100644 index 00000000..4f29098e --- /dev/null +++ "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214_64_\344\270\255\347\255\211/Solution4.java" @@ -0,0 +1,50 @@ +package cn.lastwhisper.leetcode.dynamic.最小路径和_64_中等; + +class Solution4 { + /** + * 题目地址:https://leetcode-cn.com/problems/minimum-path-sum/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:动态规划——基于思路三 + * 空间优化: + * 只需要左边和上边的值保存即可,一维数组dp[j]存储下边的值, + * dp[j+1]存储右边的值 + * ------------------------------------------------------------------- + * 时间复杂度:O(n^2) + * 空间复杂度:O(n^2) + */ + public int minPathSum(int[][] grid) { + // 特判 + if (grid == null || grid.length == 0) { + return 0; + } + int row = grid.length; + int column = grid[0].length; + + int[] dp = new int[column ]; + for (int i = row - 1; i >= 0; i--) { + for (int j = column - 1; j >= 0; j--) { + if (i == row - 1 && j == column - 1) { + dp[j] = grid[i][j]; + } else if (j == column - 1) { + dp[j] = dp[j] + grid[i][j]; + } else if (i == row - 1) { + dp[j] = dp[j + 1] + grid[i][j]; + } else { + dp[j] = Math.min(dp[j], dp[j + 1]) + grid[i][j]; + } + } + } + return dp[0]; + } + + public static void main(String[] args) { + int[][] grid = { + {1, 3, 1}, + {1, 5, 1}, + {4, 2, 1} + }; + System.out.println(new Solution4().minPathSum(grid)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214_64_\344\270\255\347\255\211/recursion/Solution1.java" "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214_64_\344\270\255\347\255\211/recursion/Solution1.java" new file mode 100644 index 00000000..5b1fab4e --- /dev/null +++ "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214_64_\344\270\255\347\255\211/recursion/Solution1.java" @@ -0,0 +1,55 @@ +package cn.lastwhisper.leetcode.dynamic.最小路径和_64_中等.recursion; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/minimum-path-sum/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:递归 + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + private int min=Integer.MAX_VALUE, m, n; + private int[][] dir = {{0, 1}, {1, 0}}; + + public int minPathSum(int[][] grid) { + m = grid.length; + n = grid[0].length; + findMin(grid, 0, 0, grid[0][0]); + return min; + } + + /** + * 此种递归无法缓存中间值重复使用 + */ + private void findMin(int[][] grid, int startX, int startY, int result) { + // 终点 + if (m - 1 == startX && n - 1 == startY) { + min = Math.min(min, result); + return; + } + for (int i = 0; i < dir.length; i++) { + int newX = startX + dir[i][0]; + int newY = startY + dir[i][1]; + // 防止不合法坐标 + if (isValid(newX, newY)) { + findMin(grid, newX, newY, grid[newX][newY] + result); + } + } + } + + private boolean isValid(int x, int y) { + return x < m && y < n; + } + + public static void main(String[] args) { + int[][] grid = { + {1, 3, 1}, + {1, 5, 1}, + {4, 2, 1} + }; + System.out.println(new Solution1().minPathSum(grid)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214_64_\344\270\255\347\255\211/recursion/Solution2.java" "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214_64_\344\270\255\347\255\211/recursion/Solution2.java" new file mode 100644 index 00000000..4650b63c --- /dev/null +++ "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214_64_\344\270\255\347\255\211/recursion/Solution2.java" @@ -0,0 +1,50 @@ +package cn.lastwhisper.leetcode.dynamic.最小路径和_64_中等.recursion; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/minimum-path-sum/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:递归 + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + private int m, n; + private int[][] dir = {{0, 1}, {1, 0}}; + + public int minPathSum(int[][] grid) { + m = grid.length; + n = grid[0].length; + return findMin(grid, 0, 0); + } + + private int findMin(int[][] grid, int startX, int startY) { + if (m - 1 == startX && n - 1 == startY) { + return grid[startX][startY]; + } + int result = Integer.MAX_VALUE; + for (int i = 0; i < dir.length; i++) { + int newX = startX + dir[i][0]; + int newY = startY + dir[i][1]; + if (isValid(newX, newY)) { + result = Math.min(result, grid[startX][startY] + findMin(grid, newX, newY)); + } + } + return result; + } + + private boolean isValid(int x, int y) { + return x < m && y < n; + } + + public static void main(String[] args) { + int[][] grid = { + {1, 3, 1}, + {1, 5, 1}, + {4, 2, 1} + }; + System.out.println(new Solution2().minPathSum(grid)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214_64_\344\270\255\347\255\211/recursion/Solution3.java" "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214_64_\344\270\255\347\255\211/recursion/Solution3.java" new file mode 100644 index 00000000..859df4d4 --- /dev/null +++ "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214_64_\344\270\255\347\255\211/recursion/Solution3.java" @@ -0,0 +1,16 @@ +package cn.lastwhisper.leetcode.dynamic.最小路径和_64_中等.recursion; + +public class Solution3 { + public int calculate(int[][] grid, int i, int j) { + // 不合法坐标 + if (i == grid.length || j == grid[0].length) return Integer.MAX_VALUE; + // 终点 + if (i == grid.length - 1 && j == grid[0].length - 1) return grid[i][j]; + return grid[i][j] + Math.min(calculate(grid, i + 1, j), calculate(grid, i, j + 1)); + } + + public int minPathSum(int[][] grid) { + return calculate(grid, 0, 0); + } + +} \ No newline at end of file diff --git "a/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214_64_\344\270\255\347\255\211/recursion/Solution4.java" "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214_64_\344\270\255\347\255\211/recursion/Solution4.java" new file mode 100644 index 00000000..42cd5d42 --- /dev/null +++ "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214_64_\344\270\255\347\255\211/recursion/Solution4.java" @@ -0,0 +1,56 @@ +package cn.lastwhisper.leetcode.dynamic.最小路径和_64_中等.recursion; + +class Solution4 { + /** + * 题目地址:https://leetcode-cn.com/problems/minimum-path-sum/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:递归+记忆化搜索 + * ------------------------------------------------------------------- + * 时间复杂度:O(2^(m+n))。每次移动最多可以有两种选择。 + * 空间复杂度:O(m+n)。递归的深度是 m+n。 + */ + private int m, n; + private int[][] dir = {{0, 1}, {1, 0}}; + + public int minPathSum(int[][] grid) { + m = grid.length; + n = grid[0].length; + int[][] memo = new int[m][n]; + return findMin(grid, 0, 0, memo); + } + + private int findMin(int[][] grid, int startX, int startY, int[][] memo) { + // 终点 + if (m - 1 == startX && n - 1 == startY) { + return grid[startX][startY]; + } + if (memo[startX][startY] != 0) { + return memo[startX][startY]; + } + int result = Integer.MAX_VALUE; + for (int i = 0; i < dir.length; i++) { + int newX = startX + dir[i][0]; + int newY = startY + dir[i][1]; + if (isValid(newX, newY)) { + result = Math.min(result, grid[startX][startY] + findMin(grid, newX, newY, memo)); + } + } + memo[startX][startY] = result; + return result; + } + + private boolean isValid(int x, int y) { + return x < m && y < n; + } + + public static void main(String[] args) { + int[][] grid = { + {1, 3, 1}, + {1, 5, 1}, + {4, 2, 1} + }; + System.out.println(new Solution4().minPathSum(grid)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\234\200\351\225\277\344\270\212\345\215\207\345\255\220\345\272\217\345\210\227_300_\344\270\255\347\255\211/Solution1.java" "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\234\200\351\225\277\344\270\212\345\215\207\345\255\220\345\272\217\345\210\227_300_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..58130d3c --- /dev/null +++ "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\234\200\351\225\277\344\270\212\345\215\207\345\255\220\345\272\217\345\210\227_300_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,49 @@ +package cn.lastwhisper.leetcode.dynamic.最长上升子序列_300_中等; + +import java.util.Arrays; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/longest-increasing-subsequence/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:动态规划 + * 状态定义:dp[i]表示以num[i]为结尾的上升子序列 + * 转换方程: + * j∈[0,i] + * dp[i]=max(dp[j]+1,dp[i]) + * ------------------------------------------------------------------- + * 时间复杂度:O(n^2) + * 空间复杂度:O(n) + */ + public int lengthOfLIS(int[] nums) { + if (nums.length == 0) { + return 0; + } + int res = 1; + int[] dp = new int[nums.length]; + Arrays.fill(dp, 1); + // j∈[0,i) + for (int i = 1; i < nums.length; i++) { + // num[i]是否能做num[0,i)中某个数的结尾 + for (int j = 0; j < i; j++) { + if (nums[i] > nums[j]) { + // num[i]能以num[j]为结尾,更新dp[i] + // 为什么要Math.max(dp[j] + 1, dp[i]),而不是直接dp[j] + 1? + // {1, 3, 6, 7, 9, 4, 10, 5, 6},i=6时,最长子序列是1,3,6,7,9,10,而不是1,3,4,10 + dp[i] = Math.max(dp[j] + 1, dp[i]); + } + } + // 记录最大系列长度 + res = Math.max(res, dp[i]); + } + return res; + } + + public static void main(String[] args) { + //int[] nums = {-2, -1}; + int[] nums = {10, 9, 2, 5, 3, 7, 101, 18}; + System.err.println(new Solution1().lengthOfLIS(nums)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\234\200\351\225\277\345\205\254\345\205\261\345\255\220\345\272\217\345\210\227_1143_\344\270\255\347\255\211/Solution1.java" "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\234\200\351\225\277\345\205\254\345\205\261\345\255\220\345\272\217\345\210\227_1143_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..57e78b76 --- /dev/null +++ "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\234\200\351\225\277\345\205\254\345\205\261\345\255\220\345\272\217\345\210\227_1143_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,39 @@ +package cn.lastwhisper.leetcode.dynamic.最长公共子序列_1143_中等; + +import org.junit.Assert; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/longest-common-subsequence/ + * 题号:1143/最长公共子序列(LCS) + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:暴力搜索 + * ------------------------------------------------------------------- + * 时间复杂度:O(n^2) + * 空间复杂度:O(n) + */ + public int longestCommonSubsequence(String text1, String text2) { + return dfs(text1, text2, text1.length() - 1, text2.length() - 1); + } + + public int dfs(String text1, String text2, int i, int j) { + if (i == -1 || j == -1) { + return 0; + } + if (text1.charAt(i) == text2.charAt(j)) { + // 这边找到一个 lcs 的元素,继续往前找 + return dfs(text1, text2, i - 1, j - 1) + 1; + } else { + // 谁能让 lcs 最长,就听谁的 + return Math.max(dfs(text1, text2, i - 1, j), dfs(text1, text2, i, j - 1)); + } + } + + public static void main(String[] args) { + Assert.assertEquals(3, new Solution1().longestCommonSubsequence("abcde", "ace")); + Assert.assertEquals(3, new Solution1().longestCommonSubsequence("abc", "abc")); + Assert.assertEquals(0, new Solution1().longestCommonSubsequence("abc", "def")); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\234\200\351\225\277\345\205\254\345\205\261\345\255\220\345\272\217\345\210\227_1143_\344\270\255\347\255\211/Solution2.java" "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\234\200\351\225\277\345\205\254\345\205\261\345\255\220\345\272\217\345\210\227_1143_\344\270\255\347\255\211/Solution2.java" new file mode 100644 index 00000000..2467ad54 --- /dev/null +++ "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\346\234\200\351\225\277\345\205\254\345\205\261\345\255\220\345\272\217\345\210\227_1143_\344\270\255\347\255\211/Solution2.java" @@ -0,0 +1,49 @@ +package cn.lastwhisper.leetcode.dynamic.最长公共子序列_1143_中等; + +import org.junit.Assert; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/longest-common-subsequence/ + * 题号:1143/最长公共子序列(LCS) + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:动态规划(自顶向下) + * 一、状态定义:dp[i][j]表示,对于 s1[1..i] 和 s2[1..j],它们的 LCS 长度是 dp[i][j]。 + * 二、初始状态: + * 三、转换方程: + * + * + * https://leetcode-cn.com/problems/longest-common-subsequence/solution/dong-tai-gui-hua-zhi-zui-chang-gong-gong-zi-xu-lie/ + * https://www.jianshu.com/p/6451410be00a + * ------------------------------------------------------------------- + * 时间复杂度:O(n^2) + * 空间复杂度:O(n) + */ + public int longestCommonSubsequence(String text1, String text2) { + int m = text1.length() + 1, n = text2.length() + 1; + int[][] dp = new int[m][n]; + + for (int i = 1; i < m; i++) { + for (int j = 1; j < n; j++) { + if (text1.charAt(i - 1) == text2.charAt(j - 1)) { + // 这边找到一个 lcs 的元素,继续往前找 + dp[i][j] = dp[i - 1][j - 1] + 1; + } else { + // 谁能让 lcs 最长,就听谁的 + dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]); + } + } + } + + return dp[m - 1][n - 1]; + } + + public static void main(String[] args) { + Assert.assertEquals(4, new Solution1().longestCommonSubsequence("google", "elgoog")); + //Assert.assertEquals(3, new Solution3().longestCommonSubsequence("abcde", "ace")); + //Assert.assertEquals(3, new Solution3().longestCommonSubsequence("abc", "abc")); + //Assert.assertEquals(0, new Solution3().longestCommonSubsequence("abc", "def")); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\347\210\254\346\245\274\346\242\257_70_\347\256\200\345\215\225/Solution1.java" "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\347\210\254\346\245\274\346\242\257_70_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..999e9afe --- /dev/null +++ "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\347\210\254\346\245\274\346\242\257_70_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,26 @@ +package cn.lastwhisper.leetcode.dynamic.爬楼梯_70_简单; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/climbing-stairs/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:递归(自顶向下) + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public int climbStairs(int n) { + if (n == 0 || n == 1) { + return 1; + } + return climbStairs(n - 1) + climbStairs(n - 2); + } + + public static void main(String[] args) { + System.out.println(new Solution1().climbStairs(2)); + System.out.println(new Solution1().climbStairs(3)); + System.out.println(new Solution1().climbStairs(4)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\347\210\254\346\245\274\346\242\257_70_\347\256\200\345\215\225/Solution2.java" "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\347\210\254\346\245\274\346\242\257_70_\347\256\200\345\215\225/Solution2.java" new file mode 100644 index 00000000..04ffc448 --- /dev/null +++ "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\347\210\254\346\245\274\346\242\257_70_\347\256\200\345\215\225/Solution2.java" @@ -0,0 +1,37 @@ +package cn.lastwhisper.leetcode.dynamic.爬楼梯_70_简单; + +import java.util.HashMap; +import java.util.Map; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/climbing-stairs/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:递归(自顶向下)+记忆化搜索 + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + private Map map = new HashMap<>(); + + public int climbStairs(int n) { + if (n == 0 || n == 1) { + return 1; + } + + Integer result = map.getOrDefault(n, -1); + if (result == -1) { + result = climbStairs(n - 1) + climbStairs(n - 2); + map.put(n, result); + } + return result; + } + + public static void main(String[] args) { + System.out.println(new Solution2().climbStairs(2));//2 + System.out.println(new Solution2().climbStairs(3));//3 + System.out.println(new Solution2().climbStairs(4));//5 + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\347\210\254\346\245\274\346\242\257_70_\347\256\200\345\215\225/Solution3.java" "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\347\210\254\346\245\274\346\242\257_70_\347\256\200\345\215\225/Solution3.java" new file mode 100644 index 00000000..74359179 --- /dev/null +++ "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\347\210\254\346\245\274\346\242\257_70_\347\256\200\345\215\225/Solution3.java" @@ -0,0 +1,28 @@ +package cn.lastwhisper.leetcode.dynamic.爬楼梯_70_简单; + +class Solution3 { + /** + * 题目地址:https://leetcode-cn.com/problems/climbing-stairs/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:尾递归(自底向上) + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + + public int climbStairs(int n) { + return climbStairs(n,0,1); + } + + private int climbStairs(int n, int rt1, int rt2) { + return n == 0 ? rt2 : climbStairs(n - 1, rt2, rt1 + rt2); + } + + public static void main(String[] args) { + System.out.println(new Solution3().climbStairs(2));//2 + System.out.println(new Solution3().climbStairs(3));//3 + System.out.println(new Solution3().climbStairs(4));//5 + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\347\210\254\346\245\274\346\242\257_70_\347\256\200\345\215\225/Solution4.java" "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\347\210\254\346\245\274\346\242\257_70_\347\256\200\345\215\225/Solution4.java" new file mode 100644 index 00000000..894e4e07 --- /dev/null +++ "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\347\210\254\346\245\274\346\242\257_70_\347\256\200\345\215\225/Solution4.java" @@ -0,0 +1,35 @@ +package cn.lastwhisper.leetcode.dynamic.爬楼梯_70_简单; + +class Solution4 { + /** + * 题目地址:https://leetcode-cn.com/problems/climbing-stairs/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:动态规划(自底向上) + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + + public int climbStairs(int n) { + if (n < 2) { + return n; + } + int[] arr = new int[n + 1]; + arr[0] = 1; + arr[1] = 1; + + for (int i = 2; i <= n; i++) { + arr[i] = arr[i - 1] + arr[i - 2]; + } + return arr[n]; + } + + + public static void main(String[] args) { + System.out.println(new Solution4().climbStairs(2));//2 + System.out.println(new Solution4().climbStairs(3));//3 + System.out.println(new Solution4().climbStairs(4));//5 + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\347\210\254\346\245\274\346\242\257_70_\347\256\200\345\215\225/Solution5.java" "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\347\210\254\346\245\274\346\242\257_70_\347\256\200\345\215\225/Solution5.java" new file mode 100644 index 00000000..432d9bf2 --- /dev/null +++ "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\347\210\254\346\245\274\346\242\257_70_\347\256\200\345\215\225/Solution5.java" @@ -0,0 +1,33 @@ +package cn.lastwhisper.leetcode.dynamic.爬楼梯_70_简单; + +class Solution5 { + /** + * 题目地址:https://leetcode-cn.com/problems/climbing-stairs/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:动态规划(自底向上)的另一种写法 + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public int climbStairs(int n) { + if (n < 2) return n; + int item1 = 1; + int item2 = 1; + int sum = 0; + for (int i = 2; i <= n; i++) { + sum = item1 + item2; + item1 = item2; + item2 = sum; + } + return sum; + } + + + public static void main(String[] args) { + System.out.println(new Solution5().climbStairs(2));//2 + System.out.println(new Solution5().climbStairs(3));//3 + System.out.println(new Solution5().climbStairs(4));//5 + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\350\247\243\347\240\201\346\226\271\346\263\225_91_\344\270\255\347\255\211/Solution1.java" "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\350\247\243\347\240\201\346\226\271\346\263\225_91_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..13b0fad0 --- /dev/null +++ "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\350\247\243\347\240\201\346\226\271\346\263\225_91_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,33 @@ +package cn.lastwhisper.leetcode.dynamic.解码方法_91_中等; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/decode-ways/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(1) + */ + public int numDecodings(String s) { + if (s.charAt(0) == '0') return 0; + int pre = 1, curr = 1;//dp[-1]= dp[0]= 1 + for (int i = 1; i < s.length(); i++) { + int tmp = curr; + if (s.charAt(i) == '0') + if (s.charAt(i - 1) == '1' || s.charAt(i - 1) == '2') curr = pre; + else return 0; + else if (s.charAt(i - 1) == '1' || (s.charAt(i - 1) == '2' && s.charAt(i) >= '1' && s.charAt(i) <= '6')) + curr = curr + pre; + pre = tmp; + } + return curr; + } + + public static void main(String[] args) { + System.out.println(new Solution1().numDecodings("12"));//"AB"(1 2)或者 "L"(12) + System.out.println(new Solution1().numDecodings("226"));// "BZ" (2 26), "VF" (22 6), 或者 "BBF" (2 2 6) + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\351\233\266\351\222\261\345\205\221\346\215\242_322_\344\270\255\347\255\211/Solution1.java" "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\351\233\266\351\222\261\345\205\221\346\215\242_322_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..e2508b5e --- /dev/null +++ "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\351\233\266\351\222\261\345\205\221\346\215\242_322_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,45 @@ +package cn.lastwhisper.leetcode.dynamic.零钱兑换_322_中等; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/coin-change/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:递归dfs-暴力搜索 + * 先找到子问题 + * ------------------------------------------------------------------- + * 时间复杂度:O(n^k*k),n^k个结点 + * 空间复杂度:O(n^k) + */ + public int coinChange(int[] coins, int amount) { + return tryCoinChange(coins, amount); + } + + public int tryCoinChange(int[] coins, int amount) { + if (amount == 0) { + return 0; + } + if (amount < 0) { + return -1; + } + int freq = Integer.MAX_VALUE; + for (int coin : coins) { + int subFreq = tryCoinChange(coins, amount - coin); + if (subFreq == -1) { + continue; + } + freq = Math.min(freq, 1 + subFreq); + } + + return freq == Integer.MAX_VALUE ? -1 : freq; + } + + public static void main(String[] args) { + //int[] coins = {1, 2, 5}; + //int amount = 11; + int[] coins = {2}; + int amount = 3; + System.err.println(new Solution1().coinChange(coins, amount)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\351\233\266\351\222\261\345\205\221\346\215\242_322_\344\270\255\347\255\211/Solution2.java" "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\351\233\266\351\222\261\345\205\221\346\215\242_322_\344\270\255\347\255\211/Solution2.java" new file mode 100644 index 00000000..71b89a41 --- /dev/null +++ "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\351\233\266\351\222\261\345\205\221\346\215\242_322_\344\270\255\347\255\211/Solution2.java" @@ -0,0 +1,51 @@ +package cn.lastwhisper.leetcode.dynamic.零钱兑换_322_中等; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/coin-change/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:递归dfs-暴力搜索-备忘录 + * 先找到子问题 + * ------------------------------------------------------------------- + * 时间复杂度:O(n^k*k),n^k个结点 + * 空间复杂度:O() + */ + public int coinChange(int[] coins, int amount) { + int[] memo = new int[amount + 1]; + return tryCoinChange(coins, amount, memo); + } + + public int tryCoinChange(int[] coins, int amount, int[] memo) { + if (amount == 0) { + return 0; + } + if (amount < 0) { + return -1; + } + if (memo[amount] != 0) { + return memo[amount]; + } + int freq = Integer.MAX_VALUE; + for (int coin : coins) { + int subFreq = tryCoinChange(coins, amount - coin, memo); + // 子问题无解,不更新freq + if (subFreq == -1) { + continue; + } + freq = Math.min(freq, 1 + subFreq); + } + // 所有子问题都无解,返回-1 + memo[amount] = freq == Integer.MAX_VALUE ? -1 : freq; + return memo[amount]; + } + + public static void main(String[] args) { + //int[] coins = {1, 2, 5}; + //int amount = 11; + int[] coins = {2}; + int amount = 3; + System.err.println(new Solution2().coinChange(coins, amount)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\351\233\266\351\222\261\345\205\221\346\215\242_322_\344\270\255\347\255\211/Solution3.java" "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\351\233\266\351\222\261\345\205\221\346\215\242_322_\344\270\255\347\255\211/Solution3.java" new file mode 100644 index 00000000..7c669b3f --- /dev/null +++ "b/algorithms/leetcode/dynamic/src/main/java/cn/lastwhisper/leetcode/dynamic/\351\233\266\351\222\261\345\205\221\346\215\242_322_\344\270\255\347\255\211/Solution3.java" @@ -0,0 +1,39 @@ +package cn.lastwhisper.leetcode.dynamic.零钱兑换_322_中等; + +import java.util.Arrays; + +class Solution3 { + /** + * 题目地址:https://leetcode-cn.com/problems/coin-change/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:动态规划 + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public int coinChange(int[] coins, int amount) { + int max = amount + 1; + // 确定状态 + int[] dp = new int[amount + 1]; + Arrays.fill(dp, max); + dp[0] = 0; + for (int i = 1; i <= amount; i++) { + for (int coin : coins) { + if (i >= coin) { + dp[i] = Math.min(dp[i], dp[i - coin] + 1); + } + } + } + return dp[amount] > amount ? -1 : dp[amount]; + } + + public static void main(String[] args) { + int[] coins = {1, 2, 5}; + int amount = 11; + //int[] coins = {2}; + //int amount = 3; + System.err.println(new Solution3().coinChange(coins, amount)); + } +} \ No newline at end of file diff --git a/algorithms/leetcode/greedy/README.md b/algorithms/leetcode/greedy/README.md new file mode 100644 index 00000000..e69de29b diff --git "a/algorithms/leetcode/greedy/src/main/java/cn/lastwhisper/leetcode/greedy/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272II_122_\347\256\200\345\215\225/Solution1.java" "b/algorithms/leetcode/greedy/src/main/java/cn/lastwhisper/leetcode/greedy/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272II_122_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..b20adb00 --- /dev/null +++ "b/algorithms/leetcode/greedy/src/main/java/cn/lastwhisper/leetcode/greedy/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272II_122_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,59 @@ +package cn.lastwhisper.leetcode.greedy.买卖股票的最佳时机II_122_简单; + +class Solution1 { + + /** + * 题目地址:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:暴力搜索 + * 1、买入之后:1.不操作 2.卖出 + * 2、不操作之后:1.不操作 2.买入 + * 3、卖出之后:1.不操作 2.买入 + * 4、初始:1.不操作 2.买入 + * + * 共有两种状态: + * 1 持股 + * 2、3、4 未持股 + * + * ------------------------------------------------------------------- + * 时间复杂度:O(2^n) + * 空间复杂度:O(1) + */ + public int maxProfit(int[] prices) { + tryProfit(prices, 0, false, 0); + return profit; + } + + int profit = 0; + + /** + * @param prices 股价数组 + * @param index 第几天 + * @param status true持股,false不持股 + * @param profit 当前收益 + */ + private void tryProfit(int[] prices, int index, boolean status, int profit) { + if (index == prices.length ) { + this.profit = Math.max(this.profit, profit); + return; + } + // 不卖也不买 + tryProfit(prices, index + 1, status, profit); + if (status) { + // 尝试卖出 + tryProfit(prices, index + 1, false, profit + prices[index]); + } else { + // 尝试买入 + tryProfit(prices, index + 1, true, profit - prices[index]); + } + } + + + public static void main(String[] args) { + //int[] prices = {7, 1, 5, 3, 6, 4}; + int[] prices = {1, 2, 3, 4, 5}; + System.err.println(new Solution1().maxProfit(prices)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/greedy/src/main/java/cn/lastwhisper/leetcode/greedy/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272II_122_\347\256\200\345\215\225/Solution2.java" "b/algorithms/leetcode/greedy/src/main/java/cn/lastwhisper/leetcode/greedy/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272II_122_\347\256\200\345\215\225/Solution2.java" new file mode 100644 index 00000000..c5097fde --- /dev/null +++ "b/algorithms/leetcode/greedy/src/main/java/cn/lastwhisper/leetcode/greedy/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272II_122_\347\256\200\345\215\225/Solution2.java" @@ -0,0 +1,56 @@ +package cn.lastwhisper.leetcode.greedy.买卖股票的最佳时机II_122_简单; + +class Solution2 { + + /** + * 题目地址:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:暴力搜索 + * 1、买入之后:1.不操作 2.卖出 + * 2、不操作之后:1.不操作 2.买入 + * 3、卖出之后:1.不操作 2.买入 + * 4、初始:1.不操作 2.买入 + * + * 共有两种状态: + * 1 持股 + * 2、3、4 未持股 + * + * ------------------------------------------------------------------- + * 时间复杂度:O(2^n) + * 空间复杂度:O(1) + */ + public int maxProfit(int[] prices) { + return tryProfit(prices, 0, false, 0); + } + + /** + * @param prices 股价数组 + * @param index 第几天 + * @param status true持股,false不持股 + * @param profit 当前收益 + */ + private int tryProfit(int[] prices, int index, boolean status, int profit) { + if (index == prices.length) { + return profit; + } + // 不操作 + int currentMax = tryProfit(prices, index + 1, status, profit); + if (status) { + // 尝试卖出 + currentMax = Math.max(currentMax, tryProfit(prices, index + 1, false, profit + prices[index])); + } else { + // 尝试买入 + currentMax = Math.max(currentMax, tryProfit(prices, index + 1, true, profit - prices[index])); + } + return currentMax; + } + + + public static void main(String[] args) { + //int[] prices = {7, 1, 5, 3, 6, 4}; + int[] prices = {1, 2, 3, 4, 5}; + System.err.println(new Solution2().maxProfit(prices)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/greedy/src/main/java/cn/lastwhisper/leetcode/greedy/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272II_122_\347\256\200\345\215\225/Solution3.java" "b/algorithms/leetcode/greedy/src/main/java/cn/lastwhisper/leetcode/greedy/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272II_122_\347\256\200\345\215\225/Solution3.java" new file mode 100644 index 00000000..3d42e75f --- /dev/null +++ "b/algorithms/leetcode/greedy/src/main/java/cn/lastwhisper/leetcode/greedy/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272II_122_\347\256\200\345\215\225/Solution3.java" @@ -0,0 +1,25 @@ +package cn.lastwhisper.leetcode.greedy.买卖股票的最佳时机II_122_简单; + +class Solution3 { + /** + * 题目地址:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:动态规划 + * + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public int maxProfit(int[] prices) { + + return 0; + } + + public static void main(String[] args) { + //int[] prices = {7, 1, 5, 3, 6, 4}; + int[] prices = {1, 2, 3, 4, 5}; + System.err.println(new Solution3().maxProfit(prices)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/greedy/src/main/java/cn/lastwhisper/leetcode/greedy/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272II_122_\347\256\200\345\215\225/Solution4.java" "b/algorithms/leetcode/greedy/src/main/java/cn/lastwhisper/leetcode/greedy/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272II_122_\347\256\200\345\215\225/Solution4.java" new file mode 100644 index 00000000..cf2187c5 --- /dev/null +++ "b/algorithms/leetcode/greedy/src/main/java/cn/lastwhisper/leetcode/greedy/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272II_122_\347\256\200\345\215\225/Solution4.java" @@ -0,0 +1,30 @@ +package cn.lastwhisper.leetcode.greedy.买卖股票的最佳时机II_122_简单; + +class Solution4 { + /** + * 题目地址:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:贪心算法 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(1) + */ + public int maxProfit(int[] prices) { + int profit = 0, temp; + for (int i = prices.length - 1; i > 0; i--) { + temp = prices[i] - prices[i - 1]; + if (temp > 0) { + profit += temp; + } + } + return profit; + } + + public static void main(String[] args) { + //int[] prices = {7, 1, 5, 3, 6, 4}; + int[] prices = {1, 2, 3, 4, 5}; + System.err.println(new Solution4().maxProfit(prices)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/greedy/src/main/java/cn/lastwhisper/leetcode/greedy/\345\210\206\345\217\221\351\245\274\345\271\262_455_\347\256\200\345\215\225/Solution1.java" "b/algorithms/leetcode/greedy/src/main/java/cn/lastwhisper/leetcode/greedy/\345\210\206\345\217\221\351\245\274\345\271\262_455_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..ea182c46 --- /dev/null +++ "b/algorithms/leetcode/greedy/src/main/java/cn/lastwhisper/leetcode/greedy/\345\210\206\345\217\221\351\245\274\345\271\262_455_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,36 @@ +package cn.lastwhisper.leetcode.greedy.分发饼干_455_简单; + +import java.util.Arrays; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/assign-cookies/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:贪心算法 + * ------------------------------------------------------------------- + * 时间复杂度:O(nlogn) + * 空间复杂度:O(1) + */ + public int findContentChildren(int[] g, int[] s) { + int count = 0; + // 排序,从小到大 + Arrays.sort(g); + Arrays.sort(s); + for (int i = g.length - 1, j = s.length - 1; i >= 0 && j >= 0; i--) { + // 最大的饼干,满足最贪心的孩子 + if (s[j] >= g[i]) { + count++; + j--; + } + } + return count; + } + + public static void main(String[] args) { + //int[] g = {1,2},s={1,2,3}; + int[] g = {10, 9, 8, 7}, s = {5, 6, 7, 8}; + System.out.println(new Solution1().findContentChildren(g, s)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/greedy/src/main/java/cn/lastwhisper/leetcode/greedy/\345\210\244\346\226\255\345\255\220\345\272\217\345\210\227_392_\347\256\200\345\215\225/Solution1.java" "b/algorithms/leetcode/greedy/src/main/java/cn/lastwhisper/leetcode/greedy/\345\210\244\346\226\255\345\255\220\345\272\217\345\210\227_392_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..c7b20b07 --- /dev/null +++ "b/algorithms/leetcode/greedy/src/main/java/cn/lastwhisper/leetcode/greedy/\345\210\244\346\226\255\345\255\220\345\272\217\345\210\227_392_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,37 @@ +package cn.lastwhisper.leetcode.greedy.判断子序列_392_简单; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/is-subsequence/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:贪心算法 + * 将s依次放入t搜索 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(1) + */ + public boolean isSubsequence(String s, String t) { + // 记录上一个字符在t中的位置 + int prev = 0; + for (int i = 0; i < s.length(); i++) { + // 从上一个字符的位置之后进行搜索 + int index = t.indexOf(s.charAt(i), prev); + if (index == -1) { + return false; + } + prev = index + 1; + } + return true; + } + + public static void main(String[] args) { + //String s = "abc", t = "ahbgdc";//true + //String s = "axc", t = "ahbgdc";//false + String s = "acb", t = "ahbgdc";//false + //String s = "leetcode", t = "ylyeyeyeytycyoydye";//true + //String s = "leeeeetcode", t = "yyyyylyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyeyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyeyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyeyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyytyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyycyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyoyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyydyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyeyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"; + System.err.println(new Solution1().isSubsequence(s, t)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/greedy/src/main/java/cn/lastwhisper/leetcode/greedy/\345\210\244\346\226\255\345\255\220\345\272\217\345\210\227_392_\347\256\200\345\215\225/Solution2.java" "b/algorithms/leetcode/greedy/src/main/java/cn/lastwhisper/leetcode/greedy/\345\210\244\346\226\255\345\255\220\345\272\217\345\210\227_392_\347\256\200\345\215\225/Solution2.java" new file mode 100644 index 00000000..f6800edb --- /dev/null +++ "b/algorithms/leetcode/greedy/src/main/java/cn/lastwhisper/leetcode/greedy/\345\210\244\346\226\255\345\255\220\345\272\217\345\210\227_392_\347\256\200\345\215\225/Solution2.java" @@ -0,0 +1,35 @@ +package cn.lastwhisper.leetcode.greedy.判断子序列_392_简单; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/is-subsequence/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:贪心算法 + * 如果s是t的子序列,也就是说s中的所有字符都会按照顺序出现在t中 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(1) + */ + public boolean isSubsequence(String s, String t) { + int sIndex = 0, tIndex = 0; + // 如果s是t的子序列,也就是说s中的所有字符都会按照顺序出现在t中 + while (sIndex < s.length() && tIndex < t.length()) { + if (s.charAt(sIndex) == t.charAt(tIndex)) { + sIndex++; + } + tIndex++; + } + return sIndex == s.length(); + } + + public static void main(String[] args) { + //String s = "abc", t = "ahbgdc";//true + //String s = "axc", t = "ahbgdc";//false + //String s = "acb", t = "ahbgdc";//false + String s = "leetcode", t = "ylyeyeyeytycyoydye";//true + //String s = "leeeeetcode", t = "yyyyylyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyeyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyeyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyeyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyytyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyycyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyoyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyydyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyeyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"; + System.err.println(new Solution2().isSubsequence(s, t)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/greedy/src/main/java/cn/lastwhisper/leetcode/greedy/\346\227\240\351\207\215\345\217\240\345\214\272\351\227\264_435_\344\270\255\347\255\211/Solution1.java" "b/algorithms/leetcode/greedy/src/main/java/cn/lastwhisper/leetcode/greedy/\346\227\240\351\207\215\345\217\240\345\214\272\351\227\264_435_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..49a435ae --- /dev/null +++ "b/algorithms/leetcode/greedy/src/main/java/cn/lastwhisper/leetcode/greedy/\346\227\240\351\207\215\345\217\240\345\214\272\351\227\264_435_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,22 @@ +package cn.lastwhisper.leetcode.greedy.无重叠区间_435_中等; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/non-overlapping-intervals/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public int eraseOverlapIntervals(int[][] intervals) { + + return 0; + } + + public static void main(String[] args) { + + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\344\270\211\346\225\260\344\271\213\345\222\214_15_Middle/Solution1.java" "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\344\270\211\346\225\260\344\271\213\345\222\214_15_Middle/Solution1.java" deleted file mode 100644 index 4b2e6e4d..00000000 --- "a/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\344\270\211\346\225\260\344\271\213\345\222\214_15_Middle/Solution1.java" +++ /dev/null @@ -1,36 +0,0 @@ -package cn.lastwhisper.leetcode.hashtable.三数之和_15_Middle; - -import java.util.*; - -class Solution1 { - /** - * https://leetcode-cn.com/problems/3sum/ - * 核心思想:排序+双索引+hash表 - * 时间复杂度: - */ - public List> threeSum(int[] nums) { - if (nums == null) throw new IllegalArgumentException("非法参数"); - // 数组排序 - Arrays.sort(nums); - // hash表 - Map map = new HashMap<>(); - // 结果 - List> list = new ArrayList<>(); - // [l,r] - int l = 0, r = nums.length-1; - int k = nums[l]; - while (l { - System.out.println(); - list.forEach(System.out::print); - }); - - } -} \ No newline at end of file diff --git "a/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\344\270\211\346\225\260\344\271\213\345\222\214_15_\344\270\255\347\255\211/Solution1.java" "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\344\270\211\346\225\260\344\271\213\345\222\214_15_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..6d490bfd --- /dev/null +++ "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\344\270\211\346\225\260\344\271\213\345\222\214_15_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,62 @@ +package cn.lastwhisper.leetcode.hashtable.三数之和_15_中等; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/3sum/ + * ------------------------------------------------------------------- + * 思考: + * Q:如何将数组中的任意三个数,进行组合? + * A:三层循环,第一层i~n-2,第二层i+1~n-1,第一层i+2~n + * Q:如何保证无重复组合? + * A:先对数组排序。每一层循环时,和数组前一个数进行对比是否相等,相等说明重复了,直接跳过 + * ------------------------------------------------------------------- + * 思路: + * ------------------------------------------------------------------- + * 时间复杂度:O(n^3) + * 空间复杂度:O(n^2) + */ + public List> threeSum(int[] nums) { + if (nums == null) throw new IllegalArgumentException("非法参数"); + Arrays.sort(nums); + // 结果 + List> resultList = new ArrayList<>(); + for (int i = 0; i < nums.length - 2; i++) { + if (i > 0 && nums[i] == nums[i - 1]) { + continue; // 对i去重 + } + for (int j = i + 1; j < nums.length - 1; j++) { + if (j > i + 1 && nums[j] == nums[j - 1]) { + continue; // 对j去重 + } + for (int k = j + 1; k < nums.length; k++) { + if (k > j + 1 && nums[k] == nums[k - 1]) { + continue; // 对k去重 + } + if (nums[i] + nums[j] + nums[k] == 0) { + resultList.add(Arrays.asList(nums[i], nums[j], nums[k])); + } + } + } + } + + return resultList; + } + + public static void main(String[] args) { + //new Solution1().threeSum(new int[]{-1, 0, 1, 2, -1, -4}).forEach((list) -> { + // System.out.println(); + // list.forEach(System.out::print); + //}); + + // error example + new Solution1().threeSum(new int[]{0, 0, 0, 0}).forEach((list) -> { + System.out.println(); + list.forEach(System.out::print); + }); + + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\344\270\211\346\225\260\344\271\213\345\222\214_15_\344\270\255\347\255\211/Solution2.java" "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\344\270\211\346\225\260\344\271\213\345\222\214_15_\344\270\255\347\255\211/Solution2.java" new file mode 100644 index 00000000..25f77fb3 --- /dev/null +++ "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\344\270\211\346\225\260\344\271\213\345\222\214_15_\344\270\255\347\255\211/Solution2.java" @@ -0,0 +1,64 @@ +package cn.lastwhisper.leetcode.hashtable.三数之和_15_中等; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/3sum/ + * ------------------------------------------------------------------- + * + * ------------------------------------------------------------------- + * 优化思路:三三组合改进,排序+双索引,并对特殊情况进行剔除 + * ------------------------------------------------------------------- + * 时间复杂度:O(n^2) + * 空间复杂度:O(n^2) + */ + public List> threeSum(int[] nums) { + // 存储结果 + List> resultList = new ArrayList<>(); + if (nums == null || nums.length < 3) return resultList; + // 数组排序 + Arrays.sort(nums); + for (int i = 0; i < nums.length; i++) { + if (nums[i] > 0) { + break; //此时说明数组后面都是正值,三个数相加不可能为0 + } + if (i > 0 && nums[i] == nums[i - 1]) { + continue; // 对i去重 + } + + int l = i + 1, r = nums.length - 1; + while (l < r) { + + int sum = nums[i] + nums[l] + nums[r]; + if (sum == 0) { + resultList.add(Arrays.asList(nums[i], nums[l], nums[r])); + while (l < r && nums[l] == nums[l + 1]) l++; // 对l去重 + while (l < r && nums[r] == nums[r - 1]) r--; // 对r去重 + l++; + r--; + } else if (sum < 0) { + l++; + } else { + r--; + } + + } + } + return resultList; + } + + public static void main(String[] args) { + //new Solution2().threeSum(new int[]{-1, 0, 1, 2, -1, -4}).forEach((list) -> { + // System.out.println(); + // list.forEach(System.out::print); + //}); + + new Solution2().threeSum(new int[]{0,0,0,0}).forEach((list) -> { + System.out.println(); + list.forEach(System.out::print); + }); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\344\270\211\346\225\260\344\271\213\345\222\214_15_\344\270\255\347\255\211/Solution3.java" "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\344\270\211\346\225\260\344\271\213\345\222\214_15_\344\270\255\347\255\211/Solution3.java" new file mode 100644 index 00000000..c3ca0a1d --- /dev/null +++ "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\344\270\211\346\225\260\344\271\213\345\222\214_15_\344\270\255\347\255\211/Solution3.java" @@ -0,0 +1,77 @@ +package cn.lastwhisper.leetcode.hashtable.三数之和_15_中等; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +class Solution3 { + /** + * 题目地址:https://leetcode-cn.com/problems/3sum/ + * ------------------------------------------------------------------- + * + * ------------------------------------------------------------------- + * 优化思路:根据排序后的数据规律,剔除掉不必要的循环 + * ------------------------------------------------------------------- + * 时间复杂度:O(n^2) + * 空间复杂度:O(n^2) + * ------------------------------------------------------------------- + * 执行用时 :33 ms, 在所有 java 提交中击败了92.67%的用户 + * 内存消耗 :48.1 MB, 在所有 java 提交中击败了92.84%的用户 + */ + public List> threeSum(int[] nums) { + // 存储结果 + List> resultList = new ArrayList<>(); + if (nums == null || nums.length < 3) return resultList; + // 数组排序 + Arrays.sort(nums); + for (int i = 0; i < nums.length - 2; i++) { // i < nums.length - 2 + + if (i > 0 && nums[i] == nums[i - 1]) { + continue; // 对i去重 + } + + // 最小值比0大,不管nums[i]再怎么递增都没戏 + int min1 = nums[i] + nums[i + 1] + nums[i + 2]; + if (min1 > 0) { + break; + } + + // 最大值比0小,当前nums[i]肯定没戏了,找下一个nums[i]试试 + int max1 = nums[i] + nums[nums.length - 2] + nums[nums.length - 1]; + if (max1 < 0) { + continue; + } + + int l = i + 1, r = nums.length - 1; + while (l < r) { + + int sum = nums[i] + nums[l] + nums[r]; + if (sum == 0) { + resultList.add(Arrays.asList(nums[i], nums[l], nums[r])); + while (l < r && nums[l] == nums[l + 1]) l++; // 对l去重 + while (l < r && nums[r] == nums[r - 1]) r--; // 对r去重 + l++; + r--; + } else if (sum < 0) { + l++; + } else { + r--; + } + + } + } + return resultList; + } + + public static void main(String[] args) { + //new Solution2().threeSum(new int[]{-1, 0, 1, 2, -1, -4}).forEach((list) -> { + // System.out.println(); + // list.forEach(System.out::print); + //}); + + new Solution3().threeSum(new int[]{0, 0, 0, 0}).forEach((list) -> { + System.out.println(); + list.forEach(System.out::print); + }); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\344\270\244\344\270\252\346\225\260\347\273\204\347\232\204\344\272\244\351\233\206_349_Esay/Solution1.java" "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\344\270\244\344\270\252\346\225\260\347\273\204\347\232\204\344\272\244\351\233\206_349_Esay/Solution1.java" new file mode 100644 index 00000000..8954b872 --- /dev/null +++ "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\344\270\244\344\270\252\346\225\260\347\273\204\347\232\204\344\272\244\351\233\206_349_Esay/Solution1.java" @@ -0,0 +1,38 @@ +package cn.lastwhisper.leetcode.hashtable.两个数组的交集_349_Esay; + +import java.util.HashSet; +import java.util.Set; + +class Solution1 { + /** + * + */ + public int[] intersection(int[] nums1, int[] nums2) { + Set recorde = new HashSet(); + for (int num : nums1) { + recorde.add(num); + } + Set resSet = new HashSet(); + for (int num : nums2) { + if (recorde.contains(num)) { + resSet.add(num); + } + } + int[] res = new int[resSet.size()]; + + int index = 0; + for (Integer num : resSet) + res[index++] = num; + return res; + } + + public static void main(String[] args) { + int[] nums1 = {1, 2, 2, 1}; + int[] nums2 = {2, 2}; + int[] res = (new Solution1()).intersection(nums1, nums2); + + for (int re : res) { + System.out.println(re); + } + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\344\270\244\344\270\252\346\225\260\347\273\204\347\232\204\344\272\244\351\233\206_349_esay/Solution1.java" "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\344\270\244\344\270\252\346\225\260\347\273\204\347\232\204\344\272\244\351\233\206_349_esay/Solution1.java" deleted file mode 100644 index 99aa87b9..00000000 --- "a/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\344\270\244\344\270\252\346\225\260\347\273\204\347\232\204\344\272\244\351\233\206_349_esay/Solution1.java" +++ /dev/null @@ -1,39 +0,0 @@ -package cn.lastwhisper.leetcode.hashtable.两个数组的交集_349_esay; - -import java.util.HashSet; -import java.util.Set; - -class Solution1 { - /** - * - */ - public int[] intersection(int[] nums1, int[] nums2) { - Set recorde = new HashSet(); - for (int i = 0; i < nums1.length; i++) { - recorde.add(nums1[i]); - } - Set resSet = new HashSet(); - for (int i = 0; i < nums2.length; i++) { - if(recorde.contains(nums2[i])){ - resSet.add(nums2[i]); - } - } - int[] res = new int[resSet.size()]; - - int index = 0; - for(Integer num: resSet) - res[index++] = num; - return res; - } - - public static void main(String[] args){ - int[] nums1 = {1, 2, 2, 1}; - int[] nums2 = {2, 2}; - int[] res = (new Solution1()).intersection(nums1, nums2); - - for (int i = 0; i < res.length; i++) { - int re = res[i]; - System.out.println(re); - } - } -} \ No newline at end of file diff --git "a/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\344\270\244\344\270\252\346\225\260\347\273\204\347\232\204\344\272\244\351\233\206_II_350_Esay/Solution1.java" "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\344\270\244\344\270\252\346\225\260\347\273\204\347\232\204\344\272\244\351\233\206_II_350_Esay/Solution1.java" new file mode 100644 index 00000000..028560f8 --- /dev/null +++ "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\344\270\244\344\270\252\346\225\260\347\273\204\347\232\204\344\272\244\351\233\206_II_350_Esay/Solution1.java" @@ -0,0 +1,51 @@ +package cn.lastwhisper.leetcode.hashtable.两个数组的交集_II_350_Esay; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +class Solution1 { + public int[] intersect(int[] nums1, int[] nums2) { + Map record = new HashMap<>(); + for (int i = 0; i < nums1.length; i++) { + int num = nums1[i]; + if(!record.containsKey(num)){ + record.put(num,1); + }else { + record.put(num, record.get(num) + 1); + } + + } + + List result = new ArrayList<>(); + for (int i = 0; i < nums2.length; i++) { + int num = nums2[i]; + if(record.containsKey(num) && record.get(num)>0){ + result.add(num); + record.put(num, record.get(num) - 1); + } + + } + + int[] res = new int[result.size()]; + int index=0; + for (Integer integer : result) { + res[index] = integer; + index++; + } + + return res; + } + + public static void main(String[] args){ + int[] nums1 = {1, 2, 2, 1}; + int[] nums2 = {2, 2}; + int[] res = (new Solution1()).intersect(nums1, nums2); + + for (int i = 0; i < res.length; i++) { + int re = res[i]; + System.out.println(re); + } + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\344\270\244\344\270\252\346\225\260\347\273\204\347\232\204\344\272\244\351\233\206_II_350_esay/Solution1.java" "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\344\270\244\344\270\252\346\225\260\347\273\204\347\232\204\344\272\244\351\233\206_II_350_esay/Solution1.java" deleted file mode 100644 index 0db910bc..00000000 --- "a/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\344\270\244\344\270\252\346\225\260\347\273\204\347\232\204\344\272\244\351\233\206_II_350_esay/Solution1.java" +++ /dev/null @@ -1,51 +0,0 @@ -package cn.lastwhisper.leetcode.hashtable.两个数组的交集_II_350_esay; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -class Solution1 { - public int[] intersect(int[] nums1, int[] nums2) { - Map record = new HashMap<>(); - for (int i = 0; i < nums1.length; i++) { - int num = nums1[i]; - if(!record.containsKey(num)){ - record.put(num,1); - }else { - record.put(num, record.get(num) + 1); - } - - } - - List result = new ArrayList<>(); - for (int i = 0; i < nums2.length; i++) { - int num = nums2[i]; - if(record.containsKey(num) && record.get(num)>0){ - result.add(num); - record.put(num, record.get(num) - 1); - } - - } - - int[] res = new int[result.size()]; - int index=0; - for (Integer integer : result) { - res[index] = integer; - index++; - } - - return res; - } - - public static void main(String[] args){ - int[] nums1 = {1, 2, 2, 1}; - int[] nums2 = {2, 2}; - int[] res = (new Solution1()).intersect(nums1, nums2); - - for (int i = 0; i < res.length; i++) { - int re = res[i]; - System.out.println(re); - } - } -} \ No newline at end of file diff --git "a/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\344\270\244\346\225\260\344\271\213\345\222\214_1_Easy/Solution1.java" "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\344\270\244\346\225\260\344\271\213\345\222\214_1_Easy/Solution1.java" deleted file mode 100644 index f4a26279..00000000 --- "a/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\344\270\244\346\225\260\344\271\213\345\222\214_1_Easy/Solution1.java" +++ /dev/null @@ -1,27 +0,0 @@ -package cn.lastwhisper.leetcode.hashtable.两数之和_1_Easy; - -import java.util.Arrays; - -class Solution1 { - /** - * https://leetcode-cn.com/problems/two-sum/ - * 核心思想:找出所有组合进行对比 - * 时间复杂度:O(n^2) - * 空间复杂度:O(1) - */ - public int[] twoSum(int[] nums, int target) { - if (nums == null) throw new IllegalArgumentException("非法参数"); - for (int i = 0; i < nums.length; i++) { - for (int j = i+1; j < nums.length; j++) { - if(nums[i]+nums[j]==target){ - return new int[]{i,j}; - } - } - } - return null; - } - - public static void main(String[] args) { - System.out.println(Arrays.toString(new Solution1().twoSum(new int[]{2, 7, 11, 15}, 9))); - } -} \ No newline at end of file diff --git "a/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\344\270\244\346\225\260\344\271\213\345\222\214_1_Easy/Solution2.java" "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\344\270\244\346\225\260\344\271\213\345\222\214_1_Easy/Solution2.java" deleted file mode 100644 index 339977c9..00000000 --- "a/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\344\270\244\346\225\260\344\271\213\345\222\214_1_Easy/Solution2.java" +++ /dev/null @@ -1,25 +0,0 @@ -package cn.lastwhisper.leetcode.hashtable.两数之和_1_Easy; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.stream.Collectors; - -class Solution2 { - /** - * https://leetcode-cn.com/problems/two-sum/ - * 核心思想:先排序O(nlogn),在双索引O(n) - * 时间复杂度:O(nlogn) - * 空间复杂度:O(1) - */ - public int[] twoSum(int[] nums, int target) { - if (nums == null) throw new IllegalArgumentException("非法参数"); - - - return null; - } - - public static void main(String[] args) { - System.out.println(Arrays.toString(new Solution2().twoSum(new int[]{2, 7, 11, 15}, 9))); - } -} \ No newline at end of file diff --git "a/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\344\270\244\346\225\260\344\271\213\345\222\214_1_Easy/Solution3.java" "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\344\270\244\346\225\260\344\271\213\345\222\214_1_Easy/Solution3.java" deleted file mode 100644 index ca9137f8..00000000 --- "a/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\344\270\244\346\225\260\344\271\213\345\222\214_1_Easy/Solution3.java" +++ /dev/null @@ -1,34 +0,0 @@ -package cn.lastwhisper.leetcode.hashtable.两数之和_1_Easy; - -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; - -class Solution3 { - /** - * https://leetcode-cn.com/problems/two-sum/ - * 核心思想: - * 时间复杂度:O(n) - * 空间复杂度:O(n) - * 执行用时 : 3 ms , 在所有 Java 提交中击败了 99.01% 的用户 - * 内存消耗 : 37.9 MB , 在所有 Java 提交中击败了 79.09% 的用户 - */ - public int[] twoSum(int[] nums, int target) { - if (nums == null) throw new IllegalArgumentException("非法参数"); - // map存储数字与对应下标 - Map map = new HashMap<>(); - // 边记录边找 - for (int i = 0; i < nums.length; i++) { - int key = target-nums[i]; - if(map.containsKey(key)){ - return new int[]{i,map.get(key)}; - } - map.put(nums[i],i); - } - throw new IllegalArgumentException("No two sum solution"); - } - - public static void main(String[] args) { - System.out.println(Arrays.toString(new Solution3().twoSum(new int[]{2, 7, 11, 15}, 9))); - } -} \ No newline at end of file diff --git "a/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\344\270\244\346\225\260\344\271\213\345\222\214_1_\347\256\200\345\215\225/Solution1.java" "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\344\270\244\346\225\260\344\271\213\345\222\214_1_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..9be5d0c5 --- /dev/null +++ "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\344\270\244\346\225\260\344\271\213\345\222\214_1_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,29 @@ +package cn.lastwhisper.leetcode.hashtable.两数之和_1_简单; + +import java.util.Arrays; + +class Solution1 { + /** + * https://leetcode-cn.com/problems/two-sum/ + * 核心思想:找出所有组合进行对比,取其中一个即可 + * 时间复杂度:O(n^2) + * 空间复杂度:O(1) + * + * + */ + public int[] twoSum(int[] nums, int target) { + if (nums == null) throw new IllegalArgumentException("非法参数"); + for (int i = 0; i < nums.length - 1; i++) { + for (int j = i + 1; j < nums.length; j++) { + if (nums[i] + nums[j] == target) { + return new int[]{i, j}; + } + } + } + return null; + } + + public static void main(String[] args) { + System.out.println(Arrays.toString(new Solution1().twoSum(new int[]{2, 7, 11, 15}, 9))); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\344\270\244\346\225\260\344\271\213\345\222\214_1_\347\256\200\345\215\225/Solution2.java" "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\344\270\244\346\225\260\344\271\213\345\222\214_1_\347\256\200\345\215\225/Solution2.java" new file mode 100644 index 00000000..4b3aa980 --- /dev/null +++ "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\344\270\244\346\225\260\344\271\213\345\222\214_1_\347\256\200\345\215\225/Solution2.java" @@ -0,0 +1,48 @@ +package cn.lastwhisper.leetcode.hashtable.两数之和_1_简单; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +class Solution2 { + /** + * https://leetcode-cn.com/problems/two-sum/ + * 核心思想:先排序O(nlogn),在对撞指针O(n) + * 时间复杂度:O(nlogn) + * 空间复杂度:O(1) + * 相关题型:两数之和_II_输入有序数组_167 + */ + public int[] twoSum(int[] nums, int target) { + if (nums == null) throw new IllegalArgumentException("非法参数"); + // 存储原数组,下标和值映射关系(map中重复的数据会覆盖数组值与下标的对应关系) + Map map = new HashMap<>(); + for (int i = 0; i < nums.length; i++) { + map.put(nums[i], i); + } + Arrays.sort(nums); + // 对撞指针 + int l = 0, r = nums.length - 1; + while (l < r) { + int left = nums[l]; + int right = nums[r]; + if ((left + right) == target) { + return new int[]{map.get(left), map.get(right)}; + } else if ((left + right) > target) { + r--; + } else { + l++; + } + } + return null; + } + + // 没做出来,暂时保留 + public static void main(String[] args) { + //int[] arr = new int[]{3, 2, 4}; + //int target = 6; + + int[] arr = new int[]{3, 3};//此时发生错误 + int target = 6; + System.out.println(Arrays.toString(new Solution2().twoSum(arr, target))); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\344\270\244\346\225\260\344\271\213\345\222\214_1_\347\256\200\345\215\225/Solution3.java" "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\344\270\244\346\225\260\344\271\213\345\222\214_1_\347\256\200\345\215\225/Solution3.java" new file mode 100644 index 00000000..a52e83d2 --- /dev/null +++ "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\344\270\244\346\225\260\344\271\213\345\222\214_1_\347\256\200\345\215\225/Solution3.java" @@ -0,0 +1,43 @@ +package cn.lastwhisper.leetcode.hashtable.两数之和_1_简单; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +class Solution3 { + /** + * https://leetcode-cn.com/problems/two-sum/ + * 核心思想:将所有元素放入查找表,之后对于每一个元素a,查找 target - a 是否存在 + * 时间复杂度:O(n) + * 空间复杂度:O(n) + * 执行用时 : 3 ms , 在所有 Java 提交中击败了 99.01% 的用户 + * 内存消耗 : 37.9 MB , 在所有 Java 提交中击败了 79.09% 的用户 + */ + public int[] twoSum(int[] nums, int target) { + if (nums == null) throw new IllegalArgumentException("非法参数"); + // map存储数字与对应下标 + Map map = new HashMap<>(); + // 边记录边找 + for (int i = 0; i < nums.length; i++) { + int key = target-nums[i]; + if(map.containsKey(key)){ + return new int[]{i,map.get(key)}; + } + map.put(nums[i],i); + } + throw new IllegalArgumentException("No two sum solution"); + } + + public static void main(String[] args) { + //int[] arr = new int[]{3, 2, 4}; + //int target = 6; + + int[] arr = new int[]{3,3};//此时发生错误 + int target = 6; + + //int[] arr = new int[]{2, 7, 11, 15}; + //int target = 9; + + System.out.println(Arrays.toString(new Solution2().twoSum(arr, target))); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\345\233\233\346\225\260\344\271\213\345\222\214_18_Middle/Example.java" "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\345\233\233\346\225\260\344\271\213\345\222\214_18_Middle/Example.java" new file mode 100644 index 00000000..e48cd6c0 --- /dev/null +++ "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\345\233\233\346\225\260\344\271\213\345\222\214_18_Middle/Example.java" @@ -0,0 +1,109 @@ +package cn.lastwhisper.leetcode.hashtable.四数之和_18_Middle; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +class Example { + /** + * 题目地址:https://leetcode-cn.com/problems/4sum/ + * ------------------------------------------------------------------- + * 思考: + * 数据特征: + * 输入:数组、无序、所有整数 + * 输出:二维数组 + * ------------------------------------------------------------------- + * 思路: + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public List> fourSum(int[] nums, int target) { + /*定义一个返回值*/ + List> result = new ArrayList<>(); + /*当数组为null或元素小于4个时,直接返回*/ + if (nums == null || nums.length < 4) { + return result; + } + /*对数组进行从小到大排序*/ + Arrays.sort(nums); + /*数组长度*/ + int length = nums.length; + /*定义4个指针k,i,j,h k从0开始遍历,i从k+1开始遍历,留下j和h,j指向i+1,h指向数组最大值*/ + for (int k = 0; k < length - 3; k++) { + /*当k的值与前面的值相等时忽略*/ + if (k > 0 && nums[k] == nums[k - 1]) { + continue; + } + /*获取当前最小值,如果最小值比目标值大,说明后面越来越大的值根本没戏*/ + int min1 = nums[k] + nums[k + 1] + nums[k + 2] + nums[k + 3]; + if (min1 > target) { + break; + } + /*获取当前最大值,如果最大值比目标值小,说明后面越来越小的值根本没戏,忽略*/ + int max1 = nums[k] + nums[length - 1] + nums[length - 2] + nums[length - 3]; + if (max1 < target) { + continue; + } + /*第二层循环i,初始值指向k+1*/ + for (int i = k + 1; i < length - 2; i++) { + /*当i的值与前面的值相等时忽略*/ + if (i > k + 1 && nums[i] == nums[i - 1]) { + continue; + } + /*定义指针j指向i+1*/ + int j = i + 1; + /*定义指针h指向数组末尾*/ + int h = length - 1; + /*获取当前最小值,如果最小值比目标值大,说明后面越来越大的值根本没戏,忽略*/ + int min = nums[k] + nums[i] + nums[j] + nums[j + 1]; + if (min > target) { + continue; + } + /*获取当前最大值,如果最大值比目标值小,说明后面越来越小的值根本没戏,忽略*/ + int max = nums[k] + nums[i] + nums[h] + nums[h - 1]; + if (max < target) { + continue; + } + /*开始j指针和h指针的表演,计算当前和,如果等于目标值,j++并去重,h--并去重,当当前和大于目标值时h--,当当前和小于目标值时j++*/ + while (j < h) { + int curr = nums[k] + nums[i] + nums[j] + nums[h]; + if (curr == target) { + result.add(Arrays.asList(nums[k], nums[i], nums[j], nums[h])); + j++; + while (j < h && nums[j] == nums[j - 1]) { + j++; + } + h--; + while (j < h && i < h && nums[h] == nums[h + 1]) { + h--; + } + } else if (curr > target) { + h--; + } else { + j++; + } + } + } + } + return result; + } + + + public static void main(String[] args) { + //int[] nums = {1, 0, -1, 0, -2, 2}; + //int target = 0; + + // error example + //int[] nums = {-3, -1, 0, 2, 4, 5}; + //int target = 2; + + int[] nums = {-3, -2, -1, 0, 0, 1, 2, 3}; + int target = 0; + + new Example().fourSum(nums, target).forEach((list) -> { + System.out.println(); + list.forEach(System.out::print); + }); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\345\233\233\346\225\260\344\271\213\345\222\214_18_Middle/Solution1.java" "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\345\233\233\346\225\260\344\271\213\345\222\214_18_Middle/Solution1.java" new file mode 100644 index 00000000..f65d1da1 --- /dev/null +++ "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\345\233\233\346\225\260\344\271\213\345\222\214_18_Middle/Solution1.java" @@ -0,0 +1,72 @@ +package cn.lastwhisper.leetcode.hashtable.四数之和_18_Middle; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/4sum/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:在数组中任意取四个数(参考三数之和) + * ------------------------------------------------------------------- + * 时间复杂度:O(n^3) + * 空间复杂度:O(n^2) + */ + public List> fourSum(int[] nums, int target) { + // 存储结果 + List> resultList = new ArrayList<>(); + if (nums == null || nums.length < 4) return resultList; + // 数组排序 + Arrays.sort(nums); + for (int i = 0; i < nums.length - 3; i++) { + if (i > 0 && nums[i] == nums[i - 1]) { + continue; // 对i去重 + } + for (int j = i + 1; j < nums.length - 2; j++) { + if (j > i + 1 && nums[j] == nums[j - 1]) { + continue; // 对j去重 + } + int l = j + 1, r = nums.length - 1; + while (l < r) { + + int sum = nums[i] + nums[j] + nums[l] + nums[r]; + if (sum == target) { + resultList.add(Arrays.asList(nums[i], nums[j], nums[l], nums[r])); + while (l < r && nums[l] == nums[l + 1]) l++; // 对l去重 + while (l < r && nums[r] == nums[r - 1]) r--; // 对r去重 + l++; + r--; + } else if (sum < target) { + l++; + } else { + r--; + } + + } + + } + } + + return resultList; + } + + public static void main(String[] args) { + //int[] nums = {1, 0, -1, 0, -2, 2}; + //int target = 0; + + // error example + //int[] nums = {-3, -1, 0, 2, 4, 5}; + //int target = 2; + + int[] nums = {-3, -2, -1, 0, 0, 1, 2, 3}; + int target = 0; + + new Solution1().fourSum(nums, target).forEach((list) -> { + System.out.println(); + list.forEach(System.out::print); + }); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\345\233\233\346\225\260\344\271\213\345\222\214_18_Middle/Solution2.java" "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\345\233\233\346\225\260\344\271\213\345\222\214_18_Middle/Solution2.java" new file mode 100644 index 00000000..9a0c41c0 --- /dev/null +++ "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\345\233\233\346\225\260\344\271\213\345\222\214_18_Middle/Solution2.java" @@ -0,0 +1,99 @@ +package cn.lastwhisper.leetcode.hashtable.四数之和_18_Middle; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/4sum/ + * ------------------------------------------------------------------- + * + * ------------------------------------------------------------------- + * 优化思路:根据排序后的数据特征,在循环时可以进行跳过不必要的循环 + * ------------------------------------------------------------------- + * 时间复杂度:O(n^3) + * 空间复杂度:O(n^2) + * ------------------------------------------------------------------- + * 执行用时 : 4 ms, 在所有 java 提交中击败了99.54%的用户 + * 内存消耗 : 36.5 MB, 在所有 java 提交中击败了99.09%的用户 + */ + public List> fourSum(int[] nums, int target) { + // 存储结果 + List> resultList = new ArrayList<>(); + if (nums == null || nums.length < 4) return resultList; + // 数组排序 + Arrays.sort(nums); + for (int i = 0; i < nums.length - 3; i++) { + if (i > 0 && nums[i] == nums[i - 1]) { + continue; // 对i去重 + } + // 最小值比target大,不管nums[i]再怎么递增都没戏 + int min1 = nums[i] + nums[i + 1] + nums[i + 2] + nums[i + 3]; + if (min1 > target) { + break; + } + + // 最大值比target小,当前nums[i]肯定没戏了,找下一个nums[i]试试 + int max1 = nums[i] + nums[nums.length - 3] + nums[nums.length - 2] + nums[nums.length - 1]; + if (max1 < target) { + continue; + } + + for (int j = i + 1; j < nums.length - 2; j++) { + if (j > i + 1 && nums[j] == nums[j - 1]) { + continue; // 对j去重 + } + + // 最小值比target大,不管nums[j]再怎么递增都没戏 + int min2 = nums[i] + nums[j] + nums[j + 1] + nums[j + 2]; + if (min2 > target) { + break; + } + + // 最大值比target小,当前nums[j]肯定没戏了,找下一个nums[j]试试 + int max2 = nums[i] + nums[j] + nums[nums.length - 2] + nums[nums.length - 1]; + if (max2 < target) { + continue; + } + int l = j + 1, r = nums.length - 1; + while (l < r) { + + int sum = nums[i] + nums[j] + nums[l] + nums[r]; + if (sum == target) { + resultList.add(Arrays.asList(nums[i], nums[j], nums[l], nums[r])); + while (l < r && nums[l] == nums[l + 1]) l++; // 对l去重 + while (l < r && nums[r] == nums[r - 1]) r--; // 对r去重 + l++; + r--; + } else if (sum < target) { + l++; + } else { + r--; + } + + } + + } + } + + return resultList; + } + + public static void main(String[] args) { + //int[] nums = {1, 0, -1, 0, -2, 2}; + //int target = 0; + + // error example + //int[] nums = {-3, -1, 0, 2, 4, 5}; + //int target = 2; + + int[] nums = {-3, -2, -1, 0, 0, 1, 2, 3}; + int target = 0; + + new Solution2().fourSum(nums, target).forEach((list) -> { + System.out.println(); + list.forEach(System.out::print); + }); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\345\233\233\346\225\260\347\233\270\345\212\240_II_454_\344\270\255\347\255\211/Solution1.java" "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\345\233\233\346\225\260\347\233\270\345\212\240_II_454_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..5f44c6a7 --- /dev/null +++ "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\345\233\233\346\225\260\347\233\270\345\212\240_II_454_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,54 @@ +package cn.lastwhisper.leetcode.hashtable.四数相加_II_454_中等; + +import java.util.HashMap; +import java.util.Map; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/4sum-ii/ + * ------------------------------------------------------------------- + * 思考: + * 数据特征: + * 输入:数组、无序、所有整数 + * 输出:二维数组 + * ------------------------------------------------------------------- + * 优化思路: + * (1)四层循环,时间复杂度O(n^4)——超时 + * (2)使用hash存储D的所有情况,时间复杂度O(n^3)——超时 + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public int fourSumCount(int[] A, int[] B, int[] C, int[] D) { + // key:数组中某个数、value:该数出现的频率 + Map dMap = new HashMap<>(); + for (int dKey : D) { + if (dMap.containsKey(dKey)) { + dMap.put(dKey, dMap.get(dKey) + 1); + } else { + dMap.put(dKey, 1); + } + } + int count = 0; + for (int a : A) { + for (int b : B) { + for (int c : C) { + int dKey = 0 - a - b - c; + Integer dCount = dMap.get(dKey); + if (dCount != null) { + count += dCount; + } + } + } + } + return count; + } + + public static void main(String[] args) { + int[] A = {1, 2}; + int[] B = {-2, -1}; + int[] C = {-1, 2}; + int[] D = {0, 2}; + System.out.println(new Solution1().fourSumCount(A, B, C, D)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\345\233\233\346\225\260\347\233\270\345\212\240_II_454_\344\270\255\347\255\211/Solution2.java" "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\345\233\233\346\225\260\347\233\270\345\212\240_II_454_\344\270\255\347\255\211/Solution2.java" new file mode 100644 index 00000000..6b487488 --- /dev/null +++ "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\345\233\233\346\225\260\347\233\270\345\212\240_II_454_\344\270\255\347\255\211/Solution2.java" @@ -0,0 +1,53 @@ +package cn.lastwhisper.leetcode.hashtable.四数相加_II_454_中等; + +import java.util.HashMap; +import java.util.Map; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/4sum-ii/ + * ------------------------------------------------------------------- + * 优化思路: + * (3)使用hash存储CD的所有情况,时间复杂度O(n^2) + * ------------------------------------------------------------------- + * 时间复杂度:O(n^2) + * 空间复杂度:O(n^2) + * ------------------------------------------------------------------- + * 执行用时 :142 ms, 在所有 java 提交中击败了27.37%的用户 + * 内存消耗 :59 MB, 在所有 java 提交中击败了90.62%的用户 + */ + public int fourSumCount(int[] A, int[] B, int[] C, int[] D) { + // key:数组中某个数、value:该数出现的频率 + Map cdMap = new HashMap<>(); + for (int c : C) { + for (int d : D) { + int cd = c + d; + if (cdMap.containsKey(cd)) { + cdMap.put(cd, cdMap.get(cd) + 1); + } else { + cdMap.put(cd, 1); + } + } + } + + int count = 0; + for (int a : A) { + for (int b : B) { + int cd = 0 - a - b; + Integer cdCount = cdMap.get(cd); + if (cdCount != null) { + count += cdCount; + } + } + } + return count; + } + + public static void main(String[] args) { + int[] A = {1, 2}; + int[] B = {-2, -1}; + int[] C = {-1, 2}; + int[] D = {0, 2}; + System.out.println(new Solution2().fourSumCount(A, B, C, D)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\345\233\236\346\227\213\351\225\226\347\232\204\346\225\260\351\207\217_447_\347\256\200\345\215\225/Solution1.java" "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\345\233\236\346\227\213\351\225\226\347\232\204\346\225\260\351\207\217_447_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..124817c3 --- /dev/null +++ "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\345\233\236\346\227\213\351\225\226\347\232\204\346\225\260\351\207\217_447_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,54 @@ +package cn.lastwhisper.leetcode.hashtable.回旋镖的数量_447_简单; + +import java.util.HashMap; +import java.util.Map; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/number-of-boomerangs/ + * ------------------------------------------------------------------- + * 思考:计算两点问题开根号时会有精度问题 + * ------------------------------------------------------------------- + * 思路: + * ------------------------------------------------------------------- + * 时间复杂度: O(n^2) + * 空间复杂度: O(n) + */ + public int numberOfBoomerangs(int[][] points) { + int res = 0; + + // record中存储 点i 到所有其他点的距离出现的频次 + Map record = new HashMap<>(); + for (int i = 0; i < points.length; i++) { + + for (int j = 0; j < points.length; j++) { + if (i != j) { + // 计算距离时不进行开根运算, 以保证精度 + int dis = dis(points[i], points[j]); + if (record.containsKey(dis)) { + record.put(dis, record.get(dis) + 1); + } else { + record.put(dis, 1); + } + } + } + for (Integer dis : record.keySet()) { + res += record.get(dis) * (record.get(dis) - 1); + } + + // 复用map + record.clear(); + } + return res; + } + + private int dis(int[] pa, int[] pb) { + return (pa[0] - pb[0]) * (pa[0] - pb[0]) + + (pa[1] - pb[1]) * (pa[1] - pb[1]); + } + + public static void main(String[] args) { + int[][] points = {{0, 0}, {1, 0}, {2, 0}}; + System.out.println(new Solution1().numberOfBoomerangs(points)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215\345\210\206\347\273\204_49_\344\270\255\347\255\211/Solution1.java" "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215\345\210\206\347\273\204_49_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..e88ccb72 --- /dev/null +++ "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215\345\210\206\347\273\204_49_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,49 @@ +package cn.lastwhisper.leetcode.hashtable.字母异位词分组_49_中等; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/group-anagrams/ + * ------------------------------------------------------------------- + * 思路:排序字符串相等时,两个字符串是字母异位词 + * ------------------------------------------------------------------- + * 时间复杂度:O(N*K*logK) 其中 N 是 strs 的长度,而 K 是 strs 中字符串的最大长度 + * 空间复杂度:O(N*K) + * ------------------------------------------------------------------- + * 执行用时 :11 ms, 在所有 java 提交中击败了97.16%的用户 + * 内存消耗 :42.2 MB, 在所有 java 提交中击败了97.29%的用户 + */ + public List> groupAnagrams(String[] strs) { + // 空值处理 + if (strs.length == 0) return new ArrayList>(); + + // key:排序后的字符串、value:未排序的字符串集List + HashMap> map = new HashMap<>(); + + for (String str : strs) { + char[] chars = str.toCharArray(); + // 排序后如果是字母异位词都长一个样 + Arrays.sort(chars); + String key = String.valueOf(chars); + if (!map.containsKey(key)) { + map.put(key, new ArrayList<>()); + } + map.get(key).add(str); + } + + return new ArrayList<>(map.values()); + } + + public static void main(String[] args) { + String[] strs = {"eat", "tea", "tan", "ate", "nat", "bat"}; + + new Solution1().groupAnagrams(strs).forEach(list -> { + System.out.println(); + list.forEach(System.out::print); + }); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\240_III_220_\344\270\255\347\255\211/Solution1.java" "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\240_III_220_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..5af33bd9 --- /dev/null +++ "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\240_III_220_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,47 @@ +package cn.lastwhisper.leetcode.hashtable.存在重复元素_III_220_中等; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/contains-duplicate-iii/ + * 题意:nums [i] 和 nums [j] 的差的绝对值最大为 t,并且 i 和 j 之间的差的绝对值最大为 ķ + * ------------------------------------------------------------------- + * 思考: + * 数据特征: + * 输入:数组、无序、所有整数(long) + * 输出:boolean + * ------------------------------------------------------------------- + * 思路:双重for循环,满足k、t即可 + * ------------------------------------------------------------------- + * 时间复杂度:O(n*min(k,n)) + * 空间复杂度:O(1) + * ------------------------------------------------------------------- + * 执行用时 :510 ms, 在所有 Java 提交中击败了5.79%的用户 + * 内存消耗 :36.2 MB, 在所有 Java 提交中击败了98.89%的用户 + */ + public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) { + // 投机取巧,跳过耗时的测试用例 + //if(k==10000) return false; + + for (int i = 0; i < nums.length; i++) { + for (int j = i + 1; j <= i + k && j < nums.length; j++) { + if (Math.abs((long) nums[i] - (long) nums[j]) <= t) { + return true; + } + } + } + + return false; + } + + public static void main(String[] args) { + int[] nums = {1, 0, 1, 1}; + int k = 1, t = 2; + + //int[] nums = {1,2,3,1}; + //int k = 3, t = 0; + //int[] nums = {1, 5, 9, 1, 5, 9}; + //int k = 2, t = 3; + + System.out.println(new Solution1().containsNearbyAlmostDuplicate(nums, k, t)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\240_III_220_\344\270\255\347\255\211/Solution2.java" "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\240_III_220_\344\270\255\347\255\211/Solution2.java" new file mode 100644 index 00000000..47435020 --- /dev/null +++ "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\240_III_220_\344\270\255\347\255\211/Solution2.java" @@ -0,0 +1,54 @@ +package cn.lastwhisper.leetcode.hashtable.存在重复元素_III_220_中等; + +import java.util.TreeSet; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/contains-duplicate-iii/ + * 题意:nums [i] 和 nums [j] 的差的绝对值最大为 t,并且 i 和 j 之间的差的绝对值最大为 ķ + * ------------------------------------------------------------------- + * 思考: + * 数据特征: + * 输入:数组、无序、所有整数(long) + * 输出:boolean + * ------------------------------------------------------------------- + * 思路:在思路1中维护的滑动窗口中,找到满足t,需要线性搜索耗时O(o) + * 可以优化为维护一个BST,BST搜索耗时O(log(n)) + * ------------------------------------------------------------------- + * 时间复杂度:O(n*log(min(k,n))) + * 空间复杂度:O(min(k,n)) + * ------------------------------------------------------------------- + * 执行用时 :44 ms, 在所有 Java 提交中击败了25.79%的用户 + * 内存消耗 :36.9 MB, 在所有 Java 提交中击败了89.89%的用户 + */ + public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) { + TreeSet set = new TreeSet<>(); + for (int i = 0; i < nums.length; ++i) { + // Find the successor of current element + Long s = set.ceiling((long) nums[i]);//返回大于或等于给定键值的最小键值 + if (s != null && s - nums[i] <= t) return true; + + // Find the predecessor of current element + Long g = set.floor((long) nums[i]);//返回小于或等于给定键值的最大键值 + if (g != null && nums[i] - g <= t) return true; + + set.add((long) nums[i]); + if (set.size() > k) { + set.remove((long) nums[i - k]); + } + } + return false; + } + + public static void main(String[] args) { + int[] nums = {1, 0, 1, 1}; + int k = 1, t = 2;//true + + //int[] nums = {1,2,3,1};//true + //int k = 3, t = 0; + //int[] nums = {1, 5, 9, 1, 5, 9}; + //int k = 2, t = 3;//false + + System.out.println(new Solution2().containsNearbyAlmostDuplicate(nums, k, t)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\240_III_220_\344\270\255\347\255\211/Solution3.java" "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\240_III_220_\344\270\255\347\255\211/Solution3.java" new file mode 100644 index 00000000..4fd24c48 --- /dev/null +++ "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\240_III_220_\344\270\255\347\255\211/Solution3.java" @@ -0,0 +1,60 @@ +package cn.lastwhisper.leetcode.hashtable.存在重复元素_III_220_中等; + +import java.util.HashMap; +import java.util.Map; + +class Solution3 { + /** + * 题目地址:https://leetcode-cn.com/problems/contains-duplicate-iii/ + * 题意:nums [i] 和 nums [j] 的差的绝对值最大为 t,并且 i 和 j 之间的差的绝对值最大为 ķ + * ------------------------------------------------------------------- + * 思考: + * 数据特征: + * 输入:数组、无序、所有整数(long) + * 输出:boolean + * ------------------------------------------------------------------- + * 思路: + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + * ------------------------------------------------------------------- + */ + public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) { + if (t < 0) return false; + Map d = new HashMap<>(); + long w = (long) t + 1; + for (int i = 0; i < nums.length; ++i) { + long m = getID(nums[i], w); + // check if bucket m is empty, each bucket may contain at most one element + if (d.containsKey(m)) + return true; + // check the nei***or buckets for almost duplicate + if (d.containsKey(m - 1) && Math.abs(nums[i] - d.get(m - 1)) < w) + return true; + if (d.containsKey(m + 1) && Math.abs(nums[i] - d.get(m + 1)) < w) + return true; + // now bucket m is empty and no almost duplicate in nei***or buckets + d.put(m, (long) nums[i]); + if (i >= k) d.remove(getID(nums[i - k], w)); + } + return false; + } + + // Get the ID of the bucket from element value x and bucket width w + // In Java, `-3 / 5 = 0` and but we need `-3 / 5 = -1`. + private long getID(long x, long w) { + return x < 0 ? (x + 1) / w - 1 : x / w; + } + + public static void main(String[] args) { + int[] nums = {1, 0, 1, 1}; + int k = 1, t = 2;//true + + //int[] nums = {1,2,3,1};//true + //int k = 3, t = 0; + //int[] nums = {1, 5, 9, 1, 5, 9}; + //int k = 2, t = 3;//false + + System.out.println(new Solution3().containsNearbyAlmostDuplicate(nums, k, t)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\240_II_219_\347\256\200\345\215\225/Solution1.java" "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\240_II_219_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..163ecb0f --- /dev/null +++ "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\240_II_219_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,39 @@ +package cn.lastwhisper.leetcode.hashtable.存在重复元素_II_219_简单; + +import java.util.HashMap; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/contains-duplicate-ii/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:hash表记录值和下标,出现重复值,查看k是否符合下标相减 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(n) + */ + public boolean containsNearbyDuplicate(int[] nums, int k) { + // 投机取巧,跳过耗时的测试用例 + //if (k == 35000 || nums.length < 1) { + // return false; + //} + + HashMap map = new HashMap<>(); + for (int j = 0; j < nums.length; j++) { + Integer i = map.get(nums[j]); + // 以及存在,且k >= j - i + if (i != null && k >= j - i) { + return true; + } + map.put(nums[j], j); + } + return false; + } + + public static void main(String[] args) { + int[] nums = {1, 2, 3, 1}; + int k = 3; + System.out.println(new Solution1().containsNearbyDuplicate(nums, k)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\240_II_219_\347\256\200\345\215\225/Solution2.java" "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\240_II_219_\347\256\200\345\215\225/Solution2.java" new file mode 100644 index 00000000..9f5089bd --- /dev/null +++ "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\240_II_219_\347\256\200\345\215\225/Solution2.java" @@ -0,0 +1,43 @@ +package cn.lastwhisper.leetcode.hashtable.存在重复元素_II_219_简单; + +import java.util.ArrayDeque; +import java.util.Queue; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/contains-duplicate-ii/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:维持一个大小为k的队列,在队列大小中存在重复元素 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(n) + * ------------------------------------------------------------------- + */ + public boolean containsNearbyDuplicate(int[] nums, int k) { + // 投机取巧,跳过耗时的测试用例 + //if (k == 35000 || nums.length < 1) { + // return false; + //} + + Queue queue = new ArrayDeque<>(); + for (int num : nums) { + if (queue.contains(num)) { + return true; + } + queue.add(num); + // 维持队列大小 + if (queue.size() > k) { + queue.poll(); + } + } + return false; + } + + public static void main(String[] args) { + int[] nums = {1, 2, 3, 1}; + int k = 3; + System.out.println(new Solution2().containsNearbyDuplicate(nums, k)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\240_II_219_\347\256\200\345\215\225/Solution3.java" "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\240_II_219_\347\256\200\345\215\225/Solution3.java" new file mode 100644 index 00000000..91f1f1ca --- /dev/null +++ "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\240_II_219_\347\256\200\345\215\225/Solution3.java" @@ -0,0 +1,24 @@ +package cn.lastwhisper.leetcode.hashtable.存在重复元素_II_219_简单; + +class Solution3 { + /** + * 题目地址:https://leetcode-cn.com/problems/contains-duplicate-ii/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:维持一个大小为k的窗口,查看窗口中存在重复元素(滑动窗口解法) + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(n) + * ------------------------------------------------------------------- + */ + public boolean containsNearbyDuplicate(int[] nums, int k) { + return false; + } + + public static void main(String[] args) { + int[] nums = {1, 2, 3, 1}; + int k = 3; + System.out.println(new Solution3().containsNearbyDuplicate(nums, k)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\346\211\276\345\207\272\347\254\254k\345\260\217\347\232\204\350\267\235\347\246\273\345\257\271_719_\345\233\260\351\232\276/Solution1.java" "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\346\211\276\345\207\272\347\254\254k\345\260\217\347\232\204\350\267\235\347\246\273\345\257\271_719_\345\233\260\351\232\276/Solution1.java" new file mode 100644 index 00000000..65d20e9f --- /dev/null +++ "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\346\211\276\345\207\272\347\254\254k\345\260\217\347\232\204\350\267\235\347\246\273\345\257\271_719_\345\233\260\351\232\276/Solution1.java" @@ -0,0 +1,21 @@ +package cn.lastwhisper.leetcode.hashtable.找出第k小的距离对_719_困难; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/find-k-th-smallest-pair-distance/ + * ------------------------------------------------------------------- + * 思考: + * 数据特征: + * 输入: + * 输出: + * ------------------------------------------------------------------- + * 思路: + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public int smallestDistancePair(int[] nums, int k) { + + return 0; + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\346\213\274\345\206\231\345\215\225\350\257\215_1160_\347\256\200\345\215\225/Solution1.java" "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\346\213\274\345\206\231\345\215\225\350\257\215_1160_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..2f759693 --- /dev/null +++ "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\346\213\274\345\206\231\345\215\225\350\257\215_1160_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,51 @@ +package cn.lastwhisper.leetcode.hashtable.拼写单词_1160_简单; + +import org.junit.Assert; + +import java.util.Arrays; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/find-words-that-can-be-formed-by-characters/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * ------------------------------------------------------------------- + * 时间复杂度:O(n^2) + * 空间复杂度:O(n) + */ + public int countCharacters(String[] words, String chars) { + int[] charsFreq = new int[26]; + // 统计频率 + for (int i = 0; i < chars.length(); i++) { + charsFreq[chars.charAt(i) - 'a']++; + } + int ans = 0; + + int[] wordFreq = new int[26]; + for (String word : words) { + // 字母表必须比单词长,字母只许出现一次 + if (chars.length() >= word.length()) { + Arrays.fill(wordFreq, 0); + boolean flag = true; + for (int i = 0; i < word.length(); i++) { + wordFreq[word.charAt(i) - 'a']++; + // 先加,在比较 + if (wordFreq[word.charAt(i) - 'a'] > charsFreq[word.charAt(i) - 'a']) { + flag = false; + break; + } + } + if (flag) { + ans += word.length(); + } + } + } + return ans; + } + + public static void main(String[] args) { + Assert.assertEquals(6, new Solution1().countCharacters(new String[]{"cat", "bt", "hat", "tree"}, "atach")); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\346\234\200\346\216\245\350\277\221\347\232\204\344\270\211\346\225\260\344\271\213\345\222\214_16_Middle/Solution1.java" "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\346\234\200\346\216\245\350\277\221\347\232\204\344\270\211\346\225\260\344\271\213\345\222\214_16_Middle/Solution1.java" new file mode 100644 index 00000000..3426999d --- /dev/null +++ "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\346\234\200\346\216\245\350\277\221\347\232\204\344\270\211\346\225\260\344\271\213\345\222\214_16_Middle/Solution1.java" @@ -0,0 +1,65 @@ +package cn.lastwhisper.leetcode.hashtable.最接近的三数之和_16_Middle; + +import java.util.Arrays; + +class Solution1 { + + /** + * 题目地址:https://leetcode-cn.com/problems/3sum-closest/ + * ------------------------------------------------------------------- + * 思考: + * Q:什么叫做接近? + * A: abs((n1+n2+n3)-target)>abs((n2+n3+n4)-target) + * n2+n3+n4比n1+n2+n3接近target + * 数据特征: + * 输入:数组、无序、所有整数 + * 输出:整数 + * ------------------------------------------------------------------- + * 思路:在三数之和的基础上,理解什么叫做“接近”即可 + * ------------------------------------------------------------------- + * 时间复杂度:O(n^2) + * 空间复杂度:O(1): + * ------------------------------------------------------------------- + * 执行用时 :7 ms, 在所有 java 提交中击败了58.60%的用户 + * 内存消耗 :36.6 MB, 在所有 java 提交中击败了84.07%的用户 + */ + public int threeSumClosest(int[] nums, int target) { + + int closest = nums[0] + nums[1] + nums[2]; + // 数组排序2 + Arrays.sort(nums); + for (int i = 0; i < nums.length; i++) { + + if (i > 0 && nums[i] == nums[i - 1]) { + continue; // 对i去重 + } + + int l = i + 1, r = nums.length - 1; + while (l < r) { + int sum = nums[i] + nums[l] + nums[r]; + if (Math.abs(target - sum) < Math.abs(target - closest)) { + closest = sum; + } + + if (sum < target) { + l++; + } else if (sum > target) { + r--; + } else { + return closest; + } + + } + } + + return closest; + } + + public static void main(String[] args) { + //example + int[] nums = {-1, 2, 1, -4}; + int target = 1; + + System.out.println(new Solution1().threeSumClosest(nums, target)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\346\240\271\346\215\256\345\255\227\347\254\246\345\207\272\347\216\260\351\242\221\347\216\207\346\216\222\345\272\217_451_Middle/Solution1.java" "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\346\240\271\346\215\256\345\255\227\347\254\246\345\207\272\347\216\260\351\242\221\347\216\207\346\216\222\345\272\217_451_Middle/Solution1.java" index e6a2d912..4753700c 100644 --- "a/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\346\240\271\346\215\256\345\255\227\347\254\246\345\207\272\347\216\260\351\242\221\347\216\207\346\216\222\345\272\217_451_Middle/Solution1.java" +++ "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\346\240\271\346\215\256\345\255\227\347\254\246\345\207\272\347\216\260\351\242\221\347\216\207\346\216\222\345\272\217_451_Middle/Solution1.java" @@ -35,7 +35,7 @@ public String frequencySort(String s) { for (Map.Entry entry : map.entrySet()) { Integer freq = entry.getValue(); if (buckets[freq] == null) { - buckets[freq] = new ArrayList(); + buckets[freq] = new ArrayList<>(); } buckets[freq].add(entry.getKey()); } diff --git "a/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\347\233\264\347\272\277\344\270\212\346\234\200\345\244\232\347\232\204\347\202\271\346\225\260_149_\345\233\260\351\232\276/Solution1.java" "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\347\233\264\347\272\277\344\270\212\346\234\200\345\244\232\347\232\204\347\202\271\346\225\260_149_\345\233\260\351\232\276/Solution1.java" new file mode 100644 index 00000000..a0a8594c --- /dev/null +++ "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\347\233\264\347\272\277\344\270\212\346\234\200\345\244\232\347\232\204\347\202\271\346\225\260_149_\345\233\260\351\232\276/Solution1.java" @@ -0,0 +1,126 @@ +package cn.lastwhisper.leetcode.hashtable.直线上最多的点数_149_困难; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/max-points-on-a-line/ + * ------------------------------------------------------------------- + * 思路:暴力解法,任意取两个点构成一条直线,判断其它点在不在这个直线上(斜率) + * ------------------------------------------------------------------- + * 思考: + * 1、统计斜率相同且点不同的点数,并输出最大的点数 + * 2、Q:计算斜率时如何保证浮点数的精确度? + * A:(1)将除法意义转为乘法 + * Q:如何保证乘法不溢出?(65535*65535) + * A:long、BigInteger + * (2)将直接除法转为求分子分母同时除以(分子分母的)最大公约数后,等式两边分子分母是否同时相等问题 + * ------------------------------------------------------------------- + * 时间复杂度:O(n^3) + * 空间复杂度:O(1) + * ------------------------------------------------------------------- + * 执行用时 :24 ms, 在所有 Java 提交中击败了42.54%的用户 + * 内存消耗 :34.5 MB, 在所有 Java 提交中击败了82.67%的用户 + */ + public int maxPoints(int[][] points) { + // 特殊情况一:0、1、2个点,直接返回点数 + if (points.length < 3) { + return points.length; + } + + // 特殊情况二:全为相同的点,直接返回点数 + int equalNum = 0; + for (; equalNum < points.length - 1; equalNum++) { + if (points[equalNum][0] != points[equalNum + 1][0] || points[equalNum][1] != points[equalNum + 1][1]) { + break; + } + } + if (equalNum == points.length - 1) { + return points.length; + } + + int max = 0; + for (int i = 0; i < points.length; i++) { + // 防止数组下标相同i==j时,ij并不构成一根直线 + for (int j = i + 1; j < points.length; j++) { + // 防止数组值相同arr[i]==arr[j]时,ij并不构成一根直线 + if (points[i][0] == points[j][0] && points[i][1] == points[j][1]) { + continue; + } + // 前两层循环构成直线 + int record = 2; + for (int k = 0; k < points.length; k++) { + // 防止数组下标相同k==i或者k==j时,仅剩两个点(i=0j=2k=0、i=1j=2k=2) + if (k != i && k != j) { + if (isExist(points[i][0], points[i][1], points[j][0] + , points[j][1], points[k][0], points[k][1])) { + record++; + } + } + } + if (record > max) { + max = record; + } + } + } + // 加上直线本身的两个点 + return max; + } + + /** + * 判断一个点是否在一条直线上 + */ + //private boolean isExist(int x1, int y1, int x2, int y2, int x, int y) { + // return (y2 - y1) * (x - x2) == (y - y2) * (x2 - x1); + //} + + private boolean isExist(long x1, long y1, long x2, long y2, long x, long y) { + return (y2 - y1) * (x - x2) == (y - y2) * (x2 - x1); + } + + //private boolean isExist(int x1, int y1, int x2, int y2, int x, int y) { + // BigInteger x11 = BigInteger.valueOf(x1); + // BigInteger x22 = BigInteger.valueOf(x2); + // BigInteger y11 = BigInteger.valueOf(y1); + // BigInteger y22 = BigInteger.valueOf(y2); + // BigInteger x0 = BigInteger.valueOf(x); + // BigInteger y0 = BigInteger.valueOf(y); + // return y22.subtract(y11).multiply(x0.subtract(x22)).equals(y0.subtract(y22).multiply(x22.subtract(x11))); + //} + + //private boolean isExist(int x1, int y1, int x2, int y2, int x, int y) { + // int g1 = gcdlcm(y2 - y1, x2 - x1); + // if(y == y2 && x == x2){ + // return true; + // } + // int g2 = gcdlcm(y - y2, x - x2); + // return (y2 - y1) / g1 == (y - y2) / g2 && (x2 - x1) / g1 == (x - x2) / g2; + //} + + + /** + * 求a、b最大公约数 + */ + private int gcd(int a, int b) { + while (b != 0) { + int temp = a % b; + a = b; + b = temp; + } + return a; + } + + + public static void main(String[] args) { + // example + //int[][] points = {{1, 1}, {2, 2}, {3, 3}}; + // error example + //int[][] points = {{0, 0}}; + //int[][] points = {{0, 0}, {0, 0}}; + //int[][] points = {{0, 0}, {0, 0}, {0, 0}}; + //int[][] points = {{0, 0}, {1, 65536}, {65536, 0}}; + int[][] points = {{1, 1}, {1, 1}, {2, 3}}; + System.out.println(new Solution1().maxPoints(points)); + + //System.out.println(new Solution1().isExist(3, 3, 2, 2, 1, 1)); + } +} + diff --git "a/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\347\233\264\347\272\277\344\270\212\346\234\200\345\244\232\347\232\204\347\202\271\346\225\260_149_\345\233\260\351\232\276/Solution2.java" "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\347\233\264\347\272\277\344\270\212\346\234\200\345\244\232\347\232\204\347\202\271\346\225\260_149_\345\233\260\351\232\276/Solution2.java" new file mode 100644 index 00000000..4045a88a --- /dev/null +++ "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\347\233\264\347\272\277\344\270\212\346\234\200\345\244\232\347\232\204\347\202\271\346\225\260_149_\345\233\260\351\232\276/Solution2.java" @@ -0,0 +1,119 @@ +package cn.lastwhisper.leetcode.hashtable.直线上最多的点数_149_困难; + +import java.util.HashSet; +import java.util.Set; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/max-points-on-a-line/ + * ------------------------------------------------------------------- + * 思考:虽然已经保证ij一定构成一条直线,但是ij会重复出现。 + * ------------------------------------------------------------------- + * 思路:基于思路1,使用Hash表记录暴力解法中已经出现的直线。 + * 利用"斜截式"求得直线的k、b,将k、b拼接放入Hash表 + * ------------------------------------------------------------------- + * 时间复杂度:O(n^3) + * 空间复杂度:O(1) + * ------------------------------------------------------------------- + * 执行用时 :78 ms, 在所有 Java 提交中击败了7.91%的用户 + * 内存消耗 :39.2 MB, 在所有 Java 提交中击败了44.56%的用户 + */ + public int maxPoints(int[][] points) { + // 特殊情况一:0、1、2个点,直接返回点数 + if (points.length < 3) { + return points.length; + } + + // 特殊情况二:全为相同的点,直接返回点数 + int equalNum = 0; + for (; equalNum < points.length - 1; equalNum++) { + if (points[equalNum][0] != points[equalNum + 1][0] || points[equalNum][1] != points[equalNum + 1][1]) { + break; + } + } + if (equalNum == points.length - 1) { + return points.length; + } + + Set hash = new HashSet<>(); + + int max = 0; + for (int i = 0; i < points.length; i++) { + // 防止数组下标相同i==j时,ij并不构成一根直线 + for (int j = i + 1; j < points.length; j++) { + // 防止数组值相同arr[i]==arr[j]时,ij并不构成一根直线 + if (points[i][0] == points[j][0] && points[i][1] == points[j][1]) { + continue; + } + + String key = getK(points[i][0], points[i][1], points[j][0], points[j][1]) + + "@" + + getB(points[i][0], points[i][1], points[j][0], points[j][1]); + if (hash.contains(key)) { + continue; + } + + hash.add(key); + + // 前两层循环构成直线 + int record = 2; + for (int k = 0; k < points.length; k++) { + // 防止数组下标相同k==i或者k==j时,仅剩两个点(i=0j=2k=0、i=1j=2k=2) + if (k != i && k != j) { + if (isExist(points[i][0], points[i][1], points[j][0] + , points[j][1], points[k][0], points[k][1])) { + record++; + } + } + } + if (record > max) { + max = record; + } + } + } + // 加上直线本身的两个点 + return max; + } + + /** + * 一个点是否在一条直线上 + */ + private boolean isExist(long x1, long y1, long x2, long y2, long x, long y) { + return (y2 - y1) * (x - x2) == (y - y2) * (x2 - x1); + } + + /** + * 点斜式常数b + */ + private double getB(int x1, int y1, int x2, int y2) { + if (y2 == y1) { + return Double.POSITIVE_INFINITY; + } + return (double) (x2 - x1) * (-y1) / (y2 - y1) + x1; + } + + /** + * 点斜式斜率k + */ + private double getK(int x1, int y1, int x2, int y2) { + if (x2 - x1 == 0) { + return Double.POSITIVE_INFINITY; + } + return (double) (y2 - y1) / (x2 - x1); + } + + public static void main(String[] args) { + // example + //int[][] points = {{1, 1}, {2, 2}, {3, 3}}; + // error example + //int[][] points = {{0, 0}}; + //int[][] points = {{0, 0}, {0, 0}}; + //int[][] points = {{0, 0}, {0, 0}, {0, 0}}; + //int[][] points = {{0, 0}, {1, 65536}, {65536, 0}}; + int[][] points = {{1, 1}, {1, 1}, {2, 3}}; + System.out.println(new Solution2().maxPoints(points)); + + //System.out.println(new Solution1().isExist(3, 3, 2, 2, 1, 1)); + } +} + diff --git "a/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\347\233\264\347\272\277\344\270\212\346\234\200\345\244\232\347\232\204\347\202\271\346\225\260_149_\345\233\260\351\232\276/Solution3.java" "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\347\233\264\347\272\277\344\270\212\346\234\200\345\244\232\347\232\204\347\202\271\346\225\260_149_\345\233\260\351\232\276/Solution3.java" new file mode 100644 index 00000000..0c71c9d7 --- /dev/null +++ "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\347\233\264\347\272\277\344\270\212\346\234\200\345\244\232\347\232\204\347\202\271\346\225\260_149_\345\233\260\351\232\276/Solution3.java" @@ -0,0 +1,81 @@ +package cn.lastwhisper.leetcode.hashtable.直线上最多的点数_149_困难; + +import java.util.HashMap; +import java.util.Map; + +class Solution3 { + /** + * 题目地址:https://leetcode-cn.com/problems/max-points-on-a-line/ + * ------------------------------------------------------------------- + * 思考:统计斜率相同的点 + * ------------------------------------------------------------------- + * 思路: + * Q:计算斜率时如何保证浮点数的精确度? + * A:将斜率换成x、y相关的字符串 + * ------------------------------------------------------------------- + * 时间复杂度:O(n^2) + * 空间复杂度:O(1) + * ------------------------------------------------------------------- + * 执行用时 :20 ms, 在所有 Java 提交中击败了68.23%的用户 + * 内存消耗 :36.2 MB, 在所有 Java 提交中击败了61.39%的用户 + */ + public int maxPoints(int[][] points) { + if (points.length < 3) { + return points.length; + } + int res = 0; + //遍历每个点 + for (int i = 0; i < points.length; i++) { + int duplicate = 0; + int max = 0;//保存经过当前点的直线中,最多的点 + Map map = new HashMap<>(); + for (int j = i + 1; j < points.length; j++) { + //求出分子分母 + int x = points[j][0] - points[i][0]; + int y = points[j][1] - points[i][1]; + // 相同点 + if (x == 0 && y == 0) { + duplicate++; + continue; + } + //进行约分 + int gcd = gcd(x, y); + x = x / gcd; + y = y / gcd; + String key = x + "@" + y; + map.put(key, map.getOrDefault(key, 0) + 1); + max = Math.max(max, map.get(key)); + } + //1 代表当前考虑的点,duplicate 代表和当前的点重复的点 + res = Math.max(res, max + duplicate + 1); + } + return res; + } + + /** + * 求a、b最大公约数 + */ + private int gcd(int a, int b) { + while (b != 0) { + int temp = a % b; + a = b; + b = temp; + } + return a; + } + + public static void main(String[] args) { + // example + //int[][] points = {{1, 1}, {2, 2}, {3, 3}}; + // error example + //int[][] points = {{0, 0}}; + //int[][] points = {{0, 0}, {0, 0}}; + //int[][] points = {{0, 0}, {0, 0}, {0, 0}}; + //int[][] points = {{0, 0}, {1, 65536}, {65536, 0}}; + int[][] points = {{1, 1}, {1, 1}, {2, 3}}; + System.out.println(new Solution3().maxPoints(points)); + + //System.out.println(new Solution3().gcdlcm(3,6)); + } +} + diff --git "a/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\351\225\277\345\233\236\346\226\207\344\270\262_409_\347\256\200\345\215\225/Solution1.java" "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\351\225\277\345\233\236\346\226\207\344\270\262_409_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..ffe0ae4c --- /dev/null +++ "b/algorithms/leetcode/hashtable/src/main/java/cn/lastwhisper/leetcode/hashtable/\351\225\277\345\233\236\346\226\207\344\270\262_409_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,43 @@ +package cn.lastwhisper.leetcode.hashtable.长回文串_409_简单; + +import org.junit.Assert; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/longest-palindrome/ + * ------------------------------------------------------------------- + * 思路: + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + * ------------------------------------------------------------------- + */ + public int longestPalindrome(String s) { + int[] freq = new int[58]; + for (int i = 0; i < s.length(); i++) { + freq[s.charAt(i) - 'A']++; + } + int ans = 0; + for (int num : freq) { + // 偶数直接可以组成回文串,奇数取最大偶数组成回文串 + //不等价 if (num != 0) ans += num;return ans ; + //简写 if (num != 0) ans += num - (num & 1); + if (num != 0) { + if (num % 2 == 0) { + ans += num; + } else { + ans += num - 1;//大于1的奇数串只取偶数个,return补偿 + } + } + } + return ans < s.length() ? ans + 1 : ans; + } + + public static void main(String[] args) { + //Assert.assertEquals(7, new Solution1().longestPalindrome("abccccdd")); + Assert.assertEquals(3, new Solution1().longestPalindrome("ccc")); + } + +} \ No newline at end of file diff --git a/algorithms/leetcode/leetcode-common/pom.xml b/algorithms/leetcode/leetcode-common/pom.xml new file mode 100644 index 00000000..9fc1cf2e --- /dev/null +++ b/algorithms/leetcode/leetcode-common/pom.xml @@ -0,0 +1,15 @@ + + + + leetcode + cn.lastwhisper + 1.0-SNAPSHOT + + 4.0.0 + + leetcode-common + + + \ No newline at end of file diff --git a/algorithms/leetcode/leetcode-common/src/main/java/cn/lastwhisper/leetcode/common/array/ArrayUtil.java b/algorithms/leetcode/leetcode-common/src/main/java/cn/lastwhisper/leetcode/common/array/ArrayUtil.java new file mode 100644 index 00000000..70e5f2bc --- /dev/null +++ b/algorithms/leetcode/leetcode-common/src/main/java/cn/lastwhisper/leetcode/common/array/ArrayUtil.java @@ -0,0 +1,72 @@ +package cn.lastwhisper.leetcode.common.array; + +import java.util.ArrayList; +import java.util.List; + +/** + * + * @author lastwhisper + * @date 2020/2/4 + */ +public class ArrayUtil { + + /** + * {"ab","cd"}=> + * 创建二维字符数组 + */ + public static char[][] createCharArrays(String[] arr) { + int m = arr.length, n = arr[0].length(); + char[][] chars = new char[m][n]; + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + chars[i][j] = arr[i].charAt(j); + } + } + return chars; + } + + /** + * {{"a","b","c","d"}}=> + * 创建二维字符数组 + */ + public static char[][] createCharArrays(String[][] arr) { + int m = arr.length, n = arr[0].length; + char[][] chars = new char[m][n]; + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + chars[i][j] = arr[i][j].charAt(0); + } + } + return chars; + } + + /** + * 创建二维数组 + */ + public static int[][] createIntArrays(String[] arr) { + int m = arr.length, n = arr[0].length(); + int[][] ints = new int[m][n]; + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + ints[i][j] = arr[i].charAt(j) - '0'; + } + } + return ints; + } + + + /** + * 创建list + */ + public static List> createList(int[][] arrays) { + List> lists = new ArrayList<>(arrays.length); + for (int[] array : arrays) { + List list = new ArrayList<>(array.length); + for (int num : array) { + list.add(num); + } + lists.add(list); + } + return lists; + } +} diff --git a/algorithms/leetcode/leetcode-common/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/LinkedListUtil.java b/algorithms/leetcode/leetcode-common/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/LinkedListUtil.java new file mode 100644 index 00000000..de66fc6c --- /dev/null +++ b/algorithms/leetcode/leetcode-common/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/LinkedListUtil.java @@ -0,0 +1,151 @@ +package cn.lastwhisper.leetcode.common.linkedlist; + + +import java.util.ArrayList; +import java.util.List; + +/** + * 操作链表工具类 + * @author lastwhisper + * @date 1/7/2020 + */ +public class LinkedListUtil { + + /** + * 创建单链表 + */ + public static ListNode createListNode(int... arr) { + if (arr == null) { + return null; + } + ListNode head = new ListNode(arr[0]); + ListNode current = head; + + for (int i = 1; i < arr.length; i++) { + current.next = new ListNode(arr[i]); + current = current.next; + } + return head; + } + + /** + * 创建环形链表 + * 应用题目:https://leetcode-cn.com/problems/linked-list-cycle/ + * @param pos 成环位置 + * @param arr 链表元素 + */ + public static ListNode createLoopListNode(int pos, int... arr) { + if (arr == null) { + return null; + } + ListNode head = new ListNode(arr[0]); + ListNode current = head; + // 锚点,记录成环的位置 + ListNode anchor = null; + if (pos == 0) { + anchor = head; + } + for (int i = 1; i < arr.length; i++) { + current.next = new ListNode(arr[i]); + // 记录成环位置 + if (pos == i) { + if (pos == arr.length - 1) { + anchor = current; + } else { + anchor = current.next; + } + } + current = current.next; + } + current.next = anchor; + return head; + } + + /** + * 创建两个相交链表 + * 应用题目:https://leetcode-cn.com/problems/intersection-of-two-linked-lists/ + * @param intersectVal 相交点的值 + * @param listA 链表A元素数组 + * @param listB 链表B元素数组 + * @param skipA 链表A相交前节点数 + * @param skipB 链表B相交前节点数 + */ + public static List createIntersectListNode( + int intersectVal, int[] listA, int[] listB, int skipA, int skipB) { + List listNodes = new ArrayList<>(2); + + ListNode listNodeA = new ListNode(listA[0]); + ListNode currentA = listNodeA; + ListNode listNodeB = new ListNode(listB[0]); + ListNode currentB = listNodeB; + + for (int i = 1; i < skipA; i++) { + currentA.next = new ListNode(listA[i]); + currentA = currentA.next; + } + + for (int i = 1; i < skipB; i++) { + currentB.next = new ListNode(listB[i]); + currentB = currentB.next; + } + + ListNode intersectListNode = new ListNode(listA[skipA]); + ListNode currentIntersect = intersectListNode; + + for (int i = skipA + 1; i < listA.length; i++) { + currentIntersect.next = new ListNode(listA[i]); + currentIntersect = currentIntersect.next; + } + + currentA.next = intersectListNode; + currentB.next = intersectListNode; + + listNodes.add(listNodeA); + listNodes.add(listNodeB); + + return listNodes; + } + + + /** + * 打印单链表 + */ + public static void printListNode(String msg, ListNode head) { + System.out.println(msg + appendVal(head)); + } + + /** + * 打印单链表 + */ + public static void printListNode(ListNode head) { + System.out.println(appendVal(head)); + } + + private static String appendVal(ListNode head) { + StringBuilder sb = new StringBuilder(); + ListNode current = head; + while (current != null) { + sb.append(current.val); + sb.append("->"); + current = current.next; + } + sb.append("NULL"); + return sb.toString(); + } + + + public static void main(String[] args) { + //printListNode(createListNode(1, 2, 3, 4, 5, 6, 7)); + //ListNode headLoop = createLoopListNode(0, 4, 5, 6); + //ListNode centerLoop = createLoopListNode(1, 4, 5, 6); + + int intersectVal = 8, skipA = 2, skipB = 3; + int[] listA = {4, 1, 8, 4, 5}; + int[] listB = {5, 0, 1, 8, 4, 5}; + List intersectListNode = createIntersectListNode(intersectVal, listA, listB, skipA, skipB); + for (ListNode listNode : intersectListNode) { + printListNode(listNode); + } + + } +} diff --git a/algorithms/leetcode/leetcode-common/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/ListNode.java b/algorithms/leetcode/leetcode-common/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/ListNode.java new file mode 100644 index 00000000..4d78a4b2 --- /dev/null +++ b/algorithms/leetcode/leetcode-common/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/ListNode.java @@ -0,0 +1,11 @@ +package cn.lastwhisper.leetcode.common.linkedlist; + +public class ListNode { + public int val; + public ListNode next; + + public ListNode(int x) { + val = x; + } + +} \ No newline at end of file diff --git a/algorithms/leetcode/leetcode-common/src/main/java/cn/lastwhisper/leetcode/common/print/PrintUtil.java b/algorithms/leetcode/leetcode-common/src/main/java/cn/lastwhisper/leetcode/common/print/PrintUtil.java new file mode 100644 index 00000000..cbed2538 --- /dev/null +++ b/algorithms/leetcode/leetcode-common/src/main/java/cn/lastwhisper/leetcode/common/print/PrintUtil.java @@ -0,0 +1,93 @@ +package cn.lastwhisper.leetcode.common.print; + +import java.util.Collection; +import java.util.List; + + +/** + * 打印工具类 + * @author lastwhisper + * @date 2020/2/1 + */ +public class PrintUtil { + + /** + * 层次打印二维数组 + */ + public static void printLists(List> lists) { + System.out.println("["); + int counter1 = 1; + for (List list : lists) { + System.out.print("\t[\""); + int counter2 = 1; + for (Integer i : list) { + if (counter2 != list.size()) { + System.out.print(i + "\",\""); + } else { + System.out.print(i); + } + counter2++; + } + if (counter1 != lists.size()) { + System.out.print("\"],\n"); + } else { + System.out.print("\"]\n"); + } + counter1++; + } + System.out.println("]"); + } + + public static void printStringLists(List> lists) { + System.out.println("["); + int counter1 = 1; + for (List list : lists) { + System.out.print("\t[\""); + int counter2 = 1; + for (String i : list) { + if (counter2 != list.size()) { + System.out.print(i + "\",\""); + } else { + System.out.print(i ); + } + counter2++; + } + if (counter1 != lists.size()) { + System.out.print("\"],\n"); + } else { + System.out.print("\"]\n"); + } + counter1++; + } + System.out.println("]"); + } + + /** + * 打印数组 + */ + public static void printList(Collection collection) { + System.out.println(collection2String(collection)); + } + + /** + * 将Collection扁平化迭代成String + */ + public static String collection2String(Collection collection) { + StringBuilder sb = new StringBuilder(); + try { + sb.append("[\""); + int counter = 1; + for (Object object : collection) { + sb.append(object); + if (counter != collection.size()) { + sb.append("\",\""); + } + counter++; + } + sb.append("\"]"); + } catch (Exception e) { + e.printStackTrace(); + } + return sb.toString(); + } +} diff --git a/algorithms/leetcode/leetcode-common/src/main/java/cn/lastwhisper/leetcode/common/tree/TreeNode.java b/algorithms/leetcode/leetcode-common/src/main/java/cn/lastwhisper/leetcode/common/tree/TreeNode.java new file mode 100644 index 00000000..273e04b9 --- /dev/null +++ b/algorithms/leetcode/leetcode-common/src/main/java/cn/lastwhisper/leetcode/common/tree/TreeNode.java @@ -0,0 +1,11 @@ +package cn.lastwhisper.leetcode.common.tree; + +public class TreeNode { + public int val; + public TreeNode left; + public TreeNode right; + + public TreeNode(int x) { + val = x; + } +} \ No newline at end of file diff --git a/algorithms/leetcode/leetcode-common/src/main/java/cn/lastwhisper/leetcode/common/tree/TreeUtil.java b/algorithms/leetcode/leetcode-common/src/main/java/cn/lastwhisper/leetcode/common/tree/TreeUtil.java new file mode 100644 index 00000000..b3a6dbab --- /dev/null +++ b/algorithms/leetcode/leetcode-common/src/main/java/cn/lastwhisper/leetcode/common/tree/TreeUtil.java @@ -0,0 +1,258 @@ +package cn.lastwhisper.leetcode.common.tree; + +import javafx.util.Pair; + +import java.util.*; + +import static cn.lastwhisper.leetcode.common.print.PrintUtil.printLists; + +/** + * 树相关工具类 + * @author lastwhisper + * @date 1/16/2020 + */ +public class TreeUtil { + + /** + * 根据数组创建二叉树 + * 一、[5,4,8,11,null,13,4,7,2,null,null,null,1] + * 5 + * / \ + * 4 8 + * / / \ + * 11 13 4 + * / \ \ + * 7 2 1 + * 二、[1,null,2,3] + * 1 + * \ + * 2 + * / + * 3 + * https://blog.csdn.net/lenfranky/article/details/84444816 + * @param array 数组 + */ + public static TreeNode createTree(Integer... array) { + if (array.length == 0) return new TreeNode(0); + Deque nodeQueue = new LinkedList<>(); + // 创建一个根节点 + TreeNode root = new TreeNode(array[0]); + nodeQueue.offer(root); + TreeNode current; + // 记录当前行节点的数量(注意不一定是2的幂,而是上一行中非空节点的数量乘2) + int lineNodeNum = 2; + // 记录当前行中数字在数组中的开始位置 + int startIndex = 1; + // 记录数组中剩余的元素的数量 + int restLength = array.length - 1; + + while (restLength > 0) { + // 只有最后一行可以不满,其余行必须是满的 +// // 若输入的数组的数量是错误的,直接跳出程序 +// if (restLength < lineNodeNum) { +// System.out.println("Wrong Input!"); +// return new TreeNode(0); +// } + for (int i = startIndex; i < startIndex + lineNodeNum; i = i + 2) { + // 说明已经将nums中的数字用完,此时应停止遍历,并可以直接返回root + if (i == array.length) return root; + current = nodeQueue.poll(); + if (array[i] != null) { + current.left = new TreeNode(array[i]); + nodeQueue.offer(current.left); + } + // 同上,说明已经将nums中的数字用完,此时应停止遍历,并可以直接返回root + if (i + 1 == array.length) return root; + if (array[i + 1] != null) { + current.right = new TreeNode(array[i + 1]); + nodeQueue.offer(current.right); + } + } + startIndex += lineNodeNum; + restLength -= lineNodeNum; + lineNodeNum = nodeQueue.size() * 2; + } + + return root; + } + + /** + * 二叉树层次遍历 + */ + public static List> levelOrder(TreeNode root) { + List> result = new ArrayList<>(); + if (root == null) + return result; + + Queue queue = new LinkedList<>(); + queue.add(root); + while (!queue.isEmpty()) { + // 遍历每层的数据 + int size = queue.size(); + List list = new ArrayList<>(); + while (size > 0) { + root = queue.poll(); + list.add(root.val); + if (root.left != null) { + queue.add(root.left); + } + if (root.right != null) { + queue.add(root.right); + } + size--; + } + result.add(list); + } + return result; + } + + /** + * 相同的树 + * + * + * 输入: 1 1 + * / \ / \ + * 2 3 2 3 + * + * [1,2,3], [1,2,3] + * + * 输出: true + */ + public static boolean isSameTree(TreeNode p, TreeNode q) { + LinkedList queue = new LinkedList<>(); + queue.add(p); + queue.add(q); + while (!queue.isEmpty()) { + p = queue.poll(); + q = queue.poll(); + + if (p == null && q == null) continue; + if (p == null || q == null) return false; + if (p.val != q.val) return false; + + queue.add(p.left); + queue.add(q.left); + queue.add(p.right); + queue.add(q.right); + } + return true; + } + + /** + * 完全二叉树的左子树或右子树的高度 + * + * @param root 根节点的左子树或右子树 + * @return int 高度 + */ + private int countLevel(TreeNode root) { + int level = 0; + while (root != null) { + level++; + root = root.left; + } + return level; + } + + /** + * 所有节点之和 + * + * @param root + * @return int + */ + public int sumOfLeaves(TreeNode root) { + if (root == null) { + return 0; + } + return sumOfLeaves(root.left) + sumOfLeaves(root.right) + root.val; + } + + /** + * 二叉树根节点至叶子节点的最高高度 + * + * @param root 根节点 + * @return int 高度 + */ + public int maxDepth(TreeNode root) { + LinkedList> stack = new LinkedList<>(); + if (root != null) { + stack.push(new Pair<>(root, 0)); + } + int maxDepth = 0; + // stack模拟递归系统栈 + while (!stack.isEmpty()) { + Pair pair = stack.poll(); + root = pair.getKey(); + Integer height = pair.getValue(); + // dfs过程中更新最大深度 + maxDepth = Math.max(maxDepth, height); + if (root != null) { + stack.push(new Pair<>(root.right, height + 1)); + stack.push(new Pair<>(root.left, height + 1)); + } + } + return maxDepth; + } + + /** + * 二叉树根节点至叶子节点的最小高度 + * + * @param root 根节点 + * @return int 高度 + */ + public int minDepth(TreeNode root) { + if (root == null) { + return 0; + } + LinkedList> queue = new LinkedList<>(); + queue.add(new Pair<>(root, 1)); + + // 当前深度 + int currentDepth = 0; + Pair pair = null; + while (!queue.isEmpty()) { + pair = queue.poll(); + root = pair.getKey(); + currentDepth = pair.getValue(); + // 找到层中第一个叶子节点 + if (root.left == null && root.right == null) { + break; + } + if (root.left != null) { + queue.add(new Pair<>(root.left, currentDepth + 1)); + } + if (root.right != null) { + queue.add(new Pair<>(root.right, currentDepth + 1)); + } + + } + return currentDepth; + } + + /** + * 反转二叉树 + * + * @param root 根节点 + */ + public TreeNode invertTree(TreeNode root) { + if (root == null) + return null; + // 翻转当前节点的左右子节点 + TreeNode tempNode = root.left; + root.left = invertTree(root.right); + root.right = invertTree(tempNode); + return root; + } + + /** + * 输出二叉树层次遍历的结果 + */ + public static void printLevelOrder(TreeNode root) { + printLists(levelOrder(root)); + } + + public static void main(String[] args) { + printLevelOrder(createTree(1, null, 2, 3)); + //printLevelOrder(createTree(5, 4, 8, 11, null, 13, 4, 7, 2, null, null, null, 1)); + //printLevelOrder(createTree(1,2,3,null,4,5,null)); + } +} diff --git a/algorithms/leetcode/leetcode-common/src/main/java/cn/lastwhisper/leetcode/common/tree/TrieNode.java b/algorithms/leetcode/leetcode-common/src/main/java/cn/lastwhisper/leetcode/common/tree/TrieNode.java new file mode 100644 index 00000000..f2f2ceea --- /dev/null +++ b/algorithms/leetcode/leetcode-common/src/main/java/cn/lastwhisper/leetcode/common/tree/TrieNode.java @@ -0,0 +1,34 @@ +package cn.lastwhisper.leetcode.common.tree; + +public class TrieNode { + + private final int R = 26; + // 不存储真实的值,TrieNode[]中不为null表示存在 + private TrieNode[] links; + private boolean isEnd; + + public TrieNode() { + links = new TrieNode[R]; + } + + + public boolean containsKey(char ch) { + return links[ch - 'a'] != null; + } + + public TrieNode get(char ch) { + return links[ch - 'a']; + } + + public void put(char ch, TrieNode node) { + links[ch - 'a'] = node; + } + + public void setEnd() { + isEnd = true; + } + + public boolean isEnd() { + return isEnd; + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/leetcode\345\244\247\347\272\262.md" "b/algorithms/leetcode/leetcode\345\244\247\347\272\262.md" new file mode 100644 index 00000000..c2f29500 --- /dev/null +++ "b/algorithms/leetcode/leetcode\345\244\247\347\272\262.md" @@ -0,0 +1,4 @@ +双指针(快慢指针) 283、27、26、80、202 +滑动窗口 209、3、438、76 +对撞指针 167、125、344、345、11 +快速排序 75、 diff --git a/algorithms/leetcode/linkedlist/README.MD b/algorithms/leetcode/linkedlist/README.MD new file mode 100644 index 00000000..e69de29b diff --git a/algorithms/leetcode/linkedlist/pom.xml b/algorithms/leetcode/linkedlist/pom.xml index 27f7a73d..89eaf113 100644 --- a/algorithms/leetcode/linkedlist/pom.xml +++ b/algorithms/leetcode/linkedlist/pom.xml @@ -12,5 +12,11 @@ cn.lastwhisper.leetcode linkedlist - + + + cn.lastwhisper + leetcode-common + 1.0-SNAPSHOT + + \ No newline at end of file diff --git "a/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\344\270\244\344\270\244\344\272\244\346\215\242\351\223\276\350\241\250\344\270\255\347\232\204\350\212\202\347\202\271_24_\344\270\255\347\255\211/Solution1.java" "b/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\344\270\244\344\270\244\344\272\244\346\215\242\351\223\276\350\241\250\344\270\255\347\232\204\350\212\202\347\202\271_24_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..32309b48 --- /dev/null +++ "b/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\344\270\244\344\270\244\344\272\244\346\215\242\351\223\276\350\241\250\344\270\255\347\232\204\350\212\202\347\202\271_24_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,42 @@ +package cn.lastwhisper.leetcode.common.linkedlist.两两交换链表中的节点_24_中等; + +import cn.lastwhisper.leetcode.common.linkedlist.ListNode; + +import static cn.lastwhisper.leetcode.common.linkedlist.LinkedListUtil.createListNode; +import static cn.lastwhisper.leetcode.common.linkedlist.LinkedListUtil.printListNode; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/swap-nodes-in-pairs/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public ListNode swapPairs(ListNode head) { + + ListNode dummyHead = new ListNode(0); + dummyHead.next = head; + + ListNode p = dummyHead; + while(p.next != null && p.next.next != null ){ + ListNode node1 = p.next; + ListNode node2 = node1.next; + ListNode next = node2.next; + node2.next = node1; + node1.next = next; + p.next = node2; + p = node1; + } + + return dummyHead.next; + } + + public static void main(String[] args) { + int[] arr = {1, 2, 3, 4}; + printListNode(new Solution1().swapPairs(createListNode(arr))); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\344\270\244\346\225\260\347\233\270\345\212\240_2_\344\270\255\347\255\211/Solution1.java" "b/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\344\270\244\346\225\260\347\233\270\345\212\240_2_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..e47d6612 --- /dev/null +++ "b/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\344\270\244\346\225\260\347\233\270\345\212\240_2_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,64 @@ +package cn.lastwhisper.leetcode.common.linkedlist.两数相加_2_中等; + +import cn.lastwhisper.leetcode.common.linkedlist.ListNode; + + +import static cn.lastwhisper.leetcode.common.linkedlist.LinkedListUtil.createListNode; +import static cn.lastwhisper.leetcode.common.linkedlist.LinkedListUtil.printListNode; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/add-two-numbers/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:将链表转成正常的数字后,相加,然后反转; + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(n) + */ + public ListNode addTwoNumbers(ListNode l1, ListNode l2) { + StringBuilder numStr1 = new StringBuilder(); + StringBuilder numStr2 = new StringBuilder(); + + while (l1 != null) { + numStr1.append(l1.val); + l1 = l1.next; + } + while (l2 != null) { + numStr2.append(l2.val); + l2 = l2.next; + } + java.math.BigInteger num1 = new java.math.BigInteger(numStr1.reverse().toString()); + java.math.BigInteger num2 = new java.math.BigInteger(numStr2.reverse().toString()); + + String sum = String.valueOf(num1.add(num2)); + + return createReverseListNode(sum); + } + + private static ListNode createReverseListNode(String arr) { + if (arr == null) { + return null; + } + ListNode head = new ListNode(arr.charAt(arr.length() - 1) - '0'); + ListNode current = head; + + for (int i = arr.length() - 2; i >= 0; i--) { + current.next = new ListNode(arr.charAt(i) - '0'); + current = current.next; + } + return head; + } + + + public static void main(String[] args) { + //int[] l1 = {1, 8}; + //int[] l2 = {0}; + + int[] l1 = {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}; + int[] l2 = {5, 6, 4}; + printListNode(new Solution1().addTwoNumbers(createListNode(l1), createListNode(l2))); + } + +} \ No newline at end of file diff --git "a/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\344\270\244\346\225\260\347\233\270\345\212\240_2_\344\270\255\347\255\211/Solution2.java" "b/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\344\270\244\346\225\260\347\233\270\345\212\240_2_\344\270\255\347\255\211/Solution2.java" new file mode 100644 index 00000000..58d964cf --- /dev/null +++ "b/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\344\270\244\346\225\260\347\233\270\345\212\240_2_\344\270\255\347\255\211/Solution2.java" @@ -0,0 +1,54 @@ +package cn.lastwhisper.leetcode.common.linkedlist.两数相加_2_中等; + +import cn.lastwhisper.leetcode.common.linkedlist.ListNode; + +import static cn.lastwhisper.leetcode.common.linkedlist.LinkedListUtil.createListNode; +import static cn.lastwhisper.leetcode.common.linkedlist.LinkedListUtil.printListNode; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/add-two-numbers/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:整数逆序存储在链表中,正好可以正序相加 + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public ListNode addTwoNumbers(ListNode l1, ListNode l2) { + ListNode vHead = new ListNode(0); + ListNode current = vHead; + int carry = 0; + while (l1 != null || l2 != null) { + // num1、num2表示当前位的值,sum表示当前位的值+上一组进位值 + int num1, num2, sum; + num1 = l1 != null ? l1.val : 0; + num2 = l2 != null ? l2.val : 0; + + sum = carry + num1 + num2; + carry = sum / 10;//进位 + current.next = new ListNode(sum % 10);//当前位的值 + + current = current.next; + if (l1 != null) l1 = l1.next; + if (l2 != null) l2 = l2.next; + } + if (carry > 0) { + current.next = new ListNode(carry); + } + return vHead.next; + } + + public static void main(String[] args) { + //int[] arr1 = {2, 4, 3}; + //int[] arr2 = {5, 6, 4}; + + //int[] arr1 = {1, 8}; + //int[] arr2 = {0}; + + int[] arr1 = {1, 8}; + int[] arr2 = {1, 9}; + printListNode(new Solution2().addTwoNumbers(createListNode(arr1), createListNode(arr2))); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\344\270\244\346\225\260\347\233\270\345\212\240_II_445_\344\270\255\347\255\211/Solution1.java" "b/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\344\270\244\346\225\260\347\233\270\345\212\240_II_445_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..c13d8ec8 --- /dev/null +++ "b/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\344\270\244\346\225\260\347\233\270\345\212\240_II_445_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,84 @@ +package cn.lastwhisper.leetcode.common.linkedlist.两数相加_II_445_中等; + +import cn.lastwhisper.leetcode.common.linkedlist.ListNode; + +import static cn.lastwhisper.leetcode.common.linkedlist.LinkedListUtil.createListNode; +import static cn.lastwhisper.leetcode.common.linkedlist.LinkedListUtil.printListNode; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/add-two-numbers-ii/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:字符串相加 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(n) + */ + public ListNode addTwoNumbers(ListNode l1, ListNode l2) { + StringBuilder numStr1 = new StringBuilder(); + StringBuilder numStr2 = new StringBuilder(); + ListNode current1 = l1, current2 = l2; + while (current1 != null) { + numStr1.append(current1.val); + current1 = current1.next; + } + while (current2 != null) { + numStr2.append(current2.val); + current2 = current2.next; + } + + String sum = add(numStr1.toString(), numStr2.toString()); + + return createReverseListNode(sum); + } + + // 字符串相加 + public String add(String a, String b) { + StringBuilder sb = new StringBuilder(); + // 进位 + int carry = 0; + int aIndex = a.length() - 1, bIndex = b.length() - 1; + + while (aIndex >= 0 || bIndex >= 0) { + int x, y, sum; + x = aIndex >= 0 ? a.charAt(aIndex) - '0' : 0; + y = bIndex >= 0 ? b.charAt(bIndex) - '0' : 0; + + sum = carry + x + y; + carry = sum / 10; + sb.append(sum % 10); + + aIndex--; + bIndex--; + } + + if (carry > 0) { + sb.append(carry); + } + return sb.toString(); + } + + // 按字符串创建反序链表 + private static ListNode createReverseListNode(String arr) { + if (arr == null) { + return null; + } + + ListNode head = new ListNode(arr.charAt(arr.length() - 1) - '0'); + ListNode current = head; + + for (int i = arr.length() - 2; i >= 0; i--) { + current.next = new ListNode(arr.charAt(i) - '0'); + current = current.next; + } + return head; + } + + public static void main(String[] args) { + int[] num1 = {7, 2, 4, 3}; + int[] num2 = {5, 6, 4}; + printListNode(new Solution1().addTwoNumbers(createListNode(num1), createListNode(num2))); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\345\210\206\351\232\224\351\223\276\350\241\250_86_\344\270\255\347\255\211/Solution1.java" "b/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\345\210\206\351\232\224\351\223\276\350\241\250_86_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..59386b30 --- /dev/null +++ "b/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\345\210\206\351\232\224\351\223\276\350\241\250_86_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,58 @@ +package cn.lastwhisper.leetcode.common.linkedlist.分隔链表_86_中等; + +import cn.lastwhisper.leetcode.common.linkedlist.ListNode; + +import static cn.lastwhisper.leetcode.common.linkedlist.LinkedListUtil.createListNode; +import static cn.lastwhisper.leetcode.common.linkedlist.LinkedListUtil.printListNode; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/partition-list/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(1) + */ + public ListNode partition(ListNode head, int x) { + + if (head == null) { + return null; + } + + ListNode greaterNode = new ListNode(-1); + ListNode lessNode = new ListNode(0); + ListNode currentGreater = greaterNode; + ListNode currentLess = lessNode; + + while (head != null) { + if (head.val < x) { + currentLess.next = head; + currentLess = currentLess.next; + // 防止出现环形链表 + if (head.next == null) { + currentGreater.next = null; + } + } else { + currentGreater.next = head; + currentGreater = currentGreater.next; + if (head.next == null) { + currentLess.next = null; + } + } + head = head.next; + } + currentLess.next = greaterNode.next; + + return lessNode.next; + } + + public static void main(String[] args) { + int[] arr = {1,4,3,2,5,2}; + int x = 3; + + printListNode(new Solution1().partition(createListNode(arr), x)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\345\210\240\351\231\244\346\216\222\345\272\217\351\223\276\350\241\250\344\270\255\347\232\204\351\207\215\345\244\215\345\205\203\347\264\240_83_\347\256\200\345\215\225/Solution1.java" "b/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\345\210\240\351\231\244\346\216\222\345\272\217\351\223\276\350\241\250\344\270\255\347\232\204\351\207\215\345\244\215\345\205\203\347\264\240_83_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..050e2bd5 --- /dev/null +++ "b/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\345\210\240\351\231\244\346\216\222\345\272\217\351\223\276\350\241\250\344\270\255\347\232\204\351\207\215\345\244\215\345\205\203\347\264\240_83_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,57 @@ +package cn.lastwhisper.leetcode.common.linkedlist.删除排序链表中的重复元素_83_简单; + +import cn.lastwhisper.leetcode.common.linkedlist.ListNode; + +import java.util.HashSet; +import java.util.Set; + +import static cn.lastwhisper.leetcode.common.linkedlist.LinkedListUtil.createListNode; +import static cn.lastwhisper.leetcode.common.linkedlist.LinkedListUtil.printListNode; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/remove-duplicates-from-sorted-list/ + * ------------------------------------------------------------------- + * 思考: + * 数据特征: + * 输入:链表、**升序**、所有整数 + * ------------------------------------------------------------------- + * 思路:遍历链表并使用Hash表判断是否重复,对重复节点使用链表删除法 + * prev指针移动规则: + * 出现重复时,删除重复节点,不后移 + * 不重复时,向后移一位即可(current永远是prev的后一位) + * current指针移动规则: + * 每步都要后移一位 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(n) + * ------------------------------------------------------------------- + */ + public ListNode deleteDuplicates(ListNode head) { + if (head == null || head.next == null) + return head; + + Set set = new HashSet<>(); + ListNode prev = null; + ListNode current = head; + while (current != null) { + if (set.contains(current.val)) { + // 出现重复值时删除current节点,current节点没有指向即为删除 + prev.next = current.next; + } else { + set.add(current.val); + // 无重复,prev指针后移 + prev = current; + } + current = current.next; + } + return head; + } + + public static void main(String[] args) { + int[] arr = {1, 1, 1}; + //int[] arr = {1, 1, 2, 4}; + + printListNode(new Solution1().deleteDuplicates(createListNode(arr))); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\345\210\240\351\231\244\346\216\222\345\272\217\351\223\276\350\241\250\344\270\255\347\232\204\351\207\215\345\244\215\345\205\203\347\264\240_83_\347\256\200\345\215\225/Solution2.java" "b/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\345\210\240\351\231\244\346\216\222\345\272\217\351\223\276\350\241\250\344\270\255\347\232\204\351\207\215\345\244\215\345\205\203\347\264\240_83_\347\256\200\345\215\225/Solution2.java" new file mode 100644 index 00000000..c7f64729 --- /dev/null +++ "b/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\345\210\240\351\231\244\346\216\222\345\272\217\351\223\276\350\241\250\344\270\255\347\232\204\351\207\215\345\244\215\345\205\203\347\264\240_83_\347\256\200\345\215\225/Solution2.java" @@ -0,0 +1,49 @@ +package cn.lastwhisper.leetcode.common.linkedlist.删除排序链表中的重复元素_83_简单; + +import cn.lastwhisper.leetcode.common.linkedlist.ListNode; + +import static cn.lastwhisper.leetcode.common.linkedlist.LinkedListUtil.createListNode; +import static cn.lastwhisper.leetcode.common.linkedlist.LinkedListUtil.printListNode; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/remove-duplicates-from-sorted-list/ + * ------------------------------------------------------------------- + * 思考: + * 数据特征: + * 输入:链表、**升序**、所有整数 + * ------------------------------------------------------------------- + * 思路:链表数据升序,这个条件很重要,可以使用两个指针,current指向当前节点、next指向下一个节点 + * 判断当前节点和下一个节点是否相同,相同删除,不相同同时后移 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(1) + * ------------------------------------------------------------------- + */ + public ListNode deleteDuplicates(ListNode head) { + if (head == null || head.next == null) + return head; + + ListNode current = head; + ListNode next = head.next; + while (next != null) { + if (next.val == current.val) { + // 出现重复删除节点,并后移next节点 + current.next = next.next; + } else { + // 无重复同时后移 + current = next; + } + next = next.next; + } + return head; + } + + public static void main(String[] args) { + int[] arr = {1, 1, 1}; + //int[] arr = {1, 1, 2, 4}; + //int[] arr = {1, 2, 3, 3, 4}; + + printListNode(new Solution2().deleteDuplicates(createListNode(arr))); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\345\210\240\351\231\244\346\216\222\345\272\217\351\223\276\350\241\250\344\270\255\347\232\204\351\207\215\345\244\215\345\205\203\347\264\240_83_\347\256\200\345\215\225/Solution3.java" "b/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\345\210\240\351\231\244\346\216\222\345\272\217\351\223\276\350\241\250\344\270\255\347\232\204\351\207\215\345\244\215\345\205\203\347\264\240_83_\347\256\200\345\215\225/Solution3.java" new file mode 100644 index 00000000..f1cd9f7b --- /dev/null +++ "b/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\345\210\240\351\231\244\346\216\222\345\272\217\351\223\276\350\241\250\344\270\255\347\232\204\351\207\215\345\244\215\345\205\203\347\264\240_83_\347\256\200\345\215\225/Solution3.java" @@ -0,0 +1,47 @@ +package cn.lastwhisper.leetcode.common.linkedlist.删除排序链表中的重复元素_83_简单; + +import cn.lastwhisper.leetcode.common.linkedlist.ListNode; + +import static cn.lastwhisper.leetcode.common.linkedlist.LinkedListUtil.createListNode; +import static cn.lastwhisper.leetcode.common.linkedlist.LinkedListUtil.printListNode; + +class Solution3 { + /** + * 题目地址:https://leetcode-cn.com/problems/remove-duplicates-from-sorted-list/ + * ------------------------------------------------------------------- + * 思考: + * 数据特征: + * 输入:链表、**升序**、所有整数 + * ------------------------------------------------------------------- + * 思路:将思路2的遍历改成递归 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(n) + * ------------------------------------------------------------------- + */ + public ListNode deleteDuplicates(ListNode head) { + if (head == null || head.next == null) + return head; + ListNode next = head.next; + /* + * 外层循环可以根据数据规则添加 + * 比如{1,2,3,4,4,4,5,6,7,8,9,9,9,9},有规则重复位置 + * 此时可以用if探测是否进入规则重复位置 + */ + //if (next.val == head.val) { + // next = next.next; + while (next != null && next.val == head.val) + next = next.next; + //} + head.next = deleteDuplicates(next); + return head; + } + + public static void main(String[] args) { + //int[] arr = {1, 1, 1}; + //int[] arr = {1, 1, 2, 4}; + int[] arr = {1, 2, 3, 3, 4}; + + printListNode(new Solution3().deleteDuplicates(createListNode(arr))); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\345\210\240\351\231\244\346\216\222\345\272\217\351\223\276\350\241\250\344\270\255\347\232\204\351\207\215\345\244\215\345\205\203\347\264\240_II_82_\344\270\255\347\255\211/Solution1.java" "b/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\345\210\240\351\231\244\346\216\222\345\272\217\351\223\276\350\241\250\344\270\255\347\232\204\351\207\215\345\244\215\345\205\203\347\264\240_II_82_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..556b2c77 --- /dev/null +++ "b/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\345\210\240\351\231\244\346\216\222\345\272\217\351\223\276\350\241\250\344\270\255\347\232\204\351\207\215\345\244\215\345\205\203\347\264\240_II_82_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,73 @@ +package cn.lastwhisper.leetcode.common.linkedlist.删除排序链表中的重复元素_II_82_中等; + +import cn.lastwhisper.leetcode.common.linkedlist.ListNode; + +import static cn.lastwhisper.leetcode.common.linkedlist.LinkedListUtil.createListNode; +import static cn.lastwhisper.leetcode.common.linkedlist.LinkedListUtil.printListNode; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/remove-duplicates-from-sorted-list-ii/ + * ------------------------------------------------------------------- + * 思考: + * 数据特征: + * 输入:链表、**升序**、所有整数 + * ------------------------------------------------------------------- + * 思路:分为三种情况 + * (1)1,2,2,3 + * (2)1,1,1,1 + * (3)1,1,2,3 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(1) + */ + public ListNode deleteDuplicates(ListNode head) { + if (head == null || head.next == null) + return head; + + ListNode prev = null; + ListNode current = head; + ListNode next = head.next; + + while (next != null) { + if (current.val == next.val) { + // 删除第2个重复节点 + current.next = next.next; + next = next.next; + // 删除第2+个重复节点 + while (next != null && current.val == next.val) { + current.next = next.next; + next = next.next; + } + // prev!=null说明[m..n]出现重复 + if (prev != null) { + // 删除第1个重复节点 + prev.next = current.next; + } else { + // prev==null说明从[1..m]都是重复的,[m..n]还不好说 + head = current.next; + } + } else { + // 无重复时prev后移 + prev = current; + } + // 1,1,1这种情况,next=null + if (next == null) { + break; + } + // 不管是否重复current、next都必须后移 + current = next; + next = next.next; + } + return head; + } + + public static void main(String[] args) { + + //int[] arr = {1, 2, 3, 3, 4, 4, 5}; + //int[] arr = {1, 1, 1}; + int[] arr = {1, 1, 1, 2, 3}; + + printListNode(new Solution1().deleteDuplicates(createListNode(arr))); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\345\210\240\351\231\244\351\223\276\350\241\250\344\270\255\347\232\204\350\212\202\347\202\271_237_\347\256\200\345\215\225/Solution1.java" "b/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\345\210\240\351\231\244\351\223\276\350\241\250\344\270\255\347\232\204\350\212\202\347\202\271_237_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..02ab538c --- /dev/null +++ "b/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\345\210\240\351\231\244\351\223\276\350\241\250\344\270\255\347\232\204\350\212\202\347\202\271_237_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,38 @@ +package cn.lastwhisper.leetcode.common.linkedlist.删除链表中的节点_237_简单; + +import cn.lastwhisper.leetcode.common.linkedlist.ListNode; + +import static cn.lastwhisper.leetcode.common.linkedlist.LinkedListUtil.printListNode; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/delete-node-in-a-linked-list/ + * ------------------------------------------------------------------- + * 思考:删除节点的两种思路 + * ------------------------------------------------------------------- + * 思路:将下一个节点值给当前节点,删除下一个节点 + * ------------------------------------------------------------------- + * 时间复杂度:O(1) + * 空间复杂度:O(1) + */ + public void deleteNode(ListNode node) { + ListNode next = node.next; + node.val = next.val; + node.next = next.next; + } + + public static void main(String[] args) { + ListNode head = new ListNode(4); + ListNode listNode1 = new ListNode(5); + ListNode listNode2 = new ListNode(1); + ListNode listNode3 = new ListNode(9); + head.next = listNode1; + listNode1.next = listNode2; + listNode2.next = listNode3; + + printListNode("删除前:\t", head); + new Solution1().deleteNode(listNode1); + printListNode("删除后:\t", head); + + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\345\210\240\351\231\244\351\223\276\350\241\250\347\232\204\345\200\222\346\225\260\347\254\254N\344\270\252\350\212\202\347\202\271_19_\344\270\255\347\255\211/Solution1.java" "b/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\345\210\240\351\231\244\351\223\276\350\241\250\347\232\204\345\200\222\346\225\260\347\254\254N\344\270\252\350\212\202\347\202\271_19_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..01351ab7 --- /dev/null +++ "b/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\345\210\240\351\231\244\351\223\276\350\241\250\347\232\204\345\200\222\346\225\260\347\254\254N\344\270\252\350\212\202\347\202\271_19_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,48 @@ +package cn.lastwhisper.leetcode.common.linkedlist.删除链表的倒数第N个节点_19_中等; + +import cn.lastwhisper.leetcode.common.linkedlist.ListNode; + +import static cn.lastwhisper.leetcode.common.linkedlist.LinkedListUtil.createListNode; +import static cn.lastwhisper.leetcode.common.linkedlist.LinkedListUtil.printListNode; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/remove-nth-node-from-end-of-list/ + * ------------------------------------------------------------------- + * 思考:特殊节点,头节点、尾节点 + * ------------------------------------------------------------------- + * 思路:虚拟头节点+快慢指针 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(1) + */ + public ListNode removeNthFromEnd(ListNode head, int n) { + // 虚拟头节点解决删除头节点问题 + ListNode dummyNode = new ListNode(0); + dummyNode.next = head; + + ListNode fast = dummyNode; + ListNode slow = dummyNode; + for (int i = 0; i < n; i++) { + fast = fast.next; + } + + while (fast != null && fast.next != null) { + fast = fast.next; + slow = slow.next; + } + slow.next = slow.next.next; + + return dummyNode.next; + } + + public static void main(String[] args) { + int[] arr = {1, 2, 3, 4, 5}; + int n = 2; + + //int[] arr = {1}; + //int n =1; + + printListNode(new Solution1().removeNthFromEnd(createListNode(arr), n)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\345\217\215\350\275\254\351\223\276\350\241\250_206_\347\256\200\345\215\225/Solution1.java" "b/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\345\217\215\350\275\254\351\223\276\350\241\250_206_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..bd018759 --- /dev/null +++ "b/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\345\217\215\350\275\254\351\223\276\350\241\250_206_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,55 @@ +package cn.lastwhisper.leetcode.common.linkedlist.反转链表_206_简单; + +import cn.lastwhisper.leetcode.common.linkedlist.LinkedListUtil; +import cn.lastwhisper.leetcode.common.linkedlist.ListNode; + +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode(int x) { val = x; } + * } + */ +public class Solution1 { + + /** + * 题目地址:https://leetcode-cn.com/problems/reverse-linked-list/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:iteratively + * 需要三个指针prev、current、next帮助反转 + * prev指向前一个节点 + * current指向当前正在反转的节点 + * next指向下一个待反转的节点 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(1) + * ------------------------------------------------------------------- + * 执行用时 :0 ms, 在所有 Java 提交中击败了100.00%的用户 + * 内存消耗 :37.3 MB, 在所有 Java 提交中击败了24.92%的用户 + */ + public ListNode reverseList(ListNode head) { + + ListNode prev = null; + ListNode current = head; + ListNode next; + + while (current != null) { + next = current.next; + // 反转 + current.next = prev; + // 后移 + prev = current; + current = next; + } + + return prev; + } + + public static void main(String[] args) { + LinkedListUtil.printListNode(new Solution1().reverseList( + LinkedListUtil.createListNode(1, 2, 3, 4, 5, 6))); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\345\217\215\350\275\254\351\223\276\350\241\250_206_\347\256\200\345\215\225/Solution2.java" "b/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\345\217\215\350\275\254\351\223\276\350\241\250_206_\347\256\200\345\215\225/Solution2.java" new file mode 100644 index 00000000..878b27f3 --- /dev/null +++ "b/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\345\217\215\350\275\254\351\223\276\350\241\250_206_\347\256\200\345\215\225/Solution2.java" @@ -0,0 +1,48 @@ +package cn.lastwhisper.leetcode.common.linkedlist.反转链表_206_简单; + +import cn.lastwhisper.leetcode.common.linkedlist.LinkedListUtil; +import cn.lastwhisper.leetcode.common.linkedlist.ListNode; + +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode(int x) { val = x; } + * } + */ +public class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/reverse-linked-list/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:recursive + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(n) - 注意,递归是占用空间的,占用空间的大小和递归深度成正比 + * ------------------------------------------------------------------- + * 执行用时 :1 ms, 在所有 Java 提交中击败了7.79%的用户 + * 内存消耗 :37.4 MB, 在所有 Java 提交中击败了22.92%的用户 + */ + public ListNode reverseList(ListNode head) { + // 递归终止条件 + if (head == null || head.next == null) + return head; + + //与head关联 + ListNode rhead = reverseList(head.next); + + // 每次反转链表末尾的两个节点 + // head->next此刻指向head后面的链表的尾节点 + // head->next->next = head把head节点放在了尾部 + head.next.next = head; + head.next = null; + + return rhead; + } + + public static void main(String[] args) { + LinkedListUtil.printListNode(new Solution2().reverseList(LinkedListUtil.createListNode(new int[]{1, 2, 3,}))); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\345\217\215\350\275\254\351\223\276\350\241\250_II_92_\344\270\255\347\255\211/Solution1.java" "b/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\345\217\215\350\275\254\351\223\276\350\241\250_II_92_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..24e93aa8 --- /dev/null +++ "b/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\345\217\215\350\275\254\351\223\276\350\241\250_II_92_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,68 @@ +package cn.lastwhisper.leetcode.common.linkedlist.反转链表_II_92_中等; + +import cn.lastwhisper.leetcode.common.linkedlist.ListNode; + +import static cn.lastwhisper.leetcode.common.linkedlist.LinkedListUtil.createListNode; +import static cn.lastwhisper.leetcode.common.linkedlist.LinkedListUtil.printListNode; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/reverse-linked-list-ii/ + * ------------------------------------------------------------------- + * 思考: + * m大于n怎么办? + * m、n为负数怎么办? + * m、n超过链表长度怎么办? + * ------------------------------------------------------------------- + * 思路: + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public ListNode reverseBetween(ListNode head, int m, int n) { + if (head == null || head.next == null) + return head; + + ListNode vNode = new ListNode(-1); + vNode.next = head; + + // 保存反转前的前一个节点 + ListNode startNode = vNode; + for (int i = 0; i < m - 1; i++) { + startNode = startNode.next; + } + // 保存反转前的头节点 + ListNode mHead = startNode.next; + + // 反转需要的中间节点 + ListNode prev = null; + ListNode current = mHead; + ListNode next; + + for (int i = m; i < n+1; i++) { + // 保存next + next = current.next; + // 反转 + current.next = prev; + // prev、current后移 + prev = current; + current = next; + } + + // 反转前的前一个节点指向,反转后的头节点 + startNode.next = prev; + // 反转前的头节点指向,反转后的endNode + mHead.next = current; + + return vNode.next; + } + + public static void main(String[] args) { + //int[] arr = {1, 2, 3, 4, 5}; + //int m = 2, n = 4; + int[] arr = {3, 5}; + int m = 1, n = 2; + + printListNode(new Solution1().reverseBetween(createListNode(arr), m, n)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\351\223\276\350\241\250_21_\347\256\200\345\215\225/Solution1.java" "b/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\351\223\276\350\241\250_21_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..6b493f80 --- /dev/null +++ "b/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\351\223\276\350\241\250_21_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,52 @@ +package cn.lastwhisper.leetcode.common.linkedlist.合并两个有序链表_21_简单; + +import cn.lastwhisper.leetcode.common.linkedlist.ListNode; + +import static cn.lastwhisper.leetcode.common.linkedlist.LinkedListUtil.createListNode; +import static cn.lastwhisper.leetcode.common.linkedlist.LinkedListUtil.printListNode; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/merge-two-sorted-lists/submissions/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:设置一个虚拟头节点vNode,边遍历两个链表边比较节点大小, + * vNode指向小的那个节点,遍历完后,返回vNode.next + * ------------------------------------------------------------------- + * 时间复杂度:O(n+m),每次迭代都会添加一个链表节点,循环次数为两个链表总长度 + * 空间复杂度:O(1) + */ + public ListNode mergeTwoLists(ListNode l1, ListNode l2) { + + // 虚拟头节点,这个点不能动 + ListNode vNode = new ListNode(-1); + + // currentv负责穿针引线,l1、l2负责遍历 + ListNode currentv = vNode; + + // 将l1、l2按照升序链接到vNode上 + while (l1 != null && l2 != null) { + if (l1.val <= l2.val) { + currentv.next = l1; + l1 = l1.next; + } else { + currentv.next = l2; + l2 = l2.next; + } + currentv = currentv.next; + } + // l1、l2某个不为空,直接链接上 + currentv.next = l1 == null ? l2 : l1; + + return vNode.next; + } + + public static void main(String[] args) { + ListNode head1 = createListNode(1, 2, 4); + ListNode head2 = createListNode(1, 3, 4, 5); + printListNode(head1); + printListNode(head2); + printListNode(new Solution1().mergeTwoLists(head1, head2)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\351\223\276\350\241\250_21_\347\256\200\345\215\225/Solution2.java" "b/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\351\223\276\350\241\250_21_\347\256\200\345\215\225/Solution2.java" new file mode 100644 index 00000000..21bf176a --- /dev/null +++ "b/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\351\223\276\350\241\250_21_\347\256\200\345\215\225/Solution2.java" @@ -0,0 +1,44 @@ +package cn.lastwhisper.leetcode.common.linkedlist.合并两个有序链表_21_简单; + +import cn.lastwhisper.leetcode.common.linkedlist.ListNode; + +import static cn.lastwhisper.leetcode.common.linkedlist.LinkedListUtil.createListNode; +import static cn.lastwhisper.leetcode.common.linkedlist.LinkedListUtil.printListNode; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/merge-two-sorted-lists/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * ------------------------------------------------------------------- + * 时间复杂度:O(m+n) + * 空间复杂度:O(m+n),递归深度 + */ + public ListNode mergeTwoLists(ListNode l1, ListNode l2) { + if (l1 == null) { + return l2; + } + if (l2 == null) { + return l1; + } + + if (l1.val < l2.val) { + l1.next = mergeTwoLists(l1.next, l2); + return l1; + } else { + l2.next = mergeTwoLists(l1, l2.next); + return l2; + } + + } + + public static void main(String[] args) { + ListNode head1 = createListNode(1, 2, 4); + ListNode head2 = createListNode(1, 3, 4, 5); + printListNode(head1); + printListNode(head2); + printListNode(new Solution2().mergeTwoLists(head1, head2)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\345\233\236\346\226\207\351\223\276\350\241\250_234_\347\256\200\345\215\225/Solution1.java" "b/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\345\233\236\346\226\207\351\223\276\350\241\250_234_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..d2411e97 --- /dev/null +++ "b/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\345\233\236\346\226\207\351\223\276\350\241\250_234_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,76 @@ +package cn.lastwhisper.leetcode.common.linkedlist.回文链表_234_简单; + +import cn.lastwhisper.leetcode.common.linkedlist.ListNode; + +import static cn.lastwhisper.leetcode.common.linkedlist.LinkedListUtil.createListNode; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/palindrome-linked-list/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:使用快慢指针遍历到链表的中间节点,反转头节点到中间节点这部分链表, + * 从中间节点开始遍历,比较反转链表 + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public boolean isPalindrome(ListNode head) { + if (head == null) return true; + // 找到链表中间节点 + ListNode slow = endOfFirstHalf(head); + // 反转链表 + ListNode reverseHead = reverseListNode(slow.next); + + ListNode firstHead = head; + + while (reverseHead != null && firstHead != null) { + if (reverseHead.val != firstHead.val) { + return false; + } + reverseHead = reverseHead.next; + firstHead = firstHead.next; + } + + // 包含单个节点的情况 + return true; + } + + private ListNode endOfFirstHalf(ListNode head) { + ListNode fast = head; + ListNode slow = head; + while (fast.next != null && fast.next.next != null) { + fast = fast.next.next; + slow = slow.next; + } + return slow; + } + + /** + * 反转链表 + */ + private static ListNode reverseListNode(ListNode head) { + ListNode prev = null; + ListNode current = head; + ListNode next = null; + + while (current != null) { + next = current.next; + + current.next = prev; + prev = current; + current = next; + } + return prev; + } + + public static void main(String[] args) { + //int[] arr = {1, 2, 3, 2, 1}; + //int[] arr = {1, 2, 2, 1}; + //int[] arr = {1, 2}; + //int[] arr = {1}; + int[] arr = {1, 0, 1}; + System.out.println(new Solution1().isPalindrome(createListNode(arr))); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\345\245\207\345\201\266\351\223\276\350\241\250_328_\344\270\255\347\255\211/Solution1.java" "b/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\345\245\207\345\201\266\351\223\276\350\241\250_328_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..e6a82e4b --- /dev/null +++ "b/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\345\245\207\345\201\266\351\223\276\350\241\250_328_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,62 @@ +package cn.lastwhisper.leetcode.common.linkedlist.奇偶链表_328_中等; + +import cn.lastwhisper.leetcode.common.linkedlist.ListNode; + +import static cn.lastwhisper.leetcode.common.linkedlist.LinkedListUtil.createListNode; +import static cn.lastwhisper.leetcode.common.linkedlist.LinkedListUtil.printListNode; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/odd-even-linked-list/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:建立两个奇偶虚拟头节点,遍历输入链表,将满足条件的节点, + * 挂载到奇偶节点上,最后将奇偶链表拼接 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(1) + */ + public ListNode oddEvenList(ListNode head) { + if (head == null) { + return null; + } + + ListNode oddNode = new ListNode(-1); + ListNode evenNode = new ListNode(0); + ListNode currentOdd = oddNode; + ListNode currentEven = evenNode; + + int index = 1; + + while (head != null) { + if (index % 2 == 0) { //将index改成head.val,就是按值进行奇偶链表 + currentEven.next = head; + currentEven = currentEven.next; + /* + * 如果最后一个节点是偶数节点,将当前奇数节点的next置为null, + * 因为奇数节点的next可能指向偶数节点,但是head遍历完了,这个next无法更新, + * 会出现环形链表 + */ + if (head.next == null) { + currentOdd.next = null; + } + } else { + currentOdd.next = head; + currentOdd = currentOdd.next; + if (head.next == null) { + currentEven.next = null; + } + } + head = head.next; + index++; + } + currentOdd.next = evenNode.next; + + return oddNode.next; + } + + public static void main(String[] args) { + printListNode(new Solution1().oddEvenList(createListNode(1, 2, 3, 4, 5))); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\347\216\257\345\275\242\351\223\276\350\241\250_141_\347\256\200\345\215\225/Solution1.java" "b/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\347\216\257\345\275\242\351\223\276\350\241\250_141_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..ed1b4bf1 --- /dev/null +++ "b/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\347\216\257\345\275\242\351\223\276\350\241\250_141_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,43 @@ +package cn.lastwhisper.leetcode.common.linkedlist.环形链表_141_简单; + +import cn.lastwhisper.leetcode.common.linkedlist.ListNode; + +import static cn.lastwhisper.leetcode.common.linkedlist.LinkedListUtil.createLoopListNode; + +public class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/linked-list-cycle/submissions/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:快慢指针(龟兔赛跑) + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(1) + */ + public boolean hasCycle(ListNode head) { + if (head == null||head.next == null) { + return false; + } + ListNode fast = head; + ListNode slow = head; + + while (fast != null && fast.next != null) { + fast = fast.next.next; + slow = slow.next; + if (fast == slow) { + return true; + } + } + + return false; + } + + + public static void main(String[] args) { + int pos = 1; + int[] arr = {3, 2, 0, -4}; + ListNode loopListNode = createLoopListNode(pos, arr); + System.out.println(new Solution1().hasCycle(loopListNode)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\347\216\257\345\275\242\351\223\276\350\241\250_141_\347\256\200\345\215\225/Solution2.java" "b/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\347\216\257\345\275\242\351\223\276\350\241\250_141_\347\256\200\345\215\225/Solution2.java" new file mode 100644 index 00000000..fb2e0bab --- /dev/null +++ "b/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\347\216\257\345\275\242\351\223\276\350\241\250_141_\347\256\200\345\215\225/Solution2.java" @@ -0,0 +1,43 @@ +package cn.lastwhisper.leetcode.common.linkedlist.环形链表_141_简单; + +import cn.lastwhisper.leetcode.common.linkedlist.ListNode; + +import java.util.HashSet; + +import static cn.lastwhisper.leetcode.common.linkedlist.LinkedListUtil.createLoopListNode; + +public class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/linked-list-cycle/submissions/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:hash表 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(n) + */ + public boolean hasCycle(ListNode head) { + if (head == null || head.next == null) { + return false; + } + HashSet set = new HashSet<>(); + while (head != null) { + if (set.contains(head)) { + return true; + } + set.add(head); + head = head.next; + } + + return false; + } + + + public static void main(String[] args) { + int pos = 1; + int[] arr = {3, 2, 0, -4}; + ListNode loopListNode = createLoopListNode(pos, arr); + System.out.println(new Solution2().hasCycle(loopListNode)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\347\233\270\344\272\244\351\223\276\350\241\250_160_\347\256\200\345\215\225/Solution1.java" "b/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\347\233\270\344\272\244\351\223\276\350\241\250_160_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..a5407716 --- /dev/null +++ "b/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\347\233\270\344\272\244\351\223\276\350\241\250_160_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,33 @@ +package cn.lastwhisper.leetcode.common.linkedlist.相交链表_160_简单; + +import cn.lastwhisper.leetcode.common.linkedlist.ListNode; + +import static cn.lastwhisper.leetcode.common.linkedlist.LinkedListUtil.printListNode; + +public class Solution1 { + /** + * 题目地址: + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public ListNode getIntersectionNode(ListNode headA, ListNode headB) { + /* + 定义两个指针, 第一轮让两个到达末尾的节点指向另一个链表的头部, 最后如果相遇则为交点(在第一轮移动中恰好抹除了长度差) + 两个指针等于移动了相同的距离, 有交点就返回, 无交点就是各走了两条指针的长度 + **/ + if (headA == null || headB == null) return null; + ListNode pA = headA, pB = headB; + // 在这里第一轮体现在pA和pB第一次到达尾部会移向另一链表的表头, 而第二轮体现在如果pA或pB相交就返回交点, 不相交最后就是null==null + while (pA != pB) { + pA = pA == null ? headB : pA.next; + pB = pB == null ? headA : pB.next; + } + return pA; + } + +} \ No newline at end of file diff --git "a/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\347\233\270\344\272\244\351\223\276\350\241\250_160_\347\256\200\345\215\225/\345\217\202\350\200\203" "b/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\347\233\270\344\272\244\351\223\276\350\241\250_160_\347\256\200\345\215\225/\345\217\202\350\200\203" new file mode 100644 index 00000000..9a2c9559 --- /dev/null +++ "b/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\347\233\270\344\272\244\351\223\276\350\241\250_160_\347\256\200\345\215\225/\345\217\202\350\200\203" @@ -0,0 +1 @@ +https://leetcode.com/problems/intersection-of-two-linked-lists/solution/ \ No newline at end of file diff --git "a/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\347\247\273\351\231\244\351\223\276\350\241\250\345\205\203\347\264\240_203_\347\256\200\345\215\225/Solution1.java" "b/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\347\247\273\351\231\244\351\223\276\350\241\250\345\205\203\347\264\240_203_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..ebabad40 --- /dev/null +++ "b/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\347\247\273\351\231\244\351\223\276\350\241\250\345\205\203\347\264\240_203_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,61 @@ +package cn.lastwhisper.leetcode.common.linkedlist.移除链表元素_203_简单; + +import cn.lastwhisper.leetcode.common.linkedlist.ListNode; + +import static cn.lastwhisper.leetcode.common.linkedlist.LinkedListUtil.createListNode; +import static cn.lastwhisper.leetcode.common.linkedlist.LinkedListUtil.printListNode; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/remove-linked-list-elements/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:设置虚拟头节点 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(1) + */ + public ListNode removeElements(ListNode head, int val) { + if (head == null) + return null; + + //虚拟头节点 + ListNode vNode = new ListNode(-1); + vNode.next = head; + + // 前节点 + ListNode prev = vNode; + // 当前节点 + ListNode current = head; + + while (current != null) { + if (current.val == val) { + prev.next = current.next; + } else { + prev = prev.next; + } + current = current.next; + } + + return vNode.next; + } + + public static void main(String[] args) { + // example + int[] arr = {1, 2, 6, 3, 4, 5, 6}; + int x = 6; + + // error example + //int[] arr = {1}; + //int x = 1; + + //int[] arr = {1}; + //int x = 2; + + //int[] arr = {1, 1}; + //int x = 1; + + printListNode(new Solution1().removeElements(createListNode(arr), x)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\347\247\273\351\231\244\351\223\276\350\241\250\345\205\203\347\264\240_203_\347\256\200\345\215\225/Solution2.java" "b/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\347\247\273\351\231\244\351\223\276\350\241\250\345\205\203\347\264\240_203_\347\256\200\345\215\225/Solution2.java" new file mode 100644 index 00000000..01785c68 --- /dev/null +++ "b/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\347\247\273\351\231\244\351\223\276\350\241\250\345\205\203\347\264\240_203_\347\256\200\345\215\225/Solution2.java" @@ -0,0 +1,60 @@ +package cn.lastwhisper.leetcode.common.linkedlist.移除链表元素_203_简单; + +import cn.lastwhisper.leetcode.common.linkedlist.ListNode; + +import static cn.lastwhisper.leetcode.common.linkedlist.LinkedListUtil.createListNode; +import static cn.lastwhisper.leetcode.common.linkedlist.LinkedListUtil.printListNode; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/remove-linked-list-elements/ + * ------------------------------------------------------------------- + * 思考:不设置虚拟头节点 + * ------------------------------------------------------------------- + * 思路: + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(1) + */ + public ListNode removeElements(ListNode head, int val) { + if (head == null) + return null; + // 前节点 + ListNode prev = null; + // 当前节点 + ListNode current = head; + while (current != null) { + if (current.val == val) { + // 找到目标值之后分为两种情况 + if (prev != null) { + prev.next = current.next; + } else { + head = current.next; + } + } else { + prev = current; + } + current = current.next; + } + + return head; + } + + public static void main(String[] args) { + // example + //int[] arr = {1, 2, 6, 3, 4, 5, 6}; + //int x = 6; + + // error example + //int[] arr = {1}; + //int x = 1; + + //int[] arr = {1}; + //int x = 2; + + int[] arr = {1, 1}; + int x = 1; + + printListNode(new Solution2().removeElements(createListNode(arr), x)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\350\256\276\350\256\241\350\267\263\350\241\250_1206_\345\233\260\351\232\276/Skiplist.java" "b/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\350\256\276\350\256\241\350\267\263\350\241\250_1206_\345\233\260\351\232\276/Skiplist.java" new file mode 100644 index 00000000..d7ffab90 --- /dev/null +++ "b/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\350\256\276\350\256\241\350\267\263\350\241\250_1206_\345\233\260\351\232\276/Skiplist.java" @@ -0,0 +1,53 @@ +package cn.lastwhisper.leetcode.common.linkedlist.设计跳表_1206_困难; + +public class Skiplist { + /** + * 题目地址:https://leetcode-cn.com/problems/design-skiplist/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public Skiplist() { + + } + + public boolean search(int target) { + + return false; + } + + public void add(int num) { + + } + + public boolean erase(int num) { + + return false; + } + + /** + * Your Skiplist object will be instantiated and called as such: + * Skiplist obj = new Skiplist(); + * boolean param_1 = obj.search(target); + * obj.add(num); + * boolean param_3 = obj.erase(num); + */ + public static void main(String[] args) { + Skiplist skiplist = new Skiplist(); + + skiplist.add(1); + skiplist.add(2); + skiplist.add(3); + System.out.println(skiplist.search(0));// 返回 false + skiplist.add(4); + System.out.println(skiplist.search(1)); // 返回 true + System.out.println(skiplist.erase(0)); // 返回 false,0 不在跳表中 + System.out.println(skiplist.erase(1)); // 返回 true + System.out.println(skiplist.search(1)); // 返回 false,1 已被擦除 + } +} + diff --git "a/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\351\207\215\346\216\222\351\223\276\350\241\250_143_\344\270\255\347\255\211/Solution1.java" "b/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\351\207\215\346\216\222\351\223\276\350\241\250_143_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..b7101ae0 --- /dev/null +++ "b/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\351\207\215\346\216\222\351\223\276\350\241\250_143_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,99 @@ +package cn.lastwhisper.leetcode.common.linkedlist.重排链表_143_中等; + +import cn.lastwhisper.leetcode.common.linkedlist.ListNode; + +import static cn.lastwhisper.leetcode.common.linkedlist.LinkedListUtil.createListNode; +import static cn.lastwhisper.leetcode.common.linkedlist.LinkedListUtil.printListNode; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/reorder-list/ + * ------------------------------------------------------------------- + * 思考: + * 奇数与偶数链表情况不同,奇数链表会成环 + * ------------------------------------------------------------------- + * 思路:找到链表中间节点,然后对剩余链表进行reverse,将两个链表合并即可 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(1) + */ + public void reorderList(ListNode head) { + // 过滤空值 + if (head == null) { + return; + } + // 1、找到中间节点的前一个节点(找前一个节点是为了切断两个链表的联系) + ListNode middleBeforeNode = middleBeforeNode(head); + // 2、反转以中间节点为首之后的链表 + ListNode secondHead = reverseListNode(middleBeforeNode.next); + // 切断两个链表的联系,防止链表成环 + middleBeforeNode.next = null; + // 3、合并链表 + alterNoteMergeOne(head, secondHead); + } + + public static void alterNoteMergeOne(ListNode firstHead, ListNode secondHead) { + ListNode firstNext; + ListNode secondNext; + + while (secondHead != null) { + // 1.记录两个链表的next节点 + firstNext = firstHead.next; + secondNext = secondHead.next; + // 2.将链表1的当前节点指向链表2的当前节点,链表2的当前节点指向链表1的下一个节点 + // 链表1:1->2->3 链表2:5->4 + // 合并后的链表1:1->5->2 + firstHead.next = secondHead; + secondHead.next = firstNext; + // 3.将之前保存的next更新为当前节点,继续循环 + firstHead = firstNext; + secondHead = secondNext; + // 防止奇数节点链表成环 https://leetcode-cn.com/problems/reorder-list/ + if (secondHead == null) { + firstHead.next = null; + } + } + } + + /** + * 找到链表中间的前一个节点 + */ + public static ListNode middleBeforeNode(ListNode head) { + ListNode fast = head; + ListNode slow = head; + while (fast.next != null && fast.next.next != null) { + fast = fast.next.next; + slow = slow.next; + } + return slow; + } + + /** + * 反转链表 + */ + public static ListNode reverseListNode(ListNode head) { + ListNode prev = null; + ListNode current = head; + ListNode next = null; + + while (current != null) { + next = current.next; + + current.next = prev; + prev = current; + current = next; + } + return prev; + } + + public static void main(String[] args) { + // 偶数没问题 + int[] arr = {1, 2, 3, 4, 5, 6}; + // 奇数有问题 + //int[] arr = {1, 2, 3, 4, 5}; + ListNode head = createListNode(arr); + printListNode("重排前:\t", head); + new Solution1().reorderList(head); + printListNode("重排后:\t", head); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\351\223\276\350\241\250\347\232\204\344\270\255\351\227\264\347\273\223\347\202\271_876_\347\256\200\345\215\225/Solution.java" "b/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\351\223\276\350\241\250\347\232\204\344\270\255\351\227\264\347\273\223\347\202\271_876_\347\256\200\345\215\225/Solution.java" new file mode 100644 index 00000000..4b128317 --- /dev/null +++ "b/algorithms/leetcode/linkedlist/src/main/java/cn/lastwhisper/leetcode/common/linkedlist/\351\223\276\350\241\250\347\232\204\344\270\255\351\227\264\347\273\223\347\202\271_876_\347\256\200\345\215\225/Solution.java" @@ -0,0 +1,25 @@ +package cn.lastwhisper.leetcode.common.linkedlist.链表的中间节点_876_简单; + +import cn.lastwhisper.leetcode.common.linkedlist.ListNode; + +class Solution { + /** + * 题目地址:https://leetcode-cn.com/problems/middle-of-the-linked-list/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public ListNode middleNode(ListNode head) { + ListNode fast = head; + ListNode slow = head; + while (fast != null && fast.next != null) { + fast = fast.next.next; + slow = slow.next; + } + return slow; + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/other/src/main/java/cn/lastwhisper/leetcode/other/LRU\347\274\223\345\255\230\346\234\272\345\210\266146/LRUCache.java" "b/algorithms/leetcode/other/src/main/java/cn/lastwhisper/leetcode/other/LRU\347\274\223\345\255\230\346\234\272\345\210\266146/LRUCache.java" deleted file mode 100644 index f99b0a76..00000000 --- "a/algorithms/leetcode/other/src/main/java/cn/lastwhisper/leetcode/other/LRU\347\274\223\345\255\230\346\234\272\345\210\266146/LRUCache.java" +++ /dev/null @@ -1,150 +0,0 @@ -package cn.lastwhisper.leetcode.other.LRU缓存机制146; - -import java.util.HashMap; -import java.util.Iterator; - -/** - * 146. LRU缓存机制146 - * https://leetcode-cn.com/problems/lru-cache/ - * - * 需要满足O(1)级别的查找、添加、删除 - * 思路:hash表+双向链表 - * - */ -public class LRUCache { - // key -> Node(key, val) - private HashMap map; - // Node(k1, v1) <-> Node(k2, v2)... - private DoubleList cache; - // 最大容量 - private int cap; - - - public LRUCache(int capacity) { - this.cap = capacity; - map = new HashMap<>(); - cache = new DoubleList(); - } - - private class DoubleList implements Iterable { - private Node head, tail; // 头尾虚节点 - private int size; // 链表元素数 - - public DoubleList() { - head = new Node(0, 0); - tail = new Node(0, 0); - head.next = tail; - tail.prev = head; - size = 0; - } - - private class Itr implements Iterator { - private Node now = head; - - @Override - public boolean hasNext() { - return now.next != tail; - } - - @Override - public Node next() { - now = now.next; - return now; - } - - } - - // 在链表头部添加节点 node - public void addFirst(Node node) { - node.next = head.next; - node.prev = head; - head.next.prev = node; - head.next = node; - size++; - } - - // 删除链表中的 node 节点(node 一定存在) - public void remove(Node node) { - node.prev.next = node.next; - node.next.prev = node.prev; - size--; - } - - // 删除链表中最后一个节点,并返回该节点 - public Node removeLast() { - if (tail.prev == head) - return null; - Node last = tail.prev; - remove(last); - return last; - } - - // 返回链表长度 - public int size() { - return size; - } - - @Override - public Iterator iterator() { - return new Itr(); - } - - } - - private class Node { - public int key, val; - public Node next, prev; - - public Node(int k, int v) { - this.key = k; - this.val = v; - } - } - - public static void main(String[] args) { - LRUCache lruCache = new LRUCache(3); - lruCache.put(1, 1); - lruCache.put(2, 2); - lruCache.put(3, 3); - lruCache.get(2); - lruCache.put(4, 4); - DoubleList list = lruCache.cache; - for (Node node : list) { - System.out.println(node.key + "\t" + node.val); - } - } - - public int get(int key) { - if (!map.containsKey(key)) - return -1; - int val = map.get(key).val; - // 利用 put 方法把该数据提前 - put(key, val); - return val; - } - - public void put(int key, int val) { - // 先把新节点 node 做出来 - Node node = new Node(key, val); - - if (map.containsKey(key)) { - // 删除旧的节点,新的插到头部 - cache.remove(map.get(key)); - cache.addFirst(node); - // 更新 map 中对应的数据 - map.put(key, node); - } else { - if (cap == cache.size()) { - // 删除链表最后一个数据 - Node last = cache.removeLast(); - map.remove(last.key); - } - // 直接添加到头部 - cache.addFirst(node); - map.put(key, node); - } - } - -} - - diff --git "a/algorithms/leetcode/other/src/main/java/cn/lastwhisper/leetcode/other/LRU\347\274\223\345\255\230\346\234\272\345\210\266_146_\344\270\255\347\255\211/LRUCache.java" "b/algorithms/leetcode/other/src/main/java/cn/lastwhisper/leetcode/other/LRU\347\274\223\345\255\230\346\234\272\345\210\266_146_\344\270\255\347\255\211/LRUCache.java" new file mode 100644 index 00000000..fefbcba8 --- /dev/null +++ "b/algorithms/leetcode/other/src/main/java/cn/lastwhisper/leetcode/other/LRU\347\274\223\345\255\230\346\234\272\345\210\266_146_\344\270\255\347\255\211/LRUCache.java" @@ -0,0 +1,149 @@ +package cn.lastwhisper.leetcode.other.LRU缓存机制_146_中等; + +import java.util.HashMap; +import java.util.Iterator; + +/** + * 146. LRU缓存机制146 + * https://leetcode-cn.com/problems/lru-cache/ + * + * 需要满足O(1)级别的查找、添加、删除 + * 思路:hash表+双向链表 + * + */ +public class LRUCache { + // key -> Node(key, val) + private HashMap map; + // Node(k1, v1) <-> Node(k2, v2)... + private DoubleList cache; + // 最大容量 + private int cap; + + + public LRUCache(int capacity) { + this.cap = capacity; + map = new HashMap<>(); + cache = new DoubleList(); + } + + private static class Node { + public int key, val; + public Node next, prev; + + public Node(int k, int v) { + this.key = k; + this.val = v; + } + } + + private static class DoubleList implements Iterable { + private Node head, tail; // 头尾虚节点 + private int size; // 链表元素数 + + public DoubleList() { + head = new Node(0, 0); + tail = new Node(0, 0); + head.next = tail; + tail.prev = head; + size = 0; + } + + private class Itr implements Iterator { + private Node now = head; + + @Override + public boolean hasNext() { + return now.next != tail; + } + + @Override + public Node next() { + now = now.next; + return now; + } + + } + + // 在链表头部添加节点 node + public void addFirst(Node node) { + node.next = head.next; + node.prev = head; + head.next.prev = node; + head.next = node; + size++; + } + + // 删除链表中的 node 节点(node 一定存在) + public void remove(Node node) { + node.prev.next = node.next; + node.next.prev = node.prev; + size--; + } + + // 删除链表中最后一个节点,并返回该节点 + public Node removeLast() { + if (tail.prev == head) + return null; + Node last = tail.prev; + remove(last); + return last; + } + + // 返回链表长度 + public int size() { + return size; + } + + @Override + public Iterator iterator() { + return new Itr(); + } + + } + + public int get(int key) { + if (!map.containsKey(key)) + return -1; + int val = map.get(key).val; + // 利用 put 方法把该数据提前 + put(key, val); + return val; + } + + public void put(int key, int val) { + // 先把新节点 node 做出来 + Node node = new Node(key, val); + + if (map.containsKey(key)) { + // 删除旧的节点,新的插到头部 + cache.remove(map.get(key)); + cache.addFirst(node); + // 更新 map 中对应的数据 + map.put(key, node); + } else { + if (cap == cache.size()) { + // 删除链表最后一个数据 + Node last = cache.removeLast(); + map.remove(last.key); + } + // 直接添加到头部 + cache.addFirst(node); + map.put(key, node); + } + } + + public static void main(String[] args) { + LRUCache lruCache = new LRUCache(3); + lruCache.put(1, 1); + lruCache.put(2, 2); + lruCache.put(3, 3); + lruCache.get(2); + lruCache.put(4, 4); + DoubleList list = lruCache.cache; + for (Node node : list) { + System.out.println(node.key + "\t" + node.val); + } + } +} + + diff --git "a/algorithms/leetcode/other/src/main/java/cn/lastwhisper/leetcode/other/LRU\347\274\223\345\255\230\346\234\272\345\210\266146/MyLRUCache.java" "b/algorithms/leetcode/other/src/main/java/cn/lastwhisper/leetcode/other/LRU\347\274\223\345\255\230\346\234\272\345\210\266_146_\344\270\255\347\255\211/MyLRUCache.java" similarity index 91% rename from "algorithms/leetcode/other/src/main/java/cn/lastwhisper/leetcode/other/LRU\347\274\223\345\255\230\346\234\272\345\210\266146/MyLRUCache.java" rename to "algorithms/leetcode/other/src/main/java/cn/lastwhisper/leetcode/other/LRU\347\274\223\345\255\230\346\234\272\345\210\266_146_\344\270\255\347\255\211/MyLRUCache.java" index f3331c3c..234e6866 100644 --- "a/algorithms/leetcode/other/src/main/java/cn/lastwhisper/leetcode/other/LRU\347\274\223\345\255\230\346\234\272\345\210\266146/MyLRUCache.java" +++ "b/algorithms/leetcode/other/src/main/java/cn/lastwhisper/leetcode/other/LRU\347\274\223\345\255\230\346\234\272\345\210\266_146_\344\270\255\347\255\211/MyLRUCache.java" @@ -1,4 +1,4 @@ -package cn.lastwhisper.leetcode.other.LRU缓存机制146; +package cn.lastwhisper.leetcode.other.LRU缓存机制_146_中等; import java.util.HashMap; import java.util.Iterator; @@ -18,7 +18,7 @@ public MyLRUCache(int capacity) { this.capacity = capacity; } - class Node { + static class Node { public int key, val; public Node prev, next; @@ -29,12 +29,12 @@ public Node(int key, int val) { } /** - * 1、添加结点到链表头 - * 2、删除某结点 - * 3、获取尾结点 - * 每一步操作都要维护相关结点prev、next指针的关系 + * 1、添加节点到链表头 + * 2、删除某节点 + * 3、获取尾节点 + * 每一步操作都要维护相关节点prev、next指针的关系 */ - class DoubleLinkedList implements Iterable { + static class DoubleLinkedList implements Iterable { private Node head, tail; private int size; diff --git "a/algorithms/leetcode/other/src/main/java/cn/lastwhisper/leetcode/other/\344\272\214\350\277\233\345\210\266\346\261\202\345\222\214_67_\347\256\200\345\215\225/Solution1.java" "b/algorithms/leetcode/other/src/main/java/cn/lastwhisper/leetcode/other/\344\272\214\350\277\233\345\210\266\346\261\202\345\222\214_67_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..62558da6 --- /dev/null +++ "b/algorithms/leetcode/other/src/main/java/cn/lastwhisper/leetcode/other/\344\272\214\350\277\233\345\210\266\346\261\202\345\222\214_67_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,45 @@ +package cn.lastwhisper.leetcode.other.二进制求和_67_简单; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/add-binary/submissions/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:倒叙相加即可 + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public String addBinary(String a, String b) { + StringBuilder sb = new StringBuilder(); + // 进位 + int carry = 0; + int aIndex = a.length() - 1, bIndex = b.length() - 1; + + while (aIndex >= 0 || bIndex >= 0) { + int x, y, sum; + x = aIndex >= 0 ? a.charAt(aIndex) - '0' : 0; + y = bIndex >= 0 ? b.charAt(bIndex) - '0' : 0; + + sum = carry + x + y; + carry = sum / 2; + sb.append(sum % 2); + + aIndex--; + bIndex--; + } + + if (carry > 0) { + sb.append(carry); + } + return sb.reverse().toString(); + } + + public static void main(String[] args) { + String a = "11", b = "11"; + //String a = "1010", b = "1011"; + //String a = "11", b = "1"; + System.out.println(new Solution1().addBinary(a, b)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/other/src/main/java/cn/lastwhisper/leetcode/other/\345\210\206\347\263\226\346\236\234II_1103_\347\256\200\345\215\225/Solution.java" "b/algorithms/leetcode/other/src/main/java/cn/lastwhisper/leetcode/other/\345\210\206\347\263\226\346\236\234II_1103_\347\256\200\345\215\225/Solution.java" new file mode 100644 index 00000000..6e5c33a5 --- /dev/null +++ "b/algorithms/leetcode/other/src/main/java/cn/lastwhisper/leetcode/other/\345\210\206\347\263\226\346\236\234II_1103_\347\256\200\345\215\225/Solution.java" @@ -0,0 +1,44 @@ +package cn.lastwhisper.leetcode.other.分糖果II_1103_简单; + +import java.util.Arrays; + +class Solution { + /** + * 题目地址:https://leetcode-cn.com/problems/distribute-candies-to-people/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(num_people) + */ + public int[] distributeCandies(int candies, int num_people) { + + int[] nums = new int[num_people]; + + // 应该给的糖果 + int should = 1; + while (candies > 0) { + for (int i = 0; i < num_people; i++) { + // 当前剩余糖果大于应该给的糖果 + if (candies > should) { + candies -= should; + nums[i] += should; + } else { + nums[i] += candies; + candies -= candies; + break; + } + should++; + } + } + return nums; + } + + public static void main(String[] args) { + //int candies = 7, num_people = 4; + int candies = 10, num_people = 3; + System.out.println(Arrays.toString(new Solution().distributeCandies(candies, num_people))); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/other/src/main/java/cn/lastwhisper/leetcode/other/\345\233\233\347\232\204\345\271\202_342_\347\256\200\345\215\225/Solution1.java" "b/algorithms/leetcode/other/src/main/java/cn/lastwhisper/leetcode/other/\345\233\233\347\232\204\345\271\202_342_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..83331a61 --- /dev/null +++ "b/algorithms/leetcode/other/src/main/java/cn/lastwhisper/leetcode/other/\345\233\233\347\232\204\345\271\202_342_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,28 @@ +package cn.lastwhisper.leetcode.other.四的幂_342_简单; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/power-of-four/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * ------------------------------------------------------------------- + * 时间复杂度:O(1) + * 空间复杂度:O(1) + */ + //public boolean isPowerOfFour(int n) { + // if (n == 0) return false; + // while (n % 4 == 0) n /= 4; + // return n == 1; + //} + + public boolean isPowerOfFour(int num) { + return (num > 0) && (Math.log(num) / Math.log(2) % 2 == 0); + } + + public static void main(String[] args) { + int num = 16; + System.out.println(new Solution1().isPowerOfFour(num)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/other/src/main/java/cn/lastwhisper/leetcode/other/\351\207\215\345\244\215\345\217\240\345\212\240\345\255\227\347\254\246\344\270\262\345\214\271\351\205\215_686_\347\256\200\345\215\225/Solution1.java" "b/algorithms/leetcode/other/src/main/java/cn/lastwhisper/leetcode/other/\351\207\215\345\244\215\345\217\240\345\212\240\345\255\227\347\254\246\344\270\262\345\214\271\351\205\215_686_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..3c546398 --- /dev/null +++ "b/algorithms/leetcode/other/src/main/java/cn/lastwhisper/leetcode/other/\351\207\215\345\244\215\345\217\240\345\212\240\345\255\227\347\254\246\344\270\262\345\214\271\351\205\215_686_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,61 @@ +package cn.lastwhisper.leetcode.other.重复叠加字符串匹配_686_简单; + +class Solution1 { + /** + * 本题:https://leetcode-cn.com/problems/repeated-string-match/ + * ------------------------------------------------------------------- + * 数据特征: + * 输入:字符串、无序、26个小写字母 + * 输出:整数(-1或者叠加次数) + * ------------------------------------------------------------------- + * 思路:循环叠加A,使用String API查看是否包含B, + * 循环的终止条件为: + * (1)B.length() / A.length() + * (2)包含B + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(n) + * ------------------------------------------------------------------- + * 思考:lastIndexOf与indexOf要看数据的规律而是用, + * 比如这里使用lastIndexOf比使用indexOf要快很多 + */ + public int repeatedStringMatch(String A, String B) { + // B直接是A的子串 + if (A.lastIndexOf(B) != -1) return 1; + + /* + * A需要自己叠加多次,才满足B直接是A的子串, + * 这个叠加次数的限制满足 B.length() / A.length() + */ + int frequency = B.length() / A.length(); + StringBuilder sb = new StringBuilder(A); + for (int i = 2; i <= frequency + 2; i++) { + sb.append(A); + if (i >= frequency && sb.toString().lastIndexOf(B) != -1) return i; + } + return -1; + } + + public static void main(String[] args) { + // exmaple + //String A = "abcd"; + //String B = "cdabcdab"; + + // error example + //String A = "abc"; + //String B = "cabcabca"; + + //String A = "abcabcabcabc"; + //String B = "abac"; + + //String A = "aa"; + //String B = "a"; + + //String A = "aaaaaaaaaaaaaaaaaaaaaab"; + //String B = "ba"; + + String A = "a"; + String B = "aa"; + System.out.println(new Solution1().repeatedStringMatch(A, B)); + } +} \ No newline at end of file diff --git a/algorithms/leetcode/pom.xml b/algorithms/leetcode/pom.xml index 29cedc14..92f2b873 100644 --- a/algorithms/leetcode/pom.xml +++ b/algorithms/leetcode/pom.xml @@ -9,7 +9,6 @@ 4.0.0 - cn.lastwhisper leetcode pom @@ -18,10 +17,18 @@ linkedlist stackqueue binarytree - recurionbacktracking + recursion-backtracking dynamic greedy other + leetcode-common + binarysearch + union-find + week + bitoperation + dfsbfs + string + divide diff --git a/algorithms/leetcode/readme.md b/algorithms/leetcode/readme.md new file mode 100644 index 00000000..b5f83969 --- /dev/null +++ b/algorithms/leetcode/readme.md @@ -0,0 +1,168 @@ +``# 分类 + + + +- array 数组 +- hashtable 查找表 +- linkedlist 链表 +- stackqueue 栈与队列 +- binarysearch 二叉树和递归 +- recursion-backtracking 递归与回溯 +- dynamic 动态规划 +- greedy 贪心 +- binarysearch 二分查找 +- bitoperation 位运算 +- dfsbfs 深度宽度搜索 +- divide 分治 +- leetcode-common 工具类 +- string 字符串 +- union-find 并查集 + +# 第一遍 + +| 章节 | 讲解例题 | 课程练习题 | +| ------------------------------------------------------------ | ---------- | ----------------------- | +| **第一章 算法面试到底是什么鬼?** | [无] | [无] | +| **第二章 面试中的复杂度分析** | [无] | [无] | +| **第三章 数组中的问题最常见** | | | +| 3-1 从二分查找法看如何写出正确的程序 | [无] | [无] | +| 3-2 改变变量定义,依然可以写出正确的算法 | [无] | [无] | +| 3-3 在LeetCode上解决第一个问题 Move Zeros | ~~283~~ | [无] | +| 3-4 即使简单的问题,也有很多优化的思路 | ~~283~~ | ~~27 26 80~~ | +| 3-5 三路快排partition思路的应用 Sort Color | ~~75~~ of40 | ~~88 215~~ | +| 3-6 对撞指针 Two Sum II - Input Array is Sorted | ~~167~~ | ~~125 344 345 11~~ | +| 3-7 滑动窗口 Minimum Size Subarray Sum | ~~209 3~~ | ~~438 76~~ | +| 3-8 其他 | | 1013 | +| **第四章 查找表相关问题** | | | +| 4-1 set的使用 Intersection of Two Arrays | ~~349~~ | [无] | +| 4-2 map的使用 Intersection of Two Arrays II | ~~350~~ | [无] | +| 4-3 set和map不同底层实现的区别 | ~~349 350~~ | ~~136 242 202 290 205 451~~ | +| 4-4 使用查找表的经典问题 Two Sum | ~~1~~ | ~~15 18 16~~ | +| 4-5 灵活选择键值 4Sum II | ~~454~~ | ~~49~~ | +| 4-6 灵活选择键值 Number of Boomerangs | ~~447~~ | ~~*149~~ **719** | +| 4-7 查找表和滑动窗口 Contain Duplicate II | ~~219~~ | | +| 4-8 二分搜索树底层实现的顺序性 Contain Duplicate III | ~~*220~~ | [无] | +| **第五章 在链表中穿针引线** | | | +| 5-1 链表,在节点间穿针引线 Reverse Linked List | ~~206~~ | ~~*92~~ | +| 5-2 测试你的链表程序 | ~~206~~ | ~~83~~ ~~86~~ ~~328~~ ~~2 445~~ | +| 5-3 设立链表的虚拟头节点 Remove Linked List Elements | ~~203~~ | ~~82~~ ~~*21(递归)~~ | +| 5-4 复杂的穿针引线 Swap Nodes in Pairs | ~~*24~~ | **25 147 148** | +| 5-5 不仅仅是穿针引线 Delete Node in a Linked List | ~~237~~ | [无] | +| 5-6 链表与双指针 Remove Nth Node Form End of List | ~~19~~ | **61** ~~143 234~~ | +| 额外刷题 | **160** | ~~876~~ | +| **第六章 栈、队列、优先队列** | | | +| 6-1 栈的基础应用 Valid Parentheses | ~~20~~ | ~~150 71~~ | +| 6-2 栈和递归的紧密关系 Binary Tree Preorder, Inorder and Postorder Traversal | ~~144 94 145~~ | [无] | +| 6-3 运用栈模拟递归 | ~~*144 94 145~~ | **341** | +| 6-4 队列的典型应用 Binary Tree Level Order Traversal | ~~102~~ | ~~107 103 199~~ **346** | +| 6-5 BFS和图的最短路径 Perfect Squares | ~~*279~~ | **127 126** **286** | +| 6-6 优先队列 | [无] | [无] | +| 6-7 优先队列相关的算法问题 Top K Frequent Elements | ~~347~~ | ~~23~~ | +| **第七章 二叉树和递归** | | | +| 7-1 二叉树天然的递归结构 | ~~*104(重点看)~~ | ~~*111(重点看)~~ | +| 7-2 一个简单的二叉树问题引发的血案 Invert Binary Tree | ~~*226~~ | ~~100 101 222 *110~~ | +| 7-3 注意递归的终止条件 Path Sum | ~~112~~ | ~~404~~ | +| 7-4 定义递归问题 Binary Tree Path | ~~257~~ | ~~113 129 222~~ | +| 7-5 稍复杂的递归逻辑 Path Sum III | ~~437~~ | [无] | +| 7-6 二分搜索树中的问题 Lowest Common Ancestor of a Binary Search Tree | ~~783 235~~ | ~~*98~~ **450 108 230 236 530** | +| **第八章 递归和回溯法** | | | +| 8-1 树形问题 Letter Combinations of a Phone Number | ~~*17~~ | [无] | +| 8-2 什么是回溯 | ~~17~~ | ~~*93~~ 131 | +| 8-3 排列问题 Permutations | ~~*46~~ | ~~*47~~ | +| 8-4 组合问题 Combinations | ~~*77~~ | [无] | +| 8-5 回溯法解决组合问题的优化 | ~~*77~~ | ~~39~~ ~~40~~ 216 **78 90** ~~401~~ | +| 8-6 二维平面上的回溯法 Word Search | ~~79~~ | [无] | +| 8-7 floodfill算法,一类经典问题 Number of Islands | ~~200~~ | 130 417 | +| 8-8 回溯法是经典人工智能的基础 N Queens | ~~51~~ | ~~52~~ 37 | +| **第九章 动态规划基础** | | | +| 9-1 什么是动态规划 | [无] | [无] | +| 9-2 第一个动态规划问题 Climbing Stairs | ~~70~~ | ~~120~~ ~~64~~ | +| 9-3 发现重叠子问题 Integer Break | ~~*343~~ | ~~*279 *91 62 *63~~ | +| 9-4 状态的定义和状态转移 House Robber | ~~198~~ | 213 337 309 | +| 9-5 0-1背包问题 | [无] | [无] | +| 9-6 0-1背包问题的优化和变种 | [无] | [无] | +| 9-7 面试中的0-1背包问题 Partition Equal Subset Sum | ~~*416~~ | ~~*322~~ 377 474 139 494 | +| 9-8 LIS问题 Longest Increasing Subsequence | ~~300~~ | 376 | +| 9-9 LCS,最短路,求动态规划的具体解以及更多 | [无] | [无] | +| 其他 | ~~53~~ | [无] | +| **第十章 贪心算法** | | | +| 10-1 贪心基础 Assign Cookies | ~~455~~ | ~~392~~ | +| 10-2 贪心算法与动态规划的关系 Non-overlapping Intervals | 435 | [无] | +| 10-3 贪心选择性质的证明 | [无] | [无] | + +# 第二遍 + +2022年4月21日 + +| 章节 | 讲解例题 | 课程练习题 | +| ------------------------------------------------------------ | ---------------- | ----------------------------------- | +| **第一章 算法面试到底是什么鬼?** | [无] | [无] | +| **第二章 面试中的复杂度分析** | [无] | [无] | +| **第三章 数组中的问题最常见** | | | +| 3-1 从二分查找法看如何写出正确的程序 | [无] | [无] | +| 3-2 改变变量定义,依然可以写出正确的算法 | [无] | [无] | +| 3-3 在LeetCode上解决第一个问题 Move Zeros | ~~283~~ | [无] | +| 3-4 即使简单的问题,也有很多优化的思路 | ~~283~~ | ~~27 26 80~~ | +| 3-5 三路快排partition思路的应用 Sort Color | ~~75~~ of40 | ~~88 215~~ | +| 3-6 对撞指针 Two Sum II - Input Array is Sorted | ~~167~~ | ~~125 344 345 11~~ | +| 3-7 滑动窗口 Minimum Size Subarray Sum | ~~209 3~~ | ~~438 76~~ | +| 3-8 其他 | | 1013 | +| **第四章 查找表相关问题** | | | +| 4-1 set的使用 Intersection of Two Arrays | ~~349~~ | [无] | +| 4-2 map的使用 Intersection of Two Arrays II | ~~350~~ | [无] | +| 4-3 set和map不同底层实现的区别 | ~~349 350~~ | ~~136 242 202 290 205 451~~ | +| 4-4 使用查找表的经典问题 Two Sum | ~~1~~ | ~~15 18 16~~ | +| 4-5 灵活选择键值 4Sum II | ~~454~~ | ~~49~~ | +| 4-6 灵活选择键值 Number of Boomerangs | ~~447~~ | ~~*149~~ **719** | +| 4-7 查找表和滑动窗口 Contain Duplicate II | ~~219~~ | | +| 4-8 二分搜索树底层实现的顺序性 Contain Duplicate III | ~~*220~~ | [无] | +| **第五章 在链表中穿针引线** | | | +| 5-1 链表,在节点间穿针引线 Reverse Linked List | ~~206~~ | ~~*92~~ | +| 5-2 测试你的链表程序 | ~~206~~ | ~~83~~ ~~86~~ ~~328~~ ~~2 445~~ | +| 5-3 设立链表的虚拟头节点 Remove Linked List Elements | ~~203~~ | ~~82~~ ~~*21(递归)~~ | +| 5-4 复杂的穿针引线 Swap Nodes in Pairs | ~~*24~~ | **25 147 148** | +| 5-5 不仅仅是穿针引线 Delete Node in a Linked List | ~~237~~ | [无] | +| 5-6 链表与双指针 Remove Nth Node Form End of List | ~~19~~ | **61** ~~143 234~~ | +| 额外刷题 | **160** | ~~876~~ | +| **第六章 栈、队列、优先队列** | | | +| 6-1 栈的基础应用 Valid Parentheses | ~~20~~ | ~~150 71~~ | +| 6-2 栈和递归的紧密关系 Binary Tree Preorder, Inorder and Postorder Traversal | ~~144 94 145~~ | [无] | +| 6-3 运用栈模拟递归 | ~~*144 94 145~~ | **341** | +| 6-4 队列的典型应用 Binary Tree Level Order Traversal | ~~102~~ | ~~107 103 199~~ **346** | +| 6-5 BFS和图的最短路径 Perfect Squares | ~~*279~~ | **127 126** **286** | +| 6-6 优先队列 | [无] | [无] | +| 6-7 优先队列相关的算法问题 Top K Frequent Elements | ~~347~~ | ~~23~~ | +| **第七章 二叉树和递归** | | | +| 7-1 二叉树天然的递归结构 | ~~*104(重点看)~~ | ~~*111(重点看)~~ | +| 7-2 一个简单的二叉树问题引发的血案 Invert Binary Tree | ~~*226~~ | ~~100 101 222 *110~~ | +| 7-3 注意递归的终止条件 Path Sum | ~~112~~ | ~~404~~ | +| 7-4 定义递归问题 Binary Tree Path | ~~257~~ | ~~113 129 222~~ | +| 7-5 稍复杂的递归逻辑 Path Sum III | ~~437~~ | [无] | +| 7-6 二分搜索树中的问题 Lowest Common Ancestor of a Binary Search Tree | ~~783 235~~ | ~~*98~~ **450 108 230 236 530** | +| **第八章 递归和回溯法** | | | +| 8-1 树形问题 Letter Combinations of a Phone Number | ~~*17~~ | [无] | +| 8-2 什么是回溯 | ~~17~~ | ~~*93~~ 131 | +| 8-3 排列问题 Permutations | ~~*46~~ | ~~*47~~ | +| 8-4 组合问题 Combinations | ~~*77~~ | [无] | +| 8-5 回溯法解决组合问题的优化 | ~~*77~~ | ~~39~~ ~~40~~ 216 **78 90** ~~401~~ | +| 8-6 二维平面上的回溯法 Word Search | ~~79~~ | [无] | +| 8-7 floodfill算法,一类经典问题 Number of Islands | ~~200~~ | 130 417 | +| 8-8 回溯法是经典人工智能的基础 N Queens | ~~51~~ | ~~52~~ 37 | +| **第九章 动态规划基础** | | | +| 9-1 什么是动态规划 | [无] | [无] | +| 9-2 第一个动态规划问题 Climbing Stairs | ~~70~~ | ~~120~~ ~~64~~ | +| 9-3 发现重叠子问题 Integer Break | ~~*343~~ | ~~*279 *91 62 *63~~ | +| 9-4 状态的定义和状态转移 House Robber | ~~198~~ | 213 337 309 | +| 9-5 0-1背包问题 | [无] | [无] | +| 9-6 0-1背包问题的优化和变种 | [无] | [无] | +| 9-7 面试中的0-1背包问题 Partition Equal Subset Sum | ~~*416~~ | ~~*322~~ 377 474 139 494 | +| 9-8 LIS问题 Longest Increasing Subsequence | ~~300~~ | 376 | +| 9-9 LCS,最短路,求动态规划的具体解以及更多 | [无] | [无] | +| 其他 | ~~53~~ | [无] | +| **第十章 贪心算法** | | | +| 10-1 贪心基础 Assign Cookies | ~~455~~ | ~~392~~ | +| 10-2 贪心算法与动态规划的关系 Non-overlapping Intervals | 435 | [无] | +| 10-3 贪心选择性质的证明 | [无] | [无] | + + + diff --git a/algorithms/leetcode/recurionbacktracking/pom.xml b/algorithms/leetcode/recurionbacktracking/pom.xml deleted file mode 100644 index dbb60db6..00000000 --- a/algorithms/leetcode/recurionbacktracking/pom.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - leetcode - cn.lastwhisper - 1.0-SNAPSHOT - - 4.0.0 - - cn.lastwhisper.leetcode - recurionbacktracking - - - \ No newline at end of file diff --git a/algorithms/leetcode/recursion-backtracking/pom.xml b/algorithms/leetcode/recursion-backtracking/pom.xml new file mode 100644 index 00000000..5c6ef14e --- /dev/null +++ b/algorithms/leetcode/recursion-backtracking/pom.xml @@ -0,0 +1,22 @@ + + + + leetcode + cn.lastwhisper + 1.0-SNAPSHOT + + 4.0.0 + + cn.lastwhisper.leetcode + recursion-backtracking + + + + cn.lastwhisper + leetcode-common + 1.0-SNAPSHOT + + + \ No newline at end of file diff --git "a/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/N\347\232\207\345\220\216II_52_\345\233\260\351\232\276/Solution1.java" "b/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/N\347\232\207\345\220\216II_52_\345\233\260\351\232\276/Solution1.java" new file mode 100644 index 00000000..b2ba8d2b --- /dev/null +++ "b/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/N\347\232\207\345\220\216II_52_\345\233\260\351\232\276/Solution1.java" @@ -0,0 +1,69 @@ +package cn.lastwhisper.leetcode.recurionbacktracking.N皇后II_52_困难; + +import java.util.ArrayList; +import java.util.List; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/n-queens-ii/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:递归+回溯 + * 递归: + * 1.当前列没有其他棋子 + * 2.右上到左下对角线没有其他棋子 + * 3.左上到右下对角线没有其他棋子 + * 回溯: + * 递归终止: + * index==n时,解集数量增加 + * ------------------------------------------------------------------- + * 时间复杂度:O(n*(n+1)) + * 空间复杂度: + */ + private boolean[] col;//列 + private boolean[] diagonal1;//右上到左下对角线 + private boolean[] diagonal2;//左上到右下对角线 + private int result; + + public int totalNQueens(int n) { + + col = new boolean[n]; + diagonal1 = new boolean[2 * n - 1]; + diagonal2 = new boolean[2 * n - 1]; + putQ(n, 0); + + return result; + } + + /** + * 尝试在一个n皇后问题中, 摆放第index行的皇后位置 + * + * @param n n皇后 + * @param index 当前处于第index行 + */ + private void putQ(int n, int index) { + if (n == index) { + result++; + return; + } + // n列 + for (int j = 0; j < n; j++) { + // 在第index行,第j列是否可以放 + if (!col[j] && !diagonal1[index + j] && !diagonal2[index - j + n - 1]) { + col[j] = true; + diagonal1[index + j] = true; + diagonal2[index - j + n - 1] = true; + putQ(n, index + 1); + col[j] = false; + diagonal1[index + j] = false; + diagonal2[index - j + n - 1] = false; + } + } + } + + public static void main(String[] args) { + System.out.println(new Solution1().totalNQueens(4)); + ; + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/N\347\232\207\345\220\216II_52_\345\233\260\351\232\276/Solution2.java" "b/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/N\347\232\207\345\220\216II_52_\345\233\260\351\232\276/Solution2.java" new file mode 100644 index 00000000..87589593 --- /dev/null +++ "b/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/N\347\232\207\345\220\216II_52_\345\233\260\351\232\276/Solution2.java" @@ -0,0 +1,56 @@ +package cn.lastwhisper.leetcode.recurionbacktracking.N皇后II_52_困难; + +class Solution2 { + private int backtrack(int row, int hills, int next_row, int dales, int count, int n) { + /* + row: 当前放置皇后的行号 + hills: 主对角线占据情况 [1 = 被占据,0 = 未被占据] + next_row: 下一行被占据的情况 [1 = 被占据,0 = 未被占据] + dales: 次对角线占据情况 [1 = 被占据,0 = 未被占据] + count: 所有可行解的个数 + */ + + // 棋盘所有的列都可放置, + // 即,按位表示为 n 个 '1' + // bin(cols) = 0b1111 (n = 4), bin(cols) = 0b111 (n = 3) + // [1 = 可放置] + int columns = (1 << n) - 1; + + if (row == n) // 如果已经放置了 n 个皇后 + count++; // 累加可行解 + else { + // 当前行可用的列 + // ! 表示 0 和 1 的含义对于变量 hills, next_row and dales的含义是相反的 + // [1 = 未被占据,0 = 被占据] + int free_columns = columns & ~(hills | next_row | dales); + + // 找到可以放置下一个皇后的列 + while (free_columns != 0) { + // free_columns 的第一个为 '1' 的位 + // 在该列我们放置当前皇后 + int curr_column = -free_columns & free_columns; + + // 放置皇后 + // 并且排除对应的列 + free_columns ^= curr_column; + + count = backtrack(row + 1, + (hills | curr_column) << 1, + next_row | curr_column, + (dales | curr_column) >> 1, + count, n); + } + } + + return count; + } + + public int totalNQueens(int n) { + return backtrack(0, 0, 0, 0, 0, n); + } + + + public static void main(String[] args) { + System.out.println(new Solution2().totalNQueens(4)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/N\347\232\207\345\220\216_51_\345\233\260\351\232\276/Solution1.java" "b/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/N\347\232\207\345\220\216_51_\345\233\260\351\232\276/Solution1.java" new file mode 100644 index 00000000..a5db15e7 --- /dev/null +++ "b/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/N\347\232\207\345\220\216_51_\345\233\260\351\232\276/Solution1.java" @@ -0,0 +1,95 @@ +package cn.lastwhisper.leetcode.recurionbacktracking.N皇后_51_困难; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static cn.lastwhisper.leetcode.common.print.PrintUtil.printStringLists; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/n-queens/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:递归+回溯 + * 递归: + * 1.当前列没有其他棋子 + * 2.右上到左下对角线没有其他棋子 + * 3.左上到右下对角线没有其他棋子 + * 回溯: + * 递归终止: + * index==n时,根据n和列生成对应的“n皇后”棋盘 + * ------------------------------------------------------------------- + * 时间复杂度:O(n!) + * 空间复杂度:O(n) //对角线 + */ + private boolean[] col;//列 + private boolean[] diagonal1;//右上到左下对角线 + private boolean[] diagonal2;//左上到右下对角线 + + public List> solveNQueens(int n) { + List> result = new ArrayList<>(); + if (n <= 0) { + return result; + } + col = new boolean[n]; + diagonal1 = new boolean[2 * n - 1]; + diagonal2 = new boolean[2 * n - 1]; + + putQ(n, 0, new ArrayList<>(n), result); + return result; + } + + /** + * 尝试在一个n皇后问题中, 摆放第index行的皇后位置 + * + * @param n n皇后 + * @param row 当前处于第row行 + * @param columns 已经摆放的列位置 + */ + private void putQ(int n, int row, List columns, List> result) { + if (n == row) { + result.add(generateBoard(n, columns)); + return; + } + // n列 + for (int col = 0; col < n; col++) { + // 在第row行,第j列是否可以放 + if (!this.col[col] && !diagonal1[row + col] && !diagonal2[row - col + n - 1]) { + columns.add(col); + this.col[col] = true; + diagonal1[row + col] = true; + diagonal2[row - col + n - 1] = true; + putQ(n, row + 1, columns, result); + columns.remove(columns.size() - 1); + this.col[col] = false; + diagonal1[row + col] = false; + diagonal2[row - col + n - 1] = false; + } + } + } + + /** + * 生成nQueue的一种可能 + * @param n nQueue + * @param column 棋子所在行和列 + */ + private List generateBoard(int n, List column) { + assert column.size() == n; + ArrayList board = new ArrayList<>(); + for (int i = 0; i < n; i++) { + // 每一行 + char[] charArray = new char[n]; + Arrays.fill(charArray, '.'); + // 第i行第column[i]列 + charArray[column.get(i)] = 'Q'; + board.add(new String(charArray)); + } + return board; + } + + public static void main(String[] args) { + printStringLists(new Solution1().solveNQueens(4)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/N\347\232\207\345\220\216_51_\345\233\260\351\232\276/Solution2.java" "b/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/N\347\232\207\345\220\216_51_\345\233\260\351\232\276/Solution2.java" new file mode 100644 index 00000000..82a0bf06 --- /dev/null +++ "b/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/N\347\232\207\345\220\216_51_\345\233\260\351\232\276/Solution2.java" @@ -0,0 +1,81 @@ +package cn.lastwhisper.leetcode.recurionbacktracking.N皇后_51_困难; + +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; + +import static cn.lastwhisper.leetcode.common.print.PrintUtil.printStringLists; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/n-queens/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:递归+回溯 + * 递归: + * 回溯: + * 递归终止: + * ------------------------------------------------------------------- + * 时间复杂度:O(n!) + * 空间复杂度:O(n) //对角线 + */ + private static List charToString(char[][] array) { + List result = new LinkedList<>(); + for (char[] chars : array) { + result.add(String.valueOf(chars)); + } + return result; + } + + public List> solveNQueens(int n) { + if (n <= 0) return null; + List> result = new LinkedList<>(); + char[][] board = new char[n][n]; + for (char[] chars : board) Arrays.fill(chars, '.'); + backtrack(board, 0, result); + return result; + } + + /** + * 路径:board中小于row的那些行都已经成功放置了皇后 + * 可选择列表: 第row行的所有列都是放置Q的选择 + * 结束条件: row超过board的最后一行 + * + * @param board + * @param row + */ + private void backtrack(char[][] board, int row, List> result) { + if (row == board.length) { + result.add(charToString(board)); + return; + } + int n = board[row].length; + for (int col = 0; col < n; col++) { + if (isValid(board, row, col)) { + board[row][col] = 'Q'; + backtrack(board, row + 1, result); + board[row][col] = '.'; + } + } + } + + private boolean isValid(char[][] board, int row, int col) { + int rows = board.length; + // 垂直方向 + for (char[] chars : board) if (chars[col] == 'Q') return false; + // 右上 + for (int i = row - 1, j = col + 1; i >= 0 && j < rows; i--, j++) { + if (board[i][j] == 'Q') return false; + } + // 左上 + for (int i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) { + if (board[i][j] == 'Q') return false; + } + return true; + } + + public static void main(String[] args) { + printStringLists(new Solution2().solveNQueens(4)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/\344\272\214\350\277\233\345\210\266\346\211\213\350\241\250_401_\347\256\200\345\215\225/Solution1.java" "b/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/\344\272\214\350\277\233\345\210\266\346\211\213\350\241\250_401_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..8b6a396f --- /dev/null +++ "b/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/\344\272\214\350\277\233\345\210\266\346\211\213\350\241\250_401_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,39 @@ +package cn.lastwhisper.leetcode.recurionbacktracking.二进制手表_401_简单; + +import java.util.ArrayList; +import java.util.List; + +import static cn.lastwhisper.leetcode.common.print.PrintUtil.printList; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/binary-watch/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:暴力 + * 表中的十位数:“1、2、4、8”、“1、2、4、8、16、32”,在二进制中都只有一位为1,12小时可以使用这十个最基本的数组成。 + * num表示这十位数出现几个,实际上出现几个就有几个二进制的1。 + * 从0:00-》11:59 直接判断小时位出现的1个数+分秒位出现的1个数 + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public List readBinaryWatch(int num) { + List result = new ArrayList<>(); + for (int i = 0; i < 12; i++) { + for (int j = 0; j < 60; j++) { + // num=hour二进制为1的数量+second二进制为1的数量 + if (Integer.bitCount(i) + Integer.bitCount(j) == num) { + result.add(String.format("%d:%02d", i, j)); + } + } + } + return result; + } + + public static void main(String[] args) { + printList(new Solution1().readBinaryWatch(3)); + //System.out.println(Integer.bitCount(4)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/\344\272\214\350\277\233\345\210\266\346\211\213\350\241\250_401_\347\256\200\345\215\225/Solution2.java" "b/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/\344\272\214\350\277\233\345\210\266\346\211\213\350\241\250_401_\347\256\200\345\215\225/Solution2.java" new file mode 100644 index 00000000..17ef599c --- /dev/null +++ "b/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/\344\272\214\350\277\233\345\210\266\346\211\213\350\241\250_401_\347\256\200\345\215\225/Solution2.java" @@ -0,0 +1,52 @@ +package cn.lastwhisper.leetcode.recurionbacktracking.二进制手表_401_简单; + +import java.util.ArrayList; +import java.util.List; + +import static cn.lastwhisper.leetcode.common.print.PrintUtil.printList; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/binary-watch/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:树形问题——递归回溯 + * ------------------------------------------------------------------- + * 时间复杂度:O(n*n!) + * 空间复杂度:O(n*n!) + */ + public List readBinaryWatch(int num) { + List result = new ArrayList<>(); + dfs(num, 0, new int[10], result); + return result; + } + + /** + * C(10,num) 问题 + * @param num 未被点亮的灯数 + * @param index 递归的起始值 + * @param stat 基础的十个数,0表示未点亮,1表示点亮 + */ + public void dfs(int num, int index, int[] stat, List result) { + // 灯都被点亮过了 + if (num == 0) { + int hour = stat[0] + 2 * stat[1] + 4 * stat[2] + 8 * stat[3]; + int minute = stat[4] + 2 * stat[5] + 4 * stat[6] + 8 * stat[7] + 16 * stat[8] + 32 * stat[9]; + if (hour < 12 && minute < 60) { + result.add(String.format("%d:%02d", hour, minute)); + } + return; + } + + for (int i = index; i < stat.length; i++) { + stat[i] = 1; + dfs(num - 1, i + 1, stat, result); + stat[i] = 0; + } + } + + public static void main(String[] args) { + printList(new Solution2().readBinaryWatch(2)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/\344\272\214\350\277\233\345\210\266\346\211\213\350\241\250_401_\347\256\200\345\215\225/Solution3.java" "b/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/\344\272\214\350\277\233\345\210\266\346\211\213\350\241\250_401_\347\256\200\345\215\225/Solution3.java" new file mode 100644 index 00000000..fb65748a --- /dev/null +++ "b/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/\344\272\214\350\277\233\345\210\266\346\211\213\350\241\250_401_\347\256\200\345\215\225/Solution3.java" @@ -0,0 +1,52 @@ +package cn.lastwhisper.leetcode.recurionbacktracking.二进制手表_401_简单; + +import java.util.ArrayList; +import java.util.List; + +import static cn.lastwhisper.leetcode.common.print.PrintUtil.printList; + +class Solution3 { + /** + * 题目地址:https://leetcode-cn.com/problems/binary-watch/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:树形问题——递归回溯——剪枝 + * ------------------------------------------------------------------- + * 时间复杂度:O(n*n!) + * 空间复杂度:O(n*n!) + */ + public List readBinaryWatch(int num) { + List result = new ArrayList<>(); + dfs(num, 0, 0, new int[10], result); + return result; + } + + /** + * C(10,num) 问题 + * @param num 未被点亮的灯数 + * @param index 递归的起始值 + * @param stat 基础的十个数,0表示未点亮,1表示点亮 + */ + public void dfs(int num, int index, int len, int[] stat, List result) { + // 灯都被点亮过了 + if (num == len) { + int hour = stat[0] + 2 * stat[1] + 4 * stat[2] + 8 * stat[3]; + int minute = stat[4] + 2 * stat[5] + 4 * stat[6] + 8 * stat[7] + 16 * stat[8] + 32 * stat[9]; + if (hour < 12 && minute < 60) { + result.add(String.format("%d:%02d", hour, minute)); + } + return; + } + // 剪枝 i<=9 ----> i<=9-(num-len)+1 + for (int i = index; i <= (9 - (num - len) + 1); i++) { + stat[i] = 1; + dfs(num, i + 1, len + 1, stat, result); + stat[i] = 0; + } + } + + public static void main(String[] args) { + printList(new Solution3().readBinaryWatch(2)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/\345\205\250\346\216\222\345\210\227_46_\344\270\255\347\255\211/Solution1.java" "b/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/\345\205\250\346\216\222\345\210\227_46_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..ebd5f4b3 --- /dev/null +++ "b/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/\345\205\250\346\216\222\345\210\227_46_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,68 @@ +package cn.lastwhisper.leetcode.recurionbacktracking.全排列_46_中等; + +import java.util.ArrayList; +import java.util.List; + +import static cn.lastwhisper.leetcode.common.print.PrintUtil.collection2String; +import static cn.lastwhisper.leetcode.common.print.PrintUtil.printLists; + +class Solution1 { + static Integer count = 0; + + /** + * 题目地址:https://leetcode-cn.com/problems/letter-combinations-of-a-phone-number/ + * ------------------------------------------------------------------- + * 思考: + * Q:为什么需要回溯? + * A:在树形问题中,每一个节点保存了上一个结点的值,由于这里使用一个集合存储结点值, + * 为了复用这个集合,必须回溯,重置集合的状态。 + * Q:可以不回溯吗? + * A:可以,每个结点存储上一个结点的值即可,不过这样会产生大量的临时变量。 + * ------------------------------------------------------------------- + * 思路:树形问题-递归回溯 + * ------------------------------------------------------------------- + * 时间复杂度:O(n*n!) + * 空间复杂度:O(n*n!) + */ + public List> permute(int[] nums) { + List> result = new ArrayList<>(); + boolean[] visited = new boolean[nums.length]; + dfsPermute(nums, visited, new ArrayList<>(), result); + return result; + } + + /** + * @param nums 输入数字数组 + * @param visited 数字被访问过true,没有为false + * @param permute 排列 + * @param result 返回结果 + */ + private void dfsPermute(int[] nums, boolean[] visited, List permute, List> result) { + count++; + if (permute.size() == nums.length) { + // 每次必须new,因为这个permute集合需要重复使用 + result.add(new ArrayList<>(permute)); + System.out.println("递归终止——第" + count + "层递归——permute=" + collection2String(permute)); + return; + } + for (int i = 0; i < nums.length; i++) { + // 使用visited数组(O(1))查询是否访问过,而不使用List.contains(O(n))。 + if (!visited[i]) { + visited[i] = true; + permute.add(nums[i]); + System.out.println("递归——第" + count + "层递归——visited[" + i + "]=" + visited[i] + ",permute=" + collection2String(permute)); + dfsPermute(nums, visited, permute, result); + count--; + // backtracking + visited[i] = false; + permute.remove(permute.size() - 1); + System.out.println("回溯————第" + count + "层递归——visited[" + i + "]=" + visited[i] + ",permute=" + collection2String(permute)); + } + } + System.out.println("递归终止——第" + count + "层递归——permute=" + collection2String(permute)); + } + + public static void main(String[] args) { + printLists(new Solution1().permute(new int[]{1, 2, 3})); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/\345\205\250\346\216\222\345\210\227_46_\344\270\255\347\255\211/Solution2.java" "b/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/\345\205\250\346\216\222\345\210\227_46_\344\270\255\347\255\211/Solution2.java" new file mode 100644 index 00000000..34fd2e06 --- /dev/null +++ "b/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/\345\205\250\346\216\222\345\210\227_46_\344\270\255\347\255\211/Solution2.java" @@ -0,0 +1,66 @@ +package cn.lastwhisper.leetcode.recurionbacktracking.全排列_46_中等; + +import java.util.ArrayList; +import java.util.List; + +import static cn.lastwhisper.leetcode.common.print.PrintUtil.printLists; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/letter-combinations-of-a-phone-number/ + * ------------------------------------------------------------------- + * 思考: + * https://leetcode-cn.com/problems/permutations/solution/hui-su-suan-fa-python-dai-ma-java-dai-ma-by-liweiw/ + * ------------------------------------------------------------------- + * 思路:树形问题-递归,不进行回溯 + * ------------------------------------------------------------------- + * 时间复杂度:O(n*n!) + * 空间复杂度:O(n*n!) + */ + public List> permute(int[] nums) { + List> result = new ArrayList<>(); + boolean[] visited = new boolean[nums.length]; + dfsPermute(nums, visited, new ArrayList<>(), result); + return result; + } + + /** + * @param nums 输入数字数组 + * @param visited 数字被访问过true,没有为false + * @param permute 排列 + * @param result 返回结果 + */ + public void dfsPermute(int[] nums, boolean[] visited, List permute, List> result) { + if (permute.size() == nums.length) { + // 3、不用拷贝,因为每一层传递下来的 permute 变量都是新建的 + result.add(permute); + return; + } + for (int i = 0; i < nums.length; i++) { + if (!visited[i]) { + /* + * //不能这样写,因为这样改变了上一个结点的值 + * permute.add(nums[i]); + * visited[i] = true; + * + * List newPermute = new ArrayList<>(permute); + * boolean[] newVisited = new boolean[nums.length]; + * System.arraycopy(visited, 0, newVisited, 0, nums.length); + */ + // 1、每一次尝试都创建新的变量表示当前的"状态" + List newPermute = new ArrayList<>(permute); + newPermute.add(nums[i]); + boolean[] newVisited = new boolean[nums.length]; + System.arraycopy(visited, 0, newVisited, 0, nums.length); + newVisited[i] = true; + + dfsPermute(nums, newVisited, newPermute, result); + // 2、无需回溯 + } + } + } + + public static void main(String[] args) { + printLists(new Solution2().permute(new int[]{1, 2, 3})); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/\345\205\250\346\216\222\345\210\227_46_\344\270\255\347\255\211/Solution3.java" "b/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/\345\205\250\346\216\222\345\210\227_46_\344\270\255\347\255\211/Solution3.java" new file mode 100644 index 00000000..74642a5a --- /dev/null +++ "b/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/\345\205\250\346\216\222\345\210\227_46_\344\270\255\347\255\211/Solution3.java" @@ -0,0 +1,67 @@ +package cn.lastwhisper.leetcode.recurionbacktracking.全排列_46_中等; + +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Deque; +import java.util.List; + +import static cn.lastwhisper.leetcode.common.print.PrintUtil.printLists; + + +public class Solution3 { + /** + * 题目地址:https://leetcode-cn.com/problems/letter-combinations-of-a-phone-number/ + * ------------------------------------------------------------------- + * 思考: + * https://leetcode-cn.com/problems/permutations/solution/hui-su-suan-fa-python-dai-ma-java-dai-ma-by-liweiw/ + * ------------------------------------------------------------------- + * 思路:树形问题-递归 + * ------------------------------------------------------------------- + * 时间复杂度:O(n*n!) + * 空间复杂度:O(n*n!) + */ + public List> permute(int[] nums) { + int len = nums.length; + List> res = new ArrayList<>(factorial(len)); + if (len == 0) { + return res; + } + + int used = 0; + Deque path = new ArrayDeque<>(len); + dfs(nums, path, used, res); + return res; + } + + private int factorial(int n) { + int res = 1; + for (int i = 2; i <= n; i++) { + res *= i; + } + return res; + } + + private void dfs(int[] nums, + Deque path, int used, + List> res) { + if (path.size() == nums.length) { + res.add(new ArrayList<>(path)); + return; + } + + for (int i = 0; i < nums.length; i++) { + if (((used >> i) & 1) == 0) { + path.addLast(nums[i]); + used ^= (1 << i); + + dfs(nums, path, used, res); + used ^= (1 << i); + path.removeLast(); + } + } + } + + public static void main(String[] args) { + printLists(new Solution3().permute(new int[]{1, 2, 3})); + } +} diff --git "a/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/\345\205\250\346\216\222\345\210\227_II_47_\344\270\255\347\255\211/Solution1.java" "b/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/\345\205\250\346\216\222\345\210\227_II_47_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..303e3f1b --- /dev/null +++ "b/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/\345\205\250\346\216\222\345\210\227_II_47_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,65 @@ +package cn.lastwhisper.leetcode.recurionbacktracking.全排列_II_47_中等; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static cn.lastwhisper.leetcode.common.print.PrintUtil.printLists; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/letter-combinations-of-a-phone-number/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:树形问题-递归回溯 + * ------------------------------------------------------------------- + * 时间复杂度:O(n*n!) + * 空间复杂度:O(n*n!) + */ + public List> permuteUnique(int[] nums) { + List> result = new ArrayList<>(); + if (nums.length == 0) { + return result; + } + // 升序,为了剪枝方便 + Arrays.sort(nums); + + boolean[] visited = new boolean[nums.length]; + findPermute(nums, visited, new ArrayList<>(nums.length), result); + return result; + } + + /** + * @param nums 输入数字数组 + * @param visited 数字被访问过true,没有为false + * @param permute 排列 + * @param result 返回结果 + */ + public void findPermute(int[] nums, boolean[] visited, List permute, List> result) { + if (permute.size() == nums.length) { + result.add(new ArrayList<>(permute)); + return; + } + for (int i = 0; i < nums.length; i++) { + // 使用visited数组查询是否访问过。 + if (!visited[i]) { + // 剪枝条件:从第二个结点起,搜索的数和上次一样,且刚被撤销 + if (i > 0 && nums[i] == nums[i - 1] && !visited[i - 1]) { + continue; + } + visited[i] = true; + permute.add(nums[i]); + findPermute(nums, visited, permute, result); + // backtracking + visited[i] = false; + permute.remove(permute.size() - 1); + } + } + } + + public static void main(String[] args) { + //printLists(new Solution1().permuteUnique(new int[]{1, 1, 3})); + printLists(new Solution1().permuteUnique(new int[]{1, 1, 1, 2})); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/\345\205\250\346\216\222\345\210\227_II_47_\344\270\255\347\255\211/Solution2.java" "b/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/\345\205\250\346\216\222\345\210\227_II_47_\344\270\255\347\255\211/Solution2.java" new file mode 100644 index 00000000..d5da862e --- /dev/null +++ "b/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/\345\205\250\346\216\222\345\210\227_II_47_\344\270\255\347\255\211/Solution2.java" @@ -0,0 +1,63 @@ +package cn.lastwhisper.leetcode.recurionbacktracking.全排列_II_47_中等; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static cn.lastwhisper.leetcode.common.print.PrintUtil.printLists; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/letter-combinations-of-a-phone-number/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:树形问题-递归回溯 + * ------------------------------------------------------------------- + * 时间复杂度:O(n*n!) + * 空间复杂度:O(n*n!) + */ + public List> permuteUnique(int[] nums) { + List> result = new ArrayList<>(); + if (nums.length == 0) { + return result; + } + // 升序,为了剪枝方便 + Arrays.sort(nums); + + boolean[] visited = new boolean[nums.length]; + findPermute(nums, visited, new ArrayList<>(nums.length), result); + return result; + } + + /** + * @param nums 输入数字数组 + * @param visited 数字被访问过true,没有为false + * @param permute 排列 + * @param result 返回结果 + */ + public void findPermute(int[] nums, boolean[] visited, List permute, List> result) { + if (permute.size() == nums.length) { + result.add(new ArrayList<>(permute)); + return; + } + int pre = nums[0] - 1; + for (int i = 0; i < nums.length; i++) { + // pre记录上一次搜索的起点,只要起点一样就跳过这个分支 + if (!visited[i] && pre != nums[i]) { + visited[i] = true; + permute.add(nums[i]); + findPermute(nums, visited, permute, result); + // backtracking + visited[i] = false; + permute.remove(permute.size() - 1); + + pre = nums[i]; + } + } + } + + public static void main(String[] args) { + printLists(new Solution2().permuteUnique(new int[]{1, 1, 3})); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/\345\215\225\350\257\215\346\220\234\347\264\242_79_\344\270\255\347\255\211/Solution1.java" "b/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/\345\215\225\350\257\215\346\220\234\347\264\242_79_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..f69199d5 --- /dev/null +++ "b/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/\345\215\225\350\257\215\346\220\234\347\264\242_79_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,91 @@ +package cn.lastwhisper.leetcode.recurionbacktracking.单词搜索_79_中等; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/word-search/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:递归+回溯 + * 递归:在board起始位置上下左右去搜索,每一个位置保证: + * 1.与该index单词字母相同 + * 2.数组不越界 + * 3.未被访问过 + * 4.index+1也满足这1、2、3、4条件 + * 回溯:将当前位置标记为未访问 + * 递归终止:index等于单词长度-1,最后一个字母相同 + * ------------------------------------------------------------------- + * 时间复杂度:O(m*n*m*n) + * 空间复杂度:O(m*n) + */ + private int m, n; + private static final int[][] directory = new int[][]{ + {-1, 0},// up + {0, 1},// right + {1, 0},// down + {0, -1},// left + }; + + public boolean exist(char[][] board, String word) { + if (board == null || word == null) + throw new IllegalArgumentException("board or word can not be null!"); + m = board.length; + if (m == 0) + throw new IllegalArgumentException("board can not be empty."); + n = board[0].length; + if (n == 0) + throw new IllegalArgumentException("board can not be empty."); + boolean[][] visited = new boolean[m][n]; + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + if (searchWord(board, word, 0, visited, i, j)) { + return true; + } + } + } + + return false; + } + + private boolean searchWord(char[][] board, String word, int index, boolean[][] visited, int startX, int startY) { + if (index == word.length() - 1) { + return board[startX][startY] == word.charAt(index); + } + + if (board[startX][startY] == word.charAt(index)) { + visited[startX][startY] = true; + for (int i = 0; i < directory.length; i++) { + int newX = startX + directory[i][0]; + int newY = startY + directory[i][1]; + if (isArea(newX, newY) && !visited[newX][newY]) { + if (searchWord(board, word, index + 1, visited, newX, newY)) { + return true; + } + } + } + visited[startX][startY] = false; + } + + return false; + } + + + private boolean isArea(int x, int y) { + return x >= 0 && y >= 0 && x < m && y < n; + } + + + public static void main(String[] args) { + char[][] board = + { + {'A', 'B', 'C', 'E'}, + {'S', 'F', 'C', 'S'}, + {'A', 'D', 'E', 'E'} + }; + //String word = "ABCCED"; + //String word = "SEE"; + String word = "ABCB"; + System.out.println(new Solution1().exist(board, word)); + } + +} \ No newline at end of file diff --git "a/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/\345\244\215\345\216\237IP\345\234\260\345\235\200_93_\344\270\255\347\255\211/Solution1.java" "b/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/\345\244\215\345\216\237IP\345\234\260\345\235\200_93_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..2b7cf53d --- /dev/null +++ "b/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/\345\244\215\345\216\237IP\345\234\260\345\235\200_93_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,62 @@ +package cn.lastwhisper.leetcode.recurionbacktracking.复原IP地址_93_中等; + +import java.util.ArrayList; +import java.util.List; + +import static cn.lastwhisper.leetcode.common.print.PrintUtil.printList; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/restore-ip-addresses/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * ------------------------------------------------------------------- + * 时间复杂度:O(1) + * 空间复杂度:O(1) + */ + public List restoreIpAddresses(String s) { + List result = new ArrayList<>(); + StringBuilder ip = new StringBuilder(); + + for (int a = 1; a < 4; a++) { + for (int b = 1; b < 4; b++) { + for (int c = 1; c < 4; c++) { + for (int d = 1; d < 4; d++) { + /* + * 1、保障下面subString不会越界 + * 2、保障截取的字符串与输入字符串长度相同 + * //1、2比较好理解,3比较有意思 + * 3、不能保障截取的字符串转成int后与输入字符串长度相同 + * 如:字符串010010,a=1,b=1,c=1,d=3,对应字符串0,1,0,010 + * 转成int后seg1=0,seg2=1,seg3=0,seg4=10 + */ + if (a + b + c + d == s.length()) { + int seg1 = Integer.parseInt(s.substring(0, a)); + int seg2 = Integer.parseInt(s.substring(a, a + b)); + int seg3 = Integer.parseInt(s.substring(a + b, a + b + c)); + int seg4 = Integer.parseInt(s.substring(a + b + c, a + b + c + d)); + // 四个段数值满足0~255 + if (seg1 <= 255 && seg2 <= 255 && seg3 <= 255 && seg4 <= 255) { + ip.append(seg1).append(".").append(seg2).append("."). + append(seg3).append(".").append(seg4); + // 保障截取的字符串转成int后与输入字符串长度相同 + if (ip.length() == s.length() + 3) { + result.add(ip.toString()); + } + ip.delete(0, ip.length()); + } + } + } + } + } + } + return result; + } + + public static void main(String[] args) { + printList(new Solution1().restoreIpAddresses("010010")); + //printList(new Solution1().restoreIpAddresses("25525511135")); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/\345\244\215\345\216\237IP\345\234\260\345\235\200_93_\344\270\255\347\255\211/Solution2.java" "b/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/\345\244\215\345\216\237IP\345\234\260\345\235\200_93_\344\270\255\347\255\211/Solution2.java" new file mode 100644 index 00000000..894d495a --- /dev/null +++ "b/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/\345\244\215\345\216\237IP\345\234\260\345\235\200_93_\344\270\255\347\255\211/Solution2.java" @@ -0,0 +1,70 @@ +package cn.lastwhisper.leetcode.recurionbacktracking.复原IP地址_93_中等; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +class Solution2 { + int n; + String s; + LinkedList segments = new LinkedList(); + ArrayList output = new ArrayList(); + + public boolean valid(String segment) { + /* + Check if the current segment is valid : + 1. less or equal to 255 + 2. the first character could be '0' + only if the segment is equal to '0' + */ + int m = segment.length(); + if (m > 3) + return false; + return (segment.charAt(0) != '0') ? (Integer.parseInt(segment) <= 255) : (m == 1); + } + + public void update_output(int curr_pos) { + /* + Append the current list of segments + to the list of solutions + */ + String segment = s.substring(curr_pos + 1, n); + if (valid(segment)) { + segments.add(segment); + output.add(String.join(".", segments)); + segments.removeLast(); + } + } + + public void backtrack(int prev_pos, int dots) { + /* + prev_pos : the position of the previously placed dot + dots : number of dots to place + */ + // The current dot curr_pos could be placed + // in a range from prev_pos + 1 to prev_pos + 4. + // The dot couldn't be placed + // after the last character in the string. + int max_pos = Math.min(n - 1, prev_pos + 4); + for (int curr_pos = prev_pos + 1; curr_pos < max_pos; curr_pos++) { + String segment = s.substring(prev_pos + 1, curr_pos + 1); + if (valid(segment)) { + segments.add(segment); // place dot + if (dots - 1 == 0) // if all 3 dots are placed + update_output(curr_pos); // add the solution to output + else + backtrack(curr_pos, dots - 1); // continue to place dots + segments.removeLast(); // remove the last placed dot + } + } + } + + public List restoreIpAddresses(String s) { + n = s.length(); + this.s = s; + backtrack(-1, 3); + return output; + } + + +} \ No newline at end of file diff --git "a/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/\345\244\215\345\216\237IP\345\234\260\345\235\200_93_\344\270\255\347\255\211/Solution3.java" "b/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/\345\244\215\345\216\237IP\345\234\260\345\235\200_93_\344\270\255\347\255\211/Solution3.java" new file mode 100644 index 00000000..1721468b --- /dev/null +++ "b/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/\345\244\215\345\216\237IP\345\234\260\345\235\200_93_\344\270\255\347\255\211/Solution3.java" @@ -0,0 +1,31 @@ +package cn.lastwhisper.leetcode.recurionbacktracking.复原IP地址_93_中等; + +import java.util.ArrayList; +import java.util.List; + +class Solution3 { + public List restoreIpAddresses(String s) { + List res = new ArrayList<>(); + int n = s.length(); + backtrack(0, "", 4, s, res, n); + return res; + } + + private void backtrack(int i, String tmp, int flag, String s, List res, int n) { + if (i == n && flag == 0) { + res.add(tmp.substring(0, tmp.length() - 1)); + return; + } + if (flag < 0) return; + for (int j = i; j < i + 3; j++) { + if (j < n) { + if (i == j && s.charAt(j) == '0') { + backtrack(j + 1, tmp + s.charAt(j) + ".", flag - 1, s, res, n); + break; + } + if (Integer.parseInt(s.substring(i, j + 1)) <= 255) + backtrack(j + 1, tmp + s.substring(i, j + 1) + ".", flag - 1, s, res, n); + } + } + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/\345\262\233\345\261\277\346\225\260\351\207\217_200_\344\270\255\347\255\211/Solution1.java" "b/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/\345\262\233\345\261\277\346\225\260\351\207\217_200_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..94ed167c --- /dev/null +++ "b/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/\345\262\233\345\261\277\346\225\260\351\207\217_200_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,88 @@ +package cn.lastwhisper.leetcode.recurionbacktracking.岛屿数量_200_中等; + +class Solution1 { + private static final int[][] directory = new int[][]{ + {-1, 0},// up + {0, 1},// right + {1, 0},// down + {0, -1},// left + }; + /** + * 题目地址:https://leetcode-cn.com/problems/number-of-islands/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:递归+回溯 + * '0'(水)、'1'(陆地) + * 递归:标记陆地 + * 回溯:无 + * 递归终止:没有未被访问的陆地 + * ------------------------------------------------------------------- + * 时间复杂度:O(n*m) + * 空间复杂度:O(n*m) + */ + private int m, n; + + public int numIslands(char[][] grid) { + m = grid.length; + if (m == 0) { + return 0; + } + n = grid[0].length; + + boolean[][] visited = new boolean[m][n]; + int result = 0; + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + // 找到岛屿 + if (grid[i][j] == '1' && !visited[i][j]) { + result++; + // 对第一个陆地以及通过第一个陆地能到达的陆地进行dfs标记 + dfsMark(grid, i, j, visited); + } + } + } + return result; + } + + /** + * dfs遍历,对遍历的位置进行标记 + * @param grid 地图 + * @param startX 当前x坐标 + * @param startY 当前y坐标 + * @param visited 地图所到标识 + */ + private void dfsMark(char[][] grid, int startX, int startY, boolean[][] visited) { + visited[startX][startY] = true; + for (int i = 0; i < directory.length; i++) { + int newX = startX + directory[i][0]; + int newY = startY + directory[i][1]; + if (isArea(newX, newY) && !visited[newX][newY] && grid[newX][newY] == '1') { + dfsMark(grid, newX, newY, visited); + } + } + // 不需要回溯重置状态,因为该方法的作用就是对遍历到的岛屿进行标记 + //visited[startX][startY] = false; + } + + private boolean isArea(int x, int y) { + return x >= 0 && y >= 0 && x < m && y < n; + } + + + public static void main(String[] args) { + //char[][] grid = { + // {'1', '1', '1', '1', '0'}, + // {'1', '1', '0', '1', '0'}, + // {'1', '1', '0', '0', '0'}, + // {'0', '0', '0', '0', '0'}, + //}; + + char[][] grid = { + {'1', '1', '0', '0', '0'}, + {'1', '1', '0', '0', '0'}, + {'0', '0', '1', '0', '0'}, + {'0', '0', '0', '1', '1'}}; + System.out.println(new Solution1().numIslands(grid)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217\345\214\271\351\205\215_10_\345\233\260\351\232\276/Solution1.java" "b/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217\345\214\271\351\205\215_10_\345\233\260\351\232\276/Solution1.java" new file mode 100644 index 00000000..d71b8e40 --- /dev/null +++ "b/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217\345\214\271\351\205\215_10_\345\233\260\351\232\276/Solution1.java" @@ -0,0 +1,42 @@ +package cn.lastwhisper.leetcode.recurionbacktracking.正则表达式匹配_10_困难; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/regular-expression-matching/ + * ------------------------------------------------------------------- + * 思考: + * p的第二个字符是"*" + * 一、p跳过两个字符 + * 二、text和p第一个字符匹配的前提下,text跳过第一个字符 + * ------------------------------------------------------------------- + * 思路: + * ------------------------------------------------------------------- + * 时间复杂度:O() + * 空间复杂度:O() + */ + public boolean isMatch(String text, String pattern) { + if (pattern.isEmpty()) return text.isEmpty(); + // text="a",p="a"或者"."都匹配 + boolean first_match = (!text.isEmpty() && + (pattern.charAt(0) == text.charAt(0) || pattern.charAt(0) == '.')); + // p的第二个字符是"*" + if (pattern.length() >= 2 && pattern.charAt(1) == '*') { + // 一、跳过p第一个字符和第二个"*",因为"*"可以匹配0个字符,示例:text="aaa",p="ab*ac*a" + return (isMatch(text, pattern.substring(2)) || + // 二、text和p第一个字符匹配的前提下,text继续向下匹配,示例:text="aa",p="a" + (first_match && isMatch(text.substring(1), pattern))); + } else { + // text和p第一个字符匹配的前提下,p的第二个字符不是"*",继续匹配 + return first_match && isMatch(text.substring(1), pattern.substring(1)); + } + } + + + public static void main(String[] args) { + String text = "a", pattern = "c*a"; + //String text = "aaa", pattern = "a.a"; + //String text = "aaa", pattern = "ab*ac*a"; + System.err.println(new Solution1().isMatch(text, pattern)); + } + +} \ No newline at end of file diff --git "a/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/\347\224\265\350\257\235\345\217\267\347\240\201\347\232\204\345\255\227\346\257\215\347\273\204\345\220\210_17_\344\270\255\347\255\211/Solution1.java" "b/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/\347\224\265\350\257\235\345\217\267\347\240\201\347\232\204\345\255\227\346\257\215\347\273\204\345\220\210_17_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..42e63980 --- /dev/null +++ "b/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/\347\224\265\350\257\235\345\217\267\347\240\201\347\232\204\345\255\227\346\257\215\347\273\204\345\220\210_17_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,67 @@ +package cn.lastwhisper.leetcode.recurionbacktracking.电话号码的字母组合_17_中等; + +import java.util.ArrayList; +import java.util.List; + +import static cn.lastwhisper.leetcode.common.print.PrintUtil.printList; + +class Solution1 { + private String[] letterMap = { + " ", //0 + "", //1 + "abc", //2 + "def", //3 + "ghi", //4 + "jkl", //5 + "mno", //6 + "pqrs", //7 + "tuv", //8 + "wxyz" //9 + }; + + /** + * 题目地址:https://leetcode-cn.com/problems/letter-combinations-of-a-phone-number/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:树形问题 + * ------------------------------------------------------------------- + * 时间复杂度:3^n=O(2^n) + * 空间复杂度: + */ + public List letterCombinations(String digits) { + List result = new ArrayList<>(); + if (digits != null && !"".equals(digits)) { + findCombination(digits, 0, "", result); + } + return result; + } + + /** + * @param digits 数字字符串 + * digits=23 + * @param index 数字索引 + * index=0,对应数字2 + * @param s 数字对应字母字符串的组合 + * 数字2对应的字母"abc",s可能是abc中的一个,也可能是空串或者ad等 + * @param result 返回的结果 + * + */ + private void findCombination(String digits, int index, String s, List result) { + //System.out.println("index=" + index + " :s=" + s); + if (index == digits.length()) { + result.add(s); + return; + } + // 数字 + char c = digits.charAt(index); + String letter = letterMap[c - '0']; + for (int i = 0; i < letter.length(); i++) { + findCombination(digits, index + 1, s + letter.charAt(i), result); + } + } + + public static void main(String[] args) { + printList(new Solution1().letterCombinations("23")); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/\347\273\204\345\220\210_77_\344\270\255\347\255\211/Solution1.java" "b/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/\347\273\204\345\220\210_77_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..ce63d033 --- /dev/null +++ "b/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/\347\273\204\345\220\210_77_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,90 @@ +package cn.lastwhisper.leetcode.recurionbacktracking.组合_77_中等; + +import java.util.ArrayList; +import java.util.List; + +import static cn.lastwhisper.leetcode.common.print.PrintUtil.printLists; + +class Solution1 { + static int count = 0; + + /** + * 题目地址:https://leetcode-cn.com/problems/combinations/ + * ------------------------------------------------------------------- + * 思考: + * Q:集合初始化大小 + * A:result集合承载着所有组合的情况,初始化大小=C(n,k) + * combine集合承载每个节点的情况,最大不会超过k + * ------------------------------------------------------------------- + * 思路:树形问题-递归回溯 + * ------------------------------------------------------------------- + * 时间复杂度:O(n*n!) + * 空间复杂度:O(n*n!) + */ + public List> combine(int n, int k) { + if (k <= 0 || n < k) { + return new ArrayList<>(); + } + List> result = new ArrayList<>(initCapacity(n, k)); + findCombinations(1, n, k, new ArrayList<>(k), result); + return result; + } + + /** + * + * @param start 返回start...n中所有可能的k个数的组合 + * @param n C(n,k) + * @param k C(n,k) + * @param combine 保存当前结点产生的组合 + * @param result 返回结果 + */ + private void findCombinations(int start, int n, int k, List combine, List> result) { + if (combine.size() == k) { + result.add(new ArrayList<>(combine)); + return; + } + for (int i = start; i <= n; i++) { + combine.add(i); + findCombinations(i + 1, n, k, combine, result); + combine.remove(combine.size() - 1); + } + } + + //private void dubugFindCombinations(int start, int n, int k, List combine, List> result) { + // count++; + // if (combine.size() == k) { + // result.add(new ArrayList<>(combine)); + // System.out.println("递归终止——第" + count + "层递归——combine=" + collection2String(combine)); + // return; + // } + // for (int i = start; i <= n; i++) { + // combine.add(i); + // System.out.println("递归——第" + count + "层递归,combine=" + collection2String(combine)); + // dubugFindCombinations(i + 1, n, k, combine, result); + // count--; + // combine.remove(combine.size() - 1); + // System.out.println("回溯————第" + count + "层递归,combine=" + collection2String(combine)); + // } + // System.out.println("递归终止——第" + count + "层递归——combine=" + collection2String(combine)); + //} + + //初始化容量 + private int initCapacity(int n, int k) { + return (int) (factorial(n) / (factorial(n - k) * factorial(k))); + } + + // 阶乘 + private long factorial(int n) { + long result = 1; + for (int i = 1; i <= n; i++) { + result *= i; + } + return result; + } + + public static void main(String[] args) { + //printLists(new Solution1().combine(4, 2)); + printLists(new Solution1().combine(5, 3)); + //System.out.println(new Solution1().initCapacity(20, 16)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/\347\273\204\345\220\210_77_\344\270\255\347\255\211/Solution2.java" "b/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/\347\273\204\345\220\210_77_\344\270\255\347\255\211/Solution2.java" new file mode 100644 index 00000000..36ae5123 --- /dev/null +++ "b/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/\347\273\204\345\220\210_77_\344\270\255\347\255\211/Solution2.java" @@ -0,0 +1,79 @@ +package cn.lastwhisper.leetcode.recurionbacktracking.组合_77_中等; + +import java.util.ArrayList; +import java.util.List; + +import static cn.lastwhisper.leetcode.common.print.PrintUtil.printLists; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/combinations/ + * ------------------------------------------------------------------- + * 思考: + * Q:如何剪枝 + * A:画图推导 + * ------------------------------------------------------------------- + * 思路:树形问题-递归回溯 + * ------------------------------------------------------------------- + * 时间复杂度:O(n*n!) + * 空间复杂度:O(n*n!) + */ + public List> combine(int n, int k) { + if (k <= 0 || n < k) { + return new ArrayList<>(); + } + List> result = new ArrayList<>(initCapacity(n, k)); + findCombinations(1, n, k, new ArrayList<>(k), result); + return result; + } + + //初始化容量 + private int initCapacity(int n, int k) { + return (int) (factorial(n) / (factorial(n - k) * factorial(k))); + } + + // 阶乘 + private long factorial(int n) { + long result = 1; + for (int i = 2; i <= n; i++) { + result *= i; + } + return result; + } + + /** + * + * @param start 返回start...n中所有可能的k个数的组合 + * @param n C(n,k) + * @param k C(n,k) + * @param combine 保存当前结点产生的组合 + * @param result 返回结果 + */ + private void findCombinations(int start, int n, int k, List combine, List> result) { + if (combine.size() == k) { + result.add(new ArrayList<>(combine)); + return; + } + /* + * n=5,k=3时 + * combine.size()=1时,接下来要取2个数,i最大取4,最后被选择的是:[4,5]; + * combine.size()=2时,接下来要取1个数,i最大取5,最后被选择的是:[5]; + * max(i)+接下选择元素个数-1=n、接下选择元素个数=k-combine.size()===》max(i)=n-(k-combine.size())+1 + * 4=5-3+1+1 + * 5=5-3+2+1 + * + * 还有k - c.size()个空位, 所以, [i...n] 中至少要有 k - c.size() 个元素 + * i最多为 n - (k - c.size()) + 1 + */ + for (int i = start; i <= n - (k - combine.size()) + 1; i++) { + combine.add(i); + findCombinations(i + 1, n, k, combine, result); + combine.remove(combine.size() - 1); + } + } + + public static void main(String[] args) { + printLists(new Solution2().combine(4, 2)); + //System.out.println(new Solution1().initCapacity(20, 16)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/\347\273\204\345\220\210_77_\344\270\255\347\255\211/\345\211\252\346\236\235.png" "b/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/\347\273\204\345\220\210_77_\344\270\255\347\255\211/\345\211\252\346\236\235.png" new file mode 100644 index 00000000..f71dbf16 Binary files /dev/null and "b/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/\347\273\204\345\220\210_77_\344\270\255\347\255\211/\345\211\252\346\236\235.png" differ diff --git "a/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/\347\273\204\345\220\210_77_\344\270\255\347\255\211/\347\273\204\345\220\210.png" "b/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/\347\273\204\345\220\210_77_\344\270\255\347\255\211/\347\273\204\345\220\210.png" new file mode 100644 index 00000000..d897f07c Binary files /dev/null and "b/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/\347\273\204\345\220\210_77_\344\270\255\347\255\211/\347\273\204\345\220\210.png" differ diff --git "a/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/\347\273\204\345\220\210\346\200\273\345\222\214_39_\344\270\255\347\255\211/Solution1.java" "b/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/\347\273\204\345\220\210\346\200\273\345\222\214_39_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..c45dcea4 --- /dev/null +++ "b/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/\347\273\204\345\220\210\346\200\273\345\222\214_39_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,64 @@ +package cn.lastwhisper.leetcode.recurionbacktracking.组合总和_39_中等; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static cn.lastwhisper.leetcode.common.print.PrintUtil.printLists; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/combination-sum/ + * ------------------------------------------------------------------- + * 思考: + * Q:如何去重? + * A:画图观察出现重复的规律,“当前减的值比上一个减的值小”会出现重复 + * Q:如何剪枝? + * A:小于0提前终止当前递归 + * ------------------------------------------------------------------- + * 思路:树形问题-递归回溯——剪枝 + * 一定要看思路2,不排序输入 + * ------------------------------------------------------------------- + * 时间复杂度:O(n*n!) + * 空间复杂度:O(n*n!) + */ + public List> combinationSum(int[] candidates, int target) { + List> result = new ArrayList<>(); + if (candidates == null || candidates.length == 0) { + return result; + } + // 排序为了剪枝 + Arrays.sort(candidates); + findCandidates(candidates, target, 0, new ArrayList<>(), result); + return result; + } + + /** + * dfs搜索可能的解 + * @param candidates 无重复元素的数组 + * @param residue 递归树产生的中间值,初值为target + * @param result 解集 + * @param path 可能的解 + */ + private void findCandidates(int[] candidates, int residue, int start, List path, List> result) { + if (residue == 0) { + result.add(new ArrayList<>(path)); + return; + } + // i=start——>剪枝(去重)、residue-candidates[i]>= 0剪枝(减少运算,前提是输入排序) + for (int i = start; i < candidates.length && residue - candidates[i] >= 0; i++) { + path.add(candidates[i]); + findCandidates(candidates, residue - candidates[i], i, path, result); + path.remove(path.size() - 1); + } + } + + public static void main(String[] args) { + //int[] candidates = {2, 3, 6, 7}; + //int target = 7; + //int[] candidates = {2, 3, 5}; + int[] candidates = {5, 3, 2}; + int target = 8; + printLists(new Solution1().combinationSum(candidates, target)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/\347\273\204\345\220\210\346\200\273\345\222\214_39_\344\270\255\347\255\211/Solution2.java" "b/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/\347\273\204\345\220\210\346\200\273\345\222\214_39_\344\270\255\347\255\211/Solution2.java" new file mode 100644 index 00000000..39e16a3d --- /dev/null +++ "b/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/\347\273\204\345\220\210\346\200\273\345\222\214_39_\344\270\255\347\255\211/Solution2.java" @@ -0,0 +1,94 @@ +package cn.lastwhisper.leetcode.recurionbacktracking.组合总和_39_中等; + +import java.util.ArrayList; +import java.util.List; + +import static cn.lastwhisper.leetcode.common.print.PrintUtil.printLists; + +class Solution2 { + static int count = 0; + + /** + * 题目地址:https://leetcode-cn.com/problems/combination-sum/ + * ------------------------------------------------------------------- + * 思考: + * Q:如何去重? + * A:画图观察出现重复的规律,“当前减的值比上一个减的值小”会出现重复 + * ------------------------------------------------------------------- + * 思路:树形问题-递归回溯 + * 不排序输入 + * ------------------------------------------------------------------- + * 时间复杂度:O(n*n!) + * 空间复杂度:O(n*n!) + */ + public List> combinationSum(int[] candidates, int target) { + List> result = new ArrayList<>(); + if (candidates == null || candidates.length == 0) { + return result; + } + findCandidates(candidates, target, 0, new ArrayList<>(), result); + return result; + } + + /** + * dfs搜索可能的解 + * @param candidates 无重复元素的数组 + * @param residue 递归树产生的中间值,初值为target + * @param result 解集 + * @param path 可能的解 + */ + private void findCandidates(int[] candidates, int residue, int start, List path, List> result) { + if (residue == 0) { + result.add(new ArrayList<>(path)); + return; + } + if (residue < 0) { + return; + } + // i=start——>剪枝(去重) + for (int i = start; i < candidates.length; i++) { + // 不能再这里终止递归,因为组合数字可能无序,后面的数字可能和为target + //if(residue - candidates[i]<0){ + // return; + //} + path.add(candidates[i]); + findCandidates(candidates, residue - candidates[i], i, path, result); + path.remove(path.size() - 1); + } + } + + //private void dubugFindCandidates(int[] candidates, int residue, int start, List path, List> result) { + // count++; + // if (residue == 0) { + // result.add(new ArrayList<>(path)); + // System.out.println("递归终止——第" + count + "层递归——residue= " + residue + "——path=" + listConvert(path)); + // return; + // } + // if (residue < 0) { + // System.out.println("递归终止——第" + count + "层递归——residue= " + residue + "——path=" + listConvert(path)); + // return; + // } + // for (int i = start; i < candidates.length; i++) { + // // 不能再这里终止递归,因为组合数字可能无序,后面的数字可能和为target + // //if(residue - candidates[i]<0){ + // // return; + // //} + // path.add(candidates[i]); + // System.out.println("递归——第" + count + "层递归——residue= " + residue + "——path=" + listConvert(path)); + // findCandidates(candidates, residue - candidates[i], i, path, result); + // count--; + // path.remove(path.size() - 1); + // System.out.println("回溯————第" + count + "层递归——residue= " + residue + "——path=" + listConvert(path)); + // } + // System.out.println("递归终止——第" + count + "层递归——residue= " + residue + "——path=" + listConvert(path)); + //} + + public static void main(String[] args) { + int[] candidates = {2, 6, 3, 7}; + int target = 7; + //int[] candidates = {2, 3, 5}; + //int[] candidates = {5, 3, 2}; + //int target = 8; + printLists(new Solution2().combinationSum(candidates, target)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/\347\273\204\345\220\210\346\200\273\345\222\214_II_40_\344\270\255\347\255\211/Solution1.java" "b/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/\347\273\204\345\220\210\346\200\273\345\222\214_II_40_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..1ee372c5 --- /dev/null +++ "b/algorithms/leetcode/recursion-backtracking/src/main/java/cn/lastwhisper/leetcode/recurionbacktracking/\347\273\204\345\220\210\346\200\273\345\222\214_II_40_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,68 @@ +package cn.lastwhisper.leetcode.recurionbacktracking.组合总和_II_40_中等; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static cn.lastwhisper.leetcode.common.print.PrintUtil.printLists; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/combination-sum-ii/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:树形问题-递归回溯——剪枝 + * 这题一定要排序,排序之后方便去重。39题可以不排序,还记得39题不排序如何去重的吗? + * ------------------------------------------------------------------- + * 时间复杂度:O(n*n!) + * 空间复杂度:O(n*n!) + */ + public List> combinationSum2(int[] candidates, int target) { + List> result = new ArrayList<>(); + if (candidates == null || candidates.length == 0) { + return result; + } + // 排序为了去重 + Arrays.sort(candidates); + findCandidates(candidates, target, 0, new ArrayList<>(), result); + return result; + } + + /** + * dfs搜索可能的解 + * @param candidates 无重复元素的数组 + * @param residue 递归树产生的中间值,初值为target + * @param result 解集 + * @param path 可能的解 + */ + private void findCandidates(int[] candidates, int residue, int start, List path, List> result) { + if (residue == 0) { + result.add(new ArrayList<>(path)); + return; + } + // 升序输入可以在递归进入前退出,如果没升序,必须在这里退出 + //if (residue < 0) { + // return; + //} + // residue-candidates[i]>=0 剪枝(减少运算) + for (int i = start; i < candidates.length && residue - candidates[i] >= 0; i++) { + // 剪枝(去重),重复的元素一定不是排好序以后的第 1 个元素和相同元素的第 1 个元素 + if (i > start && candidates[i] == candidates[i - 1]) { + continue; + } + path.add(candidates[i]); + // 因为元素不可以重复使用,这里递归传递下去的是 i + 1 而不是 i + findCandidates(candidates, residue - candidates[i], i + 1, path, result); + path.remove(path.size() - 1); + } + } + + public static void main(String[] args) { + int[] candidates = {10, 1, 2, 7, 6, 1, 5}; + int target = 8; + //int[] candidates = {2,5,2,1,2}; + //int target = 5; + printLists(new Solution1().combinationSum2(candidates, target)); + } +} \ No newline at end of file diff --git a/algorithms/leetcode/stackqueue/pom.xml b/algorithms/leetcode/stackqueue/pom.xml index 75d514c2..70e5a888 100644 --- a/algorithms/leetcode/stackqueue/pom.xml +++ b/algorithms/leetcode/stackqueue/pom.xml @@ -12,5 +12,11 @@ cn.lastwhisper.leetcode stackqueue - + + + cn.lastwhisper + leetcode-common + 1.0-SNAPSHOT + + \ No newline at end of file diff --git "a/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\344\270\255\345\272\217\351\201\215\345\216\206_94_\344\270\255\347\255\211/Solution1.java" "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\344\270\255\345\272\217\351\201\215\345\216\206_94_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..3d0c5ce1 --- /dev/null +++ "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\344\270\255\345\272\217\351\201\215\345\216\206_94_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,39 @@ +package cn.lastwhisper.leetcode.stackqueue.二叉树的中序遍历_94_中等; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; + +import java.util.ArrayList; +import java.util.List; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/binary-tree-inorder-traversal/ + * ------------------------------------------------------------------- + * 时间复杂度:https://www.cnblogs.com/wu8685/archive/2010/12/21/1912347.html + * 空间复杂度: + */ + + List list = new ArrayList<>(); + + public List inorderTraversal(TreeNode root) { + if (root != null) { + inorderTraversal(root.left); + list.add(root.val); + inorderTraversal(root.right); + } + return list; + } + + public static void main(String[] args) { + TreeNode root = new TreeNode(1); + TreeNode node1 = new TreeNode(2); + TreeNode node2 = new TreeNode(3); + + root.right = node1; + node1.left = node2; + + new Solution1().inorderTraversal(root).forEach(node -> { + System.out.print(node + ","); + }); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\344\270\255\345\272\217\351\201\215\345\216\206_94_\344\270\255\347\255\211/Solution2.java" "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\344\270\255\345\272\217\351\201\215\345\216\206_94_\344\270\255\347\255\211/Solution2.java" new file mode 100644 index 00000000..68042732 --- /dev/null +++ "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\344\270\255\345\272\217\351\201\215\345\216\206_94_\344\270\255\347\255\211/Solution2.java" @@ -0,0 +1,44 @@ +package cn.lastwhisper.leetcode.stackqueue.二叉树的中序遍历_94_中等; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; +import cn.lastwhisper.leetcode.common.tree.TreeUtil; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/binary-tree-inorder-traversal/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:遍历 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(n) + */ + public List inorderTraversal(TreeNode root) { + List result = new ArrayList<>(); + LinkedList stack = new LinkedList<>(); + + while (root != null || !stack.isEmpty()) { + if (root != null) { + stack.push(root); + root = root.left; + } else { + root = stack.pop(); + result.add(root.val); + root = root.right; + } + } + return result; + } + + public static void main(String[] args) { + TreeNode tree = TreeUtil.createTree(); + new Solution2().inorderTraversal(tree).forEach(node -> { + System.out.print(node + ","); + }); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\344\270\255\345\272\217\351\201\215\345\216\206_94_\344\270\255\347\255\211/Solution3.java" "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\344\270\255\345\272\217\351\201\215\345\216\206_94_\344\270\255\347\255\211/Solution3.java" new file mode 100644 index 00000000..54f3b9d9 --- /dev/null +++ "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\344\270\255\345\272\217\351\201\215\345\216\206_94_\344\270\255\347\255\211/Solution3.java" @@ -0,0 +1,45 @@ +package cn.lastwhisper.leetcode.stackqueue.二叉树的中序遍历_94_中等; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +import static cn.lastwhisper.leetcode.common.print.PrintUtil.printList; +import static cn.lastwhisper.leetcode.common.tree.TreeUtil.createTree; + +class Solution3 { + /** + * 题目地址:https://leetcode-cn.com/problems/binary-tree-inorder-traversal/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:遍历 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(n) + */ + public List inorderTraversal(TreeNode root) { + List result = new ArrayList<>(); + LinkedList stack = new LinkedList<>(); + + while (root != null || !stack.isEmpty()) { + //节点不为空一直压栈 + while (root != null) { + stack.push(root); + root = root.left; //考虑左子树 + } + //节点为空,就出栈 + root = stack.pop(); + //当前值加入 + result.add(root.val); + root = root.right;//考虑右子树 + } + return result; + } + + public static void main(String[] args) { + printList(new Solution3().inorderTraversal(createTree(1, null, 2, 3))); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\344\270\255\345\272\217\351\201\215\345\216\206_94_\344\270\255\347\255\211/SolutionCommand.java" "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\344\270\255\345\272\217\351\201\215\345\216\206_94_\344\270\255\347\255\211/SolutionCommand.java" new file mode 100644 index 00000000..6af7494e --- /dev/null +++ "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\344\270\255\345\272\217\351\201\215\345\216\206_94_\344\270\255\347\255\211/SolutionCommand.java" @@ -0,0 +1,66 @@ +package cn.lastwhisper.leetcode.stackqueue.二叉树的中序遍历_94_中等; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; +import cn.lastwhisper.leetcode.common.tree.TreeUtil; + +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +class SolutionCommand { + static class Command { + String s; + TreeNode node; + + Command(String s, TreeNode node) { + this.s = s; + this.node = node; + } + } + + /** + * 题目地址:https://leetcode-cn.com/problems/binary-tree-inorder-traversal/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:遍历 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(n) + */ + public List inorderTraversal(TreeNode root) { + List result = new ArrayList<>(); + if(root==null){ + return result; + } + + Stack stack = new Stack<>(); + stack.push(new Command("go", root)); + while (!stack.empty()) { + Command command = stack.pop(); + if (command.s.equals("print")) { + result.add(command.node.val); + } else { + if (command.node.right != null) { + stack.push(new Command("go", command.node.right)); + } + stack.push(new Command("print", command.node)); + if (command.node.left != null) { + stack.push(new Command("go", command.node.left)); + } + + } + } + + return result; + } + + public static void main(String[] args) { + TreeNode tree = TreeUtil.createTree(); + + new SolutionCommand().inorderTraversal(tree).forEach(node -> { + System.out.print(node + ","); + }); + } +} + diff --git "a/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206_144_\344\270\255\347\255\211/Solution1.java" "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206_144_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..0c5d6130 --- /dev/null +++ "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206_144_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,34 @@ +package cn.lastwhisper.leetcode.stackqueue.二叉树的前序遍历_144_中等; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; +import cn.lastwhisper.leetcode.common.tree.TreeUtil; + +import java.util.ArrayList; +import java.util.List; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/binary-tree-preorder-traversal/ + * ------------------------------------------------------------------- + * 时间复杂度:https://www.cnblogs.com/wu8685/archive/2010/12/21/1912347.html + * 空间复杂度: + */ + private List list = new ArrayList<>(); + + // 递归 + public List preorderTraversal(TreeNode root) { + if (root != null) { + list.add(root.val); + preorderTraversal(root.left); + preorderTraversal(root.right); + } + return list; + } + + public static void main(String[] args) { + TreeNode root = TreeUtil.createTree(); + new Solution1().preorderTraversal(root).forEach(node -> { + System.out.print(node + ","); + }); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206_144_\344\270\255\347\255\211/Solution2.java" "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206_144_\344\270\255\347\255\211/Solution2.java" new file mode 100644 index 00000000..a7aaae17 --- /dev/null +++ "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206_144_\344\270\255\347\255\211/Solution2.java" @@ -0,0 +1,45 @@ +package cn.lastwhisper.leetcode.stackqueue.二叉树的前序遍历_144_中等; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; +import cn.lastwhisper.leetcode.common.tree.TreeUtil; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/binary-tree-preorder-traversal/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:前序遍历-迭代 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(n) + */ + public List preorderTraversal(TreeNode root) { + List result = new ArrayList<>(); + if (root == null) { + return result; + } + LinkedList stack = new LinkedList<>(); + stack.push(root); + // 根-左-右 + while (!stack.isEmpty()) { + root = stack.pop(); + result.add(root.val); + if (root.right != null) stack.push(root.right); + if (root.left != null) stack.push(root.left); + } + return result; + } + + public static void main(String[] args) { + TreeNode tree = TreeUtil.createTree(); + + new Solution2().preorderTraversal(tree).forEach(node -> { + System.out.print(node + ","); + }); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206_144_\344\270\255\347\255\211/Solution3.java" "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206_144_\344\270\255\347\255\211/Solution3.java" new file mode 100644 index 00000000..a45a5bf4 --- /dev/null +++ "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206_144_\344\270\255\347\255\211/Solution3.java" @@ -0,0 +1,45 @@ +package cn.lastwhisper.leetcode.stackqueue.二叉树的前序遍历_144_中等; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; +import cn.lastwhisper.leetcode.common.tree.TreeUtil; + +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +class Solution3 { + /** + * 题目地址:https://leetcode-cn.com/problems/binary-tree-preorder-traversal/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:先序遍历DFS + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(n) + */ + public List preorderTraversal(TreeNode root) { + List result = new ArrayList<>(); + Stack stack = new Stack<>(); + + while (root != null || !stack.empty()) { + if (root != null) { + result.add(root.val); + stack.push(root); + root = root.left; + } else { + root = stack.pop(); + root = root.right; + } + } + return result; + } + + public static void main(String[] args) { + TreeNode tree = TreeUtil.createTree(); + + new Solution3().preorderTraversal(tree).forEach(node -> { + System.out.print(node + ","); + }); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206_144_\344\270\255\347\255\211/Solution4.java" "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206_144_\344\270\255\347\255\211/Solution4.java" new file mode 100644 index 00000000..e544bc16 --- /dev/null +++ "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206_144_\344\270\255\347\255\211/Solution4.java" @@ -0,0 +1,45 @@ +package cn.lastwhisper.leetcode.stackqueue.二叉树的前序遍历_144_中等; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; +import cn.lastwhisper.leetcode.common.tree.TreeUtil; + +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +class Solution4 { + /** + * 题目地址:https://leetcode-cn.com/problems/binary-tree-preorder-traversal/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:先序遍历DFS + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(n) + */ + public List preorderTraversal(TreeNode root) { + List result = new ArrayList<>(); + Stack stack = new Stack<>(); + + while (root != null || !stack.empty()) { + while (root != null) { + result.add(root.val); + stack.push(root); + root = root.left; + } + root = stack.pop(); + root = root.right; + } + + return result; + } + + public static void main(String[] args) { + TreeNode tree = TreeUtil.createTree(); + + new Solution4().preorderTraversal(tree).forEach(node -> { + System.out.print(node + ","); + }); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206_144_\344\270\255\347\255\211/SolutionCommand.java" "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206_144_\344\270\255\347\255\211/SolutionCommand.java" new file mode 100644 index 00000000..94ae45d9 --- /dev/null +++ "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206_144_\344\270\255\347\255\211/SolutionCommand.java" @@ -0,0 +1,71 @@ +package cn.lastwhisper.leetcode.stackqueue.二叉树的前序遍历_144_中等; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; +import cn.lastwhisper.leetcode.common.tree.TreeUtil; + +import java.util.LinkedList; +import java.util.List; + +class SolutionCommand { + enum Type { + go, + print, + ; + } + + static class Command { + Type type; + TreeNode node; + + Command(Type type, TreeNode node) { + this.type = type; + this.node = node; + } + } + + /** + * 题目地址:https://leetcode-cn.com/problems/binary-tree-preorder-traversal/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:先序遍历、迭代,使用Stack模拟系统栈 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(n) + */ + public List preorderTraversal(TreeNode root) { + LinkedList result = new LinkedList<>(); + if (root == null) { + return result; + } + + LinkedList stack = new LinkedList<>(); + stack.push(new Command(Type.go, root)); + while (!stack.isEmpty()) { + Command command = stack.pop(); + if (command.type == Type.print) { + result.add(command.node.val); + } else { + // stack先进先出,入栈顺序right-left-node + // 迭代顺序node-left-right + if (command.node.right != null) { + stack.push(new Command(Type.go, command.node.right)); + } + if (command.node.left != null) { + stack.push(new Command(Type.go, command.node.left)); + } + stack.push(new Command(Type.print, command.node)); + } + } + return result; + } + + public static void main(String[] args) { + TreeNode tree = TreeUtil.createTree(); + + new SolutionCommand().preorderTraversal(tree).forEach(node -> { + System.out.print(node + ","); + }); + } +} + diff --git "a/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\345\217\263\350\247\206\345\233\276_199_\344\270\255\347\255\211/Solution1.java" "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\345\217\263\350\247\206\345\233\276_199_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..df9b3776 --- /dev/null +++ "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\345\217\263\350\247\206\345\233\276_199_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,56 @@ +package cn.lastwhisper.leetcode.stackqueue.二叉树的右视图_199_中等; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +import static cn.lastwhisper.leetcode.common.tree.TreeUtil.createTree; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/binary-tree-right-side-view/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:每一层次最后的一个值 + * ------------------------------------------------------------------- + * 时间复杂度:O(n^2) + * 空间复杂度:O(n) + */ + public List rightSideView(TreeNode root) { + List result = new ArrayList<>(); + if (root == null) + return result; + + Queue queue = new LinkedList<>(); + queue.add(root); + while (!queue.isEmpty()) { + // 遍历每层的数据 + int size = queue.size(); + Integer val = null; + for (int i = 0; i < size; i++) { + root = queue.poll(); + // 只取最后一个值 + if (i == size - 1) { + val = root.val; + } + if (root.left != null) { + queue.add(root.left); + } + if (root.right != null) { + queue.add(root.right); + } + } + result.add(val); + } + return result; + } + + public static void main(String[] args) { + TreeNode tree = createTree(1, 2, 3, null, 5, null, 4); + new Solution1().rightSideView(tree).forEach(System.out::println); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206_145_\345\233\260\351\232\276/Solution1.java" "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206_145_\345\233\260\351\232\276/Solution1.java" new file mode 100644 index 00000000..26f1ef06 --- /dev/null +++ "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206_145_\345\233\260\351\232\276/Solution1.java" @@ -0,0 +1,48 @@ +package cn.lastwhisper.leetcode.stackqueue.二叉树的后序遍历_145_困难; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; + +import java.util.ArrayList; +import java.util.List; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/binary-tree-postorder-traversal/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:后序遍历-迭代 + * ------------------------------------------------------------------- + * 时间复杂度:https://www.cnblogs.com/wu8685/archive/2010/12/21/1912347.html + * 空间复杂度: + */ + List list = new ArrayList<>(); + + public List postorderTraversal(TreeNode root) { + List list = new ArrayList<>(); + postorderTraversalHelper(root, list); + return list; + } + + private void postorderTraversalHelper(TreeNode root, List list) { + if (root == null) { + return; + } + postorderTraversalHelper(root.left, list); + postorderTraversalHelper(root.right, list); + list.add(root.val); + } + + public static void main(String[] args) { + TreeNode root = new TreeNode(1); + TreeNode node1 = new TreeNode(2); + TreeNode node2 = new TreeNode(3); + + root.right = node1; + node1.left = node2; + + new Solution1().postorderTraversal(root).forEach(node -> { + System.out.print(node + ","); + }); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206_145_\345\233\260\351\232\276/Solution2.java" "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206_145_\345\233\260\351\232\276/Solution2.java" new file mode 100644 index 00000000..bbdb8a73 --- /dev/null +++ "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206_145_\345\233\260\351\232\276/Solution2.java" @@ -0,0 +1,52 @@ +package cn.lastwhisper.leetcode.stackqueue.二叉树的后序遍历_145_困难; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; + +import java.util.LinkedList; +import java.util.List; + +import static cn.lastwhisper.leetcode.common.print.PrintUtil.printList; +import static cn.lastwhisper.leetcode.common.tree.TreeUtil.createTree; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/binary-tree-postorder-traversal/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:后序遍历-迭代(前序遍历的变种) + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(n) + */ + public List postorderTraversal(TreeNode root) { + LinkedList result = new LinkedList<>(); + if (root == null) { + return result; + } + LinkedList stack = new LinkedList<>(); + LinkedList outStack = new LinkedList<>(); + stack.push(root); + // 根-右-左顺序访问,然后逆序输出 + while (!stack.isEmpty()) { + root = stack.pop(); + outStack.push(root.val); + + if (root.left != null) { + stack.push(root.left); + } + if (root.right != null) { + stack.push(root.right); + } + } + + while (!outStack.isEmpty()) { + result.add(outStack.poll()); + } + return result; + } + + public static void main(String[] args) { + printList(new Solution2().postorderTraversal(createTree(1, null, 2, 3))); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206_145_\345\233\260\351\232\276/Solution3.java" "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206_145_\345\233\260\351\232\276/Solution3.java" new file mode 100644 index 00000000..6b82a187 --- /dev/null +++ "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206_145_\345\233\260\351\232\276/Solution3.java" @@ -0,0 +1,55 @@ +package cn.lastwhisper.leetcode.stackqueue.二叉树的后序遍历_145_困难; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; + +import java.util.*; + +import static cn.lastwhisper.leetcode.common.print.PrintUtil.printList; +import static cn.lastwhisper.leetcode.common.tree.TreeUtil.createTree; + +class Solution3 { + /** + * 题目地址:https://leetcode-cn.com/problems/binary-tree-postorder-traversal/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:后序遍历-迭代 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(n) + */ + public List postorderTraversal(TreeNode root) { + List list = new ArrayList<>(); + LinkedList stack = new LinkedList<>(); + Set set = new HashSet<>(); + TreeNode cur = root; + while (cur != null || !stack.isEmpty()) { + while (cur != null && !set.contains(cur)) { + stack.push(cur); + cur = cur.left; + } + cur = stack.peek(); + // 回到上一个节点 + //右子树为空或者第二次来到这里 + if (cur.right == null || set.contains(cur)) { + list.add(cur.val); + set.add(cur); + stack.pop();//将当前节点弹出 + if (stack.isEmpty()) { + return list; + } + //转到右子树,这种情况对应于右子树为空的情况 + cur = stack.peek(); + } else { + //从左子树过来,加到 set 中,转到右子树 + set.add(cur); + } + cur = cur.right; + } + return list; + } + + public static void main(String[] args) { + printList(new Solution3().postorderTraversal(createTree(1, null, 2, 3))); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206_145_\345\233\260\351\232\276/Solution4.java" "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206_145_\345\233\260\351\232\276/Solution4.java" new file mode 100644 index 00000000..6127892a --- /dev/null +++ "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206_145_\345\233\260\351\232\276/Solution4.java" @@ -0,0 +1,50 @@ +package cn.lastwhisper.leetcode.stackqueue.二叉树的后序遍历_145_困难; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; + +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +import static cn.lastwhisper.leetcode.common.print.PrintUtil.printList; +import static cn.lastwhisper.leetcode.common.tree.TreeUtil.createTree; + +class Solution4 { + /** + * 题目地址:https://leetcode-cn.com/problems/binary-tree-postorder-traversal/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:后序遍历-迭代 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(n) + */ + public List postorderTraversal(TreeNode root) { + List list = new ArrayList<>(); + Stack stack = new Stack<>(); + TreeNode cur = root; + TreeNode last = null; + while (cur != null || !stack.isEmpty()) { + while (cur != null) { + stack.push(cur); + cur = cur.left; + } + TreeNode temp = stack.peek(); + //是否变到右子树 + if (temp.right != null && temp.right != last) { + cur = temp.right; + } else { + list.add(temp.val); + last = temp; + stack.pop(); + } + + } + return list; + } + + public static void main(String[] args) { + printList(new Solution4().postorderTraversal(createTree(1, null, 2, 3))); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206_145_\345\233\260\351\232\276/SolutionCommand.java" "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206_145_\345\233\260\351\232\276/SolutionCommand.java" new file mode 100644 index 00000000..eadbc3d3 --- /dev/null +++ "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206_145_\345\233\260\351\232\276/SolutionCommand.java" @@ -0,0 +1,63 @@ +package cn.lastwhisper.leetcode.stackqueue.二叉树的后序遍历_145_困难; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; + +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +import static cn.lastwhisper.leetcode.common.print.PrintUtil.printList; +import static cn.lastwhisper.leetcode.common.tree.TreeUtil.createTree; + +class SolutionCommand { + static class Command { + String s; + TreeNode node; + + Command(String s, TreeNode node) { + this.s = s; + this.node = node; + } + } + + /** + * 题目地址:https://leetcode-cn.com/problems/binary-tree-inorder-traversal/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:遍历 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(n) + */ + public List postorderTraversal(TreeNode root) { + List result = new ArrayList<>(); + if(root==null){ + return result; + } + + Stack stack = new Stack<>(); + stack.push(new Command("go", root)); + while (!stack.empty()) { + Command command = stack.pop(); + if (command.s.equals("print")) { + result.add(command.node.val); + } else { + stack.push(new Command("print", command.node)); + if (command.node.right != null) { + stack.push(new Command("go", command.node.right)); + } + if (command.node.left != null) { + stack.push(new Command("go", command.node.left)); + } + + } + } + + return result; + } + + public static void main(String[] args) { + printList(new SolutionCommand().postorderTraversal(createTree(1, null, 2, 3))); + } +} diff --git "a/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206_145_\345\233\260\351\232\276/\345\217\202\350\200\203.txt" "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206_145_\345\233\260\351\232\276/\345\217\202\350\200\203.txt" new file mode 100644 index 00000000..71651fcc --- /dev/null +++ "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206_145_\345\233\260\351\232\276/\345\217\202\350\200\203.txt" @@ -0,0 +1 @@ +https://leetcode-cn.com/problems/binary-tree-postorder-traversal/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by--34/ \ No newline at end of file diff --git "a/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\346\254\241\351\201\215\345\216\206_102_\344\270\255\347\255\211/Solution1.java" "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\346\254\241\351\201\215\345\216\206_102_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..68b45503 --- /dev/null +++ "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\346\254\241\351\201\215\345\216\206_102_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,56 @@ +package cn.lastwhisper.leetcode.stackqueue.二叉树的层次遍历_102_中等; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +import static cn.lastwhisper.leetcode.common.print.PrintUtil.printLists; +import static cn.lastwhisper.leetcode.common.tree.TreeUtil.createTree; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/binary-tree-level-order-traversal/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public List> levelOrder(TreeNode root) { + List> result = new ArrayList<>(); + if (root == null) + return result; + + Queue queue = new LinkedList<>(); + queue.add(root); + while (!queue.isEmpty()) { + // 遍历每层的数据 + int size = queue.size(); + List list = new ArrayList<>(); + while (size > 0) { + root = queue.poll(); + list.add(root.val); + if (root.left != null) { + queue.add(root.left); + } + if (root.right != null) { + queue.add(root.right); + } + size--; + } + result.add(list); + } + + return result; + } + + public static void main(String[] args) { + List> lists = new Solution1().levelOrder(createTree(3, 9, 20, null, null, 15, 7)); + printLists(lists); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\346\254\241\351\201\215\345\216\206_102_\344\270\255\347\255\211/Solution2.java" "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\346\254\241\351\201\215\345\216\206_102_\344\270\255\347\255\211/Solution2.java" new file mode 100644 index 00000000..4e50312b --- /dev/null +++ "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\346\254\241\351\201\215\345\216\206_102_\344\270\255\347\255\211/Solution2.java" @@ -0,0 +1,65 @@ +package cn.lastwhisper.leetcode.stackqueue.二叉树的层次遍历_102_中等; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +import static cn.lastwhisper.leetcode.common.print.PrintUtil.printLists; +import static cn.lastwhisper.leetcode.common.tree.TreeUtil.createTree; + + +class Solution2 { + static class Pair { + public TreeNode treeNode; + public Integer level; + + public Pair(TreeNode treeNode, Integer level) { + this.treeNode = treeNode; + this.level = level; + } + } + + /** + * 题目地址:https://leetcode-cn.com/problems/binary-tree-level-order-traversal/ + * ------------------------------------------------------------------- + * 思考:迭代遍历 + * ------------------------------------------------------------------- + * 思路: + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public List> levelOrder(TreeNode root) { + List> result = new ArrayList<>(); + if (root == null) + return result; + + Queue queue = new LinkedList<>(); + queue.add(new Pair(root, 0)); + while (!queue.isEmpty()) { + Pair pair = queue.poll(); + TreeNode treeNode = pair.treeNode; + Integer level = pair.level; + if (level == result.size()) { + result.add(new ArrayList<>()); + } + result.get(level).add(treeNode.val); + if (treeNode.left != null) { + queue.add(new Pair(treeNode.left, level + 1)); + } + if (treeNode.right != null) { + queue.add(new Pair(treeNode.right, level + 1)); + } + } + + return result; + } + + public static void main(String[] args) { + List> lists = new Solution2().levelOrder(createTree()); + printLists(lists); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\346\254\241\351\201\215\345\216\206_102_\344\270\255\347\255\211/Solution3.java" "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\346\254\241\351\201\215\345\216\206_102_\344\270\255\347\255\211/Solution3.java" new file mode 100644 index 00000000..7dfb382b --- /dev/null +++ "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\346\254\241\351\201\215\345\216\206_102_\344\270\255\347\255\211/Solution3.java" @@ -0,0 +1,53 @@ +package cn.lastwhisper.leetcode.stackqueue.二叉树的层次遍历_102_中等; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; + +import java.util.ArrayList; +import java.util.List; + +import static cn.lastwhisper.leetcode.common.print.PrintUtil.printLists; +import static cn.lastwhisper.leetcode.common.tree.TreeUtil.*; + +class Solution3 { + + /** + * 题目地址:https://leetcode-cn.com/problems/binary-tree-level-order-traversal/ + * ------------------------------------------------------------------- + * 思考:将2改成递归 + * ------------------------------------------------------------------- + * 思路:递归遍历,与思路2迭代遍历相同 + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public List> levelOrder(TreeNode root) { + List> result = new ArrayList<>(); + if (root == null) + return result; + traversal(root, result, 0); + return result; + } + + /** + * 递归遍历 + */ + private void traversal(TreeNode root, List> result, int level) { + if (root == null) { + return; + } + + if (result.size() == level) { + result.add(new ArrayList<>()); + } + + result.get(level).add(root.val); + // 递归左右子树 + traversal(root.left, result, level + 1); + traversal(root.right, result, level + 1); + } + + public static void main(String[] args) { + List> lists = new Solution3().levelOrder(createTree()); + printLists(lists); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\346\254\241\351\201\215\345\216\206_II_107_\347\256\200\345\215\225/Solution1.java" "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\346\254\241\351\201\215\345\216\206_II_107_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..17ba88e5 --- /dev/null +++ "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\346\254\241\351\201\215\345\216\206_II_107_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,54 @@ +package cn.lastwhisper.leetcode.stackqueue.二叉树的层次遍历_II_107_简单; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; + +import java.util.*; + +import static cn.lastwhisper.leetcode.common.tree.TreeUtil.createTree; +import static cn.lastwhisper.leetcode.common.print.PrintUtil.printLists; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/binary-tree-level-order-traversal-ii/submissions/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * ------------------------------------------------------------------- + * 时间复杂度:O(n^2) + * 空间复杂度:O(n) + */ + public List> levelOrderBottom(TreeNode root) { + LinkedList> result = new LinkedList<>(); + if (root == null) + return result; + + Queue queue = new LinkedList<>(); + queue.add(root); + while (!queue.isEmpty()) { + // 取出每层的数据 + int size = queue.size(); + List list = new ArrayList<>(); + while (size > 0) { + root = queue.poll(); + list.add(root.val); + if (root.left != null) { + queue.add(root.left); + } + if (root.right != null) { + queue.add(root.right); + } + size--; + } + result.push(list); + } + + return result; + } + + public static void main(String[] args) { + TreeNode root = createTree(3,9,20,null,null,15,7); + List> lists = new Solution1().levelOrderBottom(root); + printLists(lists); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\346\254\241\351\201\215\345\216\206_II_107_\347\256\200\345\215\225/Solution2.java" "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\346\254\241\351\201\215\345\216\206_II_107_\347\256\200\345\215\225/Solution2.java" new file mode 100644 index 00000000..4c0e7eee --- /dev/null +++ "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\346\254\241\351\201\215\345\216\206_II_107_\347\256\200\345\215\225/Solution2.java" @@ -0,0 +1,53 @@ +package cn.lastwhisper.leetcode.stackqueue.二叉树的层次遍历_II_107_简单; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; + +import java.util.*; + +import static cn.lastwhisper.leetcode.common.tree.TreeUtil.createTree; +import static cn.lastwhisper.leetcode.common.print.PrintUtil.printLists; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/binary-tree-level-order-traversal-ii/submissions/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * ------------------------------------------------------------------- + * 时间复杂度:O(n^2) + * 空间复杂度:O(n) + */ + public List> levelOrderBottom(TreeNode root) { + Stack> stack = new Stack<>(); + if (root == null) + return stack; + + Queue queue = new LinkedList<>(); + queue.add(root); + while (!queue.isEmpty()) { + // 取出每层的数据 + int size = queue.size(); + List list = new ArrayList<>(); + while (size > 0) { + root = queue.poll(); + list.add(root.val); + if (root.left != null) { + queue.add(root.left); + } + if (root.right != null) { + queue.add(root.right); + } + size--; + } + stack.push(list); + } + return stack; + } + + public static void main(String[] args) { + TreeNode root = createTree(3, 9, 20, null, null, 15, 7); + List> lists = new Solution2().levelOrderBottom(root); + printLists(lists); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\351\224\257\351\275\277\345\275\242\345\261\202\346\254\241\351\201\215\345\216\206_103_\344\270\255\347\255\211/Solution1.java" "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\351\224\257\351\275\277\345\275\242\345\261\202\346\254\241\351\201\215\345\216\206_103_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..93f5da81 --- /dev/null +++ "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\351\224\257\351\275\277\345\275\242\345\261\202\346\254\241\351\201\215\345\216\206_103_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,62 @@ +package cn.lastwhisper.leetcode.stackqueue.二叉树的锯齿形层次遍历_103_中等; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +import static cn.lastwhisper.leetcode.common.tree.TreeUtil.createTree; +import static cn.lastwhisper.leetcode.common.print.PrintUtil.printLists; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/binary-tree-zigzag-level-order-traversal/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:BFS + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public List> zigzagLevelOrder(TreeNode root) { + List> result = new ArrayList<>(); + if (root == null) + return result; + + Queue queue = new LinkedList<>(); + queue.add(root); + while (!queue.isEmpty()) { + // 遍历每层的数据 + int size = queue.size(); + LinkedList list = new LinkedList<>(); + for (int i = 0; i < size; i++) { + root = queue.poll(); + // result.size()=0,1,2,3代表层次 + // 根据层次来判断顺序;奇数倒序,偶数正序 + if ((result.size() & 1) == 1) { + list.push(root.val); + } else { + list.add(root.val); + } + if (root.left != null) { + queue.add(root.left); + } + if (root.right != null) { + queue.add(root.right); + } + } + result.add(list); + } + + return result; + } + + public static void main(String[] args) { + TreeNode root = createTree(3,9,20,null,null,15,7); + List> lists = new Solution1().zigzagLevelOrder(root); + printLists(lists); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\351\224\257\351\275\277\345\275\242\345\261\202\346\254\241\351\201\215\345\216\206_103_\344\270\255\347\255\211/Solution2.java" "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\351\224\257\351\275\277\345\275\242\345\261\202\346\254\241\351\201\215\345\216\206_103_\344\270\255\347\255\211/Solution2.java" new file mode 100644 index 00000000..734e8133 --- /dev/null +++ "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\344\272\214\345\217\211\346\240\221\347\232\204\351\224\257\351\275\277\345\275\242\345\261\202\346\254\241\351\201\215\345\216\206_103_\344\270\255\347\255\211/Solution2.java" @@ -0,0 +1,52 @@ +package cn.lastwhisper.leetcode.stackqueue.二叉树的锯齿形层次遍历_103_中等; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; + +import java.util.ArrayList; +import java.util.List; + +import static cn.lastwhisper.leetcode.common.tree.TreeUtil.createTree; +import static cn.lastwhisper.leetcode.common.print.PrintUtil.printLists; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/binary-tree-zigzag-level-order-traversal/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:DFS + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public List> zigzagLevelOrder(TreeNode root) { + List> res = new ArrayList<>(); + traversal(root, res, 0); + return res; + } + + private void traversal(TreeNode root, List> res, int level) { + if (root == null) { + return; + } + + if (res.size() == level) { + res.add(new ArrayList<>()); + } + + if ((level & 1) == 1) { + res.get(level).add(0, root.val); + } else { + res.get(level).add(root.val); + } + + traversal(root.left, res, level + 1); + traversal(root.right, res, level + 1); + } + + public static void main(String[] args) { + TreeNode root = createTree(3,9,20,null,null,15,7); + List> lists = new Solution2().zigzagLevelOrder(root); + printLists(lists); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\345\211\215K\344\270\252\351\253\230\351\242\221\345\205\203\347\264\240_347_\344\270\255\347\255\211/Solution1.java" "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\345\211\215K\344\270\252\351\253\230\351\242\221\345\205\203\347\264\240_347_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..76461d9e --- /dev/null +++ "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\345\211\215K\344\270\252\351\253\230\351\242\221\345\205\203\347\264\240_347_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,54 @@ +package cn.lastwhisper.leetcode.stackqueue.前K个高频元素_347_中等; + +import java.util.*; +import java.util.stream.Collectors; + +class Solution1 { + static class Pair implements Comparable { + public Integer num; + public Integer freq; + + public Pair(Integer num, Integer freq) { + this.num = num; + this.freq = freq; + } + + @Override + public int compareTo(Pair o) { + return this.freq - o.freq; + } + } + + /** + * 题目地址:https://leetcode-cn.com/problems/top-k-frequent-elements/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:Map统计频率,PriorityQueue维护大小为K的队列(最小堆) + * ------------------------------------------------------------------- + * 时间复杂度:O(nlogk) + * 空间复杂度: + */ + public List topKFrequent(int[] nums, int k) { + // 1、Map统计频率 + Map map = new HashMap<>(); + for (int num : nums) { + map.put(num, map.getOrDefault(num, 0) + 1); + } + // 2、PriorityQueue维护大小为K的队列 + Queue queue = new PriorityQueue<>(); + for (Map.Entry entry : map.entrySet()) { + queue.add(new Pair(entry.getKey(), entry.getValue())); + if (queue.size() > k) { + queue.poll(); + } + } + return queue.stream().map(pair -> pair.num).collect(Collectors.toList()); + } + + public static void main(String[] args) { + int[] nums = {1, 1, 1, 2, 2, 3}; + int k = 2; + new Solution1().topKFrequent(nums, k).forEach(System.out::println); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\345\211\215K\344\270\252\351\253\230\351\242\221\345\205\203\347\264\240_347_\344\270\255\347\255\211/Solution2.java" "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\345\211\215K\344\270\252\351\253\230\351\242\221\345\205\203\347\264\240_347_\344\270\255\347\255\211/Solution2.java" new file mode 100644 index 00000000..f84cd98e --- /dev/null +++ "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\345\211\215K\344\270\252\351\253\230\351\242\221\345\205\203\347\264\240_347_\344\270\255\347\255\211/Solution2.java" @@ -0,0 +1,54 @@ +package cn.lastwhisper.leetcode.stackqueue.前K个高频元素_347_中等; + +import java.util.*; +import java.util.stream.Collectors; + +class Solution2 { + static class Pair implements Comparable { + public Integer num; + public Integer freq; + + public Pair(Integer num, Integer freq) { + this.num = num; + this.freq = freq; + } + + // 倒序 + @Override + public int compareTo(Pair o) { + return o.freq - this.freq; + } + } + + /** + * 题目地址:https://leetcode-cn.com/problems/top-k-frequent-elements/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:Map统计频率,倒序排序频率,取前k个 + * ------------------------------------------------------------------- + * 时间复杂度:O(nlogn) + * 空间复杂度: + */ + public List topKFrequent(int[] nums, int k) { + // 1、Map统计频率 + Map map = new HashMap<>(); + for (int num : nums) { + map.put(num, map.getOrDefault(num, 0) + 1); + } + // 2、倒序排序频率 + List list = new ArrayList<>(map.size()); + for (Map.Entry entry : map.entrySet()) { + list.add(new Pair(entry.getKey(), entry.getValue())); + } + Collections.sort(list); + // 3、取前k个 + return list.stream().map(pair -> pair.num).limit(k).collect(Collectors.toList()); + } + + public static void main(String[] args) { + int[] nums = {1, 1, 1, 2, 2, 3}; + int k = 2; + new Solution2().topKFrequent(nums, k).forEach(System.out::println); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\345\220\210\345\271\266K\344\270\252\346\216\222\345\272\217\351\223\276\350\241\250_23_\345\233\260\351\232\276/Solution1.java" "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\345\220\210\345\271\266K\344\270\252\346\216\222\345\272\217\351\223\276\350\241\250_23_\345\233\260\351\232\276/Solution1.java" new file mode 100644 index 00000000..6b9c0c5c --- /dev/null +++ "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\345\220\210\345\271\266K\344\270\252\346\216\222\345\272\217\351\223\276\350\241\250_23_\345\233\260\351\232\276/Solution1.java" @@ -0,0 +1,66 @@ +package cn.lastwhisper.leetcode.stackqueue.合并K个排序链表_23_困难; + +import cn.lastwhisper.leetcode.common.linkedlist.ListNode; + +import java.util.Comparator; +import java.util.PriorityQueue; +import java.util.Queue; + +import static cn.lastwhisper.leetcode.common.linkedlist.LinkedListUtil.createListNode; +import static cn.lastwhisper.leetcode.common.linkedlist.LinkedListUtil.printListNode; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/merge-k-sorted-lists + * ------------------------------------------------------------------- + * 思考:输入的链表都是有序的 + * ------------------------------------------------------------------- + * 思路: + * 1.将链表头节点都放入最小堆中 + * 2.取出最小堆顶节点minNode,将虚拟头节点next指向minNode + * 3.如果minNode的next不为空,取出minNode的next放入最小堆中 + * 4.重复1、2、3步骤,直至最小堆中没有节点,返回虚拟头节点的next即可 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(n*n) + */ + public ListNode mergeKLists(ListNode[] lists) { + if (lists.length == 0) { + return null; + } + + ListNode dummyHead = new ListNode(0); + ListNode current = dummyHead; + Queue minHeap = new PriorityQueue<>(Comparator.comparingInt(o -> o.val)); + // 链表头部放入最小堆中 + for (ListNode listNode : lists) { + if (listNode == null) { + continue; + } + minHeap.add(listNode); + } + + while (!minHeap.isEmpty()) { + ListNode minNode = minHeap.poll(); + current.next = minNode; + current = current.next; + if (minNode.next != null) { + minHeap.add(minNode.next); + } + } + + return dummyHead.next; + } + + public static void main(String[] args) { + ListNode[] listNodes = new ListNode[3]; + ListNode node1 = createListNode(1, 4, 5); + ListNode node2 = createListNode(1, 3, 4); + ListNode node3 = createListNode(2, 6); + listNodes[0] = node1; + listNodes[1] = node2; + listNodes[2] = node3; + + printListNode(new Solution1().mergeKLists(listNodes)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\345\220\210\345\271\266K\344\270\252\346\216\222\345\272\217\351\223\276\350\241\250_23_\345\233\260\351\232\276/Solution2.java" "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\345\220\210\345\271\266K\344\270\252\346\216\222\345\272\217\351\223\276\350\241\250_23_\345\233\260\351\232\276/Solution2.java" new file mode 100644 index 00000000..67749768 --- /dev/null +++ "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\345\220\210\345\271\266K\344\270\252\346\216\222\345\272\217\351\223\276\350\241\250_23_\345\233\260\351\232\276/Solution2.java" @@ -0,0 +1,73 @@ +package cn.lastwhisper.leetcode.stackqueue.合并K个排序链表_23_困难; + + +import cn.lastwhisper.leetcode.common.linkedlist.ListNode; + +import static cn.lastwhisper.leetcode.common.linkedlist.LinkedListUtil.createListNode; +import static cn.lastwhisper.leetcode.common.linkedlist.LinkedListUtil.printListNode; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/merge-k-sorted-lists + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:将n个链表以中间为对称,合并 + * 1.合并数组中第k个链表到第1个链表,合并数组中第k-1个链表到第2个链表,依次这样操作 + * 2.一轮合并之后,带合并链表分布在数组的 第1 到 第(k+1)/2个链表中,继续1这样的合并直到新链表只在数组第一个位置 + * 3.返回数组第一个元素,即合并之后的链表 + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public ListNode mergeKLists(ListNode[] lists) { + if (lists == null || lists.length == 0) { + return null; + } + int length = lists.length; + // 将n个链表以中间为对称,合并 + while (length > 1) { + for (int i = 0; i < length / 2; i++) { + lists[i] = mergeLists(lists[i], lists[length - i - 1]); + } + // 三个链表,合并两次 + length = (length + 1) / 2; + } + + return lists[0]; + } + + /** + * 合并两个有序链表 + */ + public ListNode mergeLists(ListNode l1, ListNode l2) { + ListNode dummyNode = new ListNode(0); + ListNode current = dummyNode; + + while (l1 != null && l2 != null) { + if (l1.val < l2.val) { + current.next = l1; + l1 = l1.next; + } else { + current.next = l2; + l2 = l2.next; + } + current = current.next; + } + current.next = l1 == null ? l2 : l1; + return dummyNode.next; + } + + + public static void main(String[] args) { + ListNode[] listNodes = new ListNode[3]; + ListNode node1 = createListNode(1, 4, 5); + ListNode node2 = createListNode(1, 3, 4); + ListNode node3 = createListNode(2, 6); + listNodes[0] = node1; + listNodes[1] = node2; + listNodes[2] = node3; + + printListNode(new Solution2().mergeKLists(listNodes)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\345\256\214\345\205\250\345\271\263\346\226\271\346\225\260_279_\344\270\255\347\255\211/Solution1.java" "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\345\256\214\345\205\250\345\271\263\346\226\271\346\225\260_279_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..54893b33 --- /dev/null +++ "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\345\256\214\345\205\250\345\271\263\346\226\271\346\225\260_279_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,32 @@ +package cn.lastwhisper.leetcode.stackqueue.完全平方数_279_中等; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/perfect-squares/ + * ------------------------------------------------------------------- + * 思考:无权图的BFS、迪杰斯特拉 + * ------------------------------------------------------------------- + * 思路: + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public int numSquares(int n) { + int[] dp = new int[n+1]; + for(int i = 1; i <= n; i++){ + dp[i] = Integer.MAX_VALUE; + } + for(int i = 1; i <= n; i++){ + for(int j = 1; j*j <= i; j++){ + if(i >= j*j){ + dp[i] = Math.min(dp[i],dp[i-j*j]+1); + } + } + } + return dp[n]; + } + + public static void main(String[] args) { + System.out.println(new Solution1().numSquares(12)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\346\211\201\345\271\263\345\214\226\345\265\214\345\245\227\345\210\227\350\241\250\350\277\255\344\273\243\345\231\250_341_\344\270\255\347\255\211/NestedInteger.java" "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\346\211\201\345\271\263\345\214\226\345\265\214\345\245\227\345\210\227\350\241\250\350\277\255\344\273\243\345\231\250_341_\344\270\255\347\255\211/NestedInteger.java" new file mode 100644 index 00000000..535a808a --- /dev/null +++ "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\346\211\201\345\271\263\345\214\226\345\265\214\345\245\227\345\210\227\350\241\250\350\277\255\344\273\243\345\231\250_341_\344\270\255\347\255\211/NestedInteger.java" @@ -0,0 +1,19 @@ +package cn.lastwhisper.leetcode.stackqueue.扁平化嵌套列表迭代器_341_中等; + +import java.util.List; + +// This is the interface that allows for creating nested lists. +// You should not implement it, or speculate about its implementation +public interface NestedInteger { + + // @return true if this NestedInteger holds a single integer, rather than a nested list. + public boolean isInteger(); + + // @return the single integer that this NestedInteger holds, if it holds a single integer + // Return null if this NestedInteger holds a nested list + public Integer getInteger(); + + // @return the nested list that this NestedInteger holds, if it holds a nested list + // Return null if this NestedInteger holds a single integer + public List getList(); +} \ No newline at end of file diff --git "a/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\346\211\201\345\271\263\345\214\226\345\265\214\345\245\227\345\210\227\350\241\250\350\277\255\344\273\243\345\231\250_341_\344\270\255\347\255\211/NestedIterator.java" "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\346\211\201\345\271\263\345\214\226\345\265\214\345\245\227\345\210\227\350\241\250\350\277\255\344\273\243\345\231\250_341_\344\270\255\347\255\211/NestedIterator.java" new file mode 100644 index 00000000..9540c15a --- /dev/null +++ "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\346\211\201\345\271\263\345\214\226\345\265\214\345\245\227\345\210\227\350\241\250\350\277\255\344\273\243\345\231\250_341_\344\270\255\347\255\211/NestedIterator.java" @@ -0,0 +1,38 @@ +package cn.lastwhisper.leetcode.stackqueue.扁平化嵌套列表迭代器_341_中等; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +public class NestedIterator implements Iterator { + + private List list = new ArrayList<>(); + private int index = 0; + + public NestedIterator(List nestedList) { + dfs(nestedList); + } + + /** + * 深度优先遍历 + */ + private void dfs(List nestedList) { + for (NestedInteger n : nestedList) { + if (n.isInteger()) { + list.add(n.getInteger()); + } else { + dfs(n.getList()); + } + } + } + + @Override + public Integer next() { + return list.get(index++); + } + + @Override + public boolean hasNext() { + return index < list.size(); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\346\211\201\345\271\263\345\214\226\345\265\214\345\245\227\345\210\227\350\241\250\350\277\255\344\273\243\345\231\250_341_\344\270\255\347\255\211/NestedIterator1.java" "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\346\211\201\345\271\263\345\214\226\345\265\214\345\245\227\345\210\227\350\241\250\350\277\255\344\273\243\345\231\250_341_\344\270\255\347\255\211/NestedIterator1.java" new file mode 100644 index 00000000..97848aa5 --- /dev/null +++ "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\346\211\201\345\271\263\345\214\226\345\265\214\345\245\227\345\210\227\350\241\250\350\277\255\344\273\243\345\231\250_341_\344\270\255\347\255\211/NestedIterator1.java" @@ -0,0 +1,51 @@ +package cn.lastwhisper.leetcode.stackqueue.扁平化嵌套列表迭代器_341_中等; + +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + +public class NestedIterator1 implements Iterator { + + private LinkedList> stack; + private Integer num; + private boolean flag; + + public NestedIterator1(List nestedList) { + // 构造一个栈 栈顶元素存放的是当前活跃的列表 + stack = new LinkedList<>(); + stack.add(nestedList.iterator()); + } + + @Override + public Integer next() { + flag = false; + return num; + } + + @Override + public boolean hasNext() { + if (stack.isEmpty()) return false; + // 取出栈顶活跃的迭代器 + while (!stack.isEmpty() && !flag) { + // 取出栈顶元素 + Iterator iterator = stack.peekFirst(); + if (!iterator.hasNext()) { + // 如果栈顶的迭代器已经是空了就出栈 + stack.pollFirst(); + } else { + NestedInteger next = iterator.next(); + if (next == null) continue; + if (next.isInteger()) { + num = next.getInteger(); + flag = true; + iterator.remove(); + } else { + stack.offerFirst(next.getList().iterator()); + iterator.remove(); + } + } + } + + return flag; + } +} diff --git "a/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\346\211\201\345\271\263\345\214\226\345\265\214\345\245\227\345\210\227\350\241\250\350\277\255\344\273\243\345\231\250_341_\344\270\255\347\255\211/\345\217\202\350\200\203" "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\346\211\201\345\271\263\345\214\226\345\265\214\345\245\227\345\210\227\350\241\250\350\277\255\344\273\243\345\231\250_341_\344\270\255\347\255\211/\345\217\202\350\200\203" new file mode 100644 index 00000000..9b317be7 --- /dev/null +++ "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\346\211\201\345\271\263\345\214\226\345\265\214\345\245\227\345\210\227\350\241\250\350\277\255\344\273\243\345\231\250_341_\344\270\255\347\255\211/\345\217\202\350\200\203" @@ -0,0 +1 @@ +https://leetcode-cn.com/problems/flatten-nested-list-iterator/solution/shi-yong-di-gui-he-zhan-liang-chong-jie-fa-jin-xin/ \ No newline at end of file diff --git "a/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\346\225\260\346\215\256\346\265\201\347\247\273\345\212\250\345\271\263\345\235\207\345\200\274_346_\347\256\200\345\215\225/MovingAverage.java" "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\346\225\260\346\215\256\346\265\201\347\247\273\345\212\250\345\271\263\345\235\207\345\200\274_346_\347\256\200\345\215\225/MovingAverage.java" new file mode 100644 index 00000000..cee3e2fc --- /dev/null +++ "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\346\225\260\346\215\256\346\265\201\347\247\273\345\212\250\345\271\263\345\235\207\345\200\274_346_\347\256\200\345\215\225/MovingAverage.java" @@ -0,0 +1,25 @@ +package cn.lastwhisper.leetcode.stackqueue.数据流移动平均值_346_简单; + +import java.util.LinkedList; +/** + * 给定一个整数数据流和一个窗口大小,根据该滑动窗口的大小,计算其所有整数的移动平均值。 + */ +public class MovingAverage { + private LinkedList dequeue = new LinkedList<>(); + private int size; + private long sum; + + /** Initialize your data structure here. */ + public MovingAverage(int size) { + this.size = size; + } + + public double next(int val) { + if (dequeue.size() == size) sum -= dequeue.removeFirst(); + dequeue.addLast(val); + sum += val; + // System.out.printf("size=%d, val=%d, dequeue=%s, sum=%d\n", size, val, dequeue, sum); + return (double)sum / dequeue.size(); + } + +} \ No newline at end of file diff --git "a/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\346\234\200\345\260\217\346\240\210_155_\347\256\200\345\215\225/MinStack.java" "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\346\234\200\345\260\217\346\240\210_155_\347\256\200\345\215\225/MinStack.java" new file mode 100644 index 00000000..294124c6 --- /dev/null +++ "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\346\234\200\345\260\217\346\240\210_155_\347\256\200\345\215\225/MinStack.java" @@ -0,0 +1,65 @@ +package cn.lastwhisper.leetcode.stackqueue.最小栈_155_简单; + +import org.junit.Assert; + +import java.util.LinkedList; + +class MinStack { + /** + * 题目地址:https://leetcode-cn.com/problems/min-stack/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + LinkedList dataStack = new LinkedList<>(); + LinkedList minStack = new LinkedList<>(); + + /** initialize your data structure here. */ + public MinStack() { + + } + + public void push(int x) { + // 保证minStack栈顶永远是最小值 + if (!minStack.isEmpty()) { + Integer min = minStack.peek(); + if (min > x) { + minStack.push(x); + } else { + minStack.push(min); + } + } else { + minStack.push(x); + } + dataStack.push(x); + } + + public void pop() { + dataStack.pop(); + minStack.pop(); + } + + public int top() { + return dataStack.peek(); + } + + public int getMin() { + return minStack.peek(); + } + + public static void main(String[] args) { + MinStack minStack = new MinStack(); + minStack.push(-2); + minStack.push(0); + minStack.push(-3); + Assert.assertEquals(-3, minStack.getMin()); // --> 返回 -3. + minStack.pop(); + Assert.assertEquals(0, minStack.top()); // --> 返回 0. + Assert.assertEquals(-2, minStack.getMin()); // --> 返回 -2. + } +} + diff --git "a/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\346\234\211\346\225\210\347\232\204\346\213\254\345\217\267_20_\347\256\200\345\215\225/Solution1.java" "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\346\234\211\346\225\210\347\232\204\346\213\254\345\217\267_20_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..5b927530 --- /dev/null +++ "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\346\234\211\346\225\210\347\232\204\346\213\254\345\217\267_20_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,67 @@ +package cn.lastwhisper.leetcode.stackqueue.有效的括号_20_简单; + +import java.util.LinkedList; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/valid-parentheses/ + * ------------------------------------------------------------------- + * 思考: + * 1.括号闭合长度肯定是偶数 + * 2.空字符串可被认为是有效字符串 + * 3.左括号必须用相同类型的右括号闭合 + * 4.左括号必须以正确的顺序闭合 + * 5.右括号可以出现在前面 + * ------------------------------------------------------------------- + * 思路: + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(1) + */ + public boolean isValid(String s) { + if (s.length() % 2 != 0) { + return false; + } + + LinkedList stack = new LinkedList<>(); + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + if (c == '(' || c == '{' || c == '[') { + stack.push(c); + } else { + // "})" + if (stack.isEmpty()) { + return false; + } + if (!match(stack.pop(), c)) { + return false; + } + } + } + // 两种情况""=true、"(("=false + return stack.isEmpty(); + } + + /** + * 左右括号是否配对 + */ + public boolean match(char left, char right) { + if (left == '(') { + return right == ')'; + } else if (left == '{') { + return right == '}'; + } else if (left == '[') { + return right == ']'; + } + return false; + } + + public static void main(String[] args) { + //String s = "{[]}"; + //String s = "()[]{}"; + //String s = "(("; + //String s = "}}"; + String s = ""; + System.out.println(new Solution1().isValid(s)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\347\224\250\351\230\237\345\210\227\345\256\236\347\216\260\346\240\210_225_\347\256\200\345\215\225/MyStack.java" "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\347\224\250\351\230\237\345\210\227\345\256\236\347\216\260\346\240\210_225_\347\256\200\345\215\225/MyStack.java" new file mode 100644 index 00000000..53e93d96 --- /dev/null +++ "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\347\224\250\351\230\237\345\210\227\345\256\236\347\216\260\346\240\210_225_\347\256\200\345\215\225/MyStack.java" @@ -0,0 +1,70 @@ +package cn.lastwhisper.leetcode.stackqueue.用队列实现栈_225_简单; + +import org.junit.Assert; + +import java.util.LinkedList; +import java.util.Queue; + +class MyStack { + + // 只入数据 + private Queue inQueue = new LinkedList<>(); + // 只出数据 + private Queue outQueue = new LinkedList<>(); + + /** Initialize your data structure here. */ + public MyStack() { + + } + + /** Push element x onto stack. */ + public void push(int x) { + inQueue.add(x); + + while (!outQueue.isEmpty()) { + inQueue.add(outQueue.poll()); + } + Queue temp = outQueue; + outQueue = inQueue; + inQueue = temp; + } + + /** Removes the element on top of the stack and returns that element. */ + public int pop() { + return outQueue.poll(); + } + + /** Get the top element. */ + public int top() { + return outQueue.peek(); + } + + /** Returns whether the stack is empty. */ + public boolean empty() { + return outQueue.isEmpty(); + } + + public static void main(String[] args) { + MyStack myStack = new MyStack(); + myStack.push(1); + myStack.push(2); + Assert.assertEquals(2, myStack.pop()); + Assert.assertFalse(myStack.empty()); + myStack.push(3); + myStack.push(4); + Assert.assertEquals(4, myStack.top()); + Assert.assertEquals(4, myStack.pop()); + Assert.assertEquals(3, myStack.pop()); + Assert.assertEquals(1, myStack.pop()); + Assert.assertTrue(myStack.empty()); + } +} + +/** + * Your MyStack object will be instantiated and called as such: + * MyStack obj = new MyStack(); + * obj.push(x); + * int param_2 = obj.pop(); + * int param_3 = obj.top(); + * boolean param_4 = obj.empty(); + */ \ No newline at end of file diff --git "a/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\347\224\250\351\230\237\345\210\227\345\256\236\347\216\260\346\240\210_225_\347\256\200\345\215\225/MyStack1.java" "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\347\224\250\351\230\237\345\210\227\345\256\236\347\216\260\346\240\210_225_\347\256\200\345\215\225/MyStack1.java" new file mode 100644 index 00000000..54eb9a72 --- /dev/null +++ "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\347\224\250\351\230\237\345\210\227\345\256\236\347\216\260\346\240\210_225_\347\256\200\345\215\225/MyStack1.java" @@ -0,0 +1,64 @@ +package cn.lastwhisper.leetcode.stackqueue.用队列实现栈_225_简单; + +import org.junit.Assert; + +import java.util.LinkedList; +import java.util.Queue; + +class MyStack1 { + + Queue queue; + + /** Initialize your data structure here. */ + public MyStack1() { + queue = new LinkedList<>(); + } + + /** Push element x onto stack. */ + public void push(int x) { + queue.add(x); + for (int i = 1; i < queue.size(); i++) { + queue.add(queue.poll()); + } + } + + /** Removes the element on top of the stack and returns that element. */ + public int pop() { + return queue.poll(); + } + + /** Get the top element. */ + public int top() { + return queue.peek(); + } + + /** Returns whether the stack is empty. */ + public boolean empty() { + return queue.size() == 0; + } + + + public static void main(String[] args) { + MyStack1 myStack = new MyStack1(); + myStack.push(1); + myStack.push(2); + Assert.assertEquals(2, myStack.pop()); + Assert.assertFalse(myStack.empty()); + myStack.push(3); + myStack.push(4); + Assert.assertEquals(4, myStack.top()); + Assert.assertEquals(4, myStack.pop()); + Assert.assertEquals(3, myStack.pop()); + Assert.assertEquals(1, myStack.pop()); + Assert.assertTrue(myStack.empty()); + } +} + +/** + * Your MyStack object will be instantiated and called as such: + * MyStack obj = new MyStack(); + * obj.push(x); + * int param_2 = obj.pop(); + * int param_3 = obj.top(); + * boolean param_4 = obj.empty(); + */ \ No newline at end of file diff --git "a/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\347\256\200\345\214\226\350\267\257\345\276\204_71_\344\270\255\347\255\211/Solution1.java" "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\347\256\200\345\214\226\350\267\257\345\276\204_71_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..1c673947 --- /dev/null +++ "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\347\256\200\345\214\226\350\267\257\345\276\204_71_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,56 @@ +package cn.lastwhisper.leetcode.stackqueue.简化路径_71_中等; + +import java.util.Stack; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/simplify-path/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(n) + */ + public String simplifyPath(String path) { + // 按"/"分隔,进行处理 + String[] pathArr = path.split("/"); + Stack stack = new Stack<>(); + for (String p : pathArr) { + // 处理"."和"" + if (p.equals("") || p.equals(".")) { + continue; + } + // ".."返回上一级 + if (p.equals("..")) { + if (!stack.empty()) { + stack.pop(); + } + } else { + // "path"正常路径 + stack.push(p); + } + } + // 说明path是一个"/"或者"/../"等 + if (stack.empty()) { + return "/"; + } + // 拼接处理后的路径 + StringBuilder lastPath = new StringBuilder(); + for (String p : stack) { + lastPath.append("/"); + lastPath.append(p); + } + return lastPath.toString(); + } + + public static void main(String[] args) { + //String path = "/a/../../b/../c//.//"; + //String path = "/a/./b/../../c/"; + //String path ="/"; + String path ="/../"; + System.out.println(new Solution1().simplifyPath(path)); + //System.out.println(Arrays.toString("/a/../../b/../c//.//".replaceAll("//", "/").split("/"))); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\351\200\206\346\263\242\345\205\260\350\241\250\350\276\276\345\274\217\346\261\202\345\200\274_150_\344\270\255\347\255\211/Solution1.java" "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\351\200\206\346\263\242\345\205\260\350\241\250\350\276\276\345\274\217\346\261\202\345\200\274_150_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..4a7a5739 --- /dev/null +++ "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\351\200\206\346\263\242\345\205\260\350\241\250\350\276\276\345\274\217\346\261\202\345\200\274_150_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,63 @@ +package cn.lastwhisper.leetcode.stackqueue.逆波兰表达式求值_150_中等; + +import java.util.Stack; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/evaluate-reverse-polish-notation/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:安装NPN规则即可 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(n) + */ + public int evalRPN(String[] tokens) { + Stack numStack = new Stack<>(); + for (String token : tokens) { + if (isNum(token)) { + numStack.push(token); + } else { + String num2 = numStack.pop(); + String num1 = numStack.pop(); + numStack.push(calculate(num1, num2, token)); + } + } + + return Integer.parseInt(numStack.pop()); + } + + /** + * 判断该字符串是不是数字 + */ + public boolean isNum(String token) { + java.util.regex.Pattern pattern = java.util.regex.Pattern.compile("^([-+])?\\d+(\\.\\d+)?$"); + return pattern.matcher(token).matches(); + } + + /** + * 计算 + */ + public String calculate(String num1, String num2, String expressions) { + switch (expressions) { + case "+": + return String.valueOf(Integer.parseInt(num1) + Integer.parseInt(num2)); + case "-": + return String.valueOf(Integer.parseInt(num1) - Integer.parseInt(num2)); + case "*": + return String.valueOf(Integer.parseInt(num1) * Integer.parseInt(num2)); + case "/": + return String.valueOf(Integer.parseInt(num1) / Integer.parseInt(num2)); + default: + return ""; + } + } + + public static void main(String[] args) { + //String[] tokens = new String[]{"2", "1", "+", "3", "*"}; + String[] tokens = new String[]{"10", "6", "9", "3", "+", "-11", "*", "/", "*", "17", "+", "5", "+"}; + + System.out.println(new Solution1().evalRPN(tokens)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\351\200\206\346\263\242\345\205\260\350\241\250\350\276\276\345\274\217\346\261\202\345\200\274_150_\344\270\255\347\255\211/Solution2.java" "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\351\200\206\346\263\242\345\205\260\350\241\250\350\276\276\345\274\217\346\261\202\345\200\274_150_\344\270\255\347\255\211/Solution2.java" new file mode 100644 index 00000000..8cd0f891 --- /dev/null +++ "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\351\200\206\346\263\242\345\205\260\350\241\250\350\276\276\345\274\217\346\261\202\345\200\274_150_\344\270\255\347\255\211/Solution2.java" @@ -0,0 +1,68 @@ +package cn.lastwhisper.leetcode.stackqueue.逆波兰表达式求值_150_中等; + +import java.util.Stack; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/evaluate-reverse-polish-notation/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:安装NPN规则即可 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(n) + */ + public int evalRPN(String[] tokens) { + Stack numStack = new Stack<>(); + for (String token : tokens) { + //if ("+".equals(token)) { + // //第一个弹出来的数字,要做被+-*/数 + // Integer num = numStack.pop(); + // numStack.push(numStack.pop() + num); + //} else if ("-".equals(token)) { + // Integer num = numStack.pop(); + // numStack.push(numStack.pop() - num); + //} else if ("*".equals(token)) { + // Integer num = numStack.pop(); + // numStack.push(numStack.pop() * num); + //} else if ("/".equals(token)) { + // Integer num = numStack.pop(); + // numStack.push(numStack.pop() / num); + //} else { + // numStack.push(Integer.parseInt(token)); + //} + Integer num; + switch (token){ + case "+": + num = numStack.pop(); + numStack.push(numStack.pop() +num); + break; + case "-": + num = numStack.pop(); + numStack.push(numStack.pop() - num); + break; + case "*": + num = numStack.pop(); + numStack.push(numStack.pop() * num); + break; + case "/": + num = numStack.pop(); + numStack.push(numStack.pop() / num); + break; + default: + numStack.push(Integer.parseInt(token)); + } + + } + return numStack.pop(); + } + + + public static void main(String[] args) { + //String[] tokens = new String[]{"2", "1", "+", "3", "*"}; + String[] tokens = new String[]{"10", "6", "9", "3", "+", "-11", "*", "/", "*", "17", "+", "5", "+"}; + + System.out.println(new Solution2().evalRPN(tokens)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\351\252\214\350\257\201\346\240\210\345\272\217\345\210\227_946_\344\270\255\347\255\211/Solution1.java" "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\351\252\214\350\257\201\346\240\210\345\272\217\345\210\227_946_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..553cb784 --- /dev/null +++ "b/algorithms/leetcode/stackqueue/src/main/java/cn/lastwhisper/leetcode/stackqueue/\351\252\214\350\257\201\346\240\210\345\272\217\345\210\227_946_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,36 @@ +package cn.lastwhisper.leetcode.stackqueue.验证栈序列_946_中等; + +import java.util.LinkedList; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/validate-stack-sequences/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public boolean validateStackSequences(int[] pushed, int[] popped) { + LinkedList stack = new LinkedList<>(); + + int index = 0; + for (int item : pushed) { + stack.push(item); + while (index < popped.length && !stack.isEmpty() && stack.peek() == popped[index]) { + stack.pop(); + index++; + } + } + + return index == popped.length; + } + + public static void main(String[] args) { + //int[] pushed = {1, 2, 3, 4, 5}, popped = {4, 5, 3, 2, 1}; + int[] pushed = {1, 2, 3, 4, 5}, popped = {4, 3, 5, 1, 5}; + System.out.println(new Solution1().validateStackSequences(pushed, popped)); + } +} \ No newline at end of file diff --git a/algorithms/leetcode/string/pom.xml b/algorithms/leetcode/string/pom.xml new file mode 100644 index 00000000..82fff105 --- /dev/null +++ b/algorithms/leetcode/string/pom.xml @@ -0,0 +1,15 @@ + + + + leetcode + cn.lastwhisper + 1.0-SNAPSHOT + + 4.0.0 + + string + + + \ No newline at end of file diff --git "a/algorithms/leetcode/string/src/main/java/cn/lastwhisper/leetcode/string/\345\255\227\347\254\246\344\270\262\347\232\204\346\234\200\345\244\247\345\205\254\345\233\240\345\255\220_1071_\347\256\200\345\215\225/Solution1.java" "b/algorithms/leetcode/string/src/main/java/cn/lastwhisper/leetcode/string/\345\255\227\347\254\246\344\270\262\347\232\204\346\234\200\345\244\247\345\205\254\345\233\240\345\255\220_1071_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..f2598516 --- /dev/null +++ "b/algorithms/leetcode/string/src/main/java/cn/lastwhisper/leetcode/string/\345\255\227\347\254\246\344\270\262\347\232\204\346\234\200\345\244\247\345\205\254\345\233\240\345\255\220_1071_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,36 @@ +package cn.lastwhisper.leetcode.string.字符串的最大公因子_1071_简单; + +import org.junit.Assert; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/greatest-common-divisor-of-strings/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * ------------------------------------------------------------------- + * 时间复杂度:O(n+logn) + * 空间复杂度:O(n) + */ + public String gcdOfStrings(String str1, String str2) { + // 如果 str1 和 str2 拼接后等于 str2和 str1 拼接起来的字符串(注意拼接顺序不同), + // 那么一定存在符合条件的字符串 X + if (!(str1 + str2).equals(str2 + str1)) { + return ""; + } + // 辗转相除法求gcd。 + return str1.substring(0, gcd(str1.length(), str2.length())); + } + + private int gcd(int a, int b) { + return b == 0 ? a : gcd(b, a % b); + } + + public static void main(String[] args) { + Solution1 solution = new Solution1(); + Assert.assertEquals("ABC", solution.gcdOfStrings("ABCABC", "ABC")); + //Assert.assertEquals("AB", solution.gcdOfStrings("ABABAB", "ABAB")); + + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/string/src/main/java/cn/lastwhisper/leetcode/string/\347\277\273\350\275\254\345\255\227\347\254\246\344\270\262\351\207\214\347\232\204\345\215\225\350\257\215_151_\344\270\255\347\255\211/Solution1.java" "b/algorithms/leetcode/string/src/main/java/cn/lastwhisper/leetcode/string/\347\277\273\350\275\254\345\255\227\347\254\246\344\270\262\351\207\214\347\232\204\345\215\225\350\257\215_151_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..2f0af73c --- /dev/null +++ "b/algorithms/leetcode/string/src/main/java/cn/lastwhisper/leetcode/string/\347\277\273\350\275\254\345\255\227\347\254\246\344\270\262\351\207\214\347\232\204\345\215\225\350\257\215_151_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,37 @@ +package cn.lastwhisper.leetcode.string.翻转字符串里的单词_151_中等; + +import org.junit.Assert; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/reverse-words-in-a-string/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public String reverseWords(String s) { + s = s.trim(); + String[] arr = s.split(" "); + for (int i = 0; i < arr.length / 2; i++) { + String temp = arr[i]; + arr[i] = arr[arr.length - i - 1]; + arr[arr.length - i - 1] = temp; + } + StringBuilder sb = new StringBuilder(); + for (String s1 : arr) { + if(!"".equals(s1)){ + sb.append(s1); + sb.append(" "); + } + } + return sb.toString().trim(); + } + + public static void main(String[] args) { + Assert.assertEquals("example good a", new Solution1().reverseWords("a good example")); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/string/src/main/java/cn/lastwhisper/leetcode/string/\351\235\242\350\257\225\351\242\23001_06_\345\255\227\347\254\246\344\270\262\345\216\213\347\274\251_\347\256\200\345\215\225/Solution1.java" "b/algorithms/leetcode/string/src/main/java/cn/lastwhisper/leetcode/string/\351\235\242\350\257\225\351\242\23001_06_\345\255\227\347\254\246\344\270\262\345\216\213\347\274\251_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..40d49463 --- /dev/null +++ "b/algorithms/leetcode/string/src/main/java/cn/lastwhisper/leetcode/string/\351\235\242\350\257\225\351\242\23001_06_\345\255\227\347\254\246\344\270\262\345\216\213\347\274\251_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,39 @@ +package cn.lastwhisper.leetcode.string.面试题01_06_字符串压缩_简单; + +import org.junit.Assert; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/compress-string-lcci/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(n) + */ + public String compressString(String S) { + StringBuilder compress = new StringBuilder(); + int count = 1; + char prev = ' '; + for (char c : S.toCharArray()) { + if (prev == c) {//重复 + count++; + } else if (prev != ' ') {//遇到新的 + compress.append(count); + count = 1; + } + if (count == 1) {//第一次出现 + compress.append(c); + } + prev = c; + } + compress.append(count); + return compress.length() >= S.length() ? S : compress.toString(); + } + + public static void main(String[] args) { + Assert.assertEquals("a2b1c5a3", new Solution1().compressString("aabcccccaaa")); + } +} \ No newline at end of file diff --git a/algorithms/leetcode/union-find/pom.xml b/algorithms/leetcode/union-find/pom.xml new file mode 100644 index 00000000..9505648d --- /dev/null +++ b/algorithms/leetcode/union-find/pom.xml @@ -0,0 +1,15 @@ + + + + leetcode + cn.lastwhisper + 1.0-SNAPSHOT + + 4.0.0 + + union-find + + + \ No newline at end of file diff --git a/algorithms/leetcode/week/pom.xml b/algorithms/leetcode/week/pom.xml new file mode 100644 index 00000000..4571e4d7 --- /dev/null +++ b/algorithms/leetcode/week/pom.xml @@ -0,0 +1,15 @@ + + + + leetcode + cn.lastwhisper + 1.0-SNAPSHOT + + 4.0.0 + + week + + + \ No newline at end of file diff --git "a/algorithms/leetcode/week/src/main/java/cn/lastwhisper/leetcode/week/one175/\345\210\266\351\200\240\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215\347\232\204\346\234\200\345\260\217\346\255\245\351\252\244\346\225\260_5333_\344\270\255\347\255\211/Solution.java" "b/algorithms/leetcode/week/src/main/java/cn/lastwhisper/leetcode/week/one175/\345\210\266\351\200\240\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215\347\232\204\346\234\200\345\260\217\346\255\245\351\252\244\346\225\260_5333_\344\270\255\347\255\211/Solution.java" new file mode 100644 index 00000000..32f29b83 --- /dev/null +++ "b/algorithms/leetcode/week/src/main/java/cn/lastwhisper/leetcode/week/one175/\345\210\266\351\200\240\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215\347\232\204\346\234\200\345\260\217\346\255\245\351\252\244\346\225\260_5333_\344\270\255\347\255\211/Solution.java" @@ -0,0 +1,24 @@ +package cn.lastwhisper.leetcode.week.one175.制造字母异位词的最小步骤数_5333_中等; + +class Solution { + public int minSteps(String s, String t) { + int[] map = new int[26]; + for (int i = 0; i < s.length(); i++) { + map[s.charAt(i) - 97]++; + map[t.charAt(i) - 97]--; + } + int count = 0; + for (int value : map) { + if (value > 0) { + count += value; + } + } + return count; + } + + public static void main(String[] args) { + //String s = "bab", t = "aba"; + String s = "leetcode", t = "practice"; + System.out.println(new Solution().minSteps(s, t)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/week/src/main/java/cn/lastwhisper/leetcode/week/one175/\345\217\202\345\212\240\350\200\203\350\257\225\347\232\204\346\234\200\345\244\247\345\255\246\347\224\237\346\225\260_5335_\345\233\260\351\232\276/Solution.java" "b/algorithms/leetcode/week/src/main/java/cn/lastwhisper/leetcode/week/one175/\345\217\202\345\212\240\350\200\203\350\257\225\347\232\204\346\234\200\345\244\247\345\255\246\347\224\237\346\225\260_5335_\345\233\260\351\232\276/Solution.java" new file mode 100644 index 00000000..557628e6 --- /dev/null +++ "b/algorithms/leetcode/week/src/main/java/cn/lastwhisper/leetcode/week/one175/\345\217\202\345\212\240\350\200\203\350\257\225\347\232\204\346\234\200\345\244\247\345\255\246\347\224\237\346\225\260_5335_\345\233\260\351\232\276/Solution.java" @@ -0,0 +1,77 @@ +package cn.lastwhisper.leetcode.week.one175.参加考试的最大学生数_5335_困难; + +import java.util.ArrayList; +import java.util.List; + +class Solution { + private static final int[][] directory = new int[][]{ + {-1, 0},// up + {0, 1},// right + {1, 0},// down + {0, -1},// left + }; + private int[][] dir = new int[][]{ + {0, -1}, // 左 + {-1, -1},// 左上 + {-1, 1}, // 右上 + {0, 1}, // 右 + }; + private int max = 0, num = 0; + private int m, n; + + public int maxStudents(char[][] seats) { + m = seats.length; + n = seats[0].length; + boolean[][] visited = new boolean[m][n]; + List> resultList = new ArrayList<>(); + dfs(seats, visited, 0, 0, new ArrayList<>(), resultList); + return max; + } + + public void dfs(char[][] seats, boolean[][] visited, int startX, int startY, List result, List> resultList) { + if (startX == m - 1 && startY == n - 1) { + max = Math.max(max, num); + //max = Math.max(max, result.size()); + resultList.add(new ArrayList<>(result)); + return; + } + for (int i = 0; i < directory.length; i++) { + int newX = startX + directory[i][0]; + int newY = startY + directory[i][1]; + if (isArea(newX, newY) && seats[newX][newY] == '.' && isValid(visited, newX, newY)) { + visited[newX][newY] = true; + result.add(newX + "," + newY); + num++; + dfs(seats, visited, newX, newY, result, resultList); + visited[newX][newY] = false; + result.remove(result.size() - 1); + num--; + } + } + } + + private boolean isArea(int x, int y) { + return x >= 0 && y >= 0 && x < m && y < n; + } + + + // 左侧、右侧、左上、右上没人 + public boolean isValid(boolean[][] visited, int startX, int startY) { + for (int[] ints : dir) { + int newX = startX + ints[0]; + int newY = startY + ints[1]; + if (isArea(newX, newY) && visited[newX][newY]) { + return false; + } + } + return true; + } + + public static void main(String[] args) { + char[][] seats = {{'#', '.', '#', '#', '.', '#'}, + {'.', '#', '#', '#', '#', '.'}, + {'#', '.', '#', '#', '.', '#'} + }; + System.out.println(new Solution().maxStudents(seats)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/week/src/main/java/cn/lastwhisper/leetcode/week/one175/\346\216\250\346\226\207\350\256\241\346\225\260_5334_\344\270\255\347\255\211/TweetCounts.java" "b/algorithms/leetcode/week/src/main/java/cn/lastwhisper/leetcode/week/one175/\346\216\250\346\226\207\350\256\241\346\225\260_5334_\344\270\255\347\255\211/TweetCounts.java" new file mode 100644 index 00000000..3244cb3b --- /dev/null +++ "b/algorithms/leetcode/week/src/main/java/cn/lastwhisper/leetcode/week/one175/\346\216\250\346\226\207\350\256\241\346\225\260_5334_\344\270\255\347\255\211/TweetCounts.java" @@ -0,0 +1,40 @@ +package cn.lastwhisper.leetcode.week.one175.推文计数_5334_中等; + +import java.util.List; + +class TweetCounts { + + public TweetCounts() { + + } + + /** + * 记录推文发布情况:用户 tweetName 在 time(以 秒 为单位)时刻发布了一条推文 + * + * @param tweetName 用户 + * @param time 时刻 + */ + public void recordTweet(String tweetName, int time) { + + } + + /** + * + * @param freq 分 minute,时 hour 或者 日 day 之一 + * @param tweetName 指定用户 tweetName + * @param startTime 开始时间 startTime(以 秒 为单位) + * @param endTime 结束时间 endTime(以 秒 为单位) + */ + public List getTweetCountsPerFrequency(String freq, String tweetName, int startTime, int endTime) { + + return null; + } + +} + +/** + * Your TweetCounts object will be instantiated and called as such: + * TweetCounts obj = new TweetCounts(); + * obj.recordTweet(tweetName,time); + * List param_2 = obj.getTweetCountsPerFrequency(freq,tweetName,startTime,endTime); + */ \ No newline at end of file diff --git "a/algorithms/leetcode/week/src/main/java/cn/lastwhisper/leetcode/week/one175/\346\243\200\346\237\245\346\225\264\346\225\260\345\217\212\345\205\266\344\270\244\345\200\215\346\225\260\346\230\257\345\220\246\345\255\230\345\234\250_\347\256\200\345\215\225_5332/Solution.java" "b/algorithms/leetcode/week/src/main/java/cn/lastwhisper/leetcode/week/one175/\346\243\200\346\237\245\346\225\264\346\225\260\345\217\212\345\205\266\344\270\244\345\200\215\346\225\260\346\230\257\345\220\246\345\255\230\345\234\250_\347\256\200\345\215\225_5332/Solution.java" new file mode 100644 index 00000000..fc466293 --- /dev/null +++ "b/algorithms/leetcode/week/src/main/java/cn/lastwhisper/leetcode/week/one175/\346\243\200\346\237\245\346\225\264\346\225\260\345\217\212\345\205\266\344\270\244\345\200\215\346\225\260\346\230\257\345\220\246\345\255\230\345\234\250_\347\256\200\345\215\225_5332/Solution.java" @@ -0,0 +1,23 @@ +package cn.lastwhisper.leetcode.week.one175.检查整数及其两倍数是否存在_简单_5332; + +class Solution { + //O(n^2),使用二分进行优化O(nlogn),hash优化O(n) + public boolean checkIfExist(int[] arr) { + if (arr == null || arr.length == 0) { + return false; + } + for (int i = 0; i < arr.length; i++) { + for (int j = i + 1; j < arr.length; j++) { + if (2 * arr[i] == arr[j] || arr[i] == 2 * arr[j]) { + return true; + } + } + } + return false; + } + + public static void main(String[] args) { + System.out.println(new Solution().checkIfExist(new int[]{7, 1, 14, 11})); + System.out.println(new Solution().checkIfExist(new int[]{10, 2, 5, 3})); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/week/src/main/java/cn/lastwhisper/leetcode/week/one176/\346\234\200\345\220\216K\344\270\252\346\225\260\347\232\204\344\271\230\347\247\257_5341/ProductOfNumbers.java" "b/algorithms/leetcode/week/src/main/java/cn/lastwhisper/leetcode/week/one176/\346\234\200\345\220\216K\344\270\252\346\225\260\347\232\204\344\271\230\347\247\257_5341/ProductOfNumbers.java" new file mode 100644 index 00000000..107a0b82 --- /dev/null +++ "b/algorithms/leetcode/week/src/main/java/cn/lastwhisper/leetcode/week/one176/\346\234\200\345\220\216K\344\270\252\346\225\260\347\232\204\344\271\230\347\247\257_5341/ProductOfNumbers.java" @@ -0,0 +1,34 @@ +package cn.lastwhisper.leetcode.week.one176.最后K个数的乘积_5341; + +import java.util.ArrayList; +import java.util.List; + +class ProductOfNumbers { + + private List list = new ArrayList<>(); + + public ProductOfNumbers() { + + + } + + public void add(int num) { + list.add(num); + } + + public int getProduct(int k) { + int count = 1; + for (int i = list.size() - k; i < list.size(); i++) { + count *= list.get(i); + } + return count; + } + +} + +/** + * Your ProductOfNumbers object will be instantiated and called as such: + * ProductOfNumbers obj = new ProductOfNumbers(); + * obj.add(num); + * int param_2 = obj.getProduct(k); + */ \ No newline at end of file diff --git "a/algorithms/leetcode/week/src/main/java/cn/lastwhisper/leetcode/week/one176/\346\234\200\345\244\232\345\217\257\344\273\245\345\217\202\345\212\240\347\232\204\344\274\232\350\256\256\346\225\260\347\233\256_5342/Solution.java" "b/algorithms/leetcode/week/src/main/java/cn/lastwhisper/leetcode/week/one176/\346\234\200\345\244\232\345\217\257\344\273\245\345\217\202\345\212\240\347\232\204\344\274\232\350\256\256\346\225\260\347\233\256_5342/Solution.java" new file mode 100644 index 00000000..be1631f0 --- /dev/null +++ "b/algorithms/leetcode/week/src/main/java/cn/lastwhisper/leetcode/week/one176/\346\234\200\345\244\232\345\217\257\344\273\245\345\217\202\345\212\240\347\232\204\344\274\232\350\256\256\346\225\260\347\233\256_5342/Solution.java" @@ -0,0 +1,12 @@ +package cn.lastwhisper.leetcode.week.one176.最多可以参加的会议数目_5342; + +class Solution { + + public int maxEvents(int[][] events) { + return 0; + } + + public static void main(String[] args){ + + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/week/src/main/java/cn/lastwhisper/leetcode/week/one176/\347\273\237\350\256\241\346\234\211\345\272\217\347\237\251\351\230\265\344\270\255\347\232\204\350\264\237\346\225\260_5340/Solution.java" "b/algorithms/leetcode/week/src/main/java/cn/lastwhisper/leetcode/week/one176/\347\273\237\350\256\241\346\234\211\345\272\217\347\237\251\351\230\265\344\270\255\347\232\204\350\264\237\346\225\260_5340/Solution.java" new file mode 100644 index 00000000..1d39983b --- /dev/null +++ "b/algorithms/leetcode/week/src/main/java/cn/lastwhisper/leetcode/week/one176/\347\273\237\350\256\241\346\234\211\345\272\217\347\237\251\351\230\265\344\270\255\347\232\204\350\264\237\346\225\260_5340/Solution.java" @@ -0,0 +1,25 @@ +package cn.lastwhisper.leetcode.week.one176.统计有序矩阵中的负数_5340; + +class Solution { + // 降序 + public int countNegatives(int[][] grid) { + int count = 0; + for (int i = grid.length - 1; i >= 0; i--) { + for (int j = grid[0].length - 1; j >= 0; j--) { + // 跳出当前循环 + if (grid[i][j] >= 0) { + break; + } + if (grid[i][j] < 0) { + count++; + } + } + } + return count; + } + + public static void main(String[] args) { + int[][] grid = {{4, 3, 2, -1}, {3, 2, 1, -1}, {1, 1, -1, -2}, {-1, -1, -2, -3}};//8 + System.out.println(new Solution().countNegatives(grid)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/week/src/main/java/cn/lastwhisper/leetcode/week/one177/\345\275\242\346\210\220\344\270\211\347\232\204\346\234\200\345\244\247\345\200\215\346\225\260_5172_\345\233\260\351\232\276/Solution.java" "b/algorithms/leetcode/week/src/main/java/cn/lastwhisper/leetcode/week/one177/\345\275\242\346\210\220\344\270\211\347\232\204\346\234\200\345\244\247\345\200\215\346\225\260_5172_\345\233\260\351\232\276/Solution.java" new file mode 100644 index 00000000..843c5378 --- /dev/null +++ "b/algorithms/leetcode/week/src/main/java/cn/lastwhisper/leetcode/week/one177/\345\275\242\346\210\220\344\270\211\347\232\204\346\234\200\345\244\247\345\200\215\346\225\260_5172_\345\233\260\351\232\276/Solution.java" @@ -0,0 +1,8 @@ +package cn.lastwhisper.leetcode.week.one177.形成三的最大倍数_5172_困难; + +class Solution { + public String largestMultipleOfThree(int[] digits) { + + return null; + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/week/src/main/java/cn/lastwhisper/leetcode/week/one177/\346\227\245\346\234\237\344\271\213\351\227\264\351\232\224\345\207\240\345\244\251_5169_\347\256\200\345\215\225/Solution.java" "b/algorithms/leetcode/week/src/main/java/cn/lastwhisper/leetcode/week/one177/\346\227\245\346\234\237\344\271\213\351\227\264\351\232\224\345\207\240\345\244\251_5169_\347\256\200\345\215\225/Solution.java" new file mode 100644 index 00000000..15a438d0 --- /dev/null +++ "b/algorithms/leetcode/week/src/main/java/cn/lastwhisper/leetcode/week/one177/\346\227\245\346\234\237\344\271\213\351\227\264\351\232\224\345\207\240\345\244\251_5169_\347\256\200\345\215\225/Solution.java" @@ -0,0 +1,24 @@ +package cn.lastwhisper.leetcode.week.one177.日期之间隔几天_5169_简单; + +import java.text.ParseException; +import java.text.SimpleDateFormat; + +class Solution { + public int daysBetweenDates(String date1, String date2) { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); + int count = 0; + try { + long to = sdf.parse(date1).getTime(); + long from = sdf.parse(date2).getTime(); + count = (int) ((to - from) / (1000 * 60 * 60 * 24)); + } catch (ParseException e) { + e.printStackTrace(); + } + return Math.abs(count); + } + + public static void main(String[] args) { + String date1 = "2019-06-29", date2 = "2019-06-30"; + System.out.println(new Solution().daysBetweenDates(date1, date2)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/week/src/main/java/cn/lastwhisper/leetcode/week/one177/\346\234\200\346\216\245\350\277\221\347\232\204\345\233\240\346\225\260_5171_\344\270\255\347\255\211/Solution.java" "b/algorithms/leetcode/week/src/main/java/cn/lastwhisper/leetcode/week/one177/\346\234\200\346\216\245\350\277\221\347\232\204\345\233\240\346\225\260_5171_\344\270\255\347\255\211/Solution.java" new file mode 100644 index 00000000..e587adf9 --- /dev/null +++ "b/algorithms/leetcode/week/src/main/java/cn/lastwhisper/leetcode/week/one177/\346\234\200\346\216\245\350\277\221\347\232\204\345\233\240\346\225\260_5171_\344\270\255\347\255\211/Solution.java" @@ -0,0 +1,8 @@ +package cn.lastwhisper.leetcode.week.one177.最接近的因数_5171_中等; + +class Solution { + public int[] closestDivisors(int num) { + + return null; + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/week/src/main/java/cn/lastwhisper/leetcode/week/one177/\351\252\214\350\257\201\344\272\214\345\217\211\346\240\221_5170_\344\270\255\347\255\211/Solution.java" "b/algorithms/leetcode/week/src/main/java/cn/lastwhisper/leetcode/week/one177/\351\252\214\350\257\201\344\272\214\345\217\211\346\240\221_5170_\344\270\255\347\255\211/Solution.java" new file mode 100644 index 00000000..8423345a --- /dev/null +++ "b/algorithms/leetcode/week/src/main/java/cn/lastwhisper/leetcode/week/one177/\351\252\214\350\257\201\344\272\214\345\217\211\346\240\221_5170_\344\270\255\347\255\211/Solution.java" @@ -0,0 +1,12 @@ +package cn.lastwhisper.leetcode.week.one177.验证二叉树_5170_中等; + +class Solution { + public boolean validateBinaryTreeNodes(int n, int[] leftChild, int[] rightChild) { + + return true; + } + + public static void main(String[] args) { + + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/week/src/main/java/cn/lastwhisper/leetcode/week/one178/\346\234\211\345\244\232\345\260\221\345\260\217\344\272\216\345\275\223\345\211\215\346\225\260\345\255\227\347\232\204\346\225\260\345\255\227_5344/Solution.java" "b/algorithms/leetcode/week/src/main/java/cn/lastwhisper/leetcode/week/one178/\346\234\211\345\244\232\345\260\221\345\260\217\344\272\216\345\275\223\345\211\215\346\225\260\345\255\227\347\232\204\346\225\260\345\255\227_5344/Solution.java" new file mode 100644 index 00000000..63b24012 --- /dev/null +++ "b/algorithms/leetcode/week/src/main/java/cn/lastwhisper/leetcode/week/one178/\346\234\211\345\244\232\345\260\221\345\260\217\344\272\216\345\275\223\345\211\215\346\225\260\345\255\227\347\232\204\346\225\260\345\255\227_5344/Solution.java" @@ -0,0 +1,19 @@ +package cn.lastwhisper.leetcode.week.one178.有多少小于当前数字的数字_5344; + +class Solution { + + public int[] smallerNumbersThanCurrent(int[] nums) { + int[] arr = new int[nums.length]; + for (int i = 0; i < nums.length; i++) { + int count = 0; + for (int j = 0; j < nums.length; j++) { + if (i != j && nums[j] < nums[i]) { + count++; + } + } + arr[i] = count; + } + return arr; + } + +} \ No newline at end of file diff --git "a/algorithms/leetcode/week/src/main/java/cn/lastwhisper/leetcode/week/one178/\351\200\232\350\277\207\346\212\225\347\245\250\345\257\271\345\233\242\351\230\237\346\216\222\345\220\215_5345/Solution.java" "b/algorithms/leetcode/week/src/main/java/cn/lastwhisper/leetcode/week/one178/\351\200\232\350\277\207\346\212\225\347\245\250\345\257\271\345\233\242\351\230\237\346\216\222\345\220\215_5345/Solution.java" new file mode 100644 index 00000000..96976d17 --- /dev/null +++ "b/algorithms/leetcode/week/src/main/java/cn/lastwhisper/leetcode/week/one178/\351\200\232\350\277\207\346\212\225\347\245\250\345\257\271\345\233\242\351\230\237\346\216\222\345\220\215_5345/Solution.java" @@ -0,0 +1,41 @@ +package cn.lastwhisper.leetcode.week.one178.通过投票对团队排名_5345; + +import java.util.*; +import java.util.stream.Collectors; + +class Solution { + + public String rankTeams(String[] votes) { + //key是参赛团队,value是该团队每个排位获得的票数 + Map teamRankMap = new HashMap<>(); + + for (String vote : votes) { + for (int i = 0; i < vote.length(); i++) { + int[] rankArr = teamRankMap.getOrDefault(vote.charAt(i), new int[26]); + rankArr[i]++; + teamRankMap.put(vote.charAt(i), rankArr); + } + } + + List> teamRankList = new ArrayList<>(teamRankMap.entrySet()); + teamRankList.sort((team1, team2) -> { + int[] ranks1 = team1.getValue(); + int[] ranks2 = team2.getValue(); + //根据投票排序 + for (int i = 0; i < 26; i++) { + if (ranks1[i] != ranks2[i]) { + return ranks2[i] - ranks1[i]; + } + } + //字母顺序排序 + return team1.getKey() - team2.getKey(); + }); + + //转换为字符串输出 + return teamRankList.stream().map(entry -> String.valueOf(entry.getKey())).collect(Collectors.joining()); + } + + public static void main(String[] args) { + System.err.println(new Solution().rankTeams(new String[]{"ABC", "ACB", "ABC", "ACB", "ACB"})); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/week/src/main/java/cn/lastwhisper/leetcode/week/one180/\347\237\251\351\230\265\344\270\255\347\232\204\345\271\270\350\277\220\346\225\260_5356_\347\256\200\345\215\225/Solution.java" "b/algorithms/leetcode/week/src/main/java/cn/lastwhisper/leetcode/week/one180/\347\237\251\351\230\265\344\270\255\347\232\204\345\271\270\350\277\220\346\225\260_5356_\347\256\200\345\215\225/Solution.java" new file mode 100644 index 00000000..459c327c --- /dev/null +++ "b/algorithms/leetcode/week/src/main/java/cn/lastwhisper/leetcode/week/one180/\347\237\251\351\230\265\344\270\255\347\232\204\345\271\270\350\277\220\346\225\260_5356_\347\256\200\345\215\225/Solution.java" @@ -0,0 +1,44 @@ +package cn.lastwhisper.leetcode.week.one180.矩阵中的幸运数_5356_简单; + +import java.util.ArrayList; +import java.util.List; + +class Solution { + + public List luckyNumbers(int[][] matrix) { + if (matrix == null || matrix.length == 0) { + return new ArrayList<>(); + } + List res = new ArrayList<>(); + for (int i = 0; i < matrix.length; i++) { + for (int j = 0; j < matrix[0].length; j++) { + if (luckNum(i, j, matrix)) { + res.add(matrix[i][j]); + } + } + } + return res; + } + + private boolean luckNum(int x, int y, int[][] matrix) { + for (int i = 0; i < matrix.length; i++) { + for (int j = 0; j < matrix[0].length; j++) { + // 在同一行的所有元素中最小 + if (i == x && matrix[x][y] > matrix[i][j]) { + return false; + } + // 在同一列的所有元素中最大 + if (j == y && matrix[x][y] < matrix[i][j]) { + return false; + } + } + } + return true; + } + + public static void main(String[] args) { + int[][] matrix = {{3, 7, 8}, {9, 11, 13}, {15, 16, 17}}; + System.err.println(new Solution().luckyNumbers(matrix)); + } + +} \ No newline at end of file diff --git "a/algorithms/leetcode/week/src/main/java/cn/lastwhisper/leetcode/week/one180/\347\237\251\351\230\265\344\270\255\347\232\204\345\271\270\350\277\220\346\225\260_5356_\347\256\200\345\215\225/Solution1.java" "b/algorithms/leetcode/week/src/main/java/cn/lastwhisper/leetcode/week/one180/\347\237\251\351\230\265\344\270\255\347\232\204\345\271\270\350\277\220\346\225\260_5356_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..6dcc76e6 --- /dev/null +++ "b/algorithms/leetcode/week/src/main/java/cn/lastwhisper/leetcode/week/one180/\347\237\251\351\230\265\344\270\255\347\232\204\345\271\270\350\277\220\346\225\260_5356_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,34 @@ +package cn.lastwhisper.leetcode.week.one180.矩阵中的幸运数_5356_简单; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +class Solution1 { + public List luckyNumbers(int[][] matrix) { + if (matrix == null) { + return null; + } + int m = matrix.length, n = matrix[0].length; + Map map = new HashMap<>(); + List ans = new ArrayList<>(); + + for (int[] rows : matrix) { + int max = Integer.MIN_VALUE, min = Integer.MAX_VALUE; + for (int j = 0; j < n; j++) { + map.put(rows[j], j); + min = Math.min(min, rows[j]); + } + int min_col = map.get(min); + map.clear(); + for (int[] row : matrix) { + max = Math.max(row[min_col], max); + } + if (max == min) { + ans.add(max); + } + } + return ans; + } +} diff --git "a/algorithms/leetcode/week/src/main/java/cn/lastwhisper/leetcode/week/one180/\350\256\276\350\256\241\344\270\200\344\270\252\346\224\257\346\214\201\345\242\236\351\207\217\346\223\215\344\275\234\347\232\204\346\240\210_5357_\344\270\255\347\255\211/CustomStack.java" "b/algorithms/leetcode/week/src/main/java/cn/lastwhisper/leetcode/week/one180/\350\256\276\350\256\241\344\270\200\344\270\252\346\224\257\346\214\201\345\242\236\351\207\217\346\223\215\344\275\234\347\232\204\346\240\210_5357_\344\270\255\347\255\211/CustomStack.java" new file mode 100644 index 00000000..71c23ea9 --- /dev/null +++ "b/algorithms/leetcode/week/src/main/java/cn/lastwhisper/leetcode/week/one180/\350\256\276\350\256\241\344\270\200\344\270\252\346\224\257\346\214\201\345\242\236\351\207\217\346\223\215\344\275\234\347\232\204\346\240\210_5357_\344\270\255\347\255\211/CustomStack.java" @@ -0,0 +1,54 @@ +package cn.lastwhisper.leetcode.week.one180.设计一个支持增量操作的栈_5357_中等; + +import org.junit.Assert; + +class CustomStack { + int maxSize; + int[] arr; + int top; + + public CustomStack(int maxSize) { + this.maxSize = maxSize; + arr = new int[maxSize]; + top = -1; + } + + public void push(int x) { + if (top + 1 >= maxSize) { + return; + } + arr[++top] = x; + } + + public int pop() { + if (top == -1) { + return -1; + } + return arr[top--]; + } + + public void increment(int k, int val) { + if (k > top) { + k = top + 1;// + } + for (int i = 0; i < k; i++) { + arr[i] += val; + } + } + + public static void main(String[] args) { + CustomStack customStack = new CustomStack(3); // 栈是空的 [] + customStack.push(1); // 栈变为 [1] + customStack.push(2); // 栈变为 [1, 2] + Assert.assertEquals(2, customStack.pop()); // 返回 2 --> 返回栈顶值 2,栈变为 [1] + customStack.push(2); // 栈变为 [1, 2] + customStack.push(3); // 栈变为 [1, 2, 3] + customStack.push(4); // 栈仍然是 [1, 2, 3],不能添加其他元素使栈大小变为 4 + customStack.increment(5, 100); // 栈变为 [101, 102, 103] + customStack.increment(2, 100); // 栈变为 [201, 202, 103] + Assert.assertEquals(103, customStack.pop()); // 返回 103 --> 返回栈顶值 103,栈变为 [201, 202] + Assert.assertEquals(202, customStack.pop()); // 返回 202 --> 返回栈顶值 202,栈变为 [201] + Assert.assertEquals(201, customStack.pop()); // 返回 201 --> 返回栈顶值 201,栈变为 [] + Assert.assertEquals(-1, customStack.pop()); // 返回 -1 --> 栈为空,返回 -1 + } +} diff --git "a/algorithms/leetcode/week/src/main/java/cn/lastwhisper/leetcode/week/one183/\345\260\206\344\272\214\350\277\233\345\210\266\350\241\250\347\244\272\345\207\217\345\210\2601\347\232\204\346\255\245\351\252\244\346\225\260_5377_\344\270\255\347\255\211/Solution.java" "b/algorithms/leetcode/week/src/main/java/cn/lastwhisper/leetcode/week/one183/\345\260\206\344\272\214\350\277\233\345\210\266\350\241\250\347\244\272\345\207\217\345\210\2601\347\232\204\346\255\245\351\252\244\346\225\260_5377_\344\270\255\347\255\211/Solution.java" new file mode 100644 index 00000000..c71e8c21 --- /dev/null +++ "b/algorithms/leetcode/week/src/main/java/cn/lastwhisper/leetcode/week/one183/\345\260\206\344\272\214\350\277\233\345\210\266\350\241\250\347\244\272\345\207\217\345\210\2601\347\232\204\346\255\245\351\252\244\346\225\260_5377_\344\270\255\347\255\211/Solution.java" @@ -0,0 +1,47 @@ +package cn.lastwhisper.leetcode.week.one183.将二进制表示减到1的步骤数_5377_中等; + +import org.junit.Assert; + +import java.math.BigInteger; +import java.util.LinkedList; + +class Solution { + + public int numSteps(String s) { + BigInteger num = convert(s); + System.out.println(num.toString()); + BigInteger two = BigInteger.valueOf(2); + int count = 0; + while (num.compareTo(BigInteger.ONE) != 0) { + if (num.remainder(two).compareTo(BigInteger.ZERO) == 0) { + num = num.divide(two); + } else { + num = num.add(BigInteger.ONE); + } + count++; + } + return count; + } + + private BigInteger convert(String s) { + LinkedList stack = new LinkedList<>(); + for (int i = 0; i < s.length(); i++) { + stack.push(s.charAt(i) - '0'); + } + BigInteger sum = BigInteger.ZERO; + int i = 0; + BigInteger two = BigInteger.valueOf(2); + while (!stack.isEmpty()) { + BigInteger temp = BigInteger.valueOf(stack.pop()); + sum = sum.add(temp.multiply(two.pow(i++))); + } + return sum; + } + + public static void main(String[] args) { + //Assert.assertEquals(6, new Solution().numSteps("1101")); + //Assert.assertEquals(20, new Solution().numSteps("111111001110101")); + //Assert.assertEquals(85, new Solution().numSteps("1111011110000011100000110001011011110010111001010111110001")); + Assert.assertEquals(85, new Solution().numSteps("1111110011101010110011100100101110010100101110111010111110110010")); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode/week/src/main/java/cn/lastwhisper/leetcode/week/one183/\351\235\236\351\200\222\345\242\236\351\241\272\345\272\217\347\232\204\346\234\200\345\260\217\345\255\220\345\272\217\345\210\227_5376_\347\256\200\345\215\225/Solution.java" "b/algorithms/leetcode/week/src/main/java/cn/lastwhisper/leetcode/week/one183/\351\235\236\351\200\222\345\242\236\351\241\272\345\272\217\347\232\204\346\234\200\345\260\217\345\255\220\345\272\217\345\210\227_5376_\347\256\200\345\215\225/Solution.java" new file mode 100644 index 00000000..db685d75 --- /dev/null +++ "b/algorithms/leetcode/week/src/main/java/cn/lastwhisper/leetcode/week/one183/\351\235\236\351\200\222\345\242\236\351\241\272\345\272\217\347\232\204\346\234\200\345\260\217\345\255\220\345\272\217\345\210\227_5376_\347\256\200\345\215\225/Solution.java" @@ -0,0 +1,36 @@ +package cn.lastwhisper.leetcode.week.one183.非递增顺序的最小子序列_5376_简单; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +class Solution { + + public List minSubsequence(int[] nums) { + int sum = 0; + for (int num : nums) { + sum += num; + } + Integer[] arr = new Integer[nums.length]; + for (int i = 0; i < nums.length; i++) { + arr[i] = nums[i]; + } + Arrays.sort(arr, (o1, o2) -> o2 - o1); + + List ans = new ArrayList<>(); + int nowSum = 0; + for (Integer num : arr) { + nowSum += num; + ans.add(num); + if (nowSum > (sum - nowSum)) { + break; + } + } + return ans; + } + + public static void main(String[] args) { + new Solution().minSubsequence(new int[]{4, 3, 10, 9, 8}).forEach(System.out::print); + } + +} \ No newline at end of file diff --git "a/algorithms/leetcode/week/src/main/java/cn/lastwhisper/leetcode/week/tow20/\346\240\271\346\215\256\346\225\260\345\255\227\344\272\214\350\277\233\345\210\266\344\270\2131\347\232\204\346\225\260\347\233\256\346\216\222\345\272\217_5323_\347\256\200\345\215\225/Solution.java" "b/algorithms/leetcode/week/src/main/java/cn/lastwhisper/leetcode/week/tow20/\346\240\271\346\215\256\346\225\260\345\255\227\344\272\214\350\277\233\345\210\266\344\270\2131\347\232\204\346\225\260\347\233\256\346\216\222\345\272\217_5323_\347\256\200\345\215\225/Solution.java" new file mode 100644 index 00000000..46bafad6 --- /dev/null +++ "b/algorithms/leetcode/week/src/main/java/cn/lastwhisper/leetcode/week/tow20/\346\240\271\346\215\256\346\225\260\345\255\227\344\272\214\350\277\233\345\210\266\344\270\2131\347\232\204\346\225\260\347\233\256\346\216\222\345\272\217_5323_\347\256\200\345\215\225/Solution.java" @@ -0,0 +1,42 @@ +package cn.lastwhisper.leetcode.week.tow20.根据数字二进制下1的数目排序_5323_简单; + +import java.util.Arrays; + +class Solution { + + public int[] sortByBits(int[] arr) { + Integer[] nums = new Integer[arr.length]; + for (int i = 0; i < arr.length; i++) { + nums[i] = arr[i]; + } + Arrays.sort(nums, (o1, o2) -> { + int bitCountA = Integer.bitCount(o1); + int bitCountB = Integer.bitCount(o2); + // 相同按原数,不同按位数 + return bitCountA == bitCountB ? o1 - o2 : bitCountA - bitCountB; + }); + for (int i = 0; i < arr.length; i++) { + arr[i] = nums[i]; + } + return arr; + } + + private int bitCount(int n) { + int count = 0; + while (n != 0) { + // n=10011101,n-1=10011100 + // &全1则1,否则0 + // n & (n - 1)=10011101&10011100=10011100 + // n=10011100 + n = n & (n - 1); + count++; + } + return count; + } + + public static void main(String[] args) { + //int[] arr = {0, 1, 2, 3, 4, 5, 6, 7, 8}; + int[] arr = {1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 1}; + System.out.println(Arrays.toString(new Solution().sortByBits(arr))); + } +} \ No newline at end of file diff --git a/algorithms/leetcode2/README.md b/algorithms/leetcode2/README.md new file mode 100644 index 00000000..43591dac --- /dev/null +++ b/algorithms/leetcode2/README.md @@ -0,0 +1,20 @@ +2刷力扣 + +```java +/** + * 思考: + * ------------------------------------------------------------------- + * 思路: + * ------------------------------------------------------------------- + * 时间复杂度:O(n^2) + * 空间复杂度:O(1) + */ + + +``` + +- greedy 贪心 +- point 双指针 + + + diff --git a/algorithms/leetcode2/backtracking/pom.xml b/algorithms/leetcode2/backtracking/pom.xml new file mode 100644 index 00000000..d5561633 --- /dev/null +++ b/algorithms/leetcode2/backtracking/pom.xml @@ -0,0 +1,19 @@ + + + + leetcode2 + cn.cucnhang + 1.0-SNAPSHOT + + 4.0.0 + + backtracking + + + 8 + 8 + + + \ No newline at end of file diff --git "a/algorithms/leetcode2/backtracking/src/main/java/cn/cunchang/N\347\232\207\345\220\216_51_\345\233\260\351\232\276/Solution.java" "b/algorithms/leetcode2/backtracking/src/main/java/cn/cunchang/N\347\232\207\345\220\216_51_\345\233\260\351\232\276/Solution.java" new file mode 100644 index 00000000..16dda701 --- /dev/null +++ "b/algorithms/leetcode2/backtracking/src/main/java/cn/cunchang/N\347\232\207\345\220\216_51_\345\233\260\351\232\276/Solution.java" @@ -0,0 +1,86 @@ +package cn.cunchang.N皇后_51_困难; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * @author cunchang + * @date 2022/7/1 5:33 PM + */ +class Solution { + List> result = new ArrayList<>(); + public List> solveNQueens(int n) { + char[][] chessboard = new char[n][n]; + + for (char[] chess : chessboard) { + Arrays.fill(chess,'.'); + } + + solveNQueens0(chessboard, 0); + return result; + } + + private void solveNQueens0(char[][] chessboard, int row) { + if (row == chessboard.length) { + List subResult = getSubResult(chessboard); + result.add(subResult); + return; + } + int col = chessboard[row].length; + for (int i = 0; i < col; i++) { + // 排除不合规 + if (!valid(chessboard, row, i)) { + continue; + } + // 放棋子 + chessboard[row][i] = 'Q'; + // 尝试下一列 + solveNQueens0(chessboard, row + 1); + // 撤销操作 + chessboard[row][i] = '.'; + } + } + + private List getSubResult(char[][] chessboard) { + List subResult = new ArrayList<>(chessboard.length); + for (int i = 0; i < chessboard.length; i++) { + StringBuilder rowStr = new StringBuilder(); + for (int j = 0; j < chessboard.length; j++) { + rowStr.append(chessboard[i][j]); + } + subResult.add(rowStr.toString()); + } + return subResult; + } + + private boolean valid(char[][] chessboard, int row, int col) { + + // row之前是否同列 + for (int i = 0; i <= row; i++) { + if (chessboard[i][col] == 'Q') { + return false; + } + } + + // 左对角线;行列坐标减一 + for (int i = row, j = col; i >= 0 && j >= 0; i--, j--) { + if (chessboard[i][j] == 'Q') { + return false; + } + } + + // 右对角线;行坐标减一,列坐标加一 + for (int i = row, j = col; i >= 0 && j < chessboard[0].length; i--, j++) { + if (chessboard[i][j] == 'Q') { + return false; + } + } + + return true; + } + + public static void main(String[] args) { + System.out.println(new Solution().solveNQueens(10)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode2/backtracking/src/main/java/cn/cunchang/\345\205\250\346\216\222\345\210\227II_47_\344\270\255\347\255\211/Solution.java" "b/algorithms/leetcode2/backtracking/src/main/java/cn/cunchang/\345\205\250\346\216\222\345\210\227II_47_\344\270\255\347\255\211/Solution.java" new file mode 100644 index 00000000..5db95256 --- /dev/null +++ "b/algorithms/leetcode2/backtracking/src/main/java/cn/cunchang/\345\205\250\346\216\222\345\210\227II_47_\344\270\255\347\255\211/Solution.java" @@ -0,0 +1,57 @@ +package cn.cunchang.全排列II_47_中等; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; + +/** + * @author cunchang + * @date 2022/7/2 4:02 PM + */ +class Solution { + List> result = new ArrayList<>(); + + public List> permuteUnique(int[] nums) { + // 记录「路径」 + LinkedList subResult = new LinkedList<>(); + // 「路径」中的元素会被标记为 true,避免重复使用 + boolean[] visited = new boolean[nums.length]; + // 保证有序 + Arrays.sort(nums); + permute0(nums, subResult, visited); + return result; + } + + private void permute0(int[] nums, LinkedList subResult, boolean[] visited) { + // 回溯结束,记录结果 + if (nums.length == subResult.size()) { + result.add(new ArrayList<>(subResult)); + } + // 记录上一次选择的值 + int prev = Integer.MIN_VALUE; + // 遍历选择列表 + for (int i = 0; i < nums.length; i++) { + if (visited[i]) { + continue; + } + // 选择值相同,则不选 + if (prev == nums[i]) { + continue; + } + prev = nums[i]; + // 选择值 + subResult.add(nums[i]); + visited[i] = true; + permute0(nums, subResult, visited); + // 撤销选择 + subResult.removeLast(); + visited[i] = false; + } + } + + public static void main(String[] args) { + System.out.println(new Solution().permuteUnique(new int[]{1, 2, 1})); + } + +} \ No newline at end of file diff --git "a/algorithms/leetcode2/backtracking/src/main/java/cn/cunchang/\345\205\250\346\216\222\345\210\227_46_\344\270\255\347\255\211/Solution.java" "b/algorithms/leetcode2/backtracking/src/main/java/cn/cunchang/\345\205\250\346\216\222\345\210\227_46_\344\270\255\347\255\211/Solution.java" new file mode 100644 index 00000000..171a593e --- /dev/null +++ "b/algorithms/leetcode2/backtracking/src/main/java/cn/cunchang/\345\205\250\346\216\222\345\210\227_46_\344\270\255\347\255\211/Solution.java" @@ -0,0 +1,43 @@ +package cn.cunchang.全排列_46_中等; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +class Solution { + List> result = new ArrayList<>(); + + public List> permute(int[] num) { + // 记录「路径」 + LinkedList subResult = new LinkedList<>(); + // 「路径」中的元素会被标记为 true,避免重复使用 + boolean[] visited = new boolean[num.length]; + permute0(num, subResult, visited); + return result; + } + + private void permute0(int[] num, LinkedList subResult, boolean[] visited) { + // 回溯结束,记录结果 + if (num.length == subResult.size()) { + result.add(new ArrayList<>(subResult)); + } + // 遍历选择列表 + for (int i = 0; i < num.length; i++) { + if (visited[i]) { + continue; + } + // 选择值 + subResult.add(num[i]); + visited[i] = true; + permute0(num, subResult, visited); + // 撤销选择 + subResult.removeLast(); + visited[i] = false; + } + } + + public static void main(String[] args) { + System.out.println(new Solution().permute(new int[]{1, 2, 3})); + } + +} \ No newline at end of file diff --git "a/algorithms/leetcode2/backtracking/src/main/java/cn/cunchang/\345\205\250\346\216\222\345\210\227_46_\344\270\255\347\255\211/Solution2.java" "b/algorithms/leetcode2/backtracking/src/main/java/cn/cunchang/\345\205\250\346\216\222\345\210\227_46_\344\270\255\347\255\211/Solution2.java" new file mode 100644 index 00000000..fc69920f --- /dev/null +++ "b/algorithms/leetcode2/backtracking/src/main/java/cn/cunchang/\345\205\250\346\216\222\345\210\227_46_\344\270\255\347\255\211/Solution2.java" @@ -0,0 +1,49 @@ +package cn.cunchang.全排列_46_中等; + +import java.util.ArrayList; +import java.util.List; + +class Solution2 { + List> result = new ArrayList<>(); + + public List> permute(int[] num) { + // 记录「路径」 + List subResult = new ArrayList<>(); + // 「路径」中的元素会被标记为 true,避免重复使用 + boolean[] visited = new boolean[num.length]; + permute0(num, subResult, visited, 0); + return result; + } + + /** + * + * @param num 数字序列 + * @param subResult 当前路径排列 + * @param visited 保存访问过的下标 + * @param idx idx用于撤销当前操作 + */ + private void permute0(int[] num, List subResult, boolean[] visited, int idx) { + // 回溯结束,记录结果 + if (num.length == subResult.size()) { + result.add(new ArrayList<>(subResult)); + } + // 遍历选择列表 + for (int i = 0; i < num.length; i++) { + if (visited[i]) { + continue; + } + // 选择值 + subResult.add(num[i]); + visited[i] = true; + permute0(num, subResult, visited, idx + 1); + // 撤销选择 + subResult.remove(idx); + visited[i] = false; + } + } + + public static void main(String[] args) { + System.out.println(new Solution2().permute(new int[]{1, 2, 3})); + } + +} \ No newline at end of file diff --git "a/algorithms/leetcode2/backtracking/src/main/java/cn/cunchang/\345\210\222\345\210\206\344\270\272k\344\270\252\347\233\270\347\255\211\347\232\204\345\255\220\351\233\206_698_\344\270\255\347\255\211/Solution.java" "b/algorithms/leetcode2/backtracking/src/main/java/cn/cunchang/\345\210\222\345\210\206\344\270\272k\344\270\252\347\233\270\347\255\211\347\232\204\345\255\220\351\233\206_698_\344\270\255\347\255\211/Solution.java" new file mode 100644 index 00000000..7cba38a4 --- /dev/null +++ "b/algorithms/leetcode2/backtracking/src/main/java/cn/cunchang/\345\210\222\345\210\206\344\270\272k\344\270\252\347\233\270\347\255\211\347\232\204\345\255\220\351\233\206_698_\344\270\255\347\255\211/Solution.java" @@ -0,0 +1,72 @@ +package cn.cunchang.划分为k个相等的子集_698_中等; + +import java.util.Arrays; + +/** + * @author cunchang + * @date 2022/7/2 3:34 PM + */ +class Solution { + public boolean canPartitionKSubsets(int[] nums, int k) { + //因为题目限制条件不用担心溢出 + int sum = 0; + for (int i = 0; i < nums.length; i++) { + sum += nums[i]; + } + if (sum % k != 0) { + return false; + } + //求出子集的和 + sum = sum / k; + //排序 小的放最前面大的放最后面 + Arrays.sort(nums); + //如果子集的和小于数组最大的直接返回false + if (nums[nums.length - 1] > sum) { + return false; + } + //建立一个长度为k的桶 + int[] arr = new int[k]; + //桶的每一个值都是子集的和 + Arrays.fill(arr, sum); + + boolean flag = help(nums, nums.length - 1, arr); + +// System.out.println(Arrays.toString(arr)); + return flag; + } + + /** + * @param nums {1,2,3,3,4,4,5} + * @param cur 6 + * @param arr {5,5,5,5} + */ + boolean help(int[] nums, int cur, int[] arr) { + //已经遍历到了-1说明前面的所有数都正好可以放入桶里,那所有桶的值此时都为0,说明找到了结果,返回true + if (cur < 0) { + return true; + } + //遍历k个桶 + for (int i = 0; i < arr.length; i++) { + //如果正好能放下当前的数或者放下当前的数后,还有机会继续放前面的数(剪枝) + if (arr[i] == nums[cur] || (cur > 0 && arr[i] - nums[cur] >= nums[0])) { + //放当前的数到桶i里 + arr[i] -= nums[cur]; + //开始放下一个数 + if (help(nums, cur - 1, arr)) { + return true; + } + //这个数不该放在桶i中 + //从桶中拿回当前的数 + arr[i] += nums[cur]; + } + } + return false; + } + + public static void main(String[] args) { + int[] nums = {4, 3, 2, 3, 5, 2, 1}; + int k = 4; + System.out.println(new Solution().canPartitionKSubsets(nums, k)); + } + +} \ No newline at end of file diff --git "a/algorithms/leetcode2/backtracking/src/main/java/cn/cunchang/\345\255\220\351\233\206II_90_\344\270\255\347\255\211/Solution.java" "b/algorithms/leetcode2/backtracking/src/main/java/cn/cunchang/\345\255\220\351\233\206II_90_\344\270\255\347\255\211/Solution.java" new file mode 100644 index 00000000..174a7fe2 --- /dev/null +++ "b/algorithms/leetcode2/backtracking/src/main/java/cn/cunchang/\345\255\220\351\233\206II_90_\344\270\255\347\255\211/Solution.java" @@ -0,0 +1,35 @@ +package cn.cunchang.子集II_90_中等; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; + +/** + * @author cunchang + * @date 2022/7/2 6:33 PM + */ +class Solution { + List> result = new ArrayList<>(); + LinkedList track = new LinkedList<>(); + + public List> subsetsWithDup(int[] nums) { + Arrays.sort(nums); + subsetsWithDup0(nums, 0); + return result; + } + + public void subsetsWithDup0(int[] nums, int idx) { + result.add(new ArrayList<>(track)); + for (int i = idx; i < nums.length; i++) { + // 跟前一个值相同,就需要剪枝 + if (i > idx && nums[i] == nums[i - 1]) { + continue; + } + track.add(nums[i]); + subsetsWithDup0(nums, i + 1); + track.removeLast(); + } + } + +} \ No newline at end of file diff --git "a/algorithms/leetcode2/backtracking/src/main/java/cn/cunchang/\345\255\220\351\233\206_78_\344\270\255\347\255\211/Solution.java" "b/algorithms/leetcode2/backtracking/src/main/java/cn/cunchang/\345\255\220\351\233\206_78_\344\270\255\347\255\211/Solution.java" new file mode 100644 index 00000000..b7a2ea35 --- /dev/null +++ "b/algorithms/leetcode2/backtracking/src/main/java/cn/cunchang/\345\255\220\351\233\206_78_\344\270\255\347\255\211/Solution.java" @@ -0,0 +1,33 @@ +package cn.cunchang.子集_78_中等; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +/** + * @author cunchang + * @date 2022/7/2 5:03 PM + */ +class Solution { + + List> result = new ArrayList<>(); + LinkedList track = new LinkedList<>(); + + public List> subsets(int[] nums) { + backtrack(nums, 0); + return result; + } + + public void backtrack(int[] nums, int idx) { + result.add(new LinkedList<>(track)); + // 选择列表中选择 + for (int i = idx; i < nums.length; i++) { + // 做选择 + track.add(nums[i]); + backtrack(nums, i + 1); + // 撤销选择 + track.removeLast(); + } + } + +} \ No newline at end of file diff --git "a/algorithms/leetcode2/backtracking/src/main/java/cn/cunchang/\347\273\204\345\220\210_77_\344\270\255\347\255\211/Solution.java" "b/algorithms/leetcode2/backtracking/src/main/java/cn/cunchang/\347\273\204\345\220\210_77_\344\270\255\347\255\211/Solution.java" new file mode 100644 index 00000000..49efd6e7 --- /dev/null +++ "b/algorithms/leetcode2/backtracking/src/main/java/cn/cunchang/\347\273\204\345\220\210_77_\344\270\255\347\255\211/Solution.java" @@ -0,0 +1,43 @@ +package cn.cunchang.组合_77_中等; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +/** + * @author cunchang + * @date 2022/7/2 4:59 PM + */ +class Solution { + List> result = new ArrayList<>(); + LinkedList track = new LinkedList<>(); + + public List> combine(int n, int k) { + int[] nums = new int[n]; + for (int i = 0; i < n; i++) { + nums[i] = i + 1; + } + backtrack(nums, 0, k); + return result; + } + + public void backtrack(int[] nums, int idx, int k) { + if (track.size() == k) { + result.add(new LinkedList<>(track)); + return; + } + // 选择列表中选择 + for (int i = idx; i < nums.length; i++) { + // 做选择 + track.add(nums[i]); + backtrack(nums, i + 1, k); + // 撤销选择 + track.removeLast(); + } + } + + public static void main(String[] args) { + System.out.println(new Solution().combine(4, 2)); + } + +} \ No newline at end of file diff --git a/algorithms/leetcode2/binarysearch/pom.xml b/algorithms/leetcode2/binarysearch/pom.xml new file mode 100644 index 00000000..8cf210a7 --- /dev/null +++ b/algorithms/leetcode2/binarysearch/pom.xml @@ -0,0 +1,15 @@ + + + 4.0.0 + cn.cucnhang + 1.0-SNAPSHOT + binarysearch + + + 8 + 8 + + + \ No newline at end of file diff --git "a/algorithms/leetcode2/binarysearch/src/main/java/cn/cunchang/\344\272\214\345\210\206\346\237\245\346\211\276_704_\347\256\200\345\215\225/Solution.java" "b/algorithms/leetcode2/binarysearch/src/main/java/cn/cunchang/\344\272\214\345\210\206\346\237\245\346\211\276_704_\347\256\200\345\215\225/Solution.java" new file mode 100644 index 00000000..ae43609a --- /dev/null +++ "b/algorithms/leetcode2/binarysearch/src/main/java/cn/cunchang/\344\272\214\345\210\206\346\237\245\346\211\276_704_\347\256\200\345\215\225/Solution.java" @@ -0,0 +1,46 @@ +package cn.cunchang.二分查找_704_简单; + +import org.junit.Assert; + +class Solution { + /** + * 思考: + * ------------------------------------------------------------------- + * 思路: + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public int search(int[] nums, int target) { + int l = 0, r = nums.length-1; // -1是因为最右边不存在的值会超界 + while (l <= r) {// =是因为该值有可能是正确答案 + int mid = (r + l) / 2; + if (nums[mid] > target) {// 中间值大于目标值 + r = mid - 1; // -1是因为该值不符合要求 + } else if (nums[mid] < target) { + l = mid + 1; // +1是因为该值不符合要求 + } else { + return mid; + } + } + return -1; + } + + public static void main(String[] args) { + // 偶数数组 存在 +// Assert.assertEquals(4, new Solution(). +// search(new int[]{-1, 0, 3, 5, 9, 12}, 9)); + // 偶数数组 左边中间不存在 +// Assert.assertEquals(-1, new Solution(). +// search(new int[]{-1, 0, 3, 5, 9, 12}, 2)); + // 偶数数组 最右边不存在 + Assert.assertEquals(-1, new Solution(). + search(new int[]{-1, 0, 3, 5, 9, 12}, 13)); + // 偶数数组 存在 +// Assert.assertEquals(4, new Solution(). +// search(new int[]{-1, 0, 3, 5, 9}, 9)); + // 偶数数组 不存在 +// Assert.assertEquals(-1, new Solution(). +// search(new int[]{-1, 0, 3, 5, 9}, 2)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode2/binarysearch/src/main/java/cn/cunchang/\345\234\250\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\346\237\245\346\211\276\345\205\203\347\264\240\347\232\204\347\254\254\344\270\200\344\270\252\345\222\214\346\234\200\345\220\216\344\270\200\344\270\252\344\275\215\347\275\256_34_\344\270\255\347\255\211/Solution.java" "b/algorithms/leetcode2/binarysearch/src/main/java/cn/cunchang/\345\234\250\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\346\237\245\346\211\276\345\205\203\347\264\240\347\232\204\347\254\254\344\270\200\344\270\252\345\222\214\346\234\200\345\220\216\344\270\200\344\270\252\344\275\215\347\275\256_34_\344\270\255\347\255\211/Solution.java" new file mode 100644 index 00000000..c7253abf --- /dev/null +++ "b/algorithms/leetcode2/binarysearch/src/main/java/cn/cunchang/\345\234\250\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\346\237\245\346\211\276\345\205\203\347\264\240\347\232\204\347\254\254\344\270\200\344\270\252\345\222\214\346\234\200\345\220\216\344\270\200\344\270\252\344\275\215\347\275\256_34_\344\270\255\347\255\211/Solution.java" @@ -0,0 +1,37 @@ +package cn.cunchang.在排序数组中查找元素的第一个和最后一个位置_34_中等; + +class Solution { + /** + * 找目标值的最左边和目标值+1的最左边 + * 缺点,小数不好使了 + * + */ + public int[] searchRange(int[] nums, int target) { + if (nums == null || nums.length == 0) { + return new int[]{-1, -1}; + } + int l = search(nums, target); + // l >= nums.length ==》超出右边界 searchRange(new int[]{2,2}, 3) + // nums[l] != target ==》找不到 searchRange(new int[]{5, 7, 7, 8, 8, 10}, 6) + if (l >= nums.length || nums[l] != target) { + return new int[]{-1, -1}; + } + int r = search(nums, target + 1) - 1; + return new int[]{l, r}; + } + + + private int search(int[] nums, int target) { + int l = 0, r = nums.length - 1; + while (l <= r) { + int mid = (r + l) / 2; + // 这里与无重复二分不同,=r也减少为了搜索最左边的target + if (nums[mid] >= target) { + r = mid - 1; + } else if (nums[mid] < target) { + l = mid + 1; + } + } + return l; + } +} \ No newline at end of file diff --git "a/algorithms/leetcode2/binarysearch/src/main/java/cn/cunchang/\345\234\250\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\346\237\245\346\211\276\345\205\203\347\264\240\347\232\204\347\254\254\344\270\200\344\270\252\345\222\214\346\234\200\345\220\216\344\270\200\344\270\252\344\275\215\347\275\256_34_\344\270\255\347\255\211/Solution2.java" "b/algorithms/leetcode2/binarysearch/src/main/java/cn/cunchang/\345\234\250\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\346\237\245\346\211\276\345\205\203\347\264\240\347\232\204\347\254\254\344\270\200\344\270\252\345\222\214\346\234\200\345\220\216\344\270\200\344\270\252\344\275\215\347\275\256_34_\344\270\255\347\255\211/Solution2.java" new file mode 100644 index 00000000..ecf93ea1 --- /dev/null +++ "b/algorithms/leetcode2/binarysearch/src/main/java/cn/cunchang/\345\234\250\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\346\237\245\346\211\276\345\205\203\347\264\240\347\232\204\347\254\254\344\270\200\344\270\252\345\222\214\346\234\200\345\220\216\344\270\200\344\270\252\344\275\215\347\275\256_34_\344\270\255\347\255\211/Solution2.java" @@ -0,0 +1,62 @@ +package cn.cunchang.在排序数组中查找元素的第一个和最后一个位置_34_中等; + +import java.util.Arrays; + +class Solution2 { + public int[] searchRange(int[] nums, int target) { + if (nums == null || nums.length == 0) { + return new int[]{-1, -1}; + } + int l = lowerBound(nums, target); + // l >= nums.length ==》超出右边界 searchRange(new int[]{2,2}, 3) + // nums[l] != target ==》找不到 searchRange(new int[]{5, 7, 7, 8, 8, 10}, 6) + if (l >= nums.length || nums[l] != target) { + return new int[]{-1, -1}; + } + int r = upperBound(nums, target) - 1; + return new int[]{l, r}; + } + + private int upperBound(int[] nums, int target) { + int l = 0, r = nums.length - 1; + while (l <= r) { + int mid = (r + l) / 2; + if (nums[mid] > target) { + r = mid - 1; + } else if (nums[mid] <= target) { + // 这里与无重复二分不同,=时l也增加为了缩小左边,搜索最右边的target + l = mid + 1; + } + } + return l; + } + + private int lowerBound(int[] nums, int target) { + int l = 0, r = nums.length - 1; + while (l <= r) { + int mid = (r + l) / 2; + // 这里与无重复二分不同,=时r也减少为了缩小右边,搜索最左边的target + // 这里有个问题就是,会不会跳过目标值比如 {5, 6, 7, 8, 9, 10}, 7;这里会跳过的 + // 但是l = mid + 1又加回来 + if (nums[mid] >= target) { + r = mid - 1; + } else if (nums[mid] < target) { + l = mid + 1; + } + } + return l; + } + + public static void main(String[] args) { +// System.out.println(Arrays.toString(new Solution2(). +// searchRange(new int[]{5, 7, 7, 8, 8, 10}, 8))); +// System.out.println(Arrays.toString(new Solution2(). +// searchRange(new int[]{5, 7, 7, 8, 8, 10}, 6))); +// System.out.println(Arrays.toString(new Solution2(). +// searchRange(new int[]{2, 2}, 3))); + System.out.println(Arrays.toString(new Solution2(). + searchRange(new int[]{5, 6, 7, 8, 9, 10}, 7))); +// System.out.println(Arrays.toString(new Solution2(). +// searchRange(new int[]{5, 6, 7, 8, 9, 10}, 10))); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode2/binarysearch/src/main/java/cn/cunchang/\345\234\250\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\346\237\245\346\211\276\345\205\203\347\264\240\347\232\204\347\254\254\344\270\200\344\270\252\345\222\214\346\234\200\345\220\216\344\270\200\344\270\252\344\275\215\347\275\256_34_\344\270\255\347\255\211/Solution3.java" "b/algorithms/leetcode2/binarysearch/src/main/java/cn/cunchang/\345\234\250\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\346\237\245\346\211\276\345\205\203\347\264\240\347\232\204\347\254\254\344\270\200\344\270\252\345\222\214\346\234\200\345\220\216\344\270\200\344\270\252\344\275\215\347\275\256_34_\344\270\255\347\255\211/Solution3.java" new file mode 100644 index 00000000..aa935a42 --- /dev/null +++ "b/algorithms/leetcode2/binarysearch/src/main/java/cn/cunchang/\345\234\250\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\346\237\245\346\211\276\345\205\203\347\264\240\347\232\204\347\254\254\344\270\200\344\270\252\345\222\214\346\234\200\345\220\216\344\270\200\344\270\252\344\275\215\347\275\256_34_\344\270\255\347\255\211/Solution3.java" @@ -0,0 +1,62 @@ +package cn.cunchang.在排序数组中查找元素的第一个和最后一个位置_34_中等; + +import java.util.Arrays; + +class Solution3 { + public int[] searchRange(double[] nums, double target) { + if (nums == null || nums.length == 0) { + return new int[]{-1, -1}; + } + int l = lowerBound(nums, target); + // l >= nums.length ==》超出右边界 searchRange(new double[]{2,2}, 3) + // nums[l] != target ==》找不到 searchRange(new double[]{5, 7, 7, 8, 8, 10}, 6) + if (l >= nums.length || nums[l] != target) { + return new int[]{-1, -1}; + } + int r = upperBound(nums, target) - 1; + return new int[]{l, r}; + } + + private int upperBound(double[] nums, double target) { + int l = 0, r = nums.length - 1; + while (l <= r) { + int mid = (r + l) / 2; + if (nums[mid] > target) { + r = mid - 1; + } else if (nums[mid] <= target) { + // 这里与无重复二分不同,=时l也增加为了缩小左边,搜索最右边的target + l = mid + 1; + } + } + return l; + } + + private int lowerBound(double[] nums, double target) { + int l = 0, r = nums.length - 1; + while (l <= r) { + int mid = (r + l) / 2; + // 这里与无重复二分不同,=时r也减少为了缩小右边,搜索最左边的target + // 这里有个问题就是,会不会跳过目标值比如 {5, 6, 7, 8, 9, 10}, 7;这里会跳过的 + // 但是l = mid + 1又加回来 + if (nums[mid] >= target) { + r = mid - 1; + } else if (nums[mid] < target) { + l = mid + 1; + } + } + return l; + } + + public static void main(String[] args) { +// System.out.println(Arrays.toString(new Solution2(). +// searchRange(new double[]{5, 7, 7, 8, 8, 10}, 8))); +// System.out.println(Arrays.toString(new Solution2(). +// searchRange(new double[]{5, 7, 7, 8, 8, 10}, 6))); +// System.out.println(Arrays.toString(new Solution2(). +// searchRange(new double[]{2, 2}, 3))); + System.out.println(Arrays.toString(new Solution3(). + searchRange(new double[]{7.5, 7.6, 7.7,7.7, 7.8, 7.9}, 7.7))); +// System.out.println(Arrays.toString(new Solution2(). +// searchRange(new double[]{5, 6, 7, 8, 9, 10}, 10))); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode2/binarysearch/src/main/java/cn/cunchang/\346\220\234\347\264\242\346\227\213\350\275\254\346\216\222\345\272\217\346\225\260\347\273\204_33_\344\270\255\347\255\211/Solution.java" "b/algorithms/leetcode2/binarysearch/src/main/java/cn/cunchang/\346\220\234\347\264\242\346\227\213\350\275\254\346\216\222\345\272\217\346\225\260\347\273\204_33_\344\270\255\347\255\211/Solution.java" new file mode 100644 index 00000000..6c8f60a0 --- /dev/null +++ "b/algorithms/leetcode2/binarysearch/src/main/java/cn/cunchang/\346\220\234\347\264\242\346\227\213\350\275\254\346\216\222\345\272\217\346\225\260\347\273\204_33_\344\270\255\347\255\211/Solution.java" @@ -0,0 +1,42 @@ +package cn.cunchang.搜索旋转排序数组_33_中等; + +import org.junit.Assert; + +class Solution { + public int search(int[] nums, int target) { + int l = 0, r = nums.length - 1; + // 1、找升序部分对升序部分进行二分 + while (l <= r) { + int mid = (l + r) / 2; + if (nums[mid] == target) { + return mid; + } + if (nums[mid] >= nums[l]) { + // 4,5,6,7,0,1,2;7>=4;说明[l,mid]是升序的 + // target在[l,mid]内,对[l,mid]进行二分 + if (target >= nums[l] && target < nums[mid]) { + r = mid - 1; + } else { + l = mid + 1; + } + } else { + // 4,5,6,0,1,2;0<4;说明说明[mid,r]是升序的 + // target在[mid,r]内,对[mid,r]进行二分 + if (target > nums[mid] && target <= nums[r]) { + l = mid + 1; + } else { + r = mid - 1; + } + } + } + return -1; + } + + public static void main(String[] args) { + Assert.assertEquals(5, new Solution().search(new int[]{4, 5, 6, 7, 8, 0, 1, 2, 3}, 0)); +// Assert.assertEquals(4, new Solution().search(new int[]{4, 5, 6, 7, 0, 1, 2}, 0)); +// Assert.assertEquals(-1, new Solution().search(new int[]{4, 5, 6, 7, 0, 1, 2}, 3)); + + + } +} \ No newline at end of file diff --git "a/algorithms/leetcode2/binarysearch/src/main/java/cn/cunchang/\346\220\234\347\264\242\346\227\213\350\275\254\346\216\222\345\272\217\346\225\260\347\273\204_II_81_\344\270\255\347\255\211/Solution.java" "b/algorithms/leetcode2/binarysearch/src/main/java/cn/cunchang/\346\220\234\347\264\242\346\227\213\350\275\254\346\216\222\345\272\217\346\225\260\347\273\204_II_81_\344\270\255\347\255\211/Solution.java" new file mode 100644 index 00000000..d2767e3e --- /dev/null +++ "b/algorithms/leetcode2/binarysearch/src/main/java/cn/cunchang/\346\220\234\347\264\242\346\227\213\350\275\254\346\216\222\345\272\217\346\225\260\347\273\204_II_81_\344\270\255\347\255\211/Solution.java" @@ -0,0 +1,36 @@ +package cn.cunchang.搜索旋转排序数组_II_81_中等; + +class Solution { + public boolean search(int[] nums, int target) { + int l = 0, r = nums.length - 1; + // 1、找升序部分对升序部分进行二分 + while (l <= r) { + int mid = (l + r) / 2; + if (nums[mid] == target) { + return true; + } + if (nums[mid] == nums[l]) { + // 无法判断哪个区间是增序的 + l++; + } else if (nums[mid] >= nums[l]) { + // 4,5,6,7,0,1,2;7>=4;说明[l,mid]是升序的 + // target在[l,mid]内,对[l,mid]进行二分 + if (target >= nums[l] && target < nums[mid]) { + r = mid - 1; + } else { + l = mid + 1; + } + } else { + // 4,5,6,0,1,2;0<4;说明说明[mid,r]是升序的 + // target在[mid,r]内,对[mid,r]进行二分 + if (target > nums[mid] && target <= nums[r]) { + l = mid + 1; + } else { + r = mid - 1; + } + } + } + return false; + } + +} \ No newline at end of file diff --git a/algorithms/leetcode2/dfsbfs/pom.xml b/algorithms/leetcode2/dfsbfs/pom.xml new file mode 100644 index 00000000..53da35d3 --- /dev/null +++ b/algorithms/leetcode2/dfsbfs/pom.xml @@ -0,0 +1,15 @@ + + + 4.0.0 + + dfsbfs + cn.cucnhang + 1.0-SNAPSHOT + + 8 + 8 + + + \ No newline at end of file diff --git "a/algorithms/leetcode2/dfsbfs/src/main/java/cn/cunchang/\345\244\252\345\271\263\346\264\213\345\244\247\350\245\277\346\264\213\346\265\201\346\260\264\351\227\256\351\242\230_417_\344\270\255\347\255\211/Solution.java" "b/algorithms/leetcode2/dfsbfs/src/main/java/cn/cunchang/\345\244\252\345\271\263\346\264\213\345\244\247\350\245\277\346\264\213\346\265\201\346\260\264\351\227\256\351\242\230_417_\344\270\255\347\255\211/Solution.java" new file mode 100644 index 00000000..50802ac1 --- /dev/null +++ "b/algorithms/leetcode2/dfsbfs/src/main/java/cn/cunchang/\345\244\252\345\271\263\346\264\213\345\244\247\350\245\277\346\264\213\346\265\201\346\260\264\351\227\256\351\242\230_417_\344\270\255\347\255\211/Solution.java" @@ -0,0 +1,65 @@ +package cn.cunchang.太平洋大西洋流水问题_417_中等; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +class Solution { + public List> pacificAtlantic(int[][] heights) { + int m = heights.length; + int n = heights[0].length; + int[][] enableAo = new int[m][n];//太平洋的节点记录矩阵 + int[][] enablePa = new int[m][n];//大西洋的节点记录矩阵 + //1. 从上下边界开始两大洋的回流搜索,变动的是列 + for (int i = 0; i < n; i++) { + // 最上面一列,dfs太平洋 + dfs(heights, enablePa, 0, i); + // 最下面一列,dfs大西洋 + dfs(heights, enableAo, m - 1, i); + } + //2. 从左右边界开始两大洋的回流搜索,变动的是行 + for (int i = 0; i < m; i++) { + // 最左面一行,dfs太平洋 + dfs(heights, enablePa, i, 0); + // 最右面一行,dfs大西洋 + dfs(heights, enableAo, i, n - 1); + } + //3. 输出交叠的坐标 + List> cnt = new ArrayList<>(); + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + if (enableAo[i][j] == 1 && enablePa[i][j] == 1) { + cnt.add(Arrays.asList(i, j)); + } + } + } + return cnt; + } + + public static void dfs(int[][] heights, int[][] tmp, int curI, int curJ) { + //标记可以从海洋流回经过的节点 + tmp[curI][curJ] = 1; + //开始深度优先搜索当前坐标的4个方向 + //1. 设置更新的坐标 + int[] di = new int[]{1, -1, 0, 0};//上下移动 + int[] dj = new int[]{0, 0, 1, -1};//左右移动 + //2. 更新坐标并递归搜索 + for (int index = 0; index < 4; index++) { + int newI = curI + di[index]; + int newJ = curJ + dj[index]; + //判断下标是否越界 + if (newI < 0 || newJ < 0 || newI >= heights.length || newJ >= heights[0].length) { + continue; + } + if (heights[curI][curJ] <= heights[newI][newJ] && tmp[newI][newJ] != 1) { + dfs(heights, tmp, newI, newJ); + } + } + } + + public static void main(String[] args) { + int[][] heights = {{1, 2, 2, 3, 5}, {3, 2, 3, 4, 4}, {2, 4, 5, 3, 1}, {6, 7, 1, 4, 5}, {5, 1, 1, 2, 4}}; + System.out.println(new Solution().pacificAtlantic(heights)); + } + +} diff --git "a/algorithms/leetcode2/dfsbfs/src/main/java/cn/cunchang/\345\244\252\345\271\263\346\264\213\345\244\247\350\245\277\346\264\213\346\265\201\346\260\264\351\227\256\351\242\230_417_\344\270\255\347\255\211/Solution_my.java" "b/algorithms/leetcode2/dfsbfs/src/main/java/cn/cunchang/\345\244\252\345\271\263\346\264\213\345\244\247\350\245\277\346\264\213\346\265\201\346\260\264\351\227\256\351\242\230_417_\344\270\255\347\255\211/Solution_my.java" new file mode 100644 index 00000000..294b6430 --- /dev/null +++ "b/algorithms/leetcode2/dfsbfs/src/main/java/cn/cunchang/\345\244\252\345\271\263\346\264\213\345\244\247\350\245\277\346\264\213\346\265\201\346\260\264\351\227\256\351\242\230_417_\344\270\255\347\255\211/Solution_my.java" @@ -0,0 +1,85 @@ +package cn.cunchang.太平洋大西洋流水问题_417_中等; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +class Solution_my { + public List> pacificAtlantic(int[][] heights) { + List> result = new ArrayList<>(); + // 对每个单元格搜索,判断是否可以向上或左同时向下或右,可以就说明满足 + for (int i = 0; i < heights.length; i++) { + for (int j = 0; j < heights.length; j++) { + boolean flag = pacificAtlantic(heights, i, j); + if (flag) { + result.add(Arrays.asList(i,j)); + } + } + } + return result; + } + + /** + * @param i 纵 + * @param j 横 + */ + private boolean pacificAtlantic(int[][] heights, int i, int j) { + + boolean pacificEnable1 = true; + // 上;i减减 + for (int k = i; k >= 0; k--) { + if (heights[i][j] < heights[k][j]) { + pacificEnable1 = false; + break; + } + if (i - k > 1 && heights[i][j] == heights[k][j]) { + pacificEnable1 = false; + break; + } + } + boolean pacificEnable2 = true; + // 左 j减 + for (int k = j; k >= 0; k--) { + if (heights[i][j] < heights[i][k]) { + pacificEnable2 = false; + break; + } + if (j - k > 1 && heights[i][j] == heights[k][j]) { + pacificEnable1 = false; + break; + } + } + + boolean atlanticEnable1 = true; + // 下 + for (int k = i; k < heights.length; k++) { + if (heights[i][j] < heights[k][j]) { + atlanticEnable1 = false; + break; + } + if (k - i > 1 && heights[i][j] == heights[k][j]) { + pacificEnable1 = false; + break; + } + } + boolean atlanticEnable2 = true; + // 右 + for (int k = j; k < heights.length; k++) { + if (heights[i][j] < heights[i][k]) { + atlanticEnable2 = false; + break; + } + if (k - j > 1 && heights[i][j] == heights[k][j]) { + pacificEnable1 = false; + break; + } + } + + return (pacificEnable1 || pacificEnable2) && (atlanticEnable1 || atlanticEnable2); + } + + public static void main(String[] args) { + int[][] heights = {{1, 2, 2, 3, 5}, {3, 2, 3, 4, 4}, {2, 4, 5, 3, 1}, {6, 7, 1, 4, 5}, {5, 1, 1, 2, 4}}; + System.out.println(new Solution_my().pacificAtlantic(heights)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode2/dfsbfs/src/main/java/cn/cunchang/\345\262\233\345\261\277\347\232\204\346\234\200\345\244\247\351\235\242\347\247\257_695_\344\270\255\347\255\211/Solution.java" "b/algorithms/leetcode2/dfsbfs/src/main/java/cn/cunchang/\345\262\233\345\261\277\347\232\204\346\234\200\345\244\247\351\235\242\347\247\257_695_\344\270\255\347\255\211/Solution.java" new file mode 100644 index 00000000..602f81f5 --- /dev/null +++ "b/algorithms/leetcode2/dfsbfs/src/main/java/cn/cunchang/\345\262\233\345\261\277\347\232\204\346\234\200\345\244\247\351\235\242\347\247\257_695_\344\270\255\347\255\211/Solution.java" @@ -0,0 +1,35 @@ +package cn.cunchang.岛屿的最大面积_695_中等; + +class Solution { + public int maxAreaOfIsland(int[][] grid) { + int res = 0; + // 对搜索过的岛屿进行标记 + int[][] mark = new int[grid.length][grid[0].length]; + for (int i = 0; i < grid.length; i++) { + for (int j = 0; j < grid[0].length; j++) { + int tmp = dfs(grid, i, j, mark); + res = Math.max(res, tmp); + } + } + return res; + } + + private int dfs(int[][] grid, int i, int j, int[][] mark) { + // i,j未超界 + if (i < 0 || j < 0 || i >= grid.length || j >= grid[0].length) { + return 0; + } + // 已经来过不处理 + if (mark[i][j] == 1 || grid[i][j] == 0) { + return 0; + } + mark[i][j] = 1;// 标记已经来过 + int res = 1; + res += dfs(grid, i - 1, j, mark);//上 + res += dfs(grid, i + 1, j, mark);//下 + res += dfs(grid, i, j - 1, mark);//左 + res += dfs(grid, i, j + 1, mark);//右 + return res; + } + +} \ No newline at end of file diff --git "a/algorithms/leetcode2/dfsbfs/src/main/java/cn/cunchang/\345\262\233\345\261\277\347\232\204\346\234\200\345\244\247\351\235\242\347\247\257_695_\344\270\255\347\255\211/Solution2.java" "b/algorithms/leetcode2/dfsbfs/src/main/java/cn/cunchang/\345\262\233\345\261\277\347\232\204\346\234\200\345\244\247\351\235\242\347\247\257_695_\344\270\255\347\255\211/Solution2.java" new file mode 100644 index 00000000..06684056 --- /dev/null +++ "b/algorithms/leetcode2/dfsbfs/src/main/java/cn/cunchang/\345\262\233\345\261\277\347\232\204\346\234\200\345\244\247\351\235\242\347\247\257_695_\344\270\255\347\255\211/Solution2.java" @@ -0,0 +1,71 @@ +package cn.cunchang.岛屿的最大面积_695_中等; + +import javafx.util.Pair; + +import java.util.Stack; + +class Solution2 { + /** + * 栈模拟递归 + */ + public int maxAreaOfIsland(int[][] grid) { + int res = 0; + int x, y; + int[] direction = new int[]{-1, 0, 1, 0, -1}; + Stack> stack = new Stack<>(); + // 对搜索过的岛屿进行标记 + int[][] visited = new int[grid.length][grid[0].length]; + for (int i = 0; i < grid.length; i++) { + for (int j = 0; j < grid[0].length; j++) { + if (grid[i][j] == 1 && visited[i][j] == 0) { + int areaCount = 1; + visited[i][j] = 1;//当前节点已经访问 + stack.push(new Pair<>(i, j)); + + while (!stack.isEmpty()) { + Pair pair = stack.pop(); + for (int k = 0; k < 4; ++k) { + x = pair.getKey() + direction[k]; + y = pair.getValue() + direction[k + 1]; + if (checkArea(grid, visited, x, y)) { + areaCount++; + visited[x][y] = 1; + stack.push(new Pair<>(x, y)); + } + } + + } + + res = Math.max(res, areaCount); + } + } + } + return res; + } + + private boolean checkArea(int[][] grid, int[][] visited, int x, int y) { + // i,j未超界 + if (x < 0 || y < 0 || x >= grid.length || y >= grid[0].length) { + return false; + } + // 已经来过不处理 + if (visited[x][y] == 1 || grid[x][y] == 0) { + return false; + } + return true; + } + + public static void main(String[] args) { + int[][] x = { + {0,0,1,0,0,0,0,1,0,0,0,0,0}, + {0,0,0,0,0,0,0,1,1,1,0,0,0}, + {0,1,1,0,1,0,0,0,0,0,0,0,0}, + {0,1,0,0,1,1,0,0,1,0,1,0,0}, + {0,1,0,0,1,1,0,0,1,1,1,0,0}, + {0,0,0,0,0,0,0,0,0,0,1,0,0}, + {0,0,0,0,0,0,0,1,1,1,0,0,0}, + {0,0,0,0,0,0,0,1,1,0,0,0,0}}; + System.out.println(new Solution2().maxAreaOfIsland(x)); + } + +} \ No newline at end of file diff --git "a/algorithms/leetcode2/dfsbfs/src/main/java/cn/cunchang/\347\234\201\344\273\275\346\225\260\351\207\217_547_\344\270\255\347\255\211/Solution.java" "b/algorithms/leetcode2/dfsbfs/src/main/java/cn/cunchang/\347\234\201\344\273\275\346\225\260\351\207\217_547_\344\270\255\347\255\211/Solution.java" new file mode 100644 index 00000000..3138fb69 --- /dev/null +++ "b/algorithms/leetcode2/dfsbfs/src/main/java/cn/cunchang/\347\234\201\344\273\275\346\225\260\351\207\217_547_\344\270\255\347\255\211/Solution.java" @@ -0,0 +1,40 @@ + +package cn.cunchang.省份数量_547_中等; + +class Solution { + /** + * 有几个需要注意的条件 + * isConnected[i][i] == 1 + * isConnected[i][j] == isConnected[j][i] + *

+ * isConnected[i][i] == 1 说明是个无向图 + */ + public int findCircleNum(int[][] isConnected) { + boolean[] visited = new boolean[isConnected.length]; + + int res = 0; + for (int i = 0; i < isConnected.length; i++) { + if (!visited[i]) { + findCircleNum(isConnected, i, visited); + res++; + } + } + return res; + } + // 深度遍历,相邻节点,并对访问过的节点进行标记 + private void findCircleNum(int[][] isConnected, int i, boolean[] visited) { + visited[i] = true; + for (int j = 0; j < isConnected.length; j++) { + if (isConnected[i][j] == 1 && !visited[j]) { + findCircleNum(isConnected, j, visited); + } + } + } + + public static void main(String[] args) { + int[][] isConnected = {{1, 1, 0}, + {1, 1, 0}, + {0, 0, 1}}; + System.out.println(new Solution().findCircleNum(isConnected)); + } +} \ No newline at end of file diff --git a/algorithms/leetcode2/dynamic2/pom.xml b/algorithms/leetcode2/dynamic2/pom.xml new file mode 100644 index 00000000..77cc2ec4 --- /dev/null +++ b/algorithms/leetcode2/dynamic2/pom.xml @@ -0,0 +1,19 @@ + + + + leetcode2 + cn.cucnhang + 1.0-SNAPSHOT + + 4.0.0 + + dynamic + + + 8 + 8 + + + \ No newline at end of file diff --git a/algorithms/leetcode2/dynamic2/src/main/java/cn/cunchang/knapsack01/knapsack01.md b/algorithms/leetcode2/dynamic2/src/main/java/cn/cunchang/knapsack01/knapsack01.md new file mode 100644 index 00000000..7431ee35 --- /dev/null +++ b/algorithms/leetcode2/dynamic2/src/main/java/cn/cunchang/knapsack01/knapsack01.md @@ -0,0 +1,15 @@ +| id | 0 | 1 | 2 | +| ------ | ---- | ---- | ---- | +| weight | 1 | 2 | 3 | +| value | 6 | 10 | 12 | + +​ + + + +| 物品编号\背包容量 | 0 | 1 | 2 | 3 | 4 | 5 | +|-----------| ---- | ---- | ---- | ---- | ---- | ---- | +| 0 | 0 | 6 | 6 | 6 | 6 | 6 | +| 1 | 0 | 6 | 10 | 16 | 16 | 16 | +| 2 | 0 | 6 | 10 | 16 | 18 | 22 | + diff --git "a/algorithms/leetcode2/dynamic2/src/main/java/cn/cunchang/\346\211\223\345\256\266\345\212\253\350\210\215_198_\344\270\255\347\255\211/Solution.java" "b/algorithms/leetcode2/dynamic2/src/main/java/cn/cunchang/\346\211\223\345\256\266\345\212\253\350\210\215_198_\344\270\255\347\255\211/Solution.java" new file mode 100644 index 00000000..09910cfd --- /dev/null +++ "b/algorithms/leetcode2/dynamic2/src/main/java/cn/cunchang/\346\211\223\345\256\266\345\212\253\350\210\215_198_\344\270\255\347\255\211/Solution.java" @@ -0,0 +1,30 @@ +package cn.cunchang.打家劫舍_198_中等; + +class Solution { + public int rob(int[] nums) { + return tryRob(0, nums); + } + + /** + * idx 偷窃的起始位置 + */ + public int tryRob(int idx, int[] nums) { + if (idx >= nums.length) { + return 0; + } + int max = 0, res = 0; + // 对[idx,nums.length-1]每个位置进行偷窃 + for (int i = idx; i < nums.length; i++) { + // 找当前位置可以偷窃的最佳金额 + int subMax = tryRob(i + 2, nums); + res = nums[i] + subMax; + max = Math.max(max, res); + } + return max; + } + + public static void main(String[] args) { + System.out.println(new Solution().rob(new int[]{1,2,3,1})); + } + +} \ No newline at end of file diff --git "a/algorithms/leetcode2/dynamic2/src/main/java/cn/cunchang/\346\211\223\345\256\266\345\212\253\350\210\215_198_\344\270\255\347\255\211/Solution2.java" "b/algorithms/leetcode2/dynamic2/src/main/java/cn/cunchang/\346\211\223\345\256\266\345\212\253\350\210\215_198_\344\270\255\347\255\211/Solution2.java" new file mode 100644 index 00000000..dcb878b2 --- /dev/null +++ "b/algorithms/leetcode2/dynamic2/src/main/java/cn/cunchang/\346\211\223\345\256\266\345\212\253\350\210\215_198_\344\270\255\347\255\211/Solution2.java" @@ -0,0 +1,38 @@ +package cn.cunchang.打家劫舍_198_中等; + +import java.util.Arrays; + +class Solution2 { + public int rob(int[] nums) { + int[] moment = new int[nums.length]; + Arrays.fill(moment, -1); + return tryRob(0, nums, moment); + } + + /** + * idx 偷窃的起始位置 + */ + public int tryRob(int idx, int[] nums, int[] moment) { + if (idx >= nums.length) { + return 0; + } + if (moment[idx] != -1) { + return moment[idx]; + } + int max = 0, res = 0; + // 对[idx,nums.length-1]每个位置进行偷窃 + for (int i = idx; i < nums.length; i++) { + // 找当前位置可以偷窃的最佳金额 + int subMax = tryRob(i + 2, nums, moment); + res = nums[i] + subMax; + max = Math.max(max, res); + } + moment[idx] = max; + return max; + } + + public static void main(String[] args) { + System.out.println(new Solution2().rob(new int[]{1, 2, 3, 1})); + } + +} \ No newline at end of file diff --git "a/algorithms/leetcode2/dynamic2/src/main/java/cn/cunchang/\347\210\254\346\245\274\346\242\257_70_\347\256\200\345\215\225/Solution.java" "b/algorithms/leetcode2/dynamic2/src/main/java/cn/cunchang/\347\210\254\346\245\274\346\242\257_70_\347\256\200\345\215\225/Solution.java" new file mode 100644 index 00000000..4c715f6d --- /dev/null +++ "b/algorithms/leetcode2/dynamic2/src/main/java/cn/cunchang/\347\210\254\346\245\274\346\242\257_70_\347\256\200\345\215\225/Solution.java" @@ -0,0 +1,21 @@ +package cn.cunchang.爬楼梯_70_简单; + +class Solution { + public int climbStairs(int n) { + if (n == 1) { + return 1; + } + if (n == 2) { + return 2; + } + int f1 = 1, f2 = 2; + int res = 0; + for (int i = 2; i < n; i++) { + res = f1 + f2; + f1 = f2; + f2 = res; + } + + return res; + } +} \ No newline at end of file diff --git "a/algorithms/leetcode2/dynamic2/src/main/java/cn/cunchang/\351\233\266\351\222\261\345\205\221\346\215\242_322_\344\270\255\347\255\211/Solution.java" "b/algorithms/leetcode2/dynamic2/src/main/java/cn/cunchang/\351\233\266\351\222\261\345\205\221\346\215\242_322_\344\270\255\347\255\211/Solution.java" new file mode 100644 index 00000000..f453307e --- /dev/null +++ "b/algorithms/leetcode2/dynamic2/src/main/java/cn/cunchang/\351\233\266\351\222\261\345\205\221\346\215\242_322_\344\270\255\347\255\211/Solution.java" @@ -0,0 +1,47 @@ +package cn.cunchang.零钱兑换_322_中等; + +import java.util.HashMap; + +/** + * @author cunchang + * @date 2022/6/23 5:07 PM + */ +class Solution { + + public int coinChange(int[] coins, int amount) { + HashMap meno = new HashMap<>(); + return coinChange0(coins, amount, meno); + } + + public int coinChange0(int[] coins, int amount, HashMap meno) { + if (amount < 0) { + return -1; + } + if (amount == 0) { + return 0; + } + if (meno.get(amount) != null) { + return meno.get(amount); + } + int res = Integer.MAX_VALUE; + for (int coin : coins) { + int subRes = coinChange0(coins, amount - coin, meno); + // 子问题无解 + if (subRes == -1) { + continue; + } + // 找子问题最小解 + res = Math.min(res, subRes + 1); + } + + res = (res == Integer.MAX_VALUE) ? -1 : res; + // 对amount的结果进行缓存 + meno.put(amount, res); + return res; + } + + public static void main(String[] args) { + System.out.println(new Solution().coinChange(new int[]{1, 2, 5}, 11)); +// System.out.println(new Solution().coinChange(new int[]{2}, 3)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode2/dynamic2/src/main/java/cn/cunchang/\351\233\266\351\222\261\345\205\221\346\215\242_322_\344\270\255\347\255\211/Solution2.java" "b/algorithms/leetcode2/dynamic2/src/main/java/cn/cunchang/\351\233\266\351\222\261\345\205\221\346\215\242_322_\344\270\255\347\255\211/Solution2.java" new file mode 100644 index 00000000..c804b59d --- /dev/null +++ "b/algorithms/leetcode2/dynamic2/src/main/java/cn/cunchang/\351\233\266\351\222\261\345\205\221\346\215\242_322_\344\270\255\347\255\211/Solution2.java" @@ -0,0 +1,30 @@ +package cn.cunchang.零钱兑换_322_中等; + +import java.util.Arrays; + +/** + * @author cunchang + * @date 2022/6/23 5:07 PM + */ +class Solution2 { + + public int coinChange(int[] coins, int amount) { + int max = amount + 1; + int[] dp = new int[amount + 1]; + Arrays.fill(dp, max); + dp[0] = 0; + for (int i = 1; i <= amount; i++) { + for (int j = 0; j < coins.length; j++) { + if (coins[j] <= i) { + dp[i] = Math.min(dp[i], dp[i - coins[j]] + 1); + } + } + } + return dp[amount] > amount ? -1 : dp[amount]; + } + + public static void main(String[] args) { + System.out.println(new Solution2().coinChange(new int[]{1, 2, 5}, 11)); +// System.out.println(new Solution().coinChange(new int[]{2}, 3)); + } +} \ No newline at end of file diff --git a/algorithms/leetcode2/greedy/pom.xml b/algorithms/leetcode2/greedy/pom.xml new file mode 100644 index 00000000..31a3db05 --- /dev/null +++ b/algorithms/leetcode2/greedy/pom.xml @@ -0,0 +1,22 @@ + + + 4.0.0 + + greedy + cn.cucnhang + 1.0-SNAPSHOT + + + 8 + 8 + + + + junit + junit + 4.12 + + + \ No newline at end of file diff --git "a/algorithms/leetcode2/greedy/src/main/java/cn/cunchang/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272II_122_\347\256\200\345\215\225/Solution.java" "b/algorithms/leetcode2/greedy/src/main/java/cn/cunchang/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272II_122_\347\256\200\345\215\225/Solution.java" new file mode 100644 index 00000000..46b7e94e --- /dev/null +++ "b/algorithms/leetcode2/greedy/src/main/java/cn/cunchang/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272II_122_\347\256\200\345\215\225/Solution.java" @@ -0,0 +1,31 @@ +package cn.cunchang.买卖股票的最佳时机II_122_简单; + +import org.junit.Assert; + +class Solution { + /** + * 思考: + * ------------------------------------------------------------------- + * 思路: + * 贪心策略:从后往前遍历 + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public int maxProfit(int[] prices) { + int profit = 0; + for (int i = prices.length - 1; i > 0; i--) { + if (prices[i] > prices[i - 1]) { + profit += prices[i] - prices[i - 1]; + } + } + return profit; + } + + public static void main(String[] args) { +// int[] prices = {7, 1, 5, 3, 6, 4}; +// Assert.assertEquals(7, new Solution().maxProfit(prices)); + int[] prices = {1,2,3,4,5}; + Assert.assertEquals(4, new Solution().maxProfit(prices)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode2/greedy/src/main/java/cn/cunchang/\345\210\206\345\217\221\347\263\226\346\236\234_135_\345\233\260\351\232\276/Solution1.java" "b/algorithms/leetcode2/greedy/src/main/java/cn/cunchang/\345\210\206\345\217\221\347\263\226\346\236\234_135_\345\233\260\351\232\276/Solution1.java" new file mode 100644 index 00000000..830f84ab --- /dev/null +++ "b/algorithms/leetcode2/greedy/src/main/java/cn/cunchang/\345\210\206\345\217\221\347\263\226\346\236\234_135_\345\233\260\351\232\276/Solution1.java" @@ -0,0 +1,51 @@ +package cn.cunchang.分发糖果_135_困难; + +import org.junit.Assert; + +import java.util.Arrays; + +public class Solution1 { + /** + * 思考: + * ------------------------------------------------------------------- + * 思路: + * 从前往后贪一次,从后往前再贪一次,不过第二次要判断大小,只贪最大的哪个 + *

+ * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(n) + */ + public int candy(int[] ratings) { + if (ratings.length < 2) { + return ratings.length; + } + int[] resArr = new int[ratings.length]; + Arrays.fill(resArr, 1); + // 先从左往右遍历一遍,如果右边孩子的评分比左边的高,则右边孩子的糖果数更新为左边孩子的糖果数加 1; + for (int i = 1; i < ratings.length; i++) {// i = 1而不是i = 0 + if (ratings[i] > ratings[i - 1]) { + resArr[i] = resArr[i - 1] + 1; + } + } + // 再从右往左遍历一遍,如果左边孩子的评分比右边的高,且左边孩子当前的糖果数不大于右边孩子的糖果数, + // 则左边孩子的糖果数更新为右边孩子的糖果数加 1。 + for (int i = ratings.length - 1; i > 0; i--) {// i > 0而不是i >= 0 + if (ratings[i] < ratings[i - 1]) { + resArr[i - 1] = Math.max(resArr[i - 1], resArr[i] + 1); + } + } + + int count = 0; + for (int res : resArr) { + count += res; + } + return count; + } + + public static void main(String[] args) { +// int[] g = new int[]{1, 2, 87, 87, 87, 2, 1}; + int[] g = new int[]{1, 0, 2}; + Assert.assertEquals(5, new Solution1().candy(g)); + } + +} \ No newline at end of file diff --git "a/algorithms/leetcode2/greedy/src/main/java/cn/cunchang/\345\210\206\345\217\221\351\245\274\345\271\262_455_\347\256\200\345\215\225/Solution1.java" "b/algorithms/leetcode2/greedy/src/main/java/cn/cunchang/\345\210\206\345\217\221\351\245\274\345\271\262_455_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..d8ff0bf0 --- /dev/null +++ "b/algorithms/leetcode2/greedy/src/main/java/cn/cunchang/\345\210\206\345\217\221\351\245\274\345\271\262_455_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,48 @@ +package cn.cunchang.分发饼干_455_简单; + +import org.junit.Assert; + +import java.util.Arrays; + +public class Solution1 { + /** + * 思考:因为饥饿度最小的孩子最容易吃饱,所以我们先考虑这个孩子。为了尽量使得剩下的饼干可 + * 以满足饥饿度更大的孩子,所以我们应该把大于等于这个孩子饥饿度的、且大小最小的饼干给这 + * 个孩子。满足了这个孩子之后,我们采取同样的策略,考虑剩下孩子里饥饿度最小的孩子,直到 + * 没有满足条件的饼干存在。 + * ------------------------------------------------------------------- + * 思路: + * 1、排序,对孩子的胃口和饼干大小降序排序 + * 2、将最小的饼干s[j]给胃口最小的孩子g[i],s[j] >= g[i],说明满足,满足孩子数+1、继续分发下一块饼干; + * 不满足的话,孩子数不加,继续分发下一块饼干; + * + *

+ * ------------------------------------------------------------------- + * 时间复杂度:n + * 空间复杂度: + */ + public int findContentChildren(int[] childs, int[] cookies) { + Arrays.sort(childs); + Arrays.sort(cookies); + int child = 0, cookie = 0; + while (child < childs.length && cookie < cookies.length) { + if (cookies[cookie] >= childs[child]) { + child++; + } + cookie++; + } + return child; + } + + public static void main(String[] args) { +// int[] g = new int[]{1, 2}; +// int[] s = new int[]{1, 2, 3}; +// Assert.assertEquals(2, new Solution1().findContentChildren(g, s)); + + int[] g = new int[]{1, 2, 3}; + int[] s = new int[]{1, 1}; + Assert.assertEquals(1, new Solution1().findContentChildren(g, s)); + + } + +} \ No newline at end of file diff --git "a/algorithms/leetcode2/greedy/src/main/java/cn/cunchang/\346\227\240\351\207\215\345\217\240\345\214\272\351\227\264_435_\344\270\255\347\255\211/Solution.java" "b/algorithms/leetcode2/greedy/src/main/java/cn/cunchang/\346\227\240\351\207\215\345\217\240\345\214\272\351\227\264_435_\344\270\255\347\255\211/Solution.java" new file mode 100644 index 00000000..ac08712c --- /dev/null +++ "b/algorithms/leetcode2/greedy/src/main/java/cn/cunchang/\346\227\240\351\207\215\345\217\240\345\214\272\351\227\264_435_\344\270\255\347\255\211/Solution.java" @@ -0,0 +1,45 @@ +package cn.cunchang.无重叠区间_435_中等; + +import org.junit.Assert; + +import java.util.Arrays; +import java.util.Comparator; + +public class Solution { + /** + * 思考: + * 1. 什么是“区间不重叠”?intervals[i][1]<=intervals[i+1][0],说明区间i和区间i+1不重叠,否则就是重叠 + * 2. 什么是“移除区间的最小数量,使剩余区间互不重叠”?比如“[[1,100],[11,22],[1,11],[2,12]]”移除后三个区间也不重叠,但是最小数量是移除1、4区间。 + * ------------------------------------------------------------------- + * 思路: + * 1、按照区间结尾升序 + * 2、相邻单位区间,重合就移除;不重叠继续判断 + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public int eraseOverlapIntervals(int[][] intervals) { + Arrays.sort(intervals, new Comparator() { + @Override + public int compare(int[] interval1, int[] interval2) { + return interval1[1] - interval2[1]; + } + }); + + int total = 0, pre = intervals[0][1]; + for (int i = 1; i < intervals.length; i++) { + if (intervals[i][0] >= pre) { + pre = intervals[i][1]; + } else { + total++; + } + } + return total; + } + + public static void main(String[] args) { + int[][] g = new int[][]{{1, 100}, {11, 22}, {1, 11}, {2, 12}}; + Assert.assertEquals(2, new Solution().eraseOverlapIntervals(g)); + + } +} \ No newline at end of file diff --git a/algorithms/leetcode2/leetcode2-common/pom.xml b/algorithms/leetcode2/leetcode2-common/pom.xml new file mode 100644 index 00000000..9e8d3916 --- /dev/null +++ b/algorithms/leetcode2/leetcode2-common/pom.xml @@ -0,0 +1,21 @@ + + + + + + + + 4.0.0 + + leetcode2-common + cn.cucnhang + 1.0-SNAPSHOT + + + 8 + 8 + + + \ No newline at end of file diff --git a/algorithms/leetcode2/leetcode2-common/src/main/java/cn/cunchang/array/ArrayUtil.java b/algorithms/leetcode2/leetcode2-common/src/main/java/cn/cunchang/array/ArrayUtil.java new file mode 100644 index 00000000..5e3e6325 --- /dev/null +++ b/algorithms/leetcode2/leetcode2-common/src/main/java/cn/cunchang/array/ArrayUtil.java @@ -0,0 +1,75 @@ +package cn.cunchang.array; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author lastwhisper + * @date 2020/2/4 + */ +public class ArrayUtil { + + public static int[] createArrays(int... arr) { + return arr; + } + + /** + * {"ab","cd"}=> + * 创建二维字符数组 + */ + public static char[][] createCharArrays(String[] arr) { + int m = arr.length, n = arr[0].length(); + char[][] chars = new char[m][n]; + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + chars[i][j] = arr[i].charAt(j); + } + } + return chars; + } + + /** + * {{"a","b","c","d"}}=> + * 创建二维字符数组 + */ + public static char[][] createCharArrays(String[][] arr) { + int m = arr.length, n = arr[0].length; + char[][] chars = new char[m][n]; + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + chars[i][j] = arr[i][j].charAt(0); + } + } + return chars; + } + + /** + * 创建二维数组 + */ + public static int[][] createIntArrays(String[] arr) { + int m = arr.length, n = arr[0].length(); + int[][] ints = new int[m][n]; + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + ints[i][j] = arr[i].charAt(j) - '0'; + } + } + return ints; + } + + + /** + * 创建list + */ + public static List> createList(int[][] arrays) { + List> lists = new ArrayList<>(arrays.length); + for (int[] array : arrays) { + List list = new ArrayList<>(array.length); + for (int num : array) { + list.add(num); + } + lists.add(list); + } + return lists; + } +} diff --git a/algorithms/leetcode2/leetcode2-common/src/main/java/cn/cunchang/linkedlist/LinkedListUtil.java b/algorithms/leetcode2/leetcode2-common/src/main/java/cn/cunchang/linkedlist/LinkedListUtil.java new file mode 100644 index 00000000..bdafc303 --- /dev/null +++ b/algorithms/leetcode2/leetcode2-common/src/main/java/cn/cunchang/linkedlist/LinkedListUtil.java @@ -0,0 +1,58 @@ +package cn.cunchang.linkedlist; + + +/** + * 操作链表工具类 + * + * @author lastwhisper + * @date 1/7/2020 + */ +public class LinkedListUtil { + + /** + * 创建单链表 + */ + public static ListNode createListNode(int... arr) { + if (arr == null || arr.length == 0) { + return null; + } + ListNode head = new ListNode(arr[0]); + ListNode current = head; + for (int i = 1; i < arr.length; i++) { + current.next = new ListNode(arr[i]); + current = current.next; + } + return head; + } + + /** + * 打印单链表 + */ + public static void printListNode(String msg, ListNode head) { + System.out.println(msg + appendVal(head)); + } + + /** + * 打印单链表 + */ + public static void printListNode(ListNode head) { + System.out.println(appendVal(head)); + } + + private static String appendVal(ListNode head) { + StringBuilder sb = new StringBuilder(); + ListNode current = head; + while (current != null) { + sb.append(current.val); + sb.append("->"); + current = current.next; + } + sb.append("NULL"); + return sb.toString(); + } + + + public static void main(String[] args) { + printListNode(createListNode(1, 2, 3, 4, 5, 6, 7)); + } +} diff --git a/algorithms/leetcode2/leetcode2-common/src/main/java/cn/cunchang/linkedlist/ListNode.java b/algorithms/leetcode2/leetcode2-common/src/main/java/cn/cunchang/linkedlist/ListNode.java new file mode 100644 index 00000000..3db97b0e --- /dev/null +++ b/algorithms/leetcode2/leetcode2-common/src/main/java/cn/cunchang/linkedlist/ListNode.java @@ -0,0 +1,11 @@ +package cn.cunchang.linkedlist; + +public class ListNode { + public int val; + public ListNode next; + + public ListNode(int x) { + val = x; + } + +} \ No newline at end of file diff --git a/algorithms/leetcode2/leetcode2-common/src/main/java/cn/cunchang/print/PrintUtil.java b/algorithms/leetcode2/leetcode2-common/src/main/java/cn/cunchang/print/PrintUtil.java new file mode 100644 index 00000000..d87301ac --- /dev/null +++ b/algorithms/leetcode2/leetcode2-common/src/main/java/cn/cunchang/print/PrintUtil.java @@ -0,0 +1,93 @@ +package cn.cunchang.print; + +import java.util.Collection; +import java.util.List; + + +/** + * 打印工具类 + * @author lastwhisper + * @date 2020/2/1 + */ +public class PrintUtil { + + /** + * 层次打印二维数组 + */ + public static void printLists(List> lists) { + System.out.println("["); + int counter1 = 1; + for (List list : lists) { + System.out.print("\t[\""); + int counter2 = 1; + for (Integer i : list) { + if (counter2 != list.size()) { + System.out.print(i + "\",\""); + } else { + System.out.print(i); + } + counter2++; + } + if (counter1 != lists.size()) { + System.out.print("\"],\n"); + } else { + System.out.print("\"]\n"); + } + counter1++; + } + System.out.println("]"); + } + + public static void printStringLists(List> lists) { + System.out.println("["); + int counter1 = 1; + for (List list : lists) { + System.out.print("\t[\""); + int counter2 = 1; + for (String i : list) { + if (counter2 != list.size()) { + System.out.print(i + "\",\""); + } else { + System.out.print(i ); + } + counter2++; + } + if (counter1 != lists.size()) { + System.out.print("\"],\n"); + } else { + System.out.print("\"]\n"); + } + counter1++; + } + System.out.println("]"); + } + + /** + * 打印数组 + */ + public static void printList(Collection collection) { + System.out.println(collection2String(collection)); + } + + /** + * 将Collection扁平化迭代成String + */ + public static String collection2String(Collection collection) { + StringBuilder sb = new StringBuilder(); + try { + sb.append("[\""); + int counter = 1; + for (Object object : collection) { + sb.append(object); + if (counter != collection.size()) { + sb.append("\",\""); + } + counter++; + } + sb.append("\"]"); + } catch (Exception e) { + e.printStackTrace(); + } + return sb.toString(); + } +} diff --git a/algorithms/leetcode2/leetcode2-common/src/main/java/cn/cunchang/tree/TreeNode.java b/algorithms/leetcode2/leetcode2-common/src/main/java/cn/cunchang/tree/TreeNode.java new file mode 100644 index 00000000..d3b599af --- /dev/null +++ b/algorithms/leetcode2/leetcode2-common/src/main/java/cn/cunchang/tree/TreeNode.java @@ -0,0 +1,11 @@ +package cn.cunchang.tree; + +public class TreeNode { + public int val; + public TreeNode left; + public TreeNode right; + + public TreeNode(int x) { + val = x; + } +} \ No newline at end of file diff --git a/algorithms/leetcode2/leetcode2-common/src/main/java/cn/cunchang/tree/TreeUtil.java b/algorithms/leetcode2/leetcode2-common/src/main/java/cn/cunchang/tree/TreeUtil.java new file mode 100644 index 00000000..958d39fd --- /dev/null +++ b/algorithms/leetcode2/leetcode2-common/src/main/java/cn/cunchang/tree/TreeUtil.java @@ -0,0 +1,121 @@ +package cn.cunchang.tree; + +import cn.cunchang.print.PrintUtil; +import javafx.util.Pair; + +import java.util.*; + + +/** + * 树相关工具类 + * @author lastwhisper + * @date 1/16/2020 + */ +public class TreeUtil { + + /** + * 根据数组创建二叉树 + * 一、[5,4,8,11,null,13,4,7,2,null,null,null,1] + * 5 + * / \ + * 4 8 + * / / \ + * 11 13 4 + * / \ \ + * 7 2 1 + * 二、[1,null,2,3] + * 1 + * \ + * 2 + * / + * 3 + * 参考 https://blog.csdn.net/lenfranky/article/details/84444816 + * @param array 数组 + */ + public static TreeNode createTree(Integer... array) { + if (array.length == 0) return new TreeNode(0); + Deque nodeQueue = new LinkedList<>(); + // 创建一个根节点 + TreeNode root = new TreeNode(array[0]); + nodeQueue.offer(root); + TreeNode current; + // 记录当前行节点的数量(注意不一定是2的幂,而是上一行中非空节点的数量乘2) + int lineNodeNum = 2; + // 记录当前行中数字在数组中的开始位置 + int startIndex = 1; + // 记录数组中剩余的元素的数量 + int restLength = array.length - 1; + + while (restLength > 0) { + // 只有最后一行可以不满,其余行必须是满的 +// // 若输入的数组的数量是错误的,直接跳出程序 +// if (restLength < lineNodeNum) { +// System.out.println("Wrong Input!"); +// return new TreeNode(0); +// } + for (int i = startIndex; i < startIndex + lineNodeNum; i = i + 2) { + // 说明已经将nums中的数字用完,此时应停止遍历,并可以直接返回root + if (i == array.length) return root; + current = nodeQueue.poll(); + if (array[i] != null) { + current.left = new TreeNode(array[i]); + nodeQueue.offer(current.left); + } + // 同上,说明已经将nums中的数字用完,此时应停止遍历,并可以直接返回root + if (i + 1 == array.length) return root; + if (array[i + 1] != null) { + current.right = new TreeNode(array[i + 1]); + nodeQueue.offer(current.right); + } + } + startIndex += lineNodeNum; + restLength -= lineNodeNum; + lineNodeNum = nodeQueue.size() * 2; + } + + return root; + } + + /** + * 二叉树层次遍历 + */ + public static List> levelOrder(TreeNode root) { + List> result = new ArrayList<>(); + if (root == null) + return result; + + Queue queue = new LinkedList<>(); + queue.add(root); + while (!queue.isEmpty()) { + // 遍历每层的数据 + int size = queue.size(); + List list = new ArrayList<>(); + while (size > 0) { + root = queue.poll(); + list.add(root.val); + if (root.left != null) { + queue.add(root.left); + } + if (root.right != null) { + queue.add(root.right); + } + size--; + } + result.add(list); + } + return result; + } + + /** + * 输出二叉树层次遍历的结果 + */ + public static void printLevelOrder(TreeNode root) { + PrintUtil.printLists(levelOrder(root)); + } + + public static void main(String[] args) { +// printLevelOrder(createTree(1, null, 2, 3)); + printLevelOrder(createTree(5, 4, 8, 11, null, 13, 4, 7, 2, null, null, null, 1)); + //printLevelOrder(createTree(1,2,3,null,4,5,null)); + } +} diff --git a/algorithms/leetcode2/leetcode2-common/src/main/java/cn/cunchang/tree/TrieNode.java b/algorithms/leetcode2/leetcode2-common/src/main/java/cn/cunchang/tree/TrieNode.java new file mode 100644 index 00000000..21358912 --- /dev/null +++ b/algorithms/leetcode2/leetcode2-common/src/main/java/cn/cunchang/tree/TrieNode.java @@ -0,0 +1,34 @@ +package cn.cunchang.tree; + +public class TrieNode { + // 26个字母 + private final int R = 26; + // 不存储真实的值,TrieNode[]中不为null表示存在 + private TrieNode[] links; + private boolean isEnd; + + public TrieNode() { + links = new TrieNode[R]; + } + + + public boolean containsKey(char ch) { + return links[ch - 'a'] != null; + } + + public TrieNode get(char ch) { + return links[ch - 'a']; + } + + public void put(char ch, TrieNode node) { + links[ch - 'a'] = node; + } + + public void setEnd() { + isEnd = true; + } + + public boolean isEnd() { + return isEnd; + } +} \ No newline at end of file diff --git a/algorithms/leetcode2/linkedlist/pom.xml b/algorithms/leetcode2/linkedlist/pom.xml new file mode 100644 index 00000000..b3ee7d09 --- /dev/null +++ b/algorithms/leetcode2/linkedlist/pom.xml @@ -0,0 +1,23 @@ + + + 4.0.0 + + linkedlist + cn.cucnhang + 1.0-SNAPSHOT + + + 8 + 8 + + + + + leetcode2-common + cn.cucnhang + 1.0-SNAPSHOT + + + \ No newline at end of file diff --git "a/algorithms/leetcode2/linkedlist/src/main/java/cn/cunchang/K\344\270\252\344\270\200\347\273\204\347\277\273\350\275\254\351\223\276\350\241\250_25_\345\233\260\351\232\276/Solution.java" "b/algorithms/leetcode2/linkedlist/src/main/java/cn/cunchang/K\344\270\252\344\270\200\347\273\204\347\277\273\350\275\254\351\223\276\350\241\250_25_\345\233\260\351\232\276/Solution.java" new file mode 100644 index 00000000..52526c46 --- /dev/null +++ "b/algorithms/leetcode2/linkedlist/src/main/java/cn/cunchang/K\344\270\252\344\270\200\347\273\204\347\277\273\350\275\254\351\223\276\350\241\250_25_\345\233\260\351\232\276/Solution.java" @@ -0,0 +1,69 @@ +package cn.cunchang.K个一组翻转链表_25_困难; + +import cn.cunchang.linkedlist.LinkedListUtil; +import cn.cunchang.linkedlist.ListNode; + +/** + * @author cunchang + * @date 2022/6/20 8:33 PM + */ +public class Solution { + + public ListNode reverseKGroup(ListNode head, int k) { + if (head == null) { + return null; + } + int step = 0; + ListNode result = null; // 返回结果 + ListNode current = head; // 当前起点 + ListNode next = current; // 下一个k起点 + ListNode preTail = null; // 上一次反转后的尾结点 + while (current != null) { + while (next != null && step < k) { + next = next.next; + step++; + } + // 剩余链表不够反转,就不反转了 + // next == null不能够代表"剩余链表不够反转",可能是刚好够反转 + if (step < k && preTail != null) { + preTail.next = current; + break; + } + + step = 0; + // 反转后返回头结点 + ListNode tail = reverse1(current, k); + if (preTail != null) { + preTail.next = tail; + } + if (preTail == null) { // 第一次反转的头结点 + result = tail; + } + preTail = current;//反转链表的尾结点 + + current = next; + } + return result; + } + + // 返回头 + public ListNode reverse1(ListNode head, int k) { + ListNode pre = null; + ListNode current = head; + ListNode next = null; + while (current != null && k > 0) { + next = current.next; + current.next = pre; + pre = current; + current = next; + k--; + } + return pre; + } + + public static void main(String[] args) { + ListNode listNode1 = new Solution().reverseKGroup( + LinkedListUtil.createListNode(1,2,3,4), 2); + LinkedListUtil.printListNode(listNode1); + } +} diff --git "a/algorithms/leetcode2/linkedlist/src/main/java/cn/cunchang/\344\270\244\344\270\244\344\272\244\346\216\245\351\223\276\350\241\250\344\270\255\347\232\204\350\212\202\347\202\271_24_\344\270\255\347\255\211/Solution.java" "b/algorithms/leetcode2/linkedlist/src/main/java/cn/cunchang/\344\270\244\344\270\244\344\272\244\346\216\245\351\223\276\350\241\250\344\270\255\347\232\204\350\212\202\347\202\271_24_\344\270\255\347\255\211/Solution.java" new file mode 100644 index 00000000..8ddba5a7 --- /dev/null +++ "b/algorithms/leetcode2/linkedlist/src/main/java/cn/cunchang/\344\270\244\344\270\244\344\272\244\346\216\245\351\223\276\350\241\250\344\270\255\347\232\204\350\212\202\347\202\271_24_\344\270\255\347\255\211/Solution.java" @@ -0,0 +1,58 @@ +package cn.cunchang.两两交接链表中的节点_24_中等; + +import cn.cunchang.linkedlist.LinkedListUtil; +import cn.cunchang.linkedlist.ListNode; + +class Solution { + + public ListNode swapPairs(ListNode head) { + if (head == null || head.next == null) { + return head; + } + ListNode holder = head.next; + ListNode pre = null; + ListNode headTemp = head; + while (headTemp != null && headTemp.next != null) { + ListNode next = headTemp.next.next; + // 2的next执行1 + // 4的next执行3 + headTemp.next.next = headTemp; + if (pre != null) { + // 4的next执行3时,1指向4,而不是1指向3 + pre.next = headTemp.next; + } + // 当前节点next指向下下个节点;1指向3 + headTemp.next = next; + pre = headTemp; + headTemp = next; + } + return holder; + } + +// public ListNode swapPairs(ListNode head) { +// ListNode holder = new ListNode(-1); +// holder.next = head; +// ListNode virtual = holder; +// while (virtual.next != null && virtual.next.next != null) { +// ListNode start = virtual.next; +// ListNode end = virtual.next.next; +// // 虚拟节点的next指向2 +// virtual.next = end; +// // 1的next指向2的next,就是3,1.next=3 +// start.next = end.next; +// // 2的next指向1,2.next = 1 +// end.next = start; +// // 目前就是 -1,2,1,3,4,start=1 +// virtual = start; +// } +// return holder.next; +// } + + public static void main(String[] args) { + LinkedListUtil.printListNode(new Solution().swapPairs(LinkedListUtil.createListNode(1, 2, 3, 4))); + LinkedListUtil.printListNode(new Solution().swapPairs(LinkedListUtil.createListNode(1, 2, 3, 4, 5, 6))); + LinkedListUtil.printListNode(new Solution().swapPairs(LinkedListUtil.createListNode(1, 2, 3, 4, 5))); + LinkedListUtil.printListNode(new Solution().swapPairs(LinkedListUtil.createListNode(1))); + LinkedListUtil.printListNode(new Solution().swapPairs(LinkedListUtil.createListNode())); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode2/linkedlist/src/main/java/cn/cunchang/\345\217\215\350\275\254\351\223\276\350\241\250_206_\347\256\200\345\215\225/Solution.java" "b/algorithms/leetcode2/linkedlist/src/main/java/cn/cunchang/\345\217\215\350\275\254\351\223\276\350\241\250_206_\347\256\200\345\215\225/Solution.java" new file mode 100644 index 00000000..3406a2d6 --- /dev/null +++ "b/algorithms/leetcode2/linkedlist/src/main/java/cn/cunchang/\345\217\215\350\275\254\351\223\276\350\241\250_206_\347\256\200\345\215\225/Solution.java" @@ -0,0 +1,58 @@ +package cn.cunchang.反转链表_206_简单; + +import cn.cunchang.linkedlist.LinkedListUtil; +import cn.cunchang.linkedlist.ListNode; + +import java.util.Stack; + +class Solution { + + // 递归 +// public ListNode reverseList(ListNode head) { +// if (head == null || head.next == null) { +// return head; +// } +// // newHead其实就是最后一个节点,唯一的作用就是让函数调用方拿到这个反转后的单链表的头,原先的head节点现在是尾结点了 +// // 通过递归遍历链表,在遍历每一个节点的时候,让当前节点的下一个节点next指向当前节点,当前节点next指向null +// // 由于栈先进后出,所以其实是从后往前遍历的,所以不需要像正向遍历的时候那样,记录前指针、next指针 +// ListNode newHead = reverseList(head.next); +// head.next.next = head; +// head.next = null; +// return newHead; +// } + + // 栈 + public ListNode reverseList(ListNode head) { + if (head == null) { + return null; + } + ListNode newHead; + + Stack stack = new Stack<>(); + // head=>1->2->3->4->5 + // stack=4<-3<-2<-1 + while (head.next != null) { + stack.push(head); + head = head.next; + } + // 握住尾结点,将来它是首节点;等价递归里面的newHead,也可以不要直接返回head + newHead = head; + // stack=4<-3<-2<-1 + while (!stack.isEmpty()) { + // 把4弹出来,4->5;依次把321都弹出来 + ListNode current = stack.pop(); + // 5->4 + current.next.next = current; + // 4->null + current.next = null; + } + return newHead; + } + + public static void main(String[] args) { + ListNode listNode = LinkedListUtil.createListNode(1, 2, 3, 4, 5); + LinkedListUtil.printListNode(listNode); + LinkedListUtil.printListNode(new Solution().reverseList(listNode)); + } + +} diff --git "a/algorithms/leetcode2/linkedlist/src/main/java/cn/cunchang/\345\217\215\350\275\254\351\223\276\350\241\250_206_\347\256\200\345\215\225/Solution2.java" "b/algorithms/leetcode2/linkedlist/src/main/java/cn/cunchang/\345\217\215\350\275\254\351\223\276\350\241\250_206_\347\256\200\345\215\225/Solution2.java" new file mode 100644 index 00000000..19d8a2f5 --- /dev/null +++ "b/algorithms/leetcode2/linkedlist/src/main/java/cn/cunchang/\345\217\215\350\275\254\351\223\276\350\241\250_206_\347\256\200\345\215\225/Solution2.java" @@ -0,0 +1,22 @@ +package cn.cunchang.反转链表_206_简单; + + +import cn.cunchang.linkedlist.ListNode; + +class Solution2 { + + public ListNode reverseList(ListNode head) { + ListNode pre = null;//无法找到前一个节点,所以需要记录前一个节点 + ListNode current = head;// 当前节点 + + while (current != null) { + ListNode next = current.next;// next节点,防止current反转后找不到next了 + current.next = pre; + pre = current; + current = next; + } + + return pre; + } + +} diff --git "a/algorithms/leetcode2/linkedlist/src/main/java/cn/cunchang/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\351\223\276\350\241\250_21_\344\270\255\347\255\211/Solution.java" "b/algorithms/leetcode2/linkedlist/src/main/java/cn/cunchang/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\351\223\276\350\241\250_21_\344\270\255\347\255\211/Solution.java" new file mode 100644 index 00000000..70bf5f86 --- /dev/null +++ "b/algorithms/leetcode2/linkedlist/src/main/java/cn/cunchang/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\351\223\276\350\241\250_21_\344\270\255\347\255\211/Solution.java" @@ -0,0 +1,34 @@ +package cn.cunchang.合并两个有序链表_21_中等; + +import cn.cunchang.linkedlist.LinkedListUtil; +import cn.cunchang.linkedlist.ListNode; + +class Solution { + public ListNode mergeTwoLists(ListNode list1, ListNode list2) { + ListNode mergeList = new ListNode(-1); + ListNode mergeNode = mergeList; + while (list1 != null && list2 != null) { + if (list1.val >= list2.val) { + mergeNode.next = list2; + list2 = list2.next; + } else { + mergeNode.next = list1; + list1 = list1.next; + } + mergeNode = mergeNode.next; + } + if (list1 != null) { + mergeNode.next = list1; + } + if (list2 != null) { + mergeNode.next = list2; + } + return mergeList.next; + } + + public static void main(String[] args) { + ListNode list1 = LinkedListUtil.createListNode(1, 2, 4); + ListNode list2 = LinkedListUtil.createListNode(1, 3, 4); + LinkedListUtil.printListNode(new Solution().mergeTwoLists(list1, list2)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode2/linkedlist/src/main/java/cn/cunchang/\345\233\236\346\226\207\351\223\276\350\241\250_234_\347\256\200\345\215\225/Solution.java" "b/algorithms/leetcode2/linkedlist/src/main/java/cn/cunchang/\345\233\236\346\226\207\351\223\276\350\241\250_234_\347\256\200\345\215\225/Solution.java" new file mode 100644 index 00000000..ff87fe54 --- /dev/null +++ "b/algorithms/leetcode2/linkedlist/src/main/java/cn/cunchang/\345\233\236\346\226\207\351\223\276\350\241\250_234_\347\256\200\345\215\225/Solution.java" @@ -0,0 +1,48 @@ +package cn.cunchang.回文链表_234_简单; + +import cn.cunchang.linkedlist.LinkedListUtil; +import cn.cunchang.linkedlist.ListNode; + +class Solution {public boolean isPalindrome(ListNode head) { + if (head == null || head.next == null) { + return true; + } + ListNode fast = head, slow = head; + while (fast.next != null && fast.next.next != null) { + slow = slow.next; + fast = fast.next.next; + } + ListNode list1 = reverse(slow); + ListNode list2 = head; + while (list1 != null && list2 != null) { + if (list1.val != list2.val) { + return false; + } + list1 = list1.next; + list2 = list2.next; + } + + return true; +} + + public ListNode reverse(ListNode head) { + ListNode pre = null;//无法找到前一个节点,所以需要记录前一个节点 + ListNode current = head;// 当前节点 + while (current != null) { + ListNode next = current.next;// next节点,防止current反转后找不到next了 + current.next = pre; + pre = current; + current = next; + } + return pre; + } + + + public static void main(String[] args) { +// ListNode listNode = LinkedListUtil.createListNode(1, 2, 2, 1); +// ListNode listNode = LinkedListUtil.createListNode(1, 2, 3, 2, 1); + ListNode listNode = LinkedListUtil.createListNode(1, 1); + LinkedListUtil.printListNode(listNode); + System.out.println(new Solution().isPalindrome(listNode)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode2/linkedlist/src/main/java/cn/cunchang/\346\216\222\345\272\217\351\223\276\350\241\250_148_\344\270\255\347\255\211/Solution.java" "b/algorithms/leetcode2/linkedlist/src/main/java/cn/cunchang/\346\216\222\345\272\217\351\223\276\350\241\250_148_\344\270\255\347\255\211/Solution.java" new file mode 100644 index 00000000..157baf5e --- /dev/null +++ "b/algorithms/leetcode2/linkedlist/src/main/java/cn/cunchang/\346\216\222\345\272\217\351\223\276\350\241\250_148_\344\270\255\347\255\211/Solution.java" @@ -0,0 +1,61 @@ +package cn.cunchang.排序链表_148_中等; + +import cn.cunchang.linkedlist.LinkedListUtil; +import cn.cunchang.linkedlist.ListNode; + +class Solution { + public ListNode sortList(ListNode head) { + // 递归终止点 + if (head == null || head.next == null) { + return head; + } + // 1. 快慢指针法,遍历链表找到中间节点 + ListNode fast = middleBeforeNode(head); + // 2. 中间节点切断链表 + ListNode mid = fast.next;//直接用fast当中间节点也可以,但是为了切断链表,用next比较方便 + fast.next = null; + // 3. 分别用归并排序排左右子链表 + ListNode leftNode = sortList(head); + ListNode rightNode = sortList(mid); + // 4. 合并子链表 + return mergeTwoLists(leftNode, rightNode); + } + + public static ListNode middleBeforeNode(ListNode head) { + ListNode fast = head; + ListNode slow = head; + while (fast.next != null && fast.next.next != null) { + fast = fast.next.next; + slow = slow.next; + } + return slow; + } + + public ListNode mergeTwoLists(ListNode list1, ListNode list2) { + ListNode mergeList = new ListNode(-1); + ListNode mergeNode = mergeList; + while (list1 != null && list2 != null) { + if (list1.val >= list2.val) { + mergeNode.next = list2; + list2 = list2.next; + } else { + mergeNode.next = list1; + list1 = list1.next; + } + mergeNode = mergeNode.next; + } + if (list1 != null) { + mergeNode.next = list1; + } + if (list2 != null) { + mergeNode.next = list2; + } + return mergeList.next; + } + + public static void main(String[] args) { + LinkedListUtil.printListNode(new Solution(). + sortList(LinkedListUtil.createListNode(9, 8, 7, 6, 5, 4, 3, 2, 1))); + } + +} \ No newline at end of file diff --git "a/algorithms/leetcode2/linkedlist/src/main/java/cn/cunchang/\347\233\270\344\272\244\351\223\276\350\241\250_160_\347\256\200\345\215\225/Solution.java" "b/algorithms/leetcode2/linkedlist/src/main/java/cn/cunchang/\347\233\270\344\272\244\351\223\276\350\241\250_160_\347\256\200\345\215\225/Solution.java" new file mode 100644 index 00000000..d6f9e707 --- /dev/null +++ "b/algorithms/leetcode2/linkedlist/src/main/java/cn/cunchang/\347\233\270\344\272\244\351\223\276\350\241\250_160_\347\256\200\345\215\225/Solution.java" @@ -0,0 +1,44 @@ +package cn.cunchang.相交链表_160_简单; + +import cn.cunchang.linkedlist.ListNode; + +public class Solution { + public ListNode getIntersectionNode(ListNode headA, ListNode headB) { + // 计算ab的长度 + int lenA = 0, lenB = 0; + ListNode lenHeadA = headA; + ListNode lenHeadB = headB; + while (lenHeadA != null) { + lenA++; + lenHeadA = lenHeadA.next; + } + while (lenHeadB != null) { + lenB++; + lenHeadB = lenHeadB.next; + } + // 将ab头设置到相同位置 + int diff = Math.abs(lenA - lenB); + ListNode startHeadA = headA; + ListNode startHeadB = headB; + if (lenA > lenB) { + while (diff > 0) { + startHeadA = startHeadA.next; + diff--; + } + } else { + while (diff > 0) { + startHeadB = startHeadB.next; + diff--; + } + } + // 比较,有相同说明相交 + while (startHeadA != null && startHeadB != null) { + if (startHeadA == startHeadB) { + return startHeadA; + } + startHeadA = startHeadA.next; + startHeadB = startHeadB.next; + } + return null; + } +} \ No newline at end of file diff --git a/algorithms/leetcode2/other-algo/pom.xml b/algorithms/leetcode2/other-algo/pom.xml new file mode 100644 index 00000000..2f4ad098 --- /dev/null +++ b/algorithms/leetcode2/other-algo/pom.xml @@ -0,0 +1,19 @@ + + + + leetcode2 + cn.cucnhang + 1.0-SNAPSHOT + + 4.0.0 + + other-algo + + + 8 + 8 + + + \ No newline at end of file diff --git "a/algorithms/leetcode2/other-algo/src/main/java/cn/cunchang/LRU\347\274\223\345\255\230_146_\344\270\255\347\255\211/LRUCache.java" "b/algorithms/leetcode2/other-algo/src/main/java/cn/cunchang/LRU\347\274\223\345\255\230_146_\344\270\255\347\255\211/LRUCache.java" new file mode 100644 index 00000000..19e14ec9 --- /dev/null +++ "b/algorithms/leetcode2/other-algo/src/main/java/cn/cunchang/LRU\347\274\223\345\255\230_146_\344\270\255\347\255\211/LRUCache.java" @@ -0,0 +1,126 @@ +package cn.cunchang.LRU缓存_146_中等; + +import org.junit.Assert; + +import java.util.HashMap; + +/** + * @author cunchang + * @date 2022/7/4 10:28 AM + */ +class LRUCache { + + public static void main(String[] args) { + LRUCache lRUCache = new LRUCache(2); + lRUCache.put(2, 1); + lRUCache.put(3, 2); + Assert.assertEquals(2, lRUCache.get(3)); + Assert.assertEquals(1, lRUCache.get(2)); + lRUCache.put(4, 3); + Assert.assertEquals(1, lRUCache.get(2)); + Assert.assertEquals(-1, lRUCache.get(3)); + Assert.assertEquals(3, lRUCache.get(4)); + } + + // 要求"函数 get 和 put 必须以 O(1) 的平均时间复杂度运行。" + // hashmap存储kv保证 get、put O(1)、linkedlist存储k保证淘汰队尾 + DoubleLinkedList list; + HashMap kv; + int capacity; + + /** + * 以 正整数 作为容量 capacity 初始化 LRU 缓存 + */ + public LRUCache(int capacity) { + this.capacity = capacity; + list = new DoubleLinkedList(); + kv = new HashMap<>(); + } + + /** + * 要求:如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 + * 实现: + * 1、直接从map里面get,不存在返回-1 + * 2、存在,将list里面的node节点删除,并加到队头 + */ + public int get(int key) { + Node node = kv.get(key); + if (node == null) { + return -1; + } + list.remove(node); + list.addFirst(node); + return node.v; + } + + /** + * 要求: + * 1、如果关键字 key 已经存在,则变更其数据值 value ; + * 2、如果不存在,则向缓存中插入该组 key-value 。 + * 3、如果插入操作导致关键字数量超过 capacity ,则应该 逐出 最久未使用的关键字。 + * 实现: + * 1、k在map中存在,直接覆盖 + * 2、k在map中不存在, + * - 如果插入关键字数量未超过 capacity,put到map,add到list + * - 超过了,走淘汰逻辑,移除list队尾的k,同时在map中删除k。然后继续put即可 + */ + public void put(int key, int value) { + Node node = kv.get(key); + if (node != null) { + list.remove(node); + list.addFirst(node); + node.v = value; + return; + } + if (kv.size() >= capacity) { + Node last = list.removeLast(); + kv.remove(last.k); + } + node = new Node(key, value); + kv.put(key, node); + list.addFirst(node); + } + + class DoubleLinkedList { + Node head; + Node tail; + + public DoubleLinkedList() { + head = new Node(0, 0); + tail = new Node(0, 0); + head.next = tail; + tail.prev = head; + } + + // 删除某个节点 + public void remove(Node node) { + node.prev.next = node.next; + node.next.prev = node.prev; + } + + // node节点插入 + public void addFirst(Node node) { + node.next = head.next;//构建node.next + node.prev = head; // 构建node.pre + head.next.prev = node;// 构建原head.pre + head.next = node;// 构建head.next + } + public Node removeLast() { + if (tail.prev == head) + return null; + Node last = tail.prev; + remove(last); + return last; + } + } + + static class Node { + int k, v; + Node prev, next; + + public Node(int k, int v) { + this.k = k; + this.v = v; + } + } +} \ No newline at end of file diff --git "a/algorithms/leetcode2/other-algo/src/main/java/cn/cunchang/LRU\347\274\223\345\255\230_146_\344\270\255\347\255\211/LRUCache2.java" "b/algorithms/leetcode2/other-algo/src/main/java/cn/cunchang/LRU\347\274\223\345\255\230_146_\344\270\255\347\255\211/LRUCache2.java" new file mode 100644 index 00000000..b799ea81 --- /dev/null +++ "b/algorithms/leetcode2/other-algo/src/main/java/cn/cunchang/LRU\347\274\223\345\255\230_146_\344\270\255\347\255\211/LRUCache2.java" @@ -0,0 +1,59 @@ +package cn.cunchang.LRU缓存_146_中等; + +import org.junit.Assert; + +import java.util.HashMap; +import java.util.LinkedList; + +class LRUCache2 { + + private int capacity; + + private LinkedList keyCache = new LinkedList<>(); + + private HashMap keyAndValueCache = new HashMap<>(); + + public LRUCache2(int capacity) { + this.capacity = capacity; + } + + public int get(int key) { + final Integer value = keyAndValueCache.get(key); + if (value == null) { + return -1; + } + keyCache.remove((Object)key); + keyCache.addLast(key); + return value; + } + + public void put(int key, int value) { + if (keyCache.contains(key)) { + keyCache.remove((Object)key); + keyCache.addLast(key); + keyAndValueCache.put(key, value); + return; + } + + if (keyCache.size() >= capacity) { + Integer k = keyCache.removeFirst(); + keyAndValueCache.remove(k); + } + keyCache.addLast(key); + keyAndValueCache.put(key, value); + } + + + public static void main(String[] args) { + LRUCache2 lRUCache = new LRUCache2(2); + lRUCache.put(2, 1); + lRUCache.put(3, 2); + Assert.assertEquals(2,lRUCache.get(3)); + Assert.assertEquals(1,lRUCache.get(2)); + lRUCache.put(4, 3); + Assert.assertEquals(1,lRUCache.get(2)); + Assert.assertEquals(-1,lRUCache.get(3)); + Assert.assertEquals(3,lRUCache.get(4)); + } + +} \ No newline at end of file diff --git a/algorithms/leetcode2/point/pom.xml b/algorithms/leetcode2/point/pom.xml new file mode 100644 index 00000000..deb07872 --- /dev/null +++ b/algorithms/leetcode2/point/pom.xml @@ -0,0 +1,15 @@ + + + 4.0.0 + + point + cn.cucnhang + 1.0-SNAPSHOT + + 8 + 8 + + + \ No newline at end of file diff --git "a/algorithms/leetcode2/point/src/main/java/cn/cunchang/\344\270\244\346\225\260\344\271\213\345\222\214_II_\350\276\223\345\205\245\346\234\211\345\272\217\346\225\260\347\273\204_167_\347\256\200\345\215\225/Solution.java" "b/algorithms/leetcode2/point/src/main/java/cn/cunchang/\344\270\244\346\225\260\344\271\213\345\222\214_II_\350\276\223\345\205\245\346\234\211\345\272\217\346\225\260\347\273\204_167_\347\256\200\345\215\225/Solution.java" new file mode 100644 index 00000000..c914c932 --- /dev/null +++ "b/algorithms/leetcode2/point/src/main/java/cn/cunchang/\344\270\244\346\225\260\344\271\213\345\222\214_II_\350\276\223\345\205\245\346\234\211\345\272\217\346\225\260\347\273\204_167_\347\256\200\345\215\225/Solution.java" @@ -0,0 +1,42 @@ +package cn.cunchang.两数之和_II_输入有序数组_167_简单; + +import java.util.Arrays; + +class Solution { + /** + * 思考: + * ------------------------------------------------------------------- + * 思路: + * "非递减顺序排列"表示升序 + * p1指向头,p2指向尾;num[p1]+num[p2]和target比会有三种情况; + * num[p1]+num[p2]==target说明p1、p2就是两数之和 + * num[p1]+num[p2]>target说明p2大了,p2-1再试试 + * num[p1]+num[p2] target) { + p2--; + } else if (tmp < target) { + p1++; + } else { + break; + } + } + return new int[]{p1+1, p2+1}; + } + + public static void main(String[] args) { + int[] numbers = new int[]{2, 7, 11, 15}; + int target = 9; + System.out.println(Arrays.toString( + new Solution().twoSum(numbers, target))); + } + +} \ No newline at end of file diff --git "a/algorithms/leetcode2/point/src/main/java/cn/cunchang/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\346\225\260\347\273\204_88_\347\256\200\345\215\225/Solution.java" "b/algorithms/leetcode2/point/src/main/java/cn/cunchang/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\346\225\260\347\273\204_88_\347\256\200\345\215\225/Solution.java" new file mode 100644 index 00000000..a2ce97f2 --- /dev/null +++ "b/algorithms/leetcode2/point/src/main/java/cn/cunchang/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\346\225\260\347\273\204_88_\347\256\200\345\215\225/Solution.java" @@ -0,0 +1,40 @@ +package cn.cunchang.合并两个有序数组_88_简单; + +class Solution { + /** + * 思考: + * ------------------------------------------------------------------- + * 思路: + * m为num1指针,n为num2指针,p=m+n+1为复制位置指针 + * num1、num2从后往前,最大复制到num1尾部 + * num1复制完了,把num2剩余复制到num1。num2复制完了,就结束了。 + * + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public void merge(int[] nums1, int m, int[] nums2, int n) { + // 记录复制的位置 + int p = m + n - 1; + m--; + n--; + while (m >= 0 && n >= 0) { + if (nums2[n] > nums1[m]) { + nums1[p] = nums2[n]; + n--; + } else { + nums1[p] = nums1[m]; + m--; + } + p--; + } + // 复制num2 + if (n >= 0) { + for (int i = n; i >= 0; i--) { + nums1[p] = nums2[i]; + p--; + } + } + } + +} \ No newline at end of file diff --git "a/algorithms/leetcode2/point/src/main/java/cn/cunchang/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262_76_\345\233\260\351\232\276/Solution1.java" "b/algorithms/leetcode2/point/src/main/java/cn/cunchang/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262_76_\345\233\260\351\232\276/Solution1.java" new file mode 100644 index 00000000..0f80d8a8 --- /dev/null +++ "b/algorithms/leetcode2/point/src/main/java/cn/cunchang/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262_76_\345\233\260\351\232\276/Solution1.java" @@ -0,0 +1,72 @@ +package cn.cunchang.最小覆盖子串_76_困难; + +class Solution1 { + /** + * 思考: + * ------------------------------------------------------------------- + * 思路: + * 1、将s串中的所有子串与t串比较,取最短的子串 + * 2、s子串与t串比较的逻辑:数组sarr记录t字符串的频率,遍历s字符,删除sarr中记录t字符的频率 + * 最后遍历sarr查看t字符串的频率是否还存在,存在说明不是覆盖子串 + * + * 暴力解法,超时了 + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public String minWindow(String s, String t) { + if (s.length() < t.length()) { + return ""; //"a","aa" + } + if (s.equals(t)) { + return s; + } + int l = 0, r = 0; + String target = ""; + while (l <= s.length() && r <= s.length()) { + if (r - l >= t.length()) { + String sub = s.substring(l, r); + if (isSub(sub, t)) { + if ("".equals(target)) {// 第一次找到 + target = sub; + } + if (target.length() > sub.length()) { //第n次找到,要最优的 + target = sub; + } + l++; + r = l; + } + } + r++; + } + return target; + } + + private boolean isSub(String sub, String t) { + if (sub.length() < t.length()) { + return false; + } + int[] set = new int[128]; + for (char c : t.toCharArray()) { + set[c]++;//记录t字符 + } + for (char c : sub.toCharArray()) { + set[c]--;//删除t字符 + } + for (char c : t.toCharArray()) { + if (set[c] > 0) {// 说明有t字符没有被删除,即sub不完全包含t + return false; + } + } + + return true; + } + + public static void main(String[] args) { +// String s = "ADOBECODEBANC", t = "ABC"; +// System.out.println(new Solution().minWindow(s, t)); + String s = "obzcopzocynyrsgsarijyxnkpnukkrvzuwdjldxndmnvevpgmxrmvfwkutwekrffnloyqnntbdohyfqndhzyoykiripdzwiojyoznbtogjyfpouuxvumtewmmnqnkadvzrvouqfbbdiqremqzgevkbhyoznacqwbhtrcjwfkzpdstpjswnpiqxjhywjanhdwavajrhwtwzlrqwmombxcaijzevbtcfsdcuovckoalcseaesmhrrizcjgxkbartdtotpsefsrjmvksqyahpijsrppdqpvmuocofuunonybjivbjviyftsyiicbzxnwnrmvlgkzticetyfcvqcbjvbufdxgcmesdqnowzpshuwcseenwjqhgsdlxatamysrohfnixfprdsljyyfhrnnjsagtuihuczilgvtfcjwgdhpbixlzmakebszxbhrdibpoxiwztshwczamwnninzmqrmpsviydkptjzpktksrortapgpxwojofxeasoyvyprjoguhqobehugwdvtzlenrcttuitsiijswpogicjolfxhiscjggzzissfcnxnvgftxvbfzkukqrtalvktdjsodmtgzqtuyaqvvrbuexgwqzwduixzrpnvegddyyywaquxjxrnuzlmyipuqotkghfkpknqinoidifnfyczzonxydtqroazxhjnrxfbmtlqcsfhshjrxwqvblovaouxwempdrrplefnxmwrwfjtebrfnfanvvmtbzjesctdgbsfnpxlwihalyiafincfcwgdfkvhebphtxukwgjgplrntsuchyjjuqozakiglangxkttsczhnswjksnuqwflmumpexxrznzwxurrysaokwxxqkrggytvsgkyfjrewrcvntomnoazmzycjrjrqemimyhriyxgrzcfuqtjhvjtuhwfzhwpljzajitrhryaqchnuawbxhxrpvyqcvhpggrpplhychyulijhkglinibedauhvdydkqszdbzfkzbvhldstocgydnbfjkcnkfxcyyfbzmmyojgzmasccaahpdnzproaxnexnkamwmkmwslksfpwirexxtymkmojztgmfhydvlqtddewjvsrmyqjrpycbmndhupmdqqabiuelacuvxnhxgtpvrtwfgzpcrbhhtikbcqpctlxszgpfbgcsbaaiapmtsucocmpecgixshrrnhyrpalralbccnxvjzjllarqhznzghswqsnfuyywmzbopyjyauknxddgdthlabjqtwxpxwljvoxkpjjpfvccyikbbrpdsyvlxscuoofkecwtnfkvcnzbxkeabtdusyhrqklhaqreupakxkfzxgawqfwsaboszvlshwzhosojjotgyagygguzntrouhiweuomqptfjjqsxlbylhwtpssdlltgubczxslqjgxuqnmpynnlwjgmebrpokxjnbiltvbebyytnnjlcwyzignmhedwqbfdepqakrelrdfesqrumptwwgifmmbepiktxavhuavlfaqxqhreznbvvlakzeoomykkzftthoemqwliednfsqcnbexbimrvkdhllcesrlhhjsspvfupxwdybablotibypmjutclgjurbmhztboqatrdwsomnxnmocvixxvfiqwmednahdqhxjkvcyhpxxdmzzuyyqdjibvmfkmonfxmohhshpkhmntnoplphqyprveyfsmsxjfosmicdsjrieeytpnbhlsziwxnpmgoxneqbnufhfwrjbqcsdfarybzwaplmxckkgclvwqdbpumsmqkswmjwnkuqbicykoisqwoootrdpdvcuiuswfqmrkctsgrevcxnyncmivsxbpbxzxpwchiwtkroqisnmrbmefbmatmdknaklpgpyqlsccgunaibsloyqpnsibwuowebomrmcegejozypjzjunjmeygozcjqbnrpakdermjcckartbcppmbtkhkmmtcngteigjnxxyzaibtdcwutkvpwezisskfaeljmxyjwykwglqlnofhycwuivdbnpintuyhtyqpwaoelgpbuwiuyeqhbvkqlsfgmeoheexbhnhutxvnvfjwlzfmvpcghiowocdsjcvqrdmkcizxnivbianfpsnzabxqecinhgfyjrjlbikrrgsbgfgyxtzzwwpayapfgueroncpxogouyrdgzdfucfrywtywjeefkvtzxlwmrniselyeodysirqflpduvibfdvedgcrzpzrunpadvawfsmmddqzaaahfxlifobffbyzqqbtlcpquedzjvykvarayfldvmkapjcfzfbmhscdwhciecsbdledspgpdtsteuafzbrjuvmsfrajtulwirzagiqjdiehefmfifocadxfuxrpsemavncdxuoaetjkavqicgndjkkfhbvbhjdcygfwcwyhpirrfjziqonbyxhibelinpllxsjzoiifscwzlyjdmwhnuovvugfhvquuleuzmehggdfubpzolgbhwyeqekzccuypaspozwuhbzbdqdtejuniuuyagackubauvriwneeqfhtwkocuipcelcfrcjcymcuktegiikyosumeioatfcxrheklookaqekljtvtdwhxsteajevpjviqzudnjnqbucnfvkybggaybebljwcstmktgnipdyrxbgewqczzkaxmeazpzbjsntltjwlmuclxirwytvxgvxscztryubtjweehapvxrguzzsatozzjytnamfyiitreyxmanhzeqwgpoikcjlokebksgkaqetverjegqgkicsyqcktmwjwakivtsxjwrgakphqincqrxqhzbcnxljzwturmsaklhnvyungjrxaonjqomdnxpnvihmwzphkyuhwqwdboabepmwgyatyrgtboiypxfavbjtrgwswyvcqhzwibpisydtmltbkydhznbsvxktyfxopwkxzbftzknnwipghuoijrbgqnzovxckvojvsqqraffwowfvqvfcmiicwitrhxdeombgesxexedlakitfovtydxunqnwqqdeeekiwjnwoshqcsljiicgobbbuqakjdonjawgjlezdnqhfdqnmsuavxdpnfzwipmspiabveaarshzwxmirgkmfncvtdrdvfxkpxlkdokxgtwcskmjryyymcthfnkasinihaunohkxaibtsqelockaefjmsuolebtnepauwmrxutspjwaxbmahsjtkfkxlnszribmeofbkyvbjscjtqjakuwvcgunvnonvqbbggfshauqsyznokqbhowjusypfnecffenojfvlblgzntqzlrgzprvhqnpfrrkzxznieiuivajivzijsqijigtatifmbplzqahuidegfoobpymkputzamzvweiyvvzlwihgmmmrcburbgbsdxrfjsbiylitghgcpqjbevvgypxcybubyoijijrhuzcdijfybqbfowlookqmlnplbxvjjosfqviygqyhgamuwzjklbyzopkrnhbywtfoqomweldmlrhjqswctubiknzzvcztyehouvnyiqnvkufaobehxhrjvtisxjlxoumipzjarwvbsaegdkpbsjmpevjbewzuqnfhoohhmdjgfpmjzdmtmykqvtucptwfidpwtwffzolffzqfdearclkyeecuzabjeqhxpmfodsvisnpxrqowdawheydfyhoexvcmihdlzavtqlshdhdgjzpozvvackebhgqppvcrvymljfvooauxcjnbejdivikcoaugxwzsulgfqdtefpehbrlhaoqxwcancuvbqutnfbuygoemditeagmcveatgaikwflozgdhkyfqmjcruyyuemwbqwxyyfiwnvlmbovlmccaoguieu", + t = "cjgamyzjwxrgwedhsexosmswogckohesskteksqgrjonnrwhywxqkqmywqjlxnfrayykqotkzhxmbwvzstrcjfchvluvbaobymlrcgbbqaprwlsqglsrqvynitklvzmvlamqipryqjpmwhdcsxtkutyfoiqljfhxftnnjgmbpdplnuphuksoestuckgopnlwiyltezuwdmhsgzzajtrpnkkswsglhrjprxlvwftbtdtacvclotdcepuahcootzfkwqhtydwrgqrilwvbpadvpzwybmowluikmsfkvbebrxletigjjlealczoqnnejvowptikumnokysfjyoskvsxztnqhcwsamopfzablnrxokdxktrwqjvqfjimneenqvdxufahsshiemfofwlyiionrybfchuucxtyctixlpfrbngiltgtbwivujcyrwutwnuajcxwtfowuuefpnzqljnitpgkobfkqzkzdkwwpksjgzqvoplbzzjuqqgetlojnblslhpatjlzkbuathcuilqzdwfyhwkwxvpicgkxrxweaqevziriwhjzdqanmkljfatjifgaccefukavvsfrbqshhswtchfjkausgaukeapanswimbznstubmswqadckewemzbwdbogogcysfxhzreafwxxwczigwpuvqtathgkpkijqiqrzwugtr"; + System.out.println(new Solution1().minWindow(s, t)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode2/point/src/main/java/cn/cunchang/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262_76_\345\233\260\351\232\276/Solution2.java" "b/algorithms/leetcode2/point/src/main/java/cn/cunchang/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262_76_\345\233\260\351\232\276/Solution2.java" new file mode 100644 index 00000000..3b80d759 --- /dev/null +++ "b/algorithms/leetcode2/point/src/main/java/cn/cunchang/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262_76_\345\233\260\351\232\276/Solution2.java" @@ -0,0 +1,49 @@ +package cn.cunchang.最小覆盖子串_76_困难; + +import java.util.HashMap; + +class Solution2 { + + public String minWindow(String s, String t) { + HashMap windows = new HashMap<>(); + // 记录字符串需要的字符以及数量 + HashMap need = new HashMap<>(); + for (int i = 0; i < t.length(); i++) { + char c = t.charAt(i); + need.put(c, need.getOrDefault(c, 0) + 1); + } + int l = 0, r = 0; + int valid = 0; + int start = 0, len = Integer.MAX_VALUE; + while (r < s.length()) { + char c = s.charAt(r); + // 扩大窗口 + r++; + + if (need.containsKey(c)) { + windows.put(c, windows.getOrDefault(c, 0) + 1); + if (windows.get(c).equals(need.get(c))) { + valid++; + } + } + + // s串窗口中寻找到的满足t串 + while (valid == need.size()) { + + } + + + } + + return null; + } + + + public static void main(String[] args) { + String s = "ADOBECODEBANC", t = "ABC"; + System.out.println(new Solution2().minWindow(s, t)); +// String s = "obzcopzocynyrsgsarijyxnkpnukkrvzuwdjldxndmnvevpgmxrmvfwkutwekrffnloyqnntbdohyfqndhzyoykiripdzwiojyoznbtogjyfpouuxvumtewmmnqnkadvzrvouqfbbdiqremqzgevkbhyoznacqwbhtrcjwfkzpdstpjswnpiqxjhywjanhdwavajrhwtwzlrqwmombxcaijzevbtcfsdcuovckoalcseaesmhrrizcjgxkbartdtotpsefsrjmvksqyahpijsrppdqpvmuocofuunonybjivbjviyftsyiicbzxnwnrmvlgkzticetyfcvqcbjvbufdxgcmesdqnowzpshuwcseenwjqhgsdlxatamysrohfnixfprdsljyyfhrnnjsagtuihuczilgvtfcjwgdhpbixlzmakebszxbhrdibpoxiwztshwczamwnninzmqrmpsviydkptjzpktksrortapgpxwojofxeasoyvyprjoguhqobehugwdvtzlenrcttuitsiijswpogicjolfxhiscjggzzissfcnxnvgftxvbfzkukqrtalvktdjsodmtgzqtuyaqvvrbuexgwqzwduixzrpnvegddyyywaquxjxrnuzlmyipuqotkghfkpknqinoidifnfyczzonxydtqroazxhjnrxfbmtlqcsfhshjrxwqvblovaouxwempdrrplefnxmwrwfjtebrfnfanvvmtbzjesctdgbsfnpxlwihalyiafincfcwgdfkvhebphtxukwgjgplrntsuchyjjuqozakiglangxkttsczhnswjksnuqwflmumpexxrznzwxurrysaokwxxqkrggytvsgkyfjrewrcvntomnoazmzycjrjrqemimyhriyxgrzcfuqtjhvjtuhwfzhwpljzajitrhryaqchnuawbxhxrpvyqcvhpggrpplhychyulijhkglinibedauhvdydkqszdbzfkzbvhldstocgydnbfjkcnkfxcyyfbzmmyojgzmasccaahpdnzproaxnexnkamwmkmwslksfpwirexxtymkmojztgmfhydvlqtddewjvsrmyqjrpycbmndhupmdqqabiuelacuvxnhxgtpvrtwfgzpcrbhhtikbcqpctlxszgpfbgcsbaaiapmtsucocmpecgixshrrnhyrpalralbccnxvjzjllarqhznzghswqsnfuyywmzbopyjyauknxddgdthlabjqtwxpxwljvoxkpjjpfvccyikbbrpdsyvlxscuoofkecwtnfkvcnzbxkeabtdusyhrqklhaqreupakxkfzxgawqfwsaboszvlshwzhosojjotgyagygguzntrouhiweuomqptfjjqsxlbylhwtpssdlltgubczxslqjgxuqnmpynnlwjgmebrpokxjnbiltvbebyytnnjlcwyzignmhedwqbfdepqakrelrdfesqrumptwwgifmmbepiktxavhuavlfaqxqhreznbvvlakzeoomykkzftthoemqwliednfsqcnbexbimrvkdhllcesrlhhjsspvfupxwdybablotibypmjutclgjurbmhztboqatrdwsomnxnmocvixxvfiqwmednahdqhxjkvcyhpxxdmzzuyyqdjibvmfkmonfxmohhshpkhmntnoplphqyprveyfsmsxjfosmicdsjrieeytpnbhlsziwxnpmgoxneqbnufhfwrjbqcsdfarybzwaplmxckkgclvwqdbpumsmqkswmjwnkuqbicykoisqwoootrdpdvcuiuswfqmrkctsgrevcxnyncmivsxbpbxzxpwchiwtkroqisnmrbmefbmatmdknaklpgpyqlsccgunaibsloyqpnsibwuowebomrmcegejozypjzjunjmeygozcjqbnrpakdermjcckartbcppmbtkhkmmtcngteigjnxxyzaibtdcwutkvpwezisskfaeljmxyjwykwglqlnofhycwuivdbnpintuyhtyqpwaoelgpbuwiuyeqhbvkqlsfgmeoheexbhnhutxvnvfjwlzfmvpcghiowocdsjcvqrdmkcizxnivbianfpsnzabxqecinhgfyjrjlbikrrgsbgfgyxtzzwwpayapfgueroncpxogouyrdgzdfucfrywtywjeefkvtzxlwmrniselyeodysirqflpduvibfdvedgcrzpzrunpadvawfsmmddqzaaahfxlifobffbyzqqbtlcpquedzjvykvarayfldvmkapjcfzfbmhscdwhciecsbdledspgpdtsteuafzbrjuvmsfrajtulwirzagiqjdiehefmfifocadxfuxrpsemavncdxuoaetjkavqicgndjkkfhbvbhjdcygfwcwyhpirrfjziqonbyxhibelinpllxsjzoiifscwzlyjdmwhnuovvugfhvquuleuzmehggdfubpzolgbhwyeqekzccuypaspozwuhbzbdqdtejuniuuyagackubauvriwneeqfhtwkocuipcelcfrcjcymcuktegiikyosumeioatfcxrheklookaqekljtvtdwhxsteajevpjviqzudnjnqbucnfvkybggaybebljwcstmktgnipdyrxbgewqczzkaxmeazpzbjsntltjwlmuclxirwytvxgvxscztryubtjweehapvxrguzzsatozzjytnamfyiitreyxmanhzeqwgpoikcjlokebksgkaqetverjegqgkicsyqcktmwjwakivtsxjwrgakphqincqrxqhzbcnxljzwturmsaklhnvyungjrxaonjqomdnxpnvihmwzphkyuhwqwdboabepmwgyatyrgtboiypxfavbjtrgwswyvcqhzwibpisydtmltbkydhznbsvxktyfxopwkxzbftzknnwipghuoijrbgqnzovxckvojvsqqraffwowfvqvfcmiicwitrhxdeombgesxexedlakitfovtydxunqnwqqdeeekiwjnwoshqcsljiicgobbbuqakjdonjawgjlezdnqhfdqnmsuavxdpnfzwipmspiabveaarshzwxmirgkmfncvtdrdvfxkpxlkdokxgtwcskmjryyymcthfnkasinihaunohkxaibtsqelockaefjmsuolebtnepauwmrxutspjwaxbmahsjtkfkxlnszribmeofbkyvbjscjtqjakuwvcgunvnonvqbbggfshauqsyznokqbhowjusypfnecffenojfvlblgzntqzlrgzprvhqnpfrrkzxznieiuivajivzijsqijigtatifmbplzqahuidegfoobpymkputzamzvweiyvvzlwihgmmmrcburbgbsdxrfjsbiylitghgcpqjbevvgypxcybubyoijijrhuzcdijfybqbfowlookqmlnplbxvjjosfqviygqyhgamuwzjklbyzopkrnhbywtfoqomweldmlrhjqswctubiknzzvcztyehouvnyiqnvkufaobehxhrjvtisxjlxoumipzjarwvbsaegdkpbsjmpevjbewzuqnfhoohhmdjgfpmjzdmtmykqvtucptwfidpwtwffzolffzqfdearclkyeecuzabjeqhxpmfodsvisnpxrqowdawheydfyhoexvcmihdlzavtqlshdhdgjzpozvvackebhgqppvcrvymljfvooauxcjnbejdivikcoaugxwzsulgfqdtefpehbrlhaoqxwcancuvbqutnfbuygoemditeagmcveatgaikwflozgdhkyfqmjcruyyuemwbqwxyyfiwnvlmbovlmccaoguieu", +// t = "cjgamyzjwxrgwedhsexosmswogckohesskteksqgrjonnrwhywxqkqmywqjlxnfrayykqotkzhxmbwvzstrcjfchvluvbaobymlrcgbbqaprwlsqglsrqvynitklvzmvlamqipryqjpmwhdcsxtkutyfoiqljfhxftnnjgmbpdplnuphuksoestuckgopnlwiyltezuwdmhsgzzajtrpnkkswsglhrjprxlvwftbtdtacvclotdcepuahcootzfkwqhtydwrgqrilwvbpadvpzwybmowluikmsfkvbebrxletigjjlealczoqnnejvowptikumnokysfjyoskvsxztnqhcwsamopfzablnrxokdxktrwqjvqfjimneenqvdxufahsshiemfofwlyiionrybfchuucxtyctixlpfrbngiltgtbwivujcyrwutwnuajcxwtfowuuefpnzqljnitpgkobfkqzkzdkwwpksjgzqvoplbzzjuqqgetlojnblslhpatjlzkbuathcuilqzdwfyhwkwxvpicgkxrxweaqevziriwhjzdqanmkljfatjifgaccefukavvsfrbqshhswtchfjkausgaukeapanswimbznstubmswqadckewemzbwdbogogcysfxhzreafwxxwczigwpuvqtathgkpkijqiqrzwugtr"; +// System.out.println(new Solution2().minWindow(s, t)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode2/point/src/main/java/cn/cunchang/\347\216\257\345\275\242\351\223\276\350\241\250_II_142_\344\270\255\347\255\211/Solution1.java" "b/algorithms/leetcode2/point/src/main/java/cn/cunchang/\347\216\257\345\275\242\351\223\276\350\241\250_II_142_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..1a28128c --- /dev/null +++ "b/algorithms/leetcode2/point/src/main/java/cn/cunchang/\347\216\257\345\275\242\351\223\276\350\241\250_II_142_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,42 @@ +package cn.cunchang.环形链表_II_142_中等; + +public class Solution1 { + /** + * 思考: + * ------------------------------------------------------------------- + * 思路: + *

+ * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public ListNode detectCycle(ListNode head) { + // 先找到相遇点 + ListNode fast = head, slow = head; + do { + // 说明不成环 + if (fast == null || fast.next == null) { + return null; + } + fast = fast.next.next; + slow = slow.next; + } while (fast != slow);// 说明成环 + // 再找成环点 + ListNode p1 = head, p2 = slow; + while (p1 != p2) { + p1 = p1.next; + p2 = p2.next; + } + return p1; + } + + class ListNode { + int val; + ListNode next; + + ListNode(int x) { + val = x; + next = null; + } + } +} \ No newline at end of file diff --git a/algorithms/leetcode2/pom.xml b/algorithms/leetcode2/pom.xml new file mode 100644 index 00000000..1f9885af --- /dev/null +++ b/algorithms/leetcode2/pom.xml @@ -0,0 +1,32 @@ + + + 4.0.0 + + cn.cucnhang + leetcode2 + pom + 1.0-SNAPSHOT + + leetcode2-common + sort + dynamic + backtracking + other-algo + + + + 8 + 8 + + + + + + junit + junit + 4.12 + + + \ No newline at end of file diff --git a/algorithms/leetcode2/sort/pom.xml b/algorithms/leetcode2/sort/pom.xml new file mode 100644 index 00000000..b2516fa4 --- /dev/null +++ b/algorithms/leetcode2/sort/pom.xml @@ -0,0 +1,25 @@ + + + + leetcode2 + cn.cucnhang + 1.0-SNAPSHOT + + 4.0.0 + + sort + + + 8 + 8 + + + + leetcode2-common + cn.cucnhang + 1.0-SNAPSHOT + + + \ No newline at end of file diff --git a/algorithms/leetcode2/sort/src/main/java/cn/cunchang/sort/BucketSort.java b/algorithms/leetcode2/sort/src/main/java/cn/cunchang/sort/BucketSort.java new file mode 100644 index 00000000..e08f47e1 --- /dev/null +++ b/algorithms/leetcode2/sort/src/main/java/cn/cunchang/sort/BucketSort.java @@ -0,0 +1,54 @@ +package cn.cunchang.sort; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedList; + +/** + * @author cunchang + * @date 2022/6/15 6:41 PM + */ +public class BucketSort { + + public static double[] bucketSort(double[] array) { + //第一步:找出待排序的数组中最大和最小的元素 + double max = array[0]; + double min = array[0]; + for (double i : array) { + if (i > max) { + max = i; + } + if (i < min) { + min = i; + } + } + double d = max - min; + //第二步:初始化桶 + int bucketNum = array.length; + ArrayList> bucketList = new ArrayList>(); + for (int i = 0; i < bucketNum; i++) { + bucketList.add(new LinkedList()); + } + //第三步:遍历原始数组,将每个元素放入桶中 + for (int i = 0; i < array.length; i++) { + // 定位元素属于第几个桶,是按照比例来定位:(array[i] - min) * (bucketNum-1) / d + int num = (int) ((array[i] - min) * (bucketNum - 1) / d); + bucketList.get(num).add(array[i]); + } + //第四步:对每个桶内的数据进行排序 + for (int i = 0; i < bucketList.size(); i++) { + Collections.sort(bucketList.get(i)); + } + //第五步:输入全部元素 + double[] sortArray = new double[array.length]; + int index = 0; + for (LinkedList list : bucketList) { + for (double element : list) { + sortArray[index] = element; + index++; + } + } + return sortArray; + } + +} diff --git a/algorithms/leetcode2/sort/src/main/java/cn/cunchang/sort/Heap1.java b/algorithms/leetcode2/sort/src/main/java/cn/cunchang/sort/Heap1.java new file mode 100644 index 00000000..c53463d0 --- /dev/null +++ b/algorithms/leetcode2/sort/src/main/java/cn/cunchang/sort/Heap1.java @@ -0,0 +1,100 @@ +package cn.cunchang.sort; + +import java.util.Arrays; + +public class Heap1 { + private int[] a; // 数组,从下标 1 开始存储数据 + private int n; // 堆可以存储的最大数据个数 + private int count; // 堆中已经存储的数据个数 + + public Heap1(int capacity) { + a = new int[capacity + 1]; + n = capacity; + count = 0; + } + + /** + * 插入 + */ + public void insert(int data) { + if (count >= n) return; // 堆满了 + ++count; + a[count] = data; + int i = count; + while (i / 2 > 0 && a[i] > a[i / 2]) { // 自下往上堆化 + swap(a, i, i / 2); // swap() 函数作用:交换下标为 i 和 i/2 的两个元素 + i = i / 2; + } + } + + /** + * 删除堆顶 + */ + public void removeMax() { + if (count == 0) return; // 堆中没有数据 + a[1] = a[count]; + --count; + heapify(a, count, 1); + } + + /** + * 堆化大顶堆 + * 自上往下堆化 + * + * @param arr 数组 + * @param n 堆中元素个数 + * @param i 待堆化的元素 + */ + private static void heapify(int[] arr, int n, int i) { + while (true) { + // 待堆化元素、左、右子树最大值的下标 + int maxPos = i; + // 待堆化元素小于左子树 + if (i * 2 <= n && arr[i] < arr[i * 2]) { + maxPos = i * 2; + } + // 待堆化元素左子树小于右子树, + if (i * 2 + 1 <= n && arr[maxPos] < arr[i * 2 + 1]) { + maxPos = i * 2 + 1; + } + // 最大元素是自己无需向下堆化 + if (maxPos == i) break; + // 最大元素不是自己,交互值 + swap(arr, i, maxPos); + // 将被交互的元素继续向下堆化 + i = maxPos; + } + } + + private static void buildHeap(int[] a, int n) { + // 对非叶子节点进行,自上往下堆化 + for (int i = n / 2; i >= 1; --i) { + heapify(a, n, i); + } + } + + // n 表示数据的个数,数组 a 中的数据从下标 1 到 n 的位置。 + public static void sort(int[] a, int n) { + buildHeap(a, n); + int k = n; + while (k > 1) { + swap(a, 1, k); + --k; + heapify(a, k, 1); + } + } + + private static void swap(int[] arr, int i, int j) { + int temp = arr[i]; + arr[i] = arr[j]; + arr[j] = temp; + } + + public static void main(String[] args) { + int[] arr = new int[]{-99999, 9, 8, 7, 6, 5, 4, 3, 2, 1}; + System.out.println(Arrays.toString(arr)); + Heap1.sort(arr, arr.length - 1); + System.out.println(Arrays.toString(arr)); + } + +} \ No newline at end of file diff --git a/algorithms/leetcode2/sort/src/main/java/cn/cunchang/sort/Heap2.java b/algorithms/leetcode2/sort/src/main/java/cn/cunchang/sort/Heap2.java new file mode 100644 index 00000000..12fd37cb --- /dev/null +++ b/algorithms/leetcode2/sort/src/main/java/cn/cunchang/sort/Heap2.java @@ -0,0 +1,69 @@ +package cn.cunchang.sort; + +import java.util.Arrays; + +public class Heap2 { + + + /** + * 堆化大顶堆 + * 自上往下堆化 + * + * @param arr 数组 + * @param n 堆中元素个数 + * @param i 待堆化的元素 + */ + private static void heapify(int[] arr, int n, int i) { + while (true) { + // 待堆化元素、左、右子树最大值的下标 + int maxPos = i; + // 待堆化元素小于左子树 + if (i * 2 + 1 <= n && arr[i] < arr[i * 2 + 1]) { + maxPos = i * 2 + 1; + } + // 待堆化元素左子树小于右子树, + if (i * 2 + 2 <= n && arr[maxPos] < arr[i * 2 + 2]) { + maxPos = i * 2 + 2; + } + // 最大元素是自己无需向下堆化 + if (maxPos == i) break; + // 最大元素不是自己,交互值 + swap(arr, i, maxPos); + // 将被交互的元素继续向下堆化 + i = maxPos; + } + } + + private static void buildHeap(int[] a, int n) { + // 对非叶子节点进行,自上往下堆化 + for (int i = n / 2 - 1; i >= 0; --i) { + heapify(a, n, i); + } + } + + public static void sort(int[] arr, int n) { + // 1. 构建大顶堆 + buildHeap(arr, n); + int disorder = n; + // 2. 交换堆顶元素与末尾元素,调整堆结构 + while (disorder > 0) { + swap(arr, 0, disorder); + disorder--; + heapify(arr, disorder, 0); + } + } + + private static void swap(int[] arr, int i, int j) { + int temp = arr[i]; + arr[i] = arr[j]; + arr[j] = temp; + } + + public static void main(String[] args) { + int[] arr = new int[]{9, 10, 7, 6, 5, 4, 3, 2, 1}; + System.out.println(Arrays.toString(arr)); + Heap2.sort(arr, arr.length - 1); + System.out.println(Arrays.toString(arr)); + } + +} \ No newline at end of file diff --git a/algorithms/leetcode2/sort/src/main/java/cn/cunchang/sort/QuickSort1.java b/algorithms/leetcode2/sort/src/main/java/cn/cunchang/sort/QuickSort1.java new file mode 100644 index 00000000..3cc792b0 --- /dev/null +++ b/algorithms/leetcode2/sort/src/main/java/cn/cunchang/sort/QuickSort1.java @@ -0,0 +1,65 @@ +package cn.cunchang.sort; + +import java.util.Arrays; + +/** + * @author lastwhisper + */ +public class QuickSort1 { + public static void main(String[] args) { +// int[] arr = {2, 10, 8, 1000}; +// int[] arr = {-9, 78, 0, 23, -567, 70}; +// int[] arr = {-9, 78, 0, 23, 60, 70}; +// int[] arr = {9, 0, -567}; + int[] arr = {49, 38, 65, 97, 76, 13, 27}; + sort(arr, 0, arr.length - 1); + System.out.println(Arrays.toString(arr)); + } + + private static void sort(int[] arr, int left, int right) { + if (left >= right) return; + int pivotIdx = partition(arr, left, right); + // 此时分区pivotIdx左边值小于等于arr[pivotIdx],分区右边大于arr[pivotIdx] + // 对[left,pivotIdx - 1]再次分区 + sort(arr, left, pivotIdx - 1); + // 对[pivotIdx + 1,right]再次分区 + sort(arr, pivotIdx + 1, right); + } + + /** + * @param nums 待分区数组 + * @param left 待分区左边界 + * @param right 待分区右边界 + * @return pivotIdx 中轴索引 + */ + private static int partition(int[] nums, int left, int right) { + // 选最后一个值作为中轴 + int pivot = nums[left]; + // 所依right要减一 + int start = left + 1, end = right; + while (start <= end) { + // 寻找左边大于pivot + while (start <= end && nums[start] <= pivot) { + start++; + } + // 寻找右边小于等于pivot + while (start <= end && nums[end] > pivot) { + end--; + } + if (start < end) { + swap(nums, start, end); + } + } + // 此时[left+1,start-1]的值一定小于pivot=nums[left] + // left一定大于等于start,所以将start-1与left交互 + swap(nums, start - 1, left); + return start - 1; + } + + private static void swap(int[] arr, int i, int j) { + int temp = arr[i]; + arr[i] = arr[j]; + arr[j] = temp; + } + +} diff --git a/algorithms/leetcode2/sort/src/main/java/cn/cunchang/sort/QuickSort2.java b/algorithms/leetcode2/sort/src/main/java/cn/cunchang/sort/QuickSort2.java new file mode 100644 index 00000000..6dc4c247 --- /dev/null +++ b/algorithms/leetcode2/sort/src/main/java/cn/cunchang/sort/QuickSort2.java @@ -0,0 +1,62 @@ +package cn.cunchang.sort; + +import java.util.Arrays; + +/** + * @author lastwhisper + */ +public class QuickSort2 { + public static void main(String[] args) { +// int[] arr = {2, 10, 8, 1000}; + int[] arr = {49, 38, 65, 97, 76, 13, 27}; + sort(arr, 0, arr.length - 1); + System.out.println(Arrays.toString(arr)); + } + + private static void sort(int[] arr, int left, int right) { + if (left >= right) return; + int pivotIdx = partition(arr, left, right); + // 此时分区pivotIdx左边值小于等于arr[pivotIdx],分区右边大于arr[pivotIdx] + // 对[left,pivotIdx - 1]再次分区 + sort(arr, left, pivotIdx - 1); + // 对[pivotIdx + 1,right]再次分区 + sort(arr, pivotIdx + 1, right); + } + + /** + * @param nums 待分区数组 + * @param left 待分区左边界 + * @param right 待分区右边界 + * @return pivotIdx 中轴索引 + */ + private static int partition(int[] nums, int left, int right) { + // 选最后一个值作为中轴 + int pivot = nums[right]; + // 所依right要减一 + int start = left, end = right - 1; + while (start <= end) { + // 寻找左边大于pivot + while (start <= end && nums[start] <= pivot) { + start++; + } + // 寻找右边小于等于pivot + while (start <= end && nums[end] > pivot) { + end--; + } + if (start < end) { + swap(nums, start, end); + } + } + // 此时[left,start-1]的值一定小于pivot=nums[right] + // start一定大于right,所以将start与right交互 + swap(nums, start, right); + return start; + } + + private static void swap(int[] arr, int i, int j) { + int temp = arr[i]; + arr[i] = arr[j]; + arr[j] = temp; + } + +} diff --git a/algorithms/leetcode2/sort/src/main/java/cn/cunchang/sort/QuickSort3.java b/algorithms/leetcode2/sort/src/main/java/cn/cunchang/sort/QuickSort3.java new file mode 100644 index 00000000..5e850ecb --- /dev/null +++ b/algorithms/leetcode2/sort/src/main/java/cn/cunchang/sort/QuickSort3.java @@ -0,0 +1,73 @@ +package cn.cunchang.sort; + +import java.util.Arrays; +import java.util.Random; + +/** + * @author lastwhisper + */ +public class QuickSort3 { + private final static Random random = new Random(System.currentTimeMillis()); + + public static void main(String[] args) { +// int[] arr = {2, 10, 8, 1000}; +// int[] arr = {-9, 78, 0, 23, -567, 70}; +// int[] arr = {-9, 78, 0, 23, 60, 70}; +// int[] arr = {9, 0, -567}; + int[] arr = {49, 38, 65, 97, 76, 13, 27}; + sort(arr, 0, arr.length - 1); + System.out.println(Arrays.toString(arr)); + } + + private static void sort(int[] arr, int left, int right) { + if (left >= right) return; + int pivotIdx = partition(arr, left, right); + // 此时分区pivotIdx左边值小于等于arr[pivotIdx],分区右边大于arr[pivotIdx] + // 对[left,pivotIdx - 1]再次分区 + sort(arr, left, pivotIdx - 1); + // 对[pivotIdx + 1,right]再次分区 + sort(arr, pivotIdx + 1, right); + } + + /** + * @param nums 待分区数组 + * @param left 待分区左边界 + * @param right 待分区右边界 + * @return pivotIdx 中轴索引 + */ + private static int partition(int[] nums, int left, int right) { + int randomIndex = left + random.nextInt(right - left + 1); + swap(nums, left, randomIndex); + + // all in nums[left + 1..le) <= pivot; + // all in nums(ge..right] >= pivot; + int pivot = nums[left]; + int start = left + 1; + int end = right; + + while (true) { + while (start <= end && nums[start] < pivot) { + start++; + } + while (start <= end && nums[end] > pivot) { + end--; + } + if (start >= end) { + break; + } + swap(nums, start, end); + start++; + end--; + } + + swap(nums, left, end); + return end; + } + + private static void swap(int[] arr, int i, int j) { + int temp = arr[i]; + arr[i] = arr[j]; + arr[j] = temp; + } + +} diff --git a/algorithms/leetcode2/sort/src/main/java/cn/cunchang/sort/README.md b/algorithms/leetcode2/sort/src/main/java/cn/cunchang/sort/README.md new file mode 100644 index 00000000..741b6e50 --- /dev/null +++ b/algorithms/leetcode2/sort/src/main/java/cn/cunchang/sort/README.md @@ -0,0 +1,7 @@ +快排 +QuickSort1 第一个元素做分区 +QuickSort2 最后一个元素做分区 +QuickSort3 随机一个元素做分区 +堆排序 +Heap1 数组第一个元素空出 +Heap2 数组第一个元素不空出 \ No newline at end of file diff --git "a/algorithms/leetcode2/sort/src/main/java/cn/cunchang/\345\211\215K\344\270\252\351\253\230\351\242\221\345\205\203\347\264\240_347_\344\270\255\347\255\211/Solution.java" "b/algorithms/leetcode2/sort/src/main/java/cn/cunchang/\345\211\215K\344\270\252\351\253\230\351\242\221\345\205\203\347\264\240_347_\344\270\255\347\255\211/Solution.java" new file mode 100644 index 00000000..4864a528 --- /dev/null +++ "b/algorithms/leetcode2/sort/src/main/java/cn/cunchang/\345\211\215K\344\270\252\351\253\230\351\242\221\345\205\203\347\264\240_347_\344\270\255\347\255\211/Solution.java" @@ -0,0 +1,46 @@ +package cn.cunchang.前K个高频元素_347_中等; + +import cn.cunchang.array.ArrayUtil; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +class Solution { + + public int[] topKFrequent(int[] nums, int k) { + // 记录数字出现的频率 + Map freqMap = new HashMap<>(); + for (int num : nums) { + Integer freq = freqMap.get(num); + if (freq == null) { + freqMap.put(num, 1); + } else { + freqMap.put(num, ++freq); + } + } + // 记录最大频率 + int maxTime = 0; + for (Integer freq : freqMap.values()) { + if (freq > maxTime) { + maxTime = freq; + } + } + + int[] res = new int[k]; + while (k > 0) { + for (Map.Entry entry : freqMap.entrySet()) { + if (entry.getValue() == maxTime) { + res[--k] = entry.getKey(); + } + } + maxTime--; + } + return res; + } + + public static void main(String[] args) { + System.out.println(Arrays.toString(new Solution(). + topKFrequent(ArrayUtil.createArrays(1, 1, 1, 2, 2, 3), 2))); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode2/sort/src/main/java/cn/cunchang/\346\225\260\347\273\204\344\270\255\347\232\204\347\254\254K\344\270\252\346\234\200\345\244\247\345\205\203\347\264\240_215_\344\270\255\347\255\211/Solution.java" "b/algorithms/leetcode2/sort/src/main/java/cn/cunchang/\346\225\260\347\273\204\344\270\255\347\232\204\347\254\254K\344\270\252\346\234\200\345\244\247\345\205\203\347\264\240_215_\344\270\255\347\255\211/Solution.java" new file mode 100644 index 00000000..691dc6f5 --- /dev/null +++ "b/algorithms/leetcode2/sort/src/main/java/cn/cunchang/\346\225\260\347\273\204\344\270\255\347\232\204\347\254\254K\344\270\252\346\234\200\345\244\247\345\205\203\347\264\240_215_\344\270\255\347\255\211/Solution.java" @@ -0,0 +1,65 @@ +package cn.cunchang.数组中的第K个最大元素_215_中等; + +import cn.cunchang.array.ArrayUtil; + +class Solution { + public int findKthLargest(int[] nums, int k) { + // topk的分区的位置 + int targetIdx = nums.length - k; + int left = 0, right = nums.length - 1; + + while (left <= right) { + // 中轴索引值 + int pivotIdx = partition(nums, left, right); + if (targetIdx > pivotIdx) { + // 说明要往右边分 + left = pivotIdx + 1; + } else if (targetIdx < pivotIdx) { + // 说明要往左边分 + right = pivotIdx - 1; + } else { + // 说明分区分到这个topk了 + return nums[pivotIdx]; + } + + } + return -1; + } + + private int partition(int[] nums, int left, int right) { + // 选最后一个值作为中轴 + int pivot = nums[right]; + // 所依right要减一 + int start = left, end = right - 1; + while (start <= end) { + // 寻找左边大于pivot + while (start <= end && nums[start] <= pivot) { + start++; + } + // 寻找右边小于等于pivot + while (start <= end && nums[end] > pivot) { + end--; + } + if (start <= end) { + swap(nums, start, end); + } + } + // 此时[left,start-1]的值一定小于pivot=nums[right] + // start一定大于right,所以将start与right交互 + swap(nums, start, right); + + return start; + } + + private void swap(int[] nums, int start, int end) { + int tmp = nums[start]; + nums[start] = nums[end]; + nums[end] = tmp; + } + + public static void main(String[] args) { + System.out.println(new Solution().findKthLargest(ArrayUtil.createArrays(2,1), 1)); +// System.out.println(new Solution().findKthLargest(ArrayUtil.createArrays(3, 2, 1, 5, 6, 4), 2)); + } + +} \ No newline at end of file diff --git "a/algorithms/leetcode2/sort/src/main/java/cn/cunchang/\346\225\260\347\273\204\344\270\255\347\232\204\347\254\254K\344\270\252\346\234\200\345\244\247\345\205\203\347\264\240_215_\344\270\255\347\255\211/Solution2.java" "b/algorithms/leetcode2/sort/src/main/java/cn/cunchang/\346\225\260\347\273\204\344\270\255\347\232\204\347\254\254K\344\270\252\346\234\200\345\244\247\345\205\203\347\264\240_215_\344\270\255\347\255\211/Solution2.java" new file mode 100644 index 00000000..a0c482e8 --- /dev/null +++ "b/algorithms/leetcode2/sort/src/main/java/cn/cunchang/\346\225\260\347\273\204\344\270\255\347\232\204\347\254\254K\344\270\252\346\234\200\345\244\247\345\205\203\347\264\240_215_\344\270\255\347\255\211/Solution2.java" @@ -0,0 +1,32 @@ +package cn.cunchang.数组中的第K个最大元素_215_中等; + +import cn.cunchang.array.ArrayUtil; + +import java.util.Comparator; +import java.util.PriorityQueue; + +class Solution2 { + public int findKthLargest(int[] nums, int k) { + PriorityQueue heap = new PriorityQueue<>(); + for (int num : nums) { + heap.add(num); + if (heap.size() > k) { + heap.poll(); + } + } + return heap.peek(); + } + + + private void swap(int[] nums, int start, int end) { + int tmp = nums[start]; + nums[start] = nums[end]; + nums[end] = tmp; + } + + public static void main(String[] args) { +// System.out.println(new Solution2().findKthLargest(ArrayUtil.createArrays(2, 1), 1)); + System.out.println(new Solution2().findKthLargest(ArrayUtil.createArrays(3, 2, 1, 5, 6, 4), 2)); + } + +} \ No newline at end of file diff --git "a/algorithms/leetcode2/sort/src/main/java/cn/cunchang/\346\240\271\346\215\256\345\255\227\347\254\246\345\207\272\347\216\260\351\242\221\347\216\207\346\216\222\345\272\217_451_\344\270\255\347\255\211/Solution.java" "b/algorithms/leetcode2/sort/src/main/java/cn/cunchang/\346\240\271\346\215\256\345\255\227\347\254\246\345\207\272\347\216\260\351\242\221\347\216\207\346\216\222\345\272\217_451_\344\270\255\347\255\211/Solution.java" new file mode 100644 index 00000000..d63dbf1a --- /dev/null +++ "b/algorithms/leetcode2/sort/src/main/java/cn/cunchang/\346\240\271\346\215\256\345\255\227\347\254\246\345\207\272\347\216\260\351\242\221\347\216\207\346\216\222\345\272\217_451_\344\270\255\347\255\211/Solution.java" @@ -0,0 +1,51 @@ +package cn.cunchang.根据字符出现频率排序_451_中等; + +import java.util.HashMap; +import java.util.Map; + +class Solution { + public String frequencySort(String s) { + // 记录字母出现的频率 + Map freqMap = new HashMap<>(); + for (int i = 0; i < s.length(); i++) { + Integer freq = freqMap.get(s.charAt(i)); + if (freq == null) { + freqMap.put(s.charAt(i), 1); + } else { + freqMap.put(s.charAt(i), ++freq); + } + } + // 记录最大频率 + int maxTime = 0; + for (Integer freq : freqMap.values()) { + if (freq > maxTime) { + maxTime = freq; + } + } + // 倒序记录出现频率最大的字母 + int size = freqMap.size(); + char[] charFreqOrder = new char[freqMap.size()]; + while (size > 0) { + for (Map.Entry entry : freqMap.entrySet()) { + if (entry.getValue() == maxTime) { + charFreqOrder[--size] = entry.getKey(); + } + } + maxTime--; + } + + StringBuilder sb = new StringBuilder(); + for (int i = charFreqOrder.length - 1; i >= 0; i--) { + Integer freq = freqMap.get(charFreqOrder[i]); + for (int j = 0; j < freq; j++) { + sb.append(charFreqOrder[i]); + } + } + return sb.toString(); + } + + public static void main(String[] args) { + System.out.println(new Solution().frequencySort("tree")); + System.out.println(new Solution().frequencySort("cccaaa")); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode2/sort/src/main/java/cn/cunchang/\351\242\234\350\211\262\345\210\206\347\261\273_75_\344\270\255\347\255\211/Solution.java" "b/algorithms/leetcode2/sort/src/main/java/cn/cunchang/\351\242\234\350\211\262\345\210\206\347\261\273_75_\344\270\255\347\255\211/Solution.java" new file mode 100644 index 00000000..901ce539 --- /dev/null +++ "b/algorithms/leetcode2/sort/src/main/java/cn/cunchang/\351\242\234\350\211\262\345\210\206\347\261\273_75_\344\270\255\347\255\211/Solution.java" @@ -0,0 +1,28 @@ +package cn.cunchang.颜色分类_75_中等; + +import cn.cunchang.array.ArrayUtil; + +import java.util.Arrays; + +class Solution { + public void sortColors(int[] nums) { + // 下标表示对应数字,值表示频率 + int[] freq = new int[3]; + for (int num : nums) { + freq[num]++; + } + int idx = 0; + for (int i = 0; i < freq.length; i++) { + while (freq[i]-- > 0) { + // freq[i]表i这个数字出现了freq[i]次;freq[0]=2,说明0出现了两次 + nums[idx++] = i; + } + } + } + + public static void main(String[] args) { + int[] arrays = ArrayUtil.createArrays(2, 0, 2, 1, 1, 0); + new Solution().sortColors(arrays); + System.out.println(Arrays.toString(arrays)); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode2/src/main/java/cn/cunchang/\346\216\245\351\233\250\346\260\264_42_\345\233\260\351\232\276/README.md" "b/algorithms/leetcode2/src/main/java/cn/cunchang/\346\216\245\351\233\250\346\260\264_42_\345\233\260\351\232\276/README.md" new file mode 100644 index 00000000..8a8ac1ea --- /dev/null +++ "b/algorithms/leetcode2/src/main/java/cn/cunchang/\346\216\245\351\233\250\346\260\264_42_\345\233\260\351\232\276/README.md" @@ -0,0 +1,5 @@ + +Solution1;按照自己的思路写了一遍 +Solution2;精简代码;因为Solution1超时了,,,, +Solution3;备忘录优化 + diff --git "a/algorithms/leetcode2/src/main/java/cn/cunchang/\346\216\245\351\233\250\346\260\264_42_\345\233\260\351\232\276/Solution1.java" "b/algorithms/leetcode2/src/main/java/cn/cunchang/\346\216\245\351\233\250\346\260\264_42_\345\233\260\351\232\276/Solution1.java" new file mode 100644 index 00000000..90f9b691 --- /dev/null +++ "b/algorithms/leetcode2/src/main/java/cn/cunchang/\346\216\245\351\233\250\346\260\264_42_\345\233\260\351\232\276/Solution1.java" @@ -0,0 +1,78 @@ +package cn.cunchang.接雨水_42_困难; + +import org.junit.Assert; + +class Solution1 { + /** + * 题目地址:https://leetcode.cn/problems/container-with-most-water/ + * ------------------------------------------------------------------- + * 思考:只看局部柱子最多盛放水量 + * ------------------------------------------------------------------- + * 思路(磨刀不误砍柴工,先写思路,再写代码): + * 数组n个柱子,当前柱子i,每个柱子可 + * 1、遍历每个柱子,找每个柱子左右最高层数 + * 2、找i左右最高层数 + * (1)i=0 or i=n,左最高和右最高=0;第一个柱子和最后一个柱子不管多高,自身都无法盛水 + * (2)遍历[0,i),记录左最高层数 + * (3)遍历(i,n-1],记录右最高层数 + * 3、i可盛放水量计算 + * (1)如果左最高或右最高=0,说明当前柱子无法盛水,当前柱子盛水量=0 + * (2)i自身高度大于或等于左右高度,当前柱子盛水量=0 + * (3)i最多盛放水量=左右最高里面最低的哪个层数-当前柱子层数 + * 4、[0,n-1]对应盛水量汇总 + * ------------------------------------------------------------------- + * 时间复杂度:O(n^2) + * 空间复杂度:O(1) + */ + public int trap(int[] height) { + if (height == null || height.length == 0) { + return 0; + } + int count = 0; + for (int i = 0; i < height.length; i++) { + KV kv = getMax(i, height); + if (kv.leftMax == 0 || kv.rightMax == 0) { + continue; + } + if (height[i] >= kv.leftMax || height[i] >= kv.rightMax) { + continue; + } + int low = kv.leftMax > kv.rightMax ? kv.rightMax : kv.leftMax; + // i最多盛放水量 + count += low - height[i]; + } + return count; + } + + private KV getMax(int i, int[] height) { + int leftMax = 0; + for (int j = 0; j < i; j++) { + if (leftMax < height[j]) { + leftMax = height[j]; + } + } + int rightMax = 0; + for (int j = height.length - 1; j > i; j--) { + if (rightMax < height[j]) { + rightMax = height[j]; + } + } + return new KV(leftMax, rightMax); + } + + class KV { + int leftMax; + int rightMax; + + public KV(int leftMax, int rightMax) { + this.leftMax = leftMax; + this.rightMax = rightMax; + } + } + + public static void main(String[] args) { +// Assert.assertEquals(2, new Solution1().maxDistance(new int[][]{{1, 0, 1}, {0, 0, 0}, {1, 0, 1}})); + Solution1 solution1 = new Solution1(); + Assert.assertEquals(6, solution1.trap(new int[]{0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1})); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode2/src/main/java/cn/cunchang/\346\216\245\351\233\250\346\260\264_42_\345\233\260\351\232\276/Solution2.java" "b/algorithms/leetcode2/src/main/java/cn/cunchang/\346\216\245\351\233\250\346\260\264_42_\345\233\260\351\232\276/Solution2.java" new file mode 100644 index 00000000..d2f834c4 --- /dev/null +++ "b/algorithms/leetcode2/src/main/java/cn/cunchang/\346\216\245\351\233\250\346\260\264_42_\345\233\260\351\232\276/Solution2.java" @@ -0,0 +1,39 @@ +package cn.cunchang.接雨水_42_困难; + +import org.junit.Assert; + +class Solution2 { + /** + * 题目地址:https://leetcode.cn/problems/container-with-most-water/ + * ------------------------------------------------------------------- + * 思考:只看局部柱子最多盛放水量 + * ------------------------------------------------------------------- + * 思路:基于solution1,精简代码 + * ------------------------------------------------------------------- + * 时间复杂度:O(n^2) + * 空间复杂度:O(1) + */ + public int trap(int[] height) { + int count = 0; + for (int i = 1; i < height.length - 1; i++) { + int leftMax = 0, rightMax = 0; + // 左边最高,j <= i包含自己,后面不用判断小于的情况 + for (int j = 0; j <= i; j++) { + leftMax = Math.max(leftMax, height[j]); + } + // 右边最高,j >= i 包含自己 + for (int j = height.length - 1; j >= i; j--) { + rightMax = Math.max(rightMax, height[j]); + } + count += Math.min(leftMax, rightMax) - height[i]; + } + return count; + } + + public static void main(String[] args) { +// Assert.assertEquals(2, new Solution1().maxDistance(new int[][]{{1, 0, 1}, {0, 0, 0}, {1, 0, 1}})); + Solution2 solution2 = new Solution2(); + Assert.assertEquals(6, solution2.trap(new int[]{0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1})); + + } +} \ No newline at end of file diff --git "a/algorithms/leetcode2/src/main/java/cn/cunchang/\346\216\245\351\233\250\346\260\264_42_\345\233\260\351\232\276/Solution3.java" "b/algorithms/leetcode2/src/main/java/cn/cunchang/\346\216\245\351\233\250\346\260\264_42_\345\233\260\351\232\276/Solution3.java" new file mode 100644 index 00000000..28b4370c --- /dev/null +++ "b/algorithms/leetcode2/src/main/java/cn/cunchang/\346\216\245\351\233\250\346\260\264_42_\345\233\260\351\232\276/Solution3.java" @@ -0,0 +1,31 @@ +package cn.cunchang.接雨水_42_困难; + +import org.junit.Assert; + +class Solution3 { + /** + * 题目地址:https://leetcode.cn/problems/container-with-most-water/ + * ------------------------------------------------------------------- + * 思考:只看局部柱子最多盛放水量 + * ------------------------------------------------------------------- + * 思路:备忘录 + * + * 之前的暴力解法,不是在每个位置 i 都要计算 r_max 和 l_max 吗?我们直接把结果都提前计算出来,别傻不拉几的每次都遍历,这时间复杂度不就降下来了嘛。 + * + * 我们开两个数组 r_max 和 l_max 充当备忘录,l_max[i] 表示位置 i 左边最高的柱子高度,r_max[i] 表示位置 i 右边最高的柱子高度。预先把这两个数组计算好,避免重复计算: + * + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(n) + */ + public int trap(int[] height) { + + + return 0; + } + + public static void main(String[] args) { + Solution3 solution = new Solution3(); + Assert.assertEquals(6, solution.trap(new int[]{0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1})); + } +} \ No newline at end of file diff --git a/algorithms/leetcode2/tree/pom.xml b/algorithms/leetcode2/tree/pom.xml new file mode 100644 index 00000000..601f6b08 --- /dev/null +++ b/algorithms/leetcode2/tree/pom.xml @@ -0,0 +1,23 @@ + + + 4.0.0 + + cn.cunchang + tree + 1.0-SNAPSHOT + + + 8 + 8 + + + + + leetcode2-common + cn.cucnhang + 1.0-SNAPSHOT + + + \ No newline at end of file diff --git "a/algorithms/leetcode2/tree/src/main/java/cn/cunchang/\344\272\214\345\217\211\346\240\221\345\261\225\345\274\200\344\270\272\351\223\276\350\241\250_114_\344\270\255\347\255\211/Solution.java" "b/algorithms/leetcode2/tree/src/main/java/cn/cunchang/\344\272\214\345\217\211\346\240\221\345\261\225\345\274\200\344\270\272\351\223\276\350\241\250_114_\344\270\255\347\255\211/Solution.java" new file mode 100644 index 00000000..8ad66b91 --- /dev/null +++ "b/algorithms/leetcode2/tree/src/main/java/cn/cunchang/\344\272\214\345\217\211\346\240\221\345\261\225\345\274\200\344\270\272\351\223\276\350\241\250_114_\344\270\255\347\255\211/Solution.java" @@ -0,0 +1,40 @@ +package cn.cunchang.二叉树展开为链表_114_中等; + +import cn.cunchang.tree.TreeNode; +import cn.cunchang.tree.TreeUtil; + +/** + * @author cunchang + * @date 2022/6/20 6:41 PM + */ +public class Solution { + + public void flatten(TreeNode root) { + if (root == null) { + return; + } + + flatten(root.left); + flatten(root.right); + // 原先左子树 + TreeNode left = root.left; + // 原先右子树 + TreeNode right = root.right; + // 将左子树作为当前节点的右子树 + root.left = null; + root.right = left; + // 将当前右子树(原先的左子树)的末端指向原先的右子树 + TreeNode p = root;//这里为什么是root?left行不行;left也可以,但是left可能为空需要判空 + while (p.right!=null){ + p = p.right; + } + // + p.right = right; + } + + public static void main(String[] args) { + TreeNode node = TreeUtil.createTree(1, 2, 5, 3, 4, null, 6); + new Solution().flatten(node); + TreeUtil.printLevelOrder(node); + } +} diff --git "a/algorithms/leetcode2/tree/src/main/java/cn/cunchang/\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206_144_\347\256\200\345\215\225/Solution.java" "b/algorithms/leetcode2/tree/src/main/java/cn/cunchang/\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206_144_\347\256\200\345\215\225/Solution.java" new file mode 100644 index 00000000..e29285d9 --- /dev/null +++ "b/algorithms/leetcode2/tree/src/main/java/cn/cunchang/\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206_144_\347\256\200\345\215\225/Solution.java" @@ -0,0 +1,41 @@ +package cn.cunchang.二叉树的前序遍历_144_简单; + +import cn.cunchang.tree.TreeNode; + +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +class Solution { + + public List preorderTraversal(TreeNode root) { + List preOrder = new ArrayList<>(); + Stack stack = new Stack<>(); + stack.push(root); + while (!stack.isEmpty()) { + TreeNode treeNode = stack.pop(); + if (treeNode != null) { + preOrder.add(treeNode.val); + // 先进后出,保证left先执行 + stack.push(treeNode.right); + stack.push(treeNode.left); + } + } + return preOrder; + } + +// public List preorderTraversal(TreeNode root) { +// List preOrder = new ArrayList<>(); +// preorderTraversal(root, preOrder); +// return preOrder; +// } +// +// public void preorderTraversal(TreeNode root, List preOrder) { +// if (root == null) { +// return; +// } +// preOrder.add(root.val); +// preorderTraversal(root.left, preOrder); +// preorderTraversal(root.right, preOrder); +// } +} \ No newline at end of file diff --git "a/algorithms/leetcode2/tree/src/main/java/cn/cunchang/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\345\271\263\345\235\207\345\200\274_637_\347\256\200\345\215\225/Solution.java" "b/algorithms/leetcode2/tree/src/main/java/cn/cunchang/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\345\271\263\345\235\207\345\200\274_637_\347\256\200\345\215\225/Solution.java" new file mode 100644 index 00000000..558eacd0 --- /dev/null +++ "b/algorithms/leetcode2/tree/src/main/java/cn/cunchang/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\345\271\263\345\235\207\345\200\274_637_\347\256\200\345\215\225/Solution.java" @@ -0,0 +1,38 @@ +package cn.cunchang.二叉树的层平均值_637_简单; + +import cn.cunchang.tree.TreeNode; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +class Solution { + public List averageOfLevels(TreeNode root) { + if (root == null) { + return new ArrayList<>(); + } + List resultList = new ArrayList<>(); + + Queue queue = new LinkedList<>(); + queue.offer(root); + + while (!queue.isEmpty()) { + double result = 0.0; + int levelCount = queue.size(); + for (int i = 0; i < levelCount; i++) { + TreeNode treeNode = queue.poll(); + result += treeNode.val; + if (treeNode.left != null) { + queue.offer(treeNode.left); + } + if (treeNode.right != null) { + queue.offer(treeNode.right); + } + } + resultList.add(result/levelCount); + } + return resultList; + } + +} \ No newline at end of file diff --git "a/algorithms/leetcode2/tree/src/main/java/cn/cunchang/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\244\247\346\267\261\345\272\246_104_\347\256\200\345\215\225/Solution.java" "b/algorithms/leetcode2/tree/src/main/java/cn/cunchang/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\244\247\346\267\261\345\272\246_104_\347\256\200\345\215\225/Solution.java" new file mode 100644 index 00000000..b6292a02 --- /dev/null +++ "b/algorithms/leetcode2/tree/src/main/java/cn/cunchang/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\244\247\346\267\261\345\272\246_104_\347\256\200\345\215\225/Solution.java" @@ -0,0 +1,17 @@ +package cn.cunchang.二叉树的最大深度_104_简单; + + +import cn.cunchang.tree.TreeNode; + +class Solution { + public int maxDepth(TreeNode root) { + if (root == null) { + return 0; + } + + int leftDep = maxDepth(root.left); + int rightDep = maxDepth(root.right); + + return Math.max(leftDep, rightDep) + 1; + } +} \ No newline at end of file diff --git "a/algorithms/leetcode2/tree/src/main/java/cn/cunchang/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\244\247\346\267\261\345\272\246_104_\347\256\200\345\215\225/Solution2.java" "b/algorithms/leetcode2/tree/src/main/java/cn/cunchang/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\244\247\346\267\261\345\272\246_104_\347\256\200\345\215\225/Solution2.java" new file mode 100644 index 00000000..f23e92a9 --- /dev/null +++ "b/algorithms/leetcode2/tree/src/main/java/cn/cunchang/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\244\247\346\267\261\345\272\246_104_\347\256\200\345\215\225/Solution2.java" @@ -0,0 +1,31 @@ +package cn.cunchang.二叉树的最大深度_104_简单; + + +import cn.cunchang.tree.TreeNode; + +class Solution2 { + int res = 0; + int depth = 0; + + public int maxDepth(TreeNode root) { + maxDepth2(root); + return res; + } + + public void maxDepth2(TreeNode root) { + if (root == null) { + return; + } + + // 进入节点深度增加 + depth++; + // 当前是最后一个节点了,记录一下最大位置 + if (root.left == null && root.right == null) { + res = Math.max(res, depth); + } + maxDepth(root.left); + maxDepth(root.right); + // 离开当前节点,深度减少 + depth--; + } +} \ No newline at end of file diff --git "a/algorithms/leetcode2/tree/src/main/java/cn/cunchang/\344\272\214\345\217\211\346\240\221\347\232\204\347\233\264\345\276\204_543_\347\256\200\345\215\225/Solution.java" "b/algorithms/leetcode2/tree/src/main/java/cn/cunchang/\344\272\214\345\217\211\346\240\221\347\232\204\347\233\264\345\276\204_543_\347\256\200\345\215\225/Solution.java" new file mode 100644 index 00000000..22fd643c --- /dev/null +++ "b/algorithms/leetcode2/tree/src/main/java/cn/cunchang/\344\272\214\345\217\211\346\240\221\347\232\204\347\233\264\345\276\204_543_\347\256\200\345\215\225/Solution.java" @@ -0,0 +1,22 @@ +package cn.cunchang.二叉树的直径_543_简单; + +import cn.cunchang.tree.TreeNode; + +class Solution { + int res = 1; + + public int diameterOfBinaryTree(TreeNode root) { + diameterOfBinaryTree0(root); + return res - 1; + } + + public int diameterOfBinaryTree0(TreeNode root) { + if (root == null) { + return 0; + } + int leftDep = diameterOfBinaryTree0(root.left); + int rightDep = diameterOfBinaryTree0(root.right); + res = Math.max(leftDep + rightDep + 1, res); + return Math.max(leftDep, rightDep) + 1; + } +} \ No newline at end of file diff --git "a/algorithms/leetcode2/tree/src/main/java/cn/cunchang/\344\273\216\344\270\255\345\272\217\344\270\216\345\220\216\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221_106_\344\270\255\347\255\211/Solution.java" "b/algorithms/leetcode2/tree/src/main/java/cn/cunchang/\344\273\216\344\270\255\345\272\217\344\270\216\345\220\216\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221_106_\344\270\255\347\255\211/Solution.java" new file mode 100644 index 00000000..f82d684a --- /dev/null +++ "b/algorithms/leetcode2/tree/src/main/java/cn/cunchang/\344\273\216\344\270\255\345\272\217\344\270\216\345\220\216\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221_106_\344\270\255\347\255\211/Solution.java" @@ -0,0 +1,49 @@ +package cn.cunchang.从中序与后序遍历序列构造二叉树_106_中等; + +import cn.cunchang.array.ArrayUtil; +import cn.cunchang.tree.TreeNode; +import cn.cunchang.tree.TreeUtil; + +/** + * @author cunchang + * @date 2022/6/21 8:42 PM + */ +class Solution { + public TreeNode buildTree(int[] inorder, int[] postorder) { + return buildTree0(inorder, 0, inorder.length - 1, + postorder, 0, postorder.length - 1); + } + + public TreeNode buildTree0(int[] inorder, int inLeft, int inRight, + int[] postorder, int postLeft, int postRight) { + if (postLeft > postRight) { + return null; + } + // 找到根节点postRight,并构造根节点 + TreeNode treeNode = new TreeNode(postorder[postRight]); + // 找到根节点在inorder的下标index + int postOrderIndex = 0; + for (int i = inLeft; i <= inRight; i++) { + if (postorder[postRight] == inorder[i]) { + postOrderIndex = i; + break; + } + } + // 计算根节点右子树的节点数 + int leftCount = inRight - postOrderIndex; + // 递归构造根节点的右子树 + // 右子树在inorder[postOrderIndex+1,inRight],postorder[postRight-leftCount,postRight-1] + treeNode.right = buildTree0(inorder, postOrderIndex + 1, inRight, + postorder, postRight - leftCount , postRight-1); + // 递归构造根节点的左子树 + // 左子树在inorder[inLeft,postOrderIndex-1],postorder[postLeft,leftCount-1] + treeNode.left = buildTree0(inorder, inLeft, postOrderIndex - 1, + postorder, postLeft, postRight - leftCount - 1); + return treeNode; + } + + public static void main(String[] args) { + TreeUtil.printLevelOrder(new Solution().buildTree( + ArrayUtil.createArrays(9, 3, 15, 20, 7), ArrayUtil.createArrays(9, 15, 7, 20, 3))); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode2/tree/src/main/java/cn/cunchang/\344\273\216\344\270\255\345\272\217\344\270\216\345\220\216\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221_106_\344\270\255\347\255\211/Solution2.java" "b/algorithms/leetcode2/tree/src/main/java/cn/cunchang/\344\273\216\344\270\255\345\272\217\344\270\216\345\220\216\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221_106_\344\270\255\347\255\211/Solution2.java" new file mode 100644 index 00000000..29350ce2 --- /dev/null +++ "b/algorithms/leetcode2/tree/src/main/java/cn/cunchang/\344\273\216\344\270\255\345\272\217\344\270\216\345\220\216\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221_106_\344\270\255\347\255\211/Solution2.java" @@ -0,0 +1,56 @@ +package cn.cunchang.从中序与后序遍历序列构造二叉树_106_中等; + +import cn.cunchang.array.ArrayUtil; +import cn.cunchang.tree.TreeNode; +import cn.cunchang.tree.TreeUtil; + +import java.util.HashMap; + +/** + * @author cunchang + * @date 2022/6/21 8:42 PM + */ +class Solution2 { + + public TreeNode buildTree(int[] inorder, int[] postorder) { + HashMap inorderIndexMap = new HashMap<>(); + for (int i = 0; i < inorder.length; i++) { + inorderIndexMap.put(inorder[i], i); + } + return buildTree0(inorder, 0, inorder.length - 1, + postorder, 0, postorder.length - 1, inorderIndexMap); + } + + public TreeNode buildTree0(int[] inorder, int inLeft, int inRight, + int[] postorder, int postLeft, int postRight, HashMap inorderIndexMap) { + if (postLeft > postRight) { + return null; + } + // 找到根节点postRight,并构造根节点 + TreeNode treeNode = new TreeNode(postorder[postRight]); + // 找到根节点在inorder的下标index + int postOrderIndex = inorderIndexMap.get(postorder[postRight]); +// for (int i = inLeft; i <= inRight; i++) { +// if (postorder[postRight] == inorder[i]) { +// postOrderIndex = i; +// break; +// } +// } + // 计算根节点右子树的节点数 + int leftCount = inRight - postOrderIndex; + // 递归构造根节点的右子树 + // 的右子树在在inorder[postOrderIndex+1,inRight],postorder[postRight-leftCount,postRight-1] + treeNode.right = buildTree0(inorder, postOrderIndex + 1, inRight, + postorder, postRight - leftCount, postRight - 1, inorderIndexMap); + // 递归构造根节点的左子树 + // 左子树在在inorder[inLeft,postOrderIndex-1],postorder[postLeft,leftCount-1] + treeNode.left = buildTree0(inorder, inLeft, postOrderIndex - 1, + postorder, postLeft, postRight - leftCount - 1, inorderIndexMap); + return treeNode; + } + + public static void main(String[] args) { + TreeUtil.printLevelOrder(new Solution2().buildTree( + ArrayUtil.createArrays(9, 3, 15, 20, 7), ArrayUtil.createArrays(9, 15, 7, 20, 3))); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode2/tree/src/main/java/cn/cunchang/\344\273\216\345\211\215\345\272\217\344\270\216\344\270\255\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221_105_\344\270\255\347\255\211/Solution.java" "b/algorithms/leetcode2/tree/src/main/java/cn/cunchang/\344\273\216\345\211\215\345\272\217\344\270\216\344\270\255\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221_105_\344\270\255\347\255\211/Solution.java" new file mode 100644 index 00000000..03f0a712 --- /dev/null +++ "b/algorithms/leetcode2/tree/src/main/java/cn/cunchang/\344\273\216\345\211\215\345\272\217\344\270\216\344\270\255\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221_105_\344\270\255\347\255\211/Solution.java" @@ -0,0 +1,51 @@ +package cn.cunchang.从前序与中序遍历序列构造二叉树_105_中等; + +import cn.cunchang.array.ArrayUtil; +import cn.cunchang.tree.TreeNode; +import cn.cunchang.tree.TreeUtil; + +/** + * @author cunchang + * @date 2022/6/20 6:41 PM + */ +class Solution { + + public TreeNode buildTree(int[] preorder, int[] inorder) { + return buildTree0(preorder, 0, preorder.length - 1, + inorder, 0, inorder.length - 1); + } + + public TreeNode buildTree0(int[] preorder, int preLeft, int preRight, + int[] inorder, int inLeft, int inRight) { + // 递归终止 + if (preLeft > preRight) { + return null; + } + + // 1、preLeft是preorder的根节点,对根节点进行构造 + TreeNode root = new TreeNode(preorder[preLeft]); + // 2、根节点在inorder的下标为index + int inOrderIndex = 0; + for (int i = inLeft; i <= inRight; i++) { + if (inorder[i] == preorder[preLeft]) { + inOrderIndex = i; + break; + } + } + // 3、根节点的左子树节点个数leftCount = index-inLeft,根节点左子树在preorder的范围[preLeft+1,preLeft+leftCount], + // 根节点已经构造过了,所以从preLeft+1开始,至左子树个数preLeft+leftCount结束; + // 在inorder的范围[inLeft,index-1] + int leftCount = inOrderIndex - inLeft; + root.left = buildTree0(preorder, preLeft + 1, preLeft + leftCount, + inorder, inLeft, inOrderIndex - 1); + // 4、根节点右子树在preorder的范围[preLeft+leftCount+1,preRight],在inorder的范围[index+1,inRight] + root.right = buildTree0(preorder, preLeft + leftCount + 1, preRight, + inorder, inOrderIndex + 1, inRight); + return root; + } + + public static void main(String[] args) { + TreeUtil.printLevelOrder(new Solution().buildTree( + ArrayUtil.createArrays(3, 9, 20, 15, 7), ArrayUtil.createArrays(9, 3, 15, 20, 7))); + } +} diff --git "a/algorithms/leetcode2/tree/src/main/java/cn/cunchang/\345\210\240\347\202\271\346\210\220\346\236\227_1110_\347\256\200\345\215\225/Solution.java" "b/algorithms/leetcode2/tree/src/main/java/cn/cunchang/\345\210\240\347\202\271\346\210\220\346\236\227_1110_\347\256\200\345\215\225/Solution.java" new file mode 100644 index 00000000..7e88ddb3 --- /dev/null +++ "b/algorithms/leetcode2/tree/src/main/java/cn/cunchang/\345\210\240\347\202\271\346\210\220\346\236\227_1110_\347\256\200\345\215\225/Solution.java" @@ -0,0 +1,66 @@ +package cn.cunchang.删点成林_1110_简单; + +import cn.cunchang.array.ArrayUtil; +import cn.cunchang.tree.TreeNode; +import cn.cunchang.tree.TreeUtil; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +class Solution { + List result = new ArrayList<>(); + + public List delNodes(TreeNode root, int[] to_delete) { + Set deleteSet = new HashSet<>(); + for (int deleteNum : to_delete) { + deleteSet.add(deleteNum); + } + // 根节点不需要删除,就加入到返回值,需要删除就不管了 + if (!deleteSet.contains(root.val)) { + result.add(root); + } + delNodes0(root, deleteSet); + return result; + } + + public boolean delNodes0(TreeNode root, Set deleteSet) { + if (root == null) { + return false; + } + + boolean leftDelete = delNodes0(root.left, deleteSet); + if (leftDelete) { + root.left = null; + } + boolean rightDelete = delNodes0(root.right, deleteSet); + if (rightDelete) { + root.right = null; + } + if (deleteSet.contains(root.val)) { + // 当前节点是需要删除的节点 + // 那么当前节点的左节点,不为空的话,就是一个单独的森林 + if (root.left != null) { + result.add(root.left); + } + // 当前节点的右节点,不为空的话,就是一个单独的森林 + if (root.right != null) { + result.add(root.right); + } + root.left = null; + root.right = null; + // 通知上层节点把自己删了 + return true; + } + return false; + } + + public static void main(String[] args) { + List treeNodeList = new Solution().delNodes(TreeUtil.createTree(1, 2, 3, 4, 5, 6, 7), + ArrayUtil.createArrays(3)); + for (TreeNode treeNode : treeNodeList) { + TreeUtil.printLevelOrder(treeNode); + } + } +} \ No newline at end of file diff --git "a/algorithms/leetcode2/tree/src/main/java/cn/cunchang/\345\241\253\345\205\205\346\257\217\344\270\252\350\212\202\347\202\271\347\232\204\344\270\213\344\270\200\344\270\252\345\217\263\344\276\247\350\212\202\347\202\271\346\214\207\351\222\210_116_\344\270\255\347\255\211/Solution.java" "b/algorithms/leetcode2/tree/src/main/java/cn/cunchang/\345\241\253\345\205\205\346\257\217\344\270\252\350\212\202\347\202\271\347\232\204\344\270\213\344\270\200\344\270\252\345\217\263\344\276\247\350\212\202\347\202\271\346\214\207\351\222\210_116_\344\270\255\347\255\211/Solution.java" new file mode 100644 index 00000000..1fa42bfa --- /dev/null +++ "b/algorithms/leetcode2/tree/src/main/java/cn/cunchang/\345\241\253\345\205\205\346\257\217\344\270\252\350\212\202\347\202\271\347\232\204\344\270\213\344\270\200\344\270\252\345\217\263\344\276\247\350\212\202\347\202\271\346\214\207\351\222\210_116_\344\270\255\347\255\211/Solution.java" @@ -0,0 +1,48 @@ +package cn.cunchang.填充每个节点的下一个右侧节点指针_116_中等; + +/** + * @author cunchang + * @date 2022/6/20 6:33 PM + */ +public class Solution { + public Node connect(Node root) { + if (root == null) { + return null; + } + connect2(root.left, root.right); + return root; + } + + public void connect2(Node node1, Node node2) { + if (node1 == null || node2 == null) { + return; + } + node1.next = node2; + + connect2(node1.left,node1.right); + connect2(node2.left,node2.right); + // 跨节点相连 + connect2(node1.right,node2.left); + } + + class Node { + public int val; + public Node left; + public Node right; + public Node next; + + public Node() { + } + + public Node(int _val) { + val = _val; + } + + public Node(int _val, Node _left, Node _right, Node _next) { + val = _val; + left = _left; + right = _right; + next = _next; + } + } +} diff --git "a/algorithms/leetcode2/tree/src/main/java/cn/cunchang/\345\257\271\347\247\260\344\272\214\345\217\211\346\240\221_101_\347\256\200\345\215\225/Solution.java" "b/algorithms/leetcode2/tree/src/main/java/cn/cunchang/\345\257\271\347\247\260\344\272\214\345\217\211\346\240\221_101_\347\256\200\345\215\225/Solution.java" new file mode 100644 index 00000000..4372bf7b --- /dev/null +++ "b/algorithms/leetcode2/tree/src/main/java/cn/cunchang/\345\257\271\347\247\260\344\272\214\345\217\211\346\240\221_101_\347\256\200\345\215\225/Solution.java" @@ -0,0 +1,25 @@ +package cn.cunchang.对称二叉树_101_简单; + +import cn.cunchang.tree.TreeNode; + +class Solution { + public boolean isSymmetric(TreeNode root) { + if (root == null) { + return true; + } + return isSymmetric0(root.left, root.right); + } + + public boolean isSymmetric0(TreeNode p1, TreeNode p2) { + if (p1 == null && p2 == null) { + return true; + } + if (p1 == null || p2 == null) { + return false; + } + if (p1.val != p2.val) { + return false; + } + return isSymmetric0(p1.left, p2.right) && isSymmetric0(p1.right, p2.left); + } +} \ No newline at end of file diff --git "a/algorithms/leetcode2/tree/src/main/java/cn/cunchang/\345\271\263\350\241\241\344\272\214\345\217\211\346\240\221_110_\347\256\200\345\215\225/Solution.java" "b/algorithms/leetcode2/tree/src/main/java/cn/cunchang/\345\271\263\350\241\241\344\272\214\345\217\211\346\240\221_110_\347\256\200\345\215\225/Solution.java" new file mode 100644 index 00000000..09ce8f7e --- /dev/null +++ "b/algorithms/leetcode2/tree/src/main/java/cn/cunchang/\345\271\263\350\241\241\344\272\214\345\217\211\346\240\221_110_\347\256\200\345\215\225/Solution.java" @@ -0,0 +1,21 @@ +package cn.cunchang.平衡二叉树_110_简单; + +import cn.cunchang.tree.TreeNode; + +class Solution { + public boolean isBalanced(TreeNode root) { + return isBalanced0(root) != -1; + } + + public int isBalanced0(TreeNode root) { + if (root == null) { + return 0; + } + int leftDep = isBalanced0(root.left); + int rightDep = isBalanced0(root.right); + if (leftDep == -1 || rightDep == -1 || Math.abs(leftDep - rightDep) > 1) { + return -1; + } + return Math.max(leftDep, rightDep) + 1; + } +} \ No newline at end of file diff --git "a/algorithms/leetcode2/tree/src/main/java/cn/cunchang/\346\234\200\345\244\247\344\272\214\345\217\211\346\240\221_654_\344\270\255\347\255\211/Solution.java" "b/algorithms/leetcode2/tree/src/main/java/cn/cunchang/\346\234\200\345\244\247\344\272\214\345\217\211\346\240\221_654_\344\270\255\347\255\211/Solution.java" new file mode 100644 index 00000000..52cc6d44 --- /dev/null +++ "b/algorithms/leetcode2/tree/src/main/java/cn/cunchang/\346\234\200\345\244\247\344\272\214\345\217\211\346\240\221_654_\344\270\255\347\255\211/Solution.java" @@ -0,0 +1,35 @@ +package cn.cunchang.最大二叉树_654_中等; + +import cn.cunchang.tree.TreeNode; + +/** + * @author cunchang + * @date 2022/6/20 7:50 PM + */ +class Solution { + public TreeNode constructMaximumBinaryTree(int[] nums) { + return constructMaximumBinaryTree0(nums, 0, nums.length - 1); + } + + public TreeNode constructMaximumBinaryTree0(int[] nums, int left, int right) { + if (left > right) { + return null; + } + // 找到最大值构造根节点 + int max = Integer.MIN_VALUE; + int index = -1; + for (int i = left; i <= right; i++) { + if (max < nums[i]) { + index = i; + max = nums[i]; + } + + } + TreeNode treeNode = new TreeNode(max); + // 再以最大值下标为界限,构造左右子树 + treeNode.left = constructMaximumBinaryTree0(nums, left, index - 1); + treeNode.right = constructMaximumBinaryTree0(nums, index + 1, right); + return treeNode; + } + +} \ No newline at end of file diff --git "a/algorithms/leetcode2/tree/src/main/java/cn/cunchang/\346\240\271\346\215\256\345\211\215\345\272\217\345\222\214\345\220\216\345\272\217\351\201\215\345\216\206\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221_889_\344\270\255\347\255\211/Solution.java" "b/algorithms/leetcode2/tree/src/main/java/cn/cunchang/\346\240\271\346\215\256\345\211\215\345\272\217\345\222\214\345\220\216\345\272\217\351\201\215\345\216\206\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221_889_\344\270\255\347\255\211/Solution.java" new file mode 100644 index 00000000..bdb765a0 --- /dev/null +++ "b/algorithms/leetcode2/tree/src/main/java/cn/cunchang/\346\240\271\346\215\256\345\211\215\345\272\217\345\222\214\345\220\216\345\272\217\351\201\215\345\216\206\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221_889_\344\270\255\347\255\211/Solution.java" @@ -0,0 +1,25 @@ +package cn.cunchang.根据前序和后序遍历构造二叉树_889_中等; + +import cn.cunchang.tree.TreeNode; + +/** + * @author cunchang + * @date 2022/6/21 11:59 PM + */ +class Solution { + public TreeNode constructFromPrePost(int[] preorder, int[] postorder) { + return constructFromPrePost0(preorder, 0, preorder.length - 1, postorder, 0, postorder.length - 1); + } + + private TreeNode constructFromPrePost0(int[] preorder, int preLeft, int preRight, int[] postorder, int postLeft, int postRight) { + if (preLeft > preRight) { + return null; + } + // 构造根节点 + TreeNode root = new TreeNode(preorder[preLeft]); + // 把先序遍历的第二个值当做左子树 + + + return null; + } +} diff --git "a/algorithms/leetcode2/tree/src/main/java/cn/cunchang/\347\277\273\350\275\254\344\272\214\345\217\211\346\240\221_226_\347\256\200\345\215\225/Solution.java" "b/algorithms/leetcode2/tree/src/main/java/cn/cunchang/\347\277\273\350\275\254\344\272\214\345\217\211\346\240\221_226_\347\256\200\345\215\225/Solution.java" new file mode 100644 index 00000000..212b213c --- /dev/null +++ "b/algorithms/leetcode2/tree/src/main/java/cn/cunchang/\347\277\273\350\275\254\344\272\214\345\217\211\346\240\221_226_\347\256\200\345\215\225/Solution.java" @@ -0,0 +1,42 @@ +package cn.cunchang.翻转二叉树_226_简单; + +import cn.cunchang.tree.TreeNode; + +/** + * @author cunchang + * @date 2022/6/20 6:28 PM + */ +class Solution { + public TreeNode invertTree(TreeNode root) { + invertTree2(root); + return root; + } + + /** + * 通过遍历解决 + */ + public void invertTree2(TreeNode root) { + if (root == null) { + return; + } + // 前序交换 + TreeNode tmp = root.left; + root.left = root.right; + root.right = tmp; + + invertTree2(root.left); + invertTree2(root.right); + } + +// public void invertTree2(TreeNode root) { +// if (root == null) { +// return; +// } +// invertTree2(root.left); +// invertTree2(root.right); +// // 后序交换 +// TreeNode tmp = root.left; +// root.left = root.right; +// root.right = tmp; +// } +} \ No newline at end of file diff --git "a/algorithms/leetcode2/tree/src/main/java/cn/cunchang/\347\277\273\350\275\254\344\272\214\345\217\211\346\240\221_226_\347\256\200\345\215\225/Solution2.java" "b/algorithms/leetcode2/tree/src/main/java/cn/cunchang/\347\277\273\350\275\254\344\272\214\345\217\211\346\240\221_226_\347\256\200\345\215\225/Solution2.java" new file mode 100644 index 00000000..45ebe11a --- /dev/null +++ "b/algorithms/leetcode2/tree/src/main/java/cn/cunchang/\347\277\273\350\275\254\344\272\214\345\217\211\346\240\221_226_\347\256\200\345\215\225/Solution2.java" @@ -0,0 +1,23 @@ +package cn.cunchang.翻转二叉树_226_简单; + +import cn.cunchang.tree.TreeNode; + +/** + * @author cunchang + * @date 2022/6/20 6:28 PM + */ +class Solution2 { + /** + * 通过分解解决 + */ + public TreeNode invertTree(TreeNode root) { + if (root == null) { + return null; + } + TreeNode left = invertTree(root.left); + TreeNode right = invertTree(root.right); + root.left = right; + root.right = left; + return root; + } +} \ No newline at end of file diff --git "a/algorithms/leetcode2/tree/src/main/java/cn/cunchang/\350\267\257\345\276\204\346\200\273\345\222\214_III_437_\344\270\255\347\255\211/Solution.java" "b/algorithms/leetcode2/tree/src/main/java/cn/cunchang/\350\267\257\345\276\204\346\200\273\345\222\214_III_437_\344\270\255\347\255\211/Solution.java" new file mode 100644 index 00000000..38ffe573 --- /dev/null +++ "b/algorithms/leetcode2/tree/src/main/java/cn/cunchang/\350\267\257\345\276\204\346\200\273\345\222\214_III_437_\344\270\255\347\255\211/Solution.java" @@ -0,0 +1,38 @@ +package cn.cunchang.路径总和_III_437_中等; + +import cn.cunchang.tree.TreeNode; +import cn.cunchang.tree.TreeUtil; + +class Solution { + + public int pathSum(TreeNode root, int sum) { + if (root == null) { + return 0; + } + int res = findPathSum(root, sum); + res += pathSum(root.left, sum); + res += pathSum(root.right, sum); + return res; + } + + // 从node找到路径和等于sum的数量 + public int findPathSum(TreeNode node, int sum) { + if (node == null) { + return 0; + } + int res = 0; + sum -= node.val; + if (sum == 0) { + res++; + } + res += findPathSum(node.left, sum); + res += findPathSum(node.right, sum); + + return res; + } + + public static void main(String[] args) { + System.out.println(new Solution().pathSum( + TreeUtil.createTree(10, 5, -3, 3, 2, null, 11, 3, -2, null, 1), 8)); + } +} \ No newline at end of file diff --git a/algorithms/niuke/pom.xml b/algorithms/niuke/pom.xml new file mode 100644 index 00000000..4884603b --- /dev/null +++ b/algorithms/niuke/pom.xml @@ -0,0 +1,20 @@ + + + + algorithms + cn.lastwhisper + 1.0-SNAPSHOT + + 4.0.0 + + cn.cunchang + niuke + + + 8 + 8 + + + \ No newline at end of file diff --git a/algorithms/niuke/src/main/java/cn/cunchang/od/DemoMain1.java b/algorithms/niuke/src/main/java/cn/cunchang/od/DemoMain1.java new file mode 100644 index 00000000..492077e0 --- /dev/null +++ b/algorithms/niuke/src/main/java/cn/cunchang/od/DemoMain1.java @@ -0,0 +1,17 @@ +package cn.cunchang.od; + +// 本题为考试单行多行输入输出规范示例,无需提交,不计分。 + +import java.math.BigDecimal; +import java.util.Scanner; + +public class DemoMain1 { + public static void main(String[] args) { + Scanner in = new Scanner(System.in); + while (in.hasNextInt()) {// 注意,如果输入是多个测试用例,请通过while循环处理多个测试用例 + BigDecimal a = in.nextBigDecimal(); + BigDecimal b = in.nextBigDecimal(); + System.out.println(a.add(b)); + } + } +} \ No newline at end of file diff --git a/algorithms/niuke/src/main/java/cn/cunchang/od/DemoMain2.java b/algorithms/niuke/src/main/java/cn/cunchang/od/DemoMain2.java new file mode 100644 index 00000000..ea59823c --- /dev/null +++ b/algorithms/niuke/src/main/java/cn/cunchang/od/DemoMain2.java @@ -0,0 +1,17 @@ +package cn.cunchang.od;// 本题为考试多行输入输出规范示例,无需提交,不计分。 +import java.util.Scanner; + +public class DemoMain2 { + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + int n = sc.nextInt(); + int ans = 0, x; + for(int i = 0; i < n; i++){ + for(int j = 0; j < n; j++){ + x = sc.nextInt(); + ans += x; + } + } + System.out.println(ans); + } +} \ No newline at end of file diff --git a/algorithms/niuke/src/main/java/cn/cunchang/od/Main1.java b/algorithms/niuke/src/main/java/cn/cunchang/od/Main1.java new file mode 100644 index 00000000..9ec563ab --- /dev/null +++ b/algorithms/niuke/src/main/java/cn/cunchang/od/Main1.java @@ -0,0 +1,47 @@ +package cn.cunchang.od; + + +import java.util.*; + +public class Main1 { + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + int xmH = sc.nextInt();//小明身高 + int N = sc.nextInt();// 同学数量 + + // 同学身高 + List hList = new ArrayList<>(N); + for (int i = 0; i < N; i++) { + hList.add(sc.nextInt()); + } + // 计算各个同学的身高差,按差升序,放到TreeMapList<差,同学身高list> + Map> diffSortMapList = new TreeMap<>(); + for (Integer height : hList) { + int subDiff = Math.abs(xmH - height); + List someList = diffSortMapList.get(subDiff); + if (someList == null || someList.isEmpty()) { + someList = new ArrayList<>(); + diffSortMapList.put(subDiff, someList); + } + someList.add(height); + } + + // 返回结果 + List result = new ArrayList<>(N); + + // 对同学身高list局部排序 + for (Map.Entry> entry : diffSortMapList.entrySet()) { + List someList = entry.getValue(); + Collections.sort(someList); + result.addAll(someList); + } + for (int i = 0; i < result.size(); i++) { + if (i == result.size() - 1) { + System.out.print(result.get(i)); + } else { + System.out.print(result.get(i) + " "); + } + } + } + +} \ No newline at end of file diff --git a/algorithms/niuke/src/main/java/cn/cunchang/od/Main2.java b/algorithms/niuke/src/main/java/cn/cunchang/od/Main2.java new file mode 100644 index 00000000..a514a449 --- /dev/null +++ b/algorithms/niuke/src/main/java/cn/cunchang/od/Main2.java @@ -0,0 +1,123 @@ +package cn.cunchang.od; + + +import java.util.*; + +public class Main2 { + // 映射与反映射 j=11,q=12,k=13,a=14 + static Map pokMap = new HashMap<>(); + static Map codeMap = new HashMap<>(); + + static { + pokMap.put("3", 0); + pokMap.put("4", 1); + pokMap.put("5", 2); + pokMap.put("6", 3); + pokMap.put("7", 4); + pokMap.put("8", 5); + pokMap.put("9", 6); + pokMap.put("10", 7); + pokMap.put("J", 8); + pokMap.put("Q", 9); + pokMap.put("K", 10); + pokMap.put("A", 11); + + codeMap.put(0, "3"); + codeMap.put(1, "4"); + codeMap.put(2, "5"); + codeMap.put(3, "6"); + codeMap.put(4, "7"); + codeMap.put(5, "8"); + codeMap.put(6, "9"); + codeMap.put(7, "10"); + codeMap.put(8, "J"); + codeMap.put(9, "Q"); + codeMap.put(10, "K"); + codeMap.put(11, "A"); + } + + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + String my = sc.nextLine();//我的手牌 + String show = sc.nextLine();//别人打了的 + + // 顺子【3,14】不能有 2、大小王 + + // 统计my和show里面的牌频率 + String[] mySplit = my.split("-"); + String[] showSplit = show.split("-"); + + int[] freqs = new int[12];//12种可以构成顺子的牌 + for (String myPok : mySplit) { + Integer pokCode = pokMap.get(myPok); + freqs[pokCode]++; + } + for (String showPok : showSplit) { + Integer pokCode = pokMap.get(showPok); + freqs[pokCode]++; + } + // 找到四张牌 + List fourIdxList = new ArrayList<>(); + for (int i = 0; i < freqs.length; i++) { + if (freqs[i] == 4) { + fourIdxList.add(i); + } + } + + fourIdxList.add(12);//保证结尾扑克也会被扫到,偷懒写法 + + List orderList = new ArrayList<>(); + + // 顺子12张:0,1,2,3,4,5,6,7,8,9,10,11 + int preIdx = 0; + int orderMax = 0;//顺子最大个数 + + // 构成顺子的 + for (Integer fourIdx : fourIdxList) { + // 0~fourIdx-1;fourIdx+1~fourIdx-1; + int subOrderCount = fourIdx - preIdx; + if (subOrderCount >= 5) {//构成顺子 + orderList.add(new KV(preIdx, fourIdx - 1)); + orderMax = Math.max(subOrderCount, orderMax); + } + + preIdx = fourIdx + 1; + } + + // 找到四张牌,在【3,14】的位置,没有直接返回【3,A】 + +// if (fourIdxList.isEmpty()) { +// orderList.add(new KV(0, 11)); +// orderMax = 11; +// } + + int start = -1, end = -1; + for (KV kv : orderList) { + if (kv.v - kv.k == orderMax-1) {//减1是因为这里的kv是两个闭区间 + start = kv.k; + end = kv.v; + } + } + if (start == -1) { + System.out.println("NO-CHAIN"); + } else { + for (int i = start; i <= end; i++) { + if (i == end) { + System.out.print(codeMap.get(i)); + } else { + System.out.print(codeMap.get(i) + "-"); + } + } + } + } + + static class KV { + public int k; + public int v; + + public KV(int k, int v) { + this.k = k; + this.v = v; + } + } +} \ No newline at end of file diff --git a/algorithms/niuke/src/main/java/cn/cunchang/od/Main3.java b/algorithms/niuke/src/main/java/cn/cunchang/od/Main3.java new file mode 100644 index 00000000..4eb9be04 --- /dev/null +++ b/algorithms/niuke/src/main/java/cn/cunchang/od/Main3.java @@ -0,0 +1,87 @@ +package cn.cunchang.od; + + +import java.util.Scanner; + +public class Main3 { + + static int n; + static int m; + + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + n = sc.nextInt(); + m = sc.nextInt(); + // 邻接矩阵 + int[][] arrs = new int[n][m]; + boolean[][] visited = new boolean[n][m]; + for (int i = 0; i < n; i++) { + for (int j = 0; j < m; j++) { + arrs[i][j] = sc.nextInt(); + } + } + + int res = 0; + + for (int i = 0; i < n; i++) { + for (int j = 0; j < m; j++) { + if (!visited[i][j]) { + int subResult = helper(arrs, visited, i, j); + res = Math.max(subResult, res); + } + } + } + System.out.println(res); + } + + private static int helper(int[][] arrs, boolean[][] visited, int i, int j) { + if (i < 0 || i >= n || j < 0 || j >= m) { + return 0; + } + if (visited[i][j] || arrs[i][j] != 1) { + return 0; + } + visited[i][j] = true; + int subRes = helper(arrs, visited, i + 1, j) //下 + + helper(arrs, visited, i - 1, j) // 上 + + helper(arrs, visited, i, j - 1) // 左 + + helper(arrs, visited, i, j + 1); //右 + return subRes + 1; + } + + +// public static void main(String[] args) { +// Scanner sc = new Scanner(System.in); +// int n = sc.nextInt(); +// int m = sc.nextInt(); +// // 邻接矩阵 +// int[][] arrs = new int[n][m]; +// boolean[] visited = new boolean[n]; +// for (int i = 0; i < n; i++) { +// for (int j = 0; j < m; j++) { +// arrs[i][j] = sc.nextInt(); +// } +// } +// for (int i = 0; i < n; i++) { +// if (!visited[i]) { +// helper(arrs, visited, i); +// res++; +// } +// } +// System.out.println(res); +// } +// +// public static void helper(int[][] arrs, boolean[] visited, int idx) { +// if (idx >= arrs.length) { +// return; +// } +// if (visited[idx]) { +// return; +// } +// visited[idx] = true; +// for (int i = 0; i < idx; i++) { +// helper(arrs, visited, i); +// } +// } + +} \ No newline at end of file diff --git a/algorithms/niuke/src/main/java/cn/cunchang/scanner/Main.java b/algorithms/niuke/src/main/java/cn/cunchang/scanner/Main.java new file mode 100644 index 00000000..3cab137d --- /dev/null +++ b/algorithms/niuke/src/main/java/cn/cunchang/scanner/Main.java @@ -0,0 +1,18 @@ +package cn.cunchang.scanner; + +import java.util.Scanner; + +public class Main { + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + int n = sc.nextInt(); + int ans = 0, x; + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + x = sc.nextInt(); + ans += x; + } + } + System.out.println(ans); + } +} \ No newline at end of file diff --git "a/algorithms/niuke/src/main/java/cn/cunchang/\346\262\241\346\234\211\351\207\215\345\244\215\351\241\271\346\225\260\345\255\227\347\232\204\345\205\250\346\216\222\345\210\227_BM55/Solution.java" "b/algorithms/niuke/src/main/java/cn/cunchang/\346\262\241\346\234\211\351\207\215\345\244\215\351\241\271\346\225\260\345\255\227\347\232\204\345\205\250\346\216\222\345\210\227_BM55/Solution.java" new file mode 100644 index 00000000..86cbd2b8 --- /dev/null +++ "b/algorithms/niuke/src/main/java/cn/cunchang/\346\262\241\346\234\211\351\207\215\345\244\215\351\241\271\346\225\260\345\255\227\347\232\204\345\205\250\346\216\222\345\210\227_BM55/Solution.java" @@ -0,0 +1,46 @@ +package cn.cunchang.没有重复项数字的全排列_BM55; + +import java.util.ArrayList; +import java.util.LinkedList; + +/** + * @author cunchang + * @date 2022/6/29 6:47 PM + */ +public class Solution { + ArrayList> result = new ArrayList<>(); + + public ArrayList> permute(int[] num) { + // 记录「路径」 + LinkedList subResult = new LinkedList<>(); + // 「路径」中的元素会被标记为 true,避免重复使用 + boolean[] visited = new boolean[num.length]; + permute0(num, subResult, visited); + return result; + } + + private void permute0(int[] num, LinkedList subResult, boolean[] visited) { + // 回溯结束,记录结果 + if (num.length == subResult.size()) { + result.add(new ArrayList<>(subResult)); + } + // 遍历选择列表 + for (int i = 0; i < num.length; i++) { + if (visited[i]) { + continue; + } + // 选择值 + subResult.add(num[i]); + visited[i] = true; + permute0(num, subResult, visited); + // 撤销选择 + subResult.removeLast(); + visited[i] = false; + } + } + + public static void main(String[] args) { + System.out.println(new Solution().permute(new int[]{1, 2, 3})); + } + +} \ No newline at end of file diff --git a/algorithms/offer/pom.xml b/algorithms/offer/pom.xml index 33fb58c8..ed39ef68 100644 --- a/algorithms/offer/pom.xml +++ b/algorithms/offer/pom.xml @@ -3,14 +3,19 @@ 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"> - argorithms + algorithms cn.lastwhisper 1.0-SNAPSHOT 4.0.0 - cn.lastwhisper offer - + + + cn.lastwhisper + 1.0-SNAPSHOT + leetcode-common + + \ No newline at end of file diff --git a/algorithms/offer/src/main/java/cn/lastwhisper/offer/Interview_2/Singleton1.java b/algorithms/offer/src/main/java/cn/lastwhisper/offer/Interview_2/Singleton1.java deleted file mode 100644 index 9ae35fbd..00000000 --- a/algorithms/offer/src/main/java/cn/lastwhisper/offer/Interview_2/Singleton1.java +++ /dev/null @@ -1,16 +0,0 @@ -package cn.lastwhisper.offer.Interview_2; - -/** - * 恶汉式之类加载时初始化 - * @author cn.lastwhisper - */ -public class Singleton1 { - // 类属性,所有引用共享一个地址 - private static Singleton1 instance = new Singleton1(); - - private Singleton1() { - } - public static Singleton1 getInstance() { - return instance; - } -} diff --git a/algorithms/offer/src/main/java/cn/lastwhisper/offer/Interview_2/Singleton2.java b/algorithms/offer/src/main/java/cn/lastwhisper/offer/Interview_2/Singleton2.java deleted file mode 100644 index 109ec4a4..00000000 --- a/algorithms/offer/src/main/java/cn/lastwhisper/offer/Interview_2/Singleton2.java +++ /dev/null @@ -1,21 +0,0 @@ -package cn.lastwhisper.offer.Interview_2; - -/** - * 懒汉式之同步锁 - * @author cn.lastwhisper - */ -public class Singleton2 { - // 类属性,所有引用共享一个地址 - private static Singleton2 instance; - - private Singleton2() { - - } - // - public static synchronized Singleton2 getInstance() { - if (instance == null) { - instance = new Singleton2(); - } - return instance; - } -} diff --git a/algorithms/offer/src/main/java/cn/lastwhisper/offer/Interview_2/Singleton3.java b/algorithms/offer/src/main/java/cn/lastwhisper/offer/Interview_2/Singleton3.java deleted file mode 100644 index 52f616d5..00000000 --- a/algorithms/offer/src/main/java/cn/lastwhisper/offer/Interview_2/Singleton3.java +++ /dev/null @@ -1,26 +0,0 @@ -package cn.lastwhisper.offer.Interview_2; - -/** - * 懒汉式之DCL - * @author cn.lastwhisper - */ -public class Singleton3 { - // 类属性,所有引用共享一个地址 - // volatile保证“可见性”、不保证“原子性”“有序性” - private static volatile Singleton3 instance; - - private Singleton3() { - - } - - private static Singleton3 getInstance() { - if (instance == null) { - synchronized (Singleton3.class) { - if (instance == null) { - instance = new Singleton3(); - } - } - } - return instance; - } -} diff --git a/algorithms/offer/src/main/java/cn/lastwhisper/offer/Interview_2/Singleton4.java b/algorithms/offer/src/main/java/cn/lastwhisper/offer/Interview_2/Singleton4.java deleted file mode 100644 index 997f51fd..00000000 --- a/algorithms/offer/src/main/java/cn/lastwhisper/offer/Interview_2/Singleton4.java +++ /dev/null @@ -1,18 +0,0 @@ -package cn.lastwhisper.offer.Interview_2; - -/** - * 懒汉式之静态内部类 - * @author cn.lastwhisper - */ -public class Singleton4 { - private Singleton4() { - } - - private static class InnerClass { - private static Singleton4 singleton = new Singleton4(); - } - - private static Singleton4 getInstance() { - return InnerClass.singleton; - } -} diff --git a/algorithms/offer/src/main/java/cn/lastwhisper/offer/Interview_2/Singleton5.java b/algorithms/offer/src/main/java/cn/lastwhisper/offer/Interview_2/Singleton5.java deleted file mode 100644 index 214206a1..00000000 --- a/algorithms/offer/src/main/java/cn/lastwhisper/offer/Interview_2/Singleton5.java +++ /dev/null @@ -1,12 +0,0 @@ -package cn.lastwhisper.offer.Interview_2; - -/** - * 懒汉式之枚举 - */ -public enum Singleton5 { - INSTANCE; - - public Singleton5 getInstance() { - return INSTANCE; - } -} diff --git a/algorithms/offer/src/main/java/cn/lastwhisper/offer/interview_10/Solution_10.java b/algorithms/offer/src/main/java/cn/lastwhisper/offer/interview_10/Solution_10.java deleted file mode 100644 index ea4799ec..00000000 --- a/algorithms/offer/src/main/java/cn/lastwhisper/offer/interview_10/Solution_10.java +++ /dev/null @@ -1,48 +0,0 @@ -package cn.lastwhisper.offer.interview_10; - -/** - * 面试题10:斐波那契数列 - * 青蛙跳台阶问题 - * @author cn.lastwhisper - */ -public class Solution_10 { - public static void main(String[] args) { - Solution_10 solution = new Solution_10(); - //long fibonacci = solution.fibonacci_recursion(100); - //long fibonacci = solution.fibonacci_iterative(1); - long fibonacci = solution.fibonacci_last_recursion(5,0,1); - System.out.println(fibonacci); - } - - //递归求斐波那契数列 - public long fibonacci_recursion(long n) { - if (n <= 0) { - return 0; - } - if (n == 1) { - return 1; - } - return fibonacci_recursion(n - 1) + fibonacci_recursion(n - 2); - } - - // 递归变循环 - public long fibonacci_iterative(long n) { - if(n==0||n==1)return n; - long item1 = 0; - long item2 = 1; - long sum = 0; - for (int i = 0; i < n; i++) { - sum = item1 + item2; - item1 = item2; - item2 = sum; - } - return sum; - } - - // 尾递归 - public long fibonacci_last_recursion(long n, long rt1, long rt2) { - return n == 0 ? rt1 : fibonacci_last_recursion(n - 1, rt2, rt1 + rt2); - } - - -} diff --git a/algorithms/offer/src/main/java/cn/lastwhisper/offer/interview_10/TestRecursion.java b/algorithms/offer/src/main/java/cn/lastwhisper/offer/interview_10/TestRecursion.java deleted file mode 100644 index 84a438ef..00000000 --- a/algorithms/offer/src/main/java/cn/lastwhisper/offer/interview_10/TestRecursion.java +++ /dev/null @@ -1,28 +0,0 @@ -package cn.lastwhisper.offer.interview_10; - -/** - * 递归与循环测试 - * @author cn.lastwhisper - */ -public class TestRecursion { - public static void main(String[] args) { - TestRecursion recursion = new TestRecursion(); - //int sum = recursion.addFrom1ToN_Recursion(100000); - int sum = recursion.addFrom1ToN_Iterative(100000); - System.out.println(sum); - - } - - - private int addFrom1ToN_Recursion(int n) { - return n < 0 ? 0 : n + addFrom1ToN_Recursion(n - 1); - } - - private int addFrom1ToN_Iterative(int n) { - int sum = 0; - for (int i = 0; i < n; i++) { - sum += i; - } - return sum; - } -} diff --git a/algorithms/offer/src/main/java/cn/lastwhisper/offer/interview_3/Solution_3_1.java b/algorithms/offer/src/main/java/cn/lastwhisper/offer/interview_3/Solution_3_1.java deleted file mode 100644 index e8d5a0ff..00000000 --- a/algorithms/offer/src/main/java/cn/lastwhisper/offer/interview_3/Solution_3_1.java +++ /dev/null @@ -1,58 +0,0 @@ -package cn.lastwhisper.offer.interview_3; - -/** - * 数组中重复的数字 - * 题目一:在n个数字0~n-1之间,找出数组中重复的数字 - * @author cn.lastwhisper - */ -public class Solution_3_1 { - public static void main(String[] args) { - //1.正常数据 - int[] arr1 = {2, 3, 1, 0, 2, 5, 3}; - //2.无重复数字 - int[] arr2 = {0, 1, 2, 5, 4, 3, 6}; - //3.长度为n数组包含0~n-1之外的数字 - //java.lang.ArrayIndexOutOfBoundsException: Index 100 out of bounds for length 7 - int[] arr3 = {0, 1, 2, 3, 4, 100, 100}; - //4.从非0开始的数组 - int[] arr4 = {2, 3, 1, 5, 2, 5, 3}; - duplicate(arr4); - } - - public static boolean duplicate(int[] arr) { - // 检验数据 - if (arr == null || arr.length <= 0) { - System.out.println("数组为null!"); - return false; - } - for (int a : arr) { - if (a < 1 || a > arr.length - 1) { - System.out.println("数字大小超出范围!"); - return false; - } - } - // 数字在0~n-1 - for (int i = 0; i < arr.length; i++) { - if (arr[i] < 0) { - return false; - } - } - int temp; - for (int i = 0; i < arr.length; i++) { - // i== arr[i]时说明下标与对应数值相等 - while (arr[i] != i) {//while循环里面的代码是核心,找到arr[i]==arr[a[i]]时说明数值重复 - // - if (arr[i] == arr[arr[i]]) { - System.out.println(arr[i]); - return true; - } else { - temp = arr[i]; - arr[i] = arr[temp]; - arr[temp] = temp; - } - } - } - return false; - } - -} \ No newline at end of file diff --git a/algorithms/offer/src/main/java/cn/lastwhisper/offer/interview_4/Solution.java b/algorithms/offer/src/main/java/cn/lastwhisper/offer/interview_4/Solution.java deleted file mode 100644 index 419ca62c..00000000 --- a/algorithms/offer/src/main/java/cn/lastwhisper/offer/interview_4/Solution.java +++ /dev/null @@ -1,36 +0,0 @@ -package cn.lastwhisper.offer.interview_4; - -/** - * 牛客提交版本 - */ -public class Solution { - public boolean Find(int target, int[][] array) { - boolean flag = false; - if (array == null || array.length == 0 || array[0].length == 0) { - return flag; - } - - // 矩阵行数和列数 - int rows = array.length, columns = array[0].length; - // 目标值比数组最大值还大 - if (array[rows - 1][columns - 1] < target) { - return flag; - } - // 从矩阵右上角进行剔除列和行 - int row = 0, column = columns - 1; - while (row <= rows && column >= 0) { - if (array[row][column] == target) { - //找到了 - flag = true; - break; - } else if (array[row][column] > target) { - //右上角列上最小值大于target,剔除列 - column--; - } else { - //target大于右上角列上最小值,剔除行 - row++; - } - } - return flag; - } -} \ No newline at end of file diff --git a/algorithms/offer/src/main/java/cn/lastwhisper/offer/interview_4/Solution_4.java b/algorithms/offer/src/main/java/cn/lastwhisper/offer/interview_4/Solution_4.java deleted file mode 100644 index 6001bfed..00000000 --- a/algorithms/offer/src/main/java/cn/lastwhisper/offer/interview_4/Solution_4.java +++ /dev/null @@ -1,91 +0,0 @@ -package cn.lastwhisper.offer.interview_4; - -/** - * 面试题4:二维数组中的查找 - * 从左到右、从上到下递增 - * @author cn.lastwhisper - */ -public class Solution_4 { - public static void main(String[] args) { - int[][] array1 = { - {1, 2, 8, 9}, - {2, 4, 9, 12}, - {4, 7, 10, 13}, - {6, 8, 11, 15} - }; - int[][] array2 = {{}}; - // 查询不存在的值 - //System.out.println(new Solution_4().Find(16, array1)); - // 查询空数组 - System.out.println(new Solution_4().Find(16, array2)); - - //System.out.println(new Solution_4().Find2(10, array1)); - } - - /** - * 右上角列上最小值与目标值比较 - * 大于时,说明整个列都比目标值大,剔除该列,缩小范围 - * 小于时,说明该列可能有目标值,剔除该行,缩小范围 - * 等于时,找到该值 - * - * @param target 目标值 - * @param array 规则矩阵 - * @return boolean - */ - public boolean Find(int target, int[][] array) { - boolean flag = false; - // 数据校验:防止空数组 - if (array == null || array.length == 0 || array[0].length == 0) { - return flag; - } - - // 矩阵行数和列数 - int rows = array.length, columns = array[0].length; - // 目标值比数组最大值还大 - if (array[rows - 1][columns - 1] < target) { - return flag; - } - // 从矩阵右上角进行剔除列和行 - int row = 0, column = columns - 1; - while (row <= rows && column >= 0) { - if (array[row][column] == target) { - //找到了 - flag = true; - break; - } else if (array[row][column] > target) { - //右上角列上最小值大于target,剔除列 - column--; - } else { - //target大于右上角列上最小值,剔除行 - row++; - } - } - return flag; - } - - public boolean Find2(int target, int[][] array) { - boolean flag = false; - if (array == null || array.length == 0) { - System.out.println("矩阵未初始化"); - return flag; - } - // 矩阵行数和列数 - int rows = array.length, columns = array[0].length; - // 从矩阵左下角进行剔除列和行 - int row = rows - 1, column = 0; - while (column <= columns && row >= 0) { - if (array[row][column] == target) { - //找到了 - flag = true; - break; - } else if (array[row][column] > target) { - // 左下角最大值比目标值大,目标值可能在该列,剔除行 - row--; - } else { - column++; - // 左下角最大值比目标值小,剔除列 - } - } - return flag; - } -} diff --git a/algorithms/offer/src/main/java/cn/lastwhisper/offer/interview_5/Solution_5_1.java b/algorithms/offer/src/main/java/cn/lastwhisper/offer/interview_5/Solution_5_1.java deleted file mode 100644 index 1c89d075..00000000 --- a/algorithms/offer/src/main/java/cn/lastwhisper/offer/interview_5/Solution_5_1.java +++ /dev/null @@ -1,68 +0,0 @@ -package cn.lastwhisper.offer.interview_5; - -/** - * 面试题 5:替换空格 - * @author cn.lastwhisper - */ -public class Solution_5_1 { - public static void main(String[] args) { - StringBuffer sb = new StringBuffer(); - // 1.正常数据 - //sb.append("We are happy"); - // 2.前、后、连续空格 - //sb.append(" We are happy "); - // 3.没有空格 - //sb.append("Wearehappy"); - // 4.特殊测试数据:null、一个空格字符 - sb.append(" "); - String space = new Solution_5_1().replaceSpace(sb); - System.out.println(space); - } - - /** - * 运行时间:19ms - * 占用内存:9576k - * @param str - * @return java.lang.String - */ - public String replaceSpace(StringBuffer str) { - // 校验数据 - if (str == null || str.length() == 0) { - return ""; - } - int spacenum = 0;//spacenum为计算空格数 - for (int i = 0; i < str.length(); i++) { - if (str.charAt(i) == ' ') - spacenum++; - } - // 新字符串长度 - int newlength = str.length() + spacenum * 2; - // 原字符串的尾指针 - int indexOfOrigin = str.length() - 1; - // 新字符串的尾指针 - int indexOfNew = newlength - 1; - //使str的长度扩大到转换成%20之后的长度,防止下标越界 - str.setLength(newlength);//底层新建数组后copy元素 - for (; indexOfOrigin >= 0; indexOfOrigin--) { - if (str.charAt(indexOfOrigin) == ' ') { // - str.setCharAt(indexOfNew--, '0'); - str.setCharAt(indexOfNew--, '2'); - str.setCharAt(indexOfNew--, '%'); - } else { - str.setCharAt(indexOfNew--, str.charAt(indexOfOrigin)); - } - } - return str.toString(); - } - /** - * 运行时间:17ms - * 占用内存:9580k - * - * @param str - * @return java.lang.String - */ - public String replaceSpace1(StringBuffer str) { - return str.toString().replace(" ", "%20"); - } - -} diff --git a/algorithms/offer/src/main/java/cn/lastwhisper/offer/interview_5/Solution_5_1_1.java b/algorithms/offer/src/main/java/cn/lastwhisper/offer/interview_5/Solution_5_1_1.java deleted file mode 100644 index 24381857..00000000 --- a/algorithms/offer/src/main/java/cn/lastwhisper/offer/interview_5/Solution_5_1_1.java +++ /dev/null @@ -1,48 +0,0 @@ -package cn.lastwhisper.offer.interview_5; - -/** - * 面试题 5:替换空格 - * @author cn.lastwhisper - */ -public class Solution_5_1_1 { - public static void main(String[] args) { - String str = "We are happy"; - String space = new Solution_5_1_1().replaceSpace(str.toCharArray()); - System.out.println(space); - } - - public String replaceSpace(char[] chars) { - // 校验数据 - if (chars == null || chars.length == 0) { - return ""; - } - // 原数组总长度 - int originalLength = chars.length; - // 统计空格数 - int blankCount = 0; - for (int i = 0; i < chars.length; i++) { - if (chars[i] == ' ') { - blankCount++; - } - } - // 替换空格后的字符串长度为原来长度+2*空格数 - int newLength = originalLength + 2 * blankCount; - char[] cache = new char[newLength]; - // 原字符串尾指针 - int indexOfOriginal = originalLength-1; - // 新字符串尾指针 - int indexOfNew = newLength-1; - // 从两个数组尾部进行copy字符,碰到字符不copy,而是填充"20%" - while (indexOfOriginal >= 0) { - if (chars[indexOfOriginal] == ' ') { - cache[indexOfNew--] = '0'; - cache[indexOfNew--] = '2'; - cache[indexOfNew--] = '%'; - } else { - cache[indexOfNew--] = chars[indexOfOriginal]; - } - indexOfOriginal--; - } - return new String(cache); - } -} diff --git a/algorithms/offer/src/main/java/cn/lastwhisper/offer/interview_6/Solution.java b/algorithms/offer/src/main/java/cn/lastwhisper/offer/interview_6/Solution.java deleted file mode 100644 index 48b90c4c..00000000 --- a/algorithms/offer/src/main/java/cn/lastwhisper/offer/interview_6/Solution.java +++ /dev/null @@ -1,15 +0,0 @@ -package cn.lastwhisper.offer.interview_6; - -import java.util.ArrayList; - -public class Solution { - private ArrayList list = new ArrayList(); - - public ArrayList printListFromTailToHead(ListNode listNode) { - if (listNode != null) { - this.printListFromTailToHead(listNode.next); - list.add(listNode.val); - } - return list; - } -} \ No newline at end of file diff --git a/algorithms/offer/src/main/java/cn/lastwhisper/offer/interview_6/Solution_6.java b/algorithms/offer/src/main/java/cn/lastwhisper/offer/interview_6/Solution_6.java deleted file mode 100644 index e61573ff..00000000 --- a/algorithms/offer/src/main/java/cn/lastwhisper/offer/interview_6/Solution_6.java +++ /dev/null @@ -1,67 +0,0 @@ -package cn.lastwhisper.offer.interview_6; - -import java.util.ArrayList; -import java.util.Stack; - -/** - * 面试题6:从头到尾打印链表 - * @author cn.lastwhisper - */ -public class Solution_6 { - - // 牛客提交版本 - private ArrayList list = new ArrayList(); - - public static void main(String[] args) { - ListNode listNode1 = new ListNode(1); - ListNode listNode2 = new ListNode(2); - ListNode listNode3 = new ListNode(3); - ListNode listNode4 = new ListNode(4); - ListNode listNode5 = new ListNode(5); - listNode1.next = listNode2; - listNode2.next = listNode3; - listNode3.next = listNode4; - listNode4.next = listNode5; - - Solution_6 solution_6 = new Solution_6(); - - solution_6.PrintListReversingly_Iteratively(listNode1); - System.out.println(); - solution_6.PrintListReversingly_Recursion(listNode1); - } - - /** - * 栈 - */ - public void PrintListReversingly_Iteratively(ListNode pHead) { - Stack stack = new Stack<>(); - while (pHead != null) { - stack.push(pHead); - pHead = pHead.next; - } - while (!stack.isEmpty()) { - System.out.print(stack.pop().val + "\t"); - } - } - /** - * 递归 - */ - public void PrintListReversingly_Recursion(ListNode pHead) { - if (pHead != null) { - this.PrintListReversingly_Recursion(pHead.next); - System.out.print(pHead.val + "\t"); - } - } - -} - -class ListNode { - int val; - ListNode next = null; - - ListNode(int val) { - this.val = val; - } -} - - diff --git a/algorithms/offer/src/main/java/cn/lastwhisper/offer/interview_7/ConstructBinaryTree.java b/algorithms/offer/src/main/java/cn/lastwhisper/offer/interview_7/ConstructBinaryTree.java deleted file mode 100644 index ee478b43..00000000 --- a/algorithms/offer/src/main/java/cn/lastwhisper/offer/interview_7/ConstructBinaryTree.java +++ /dev/null @@ -1,173 +0,0 @@ -package cn.lastwhisper.offer.interview_7; - -// 题目:输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输 -// 入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1, -// 2, 4, 7, 3, 5, 6, 8}和中序遍历序列{4, 7, 2, 1, 5, 3, 8, 6},则重建出 -// 二叉树并输出它的头结点。 -public class ConstructBinaryTree { - class TreeNode { - int val; - TreeNode left; - TreeNode right; - - public TreeNode(int val) { - this.val = val; - } - } - - public TreeNode reConstructBinaryTree(int[] pre, int[] in) { - if (pre == null || in == null || pre.length == 0 || in.length == 0 || pre.length != in.length) { - throw new RuntimeException("数组不符合规范!"); - } - return construct(pre, in, 0, pre.length - 1, 0, in.length - 1); - } - - /** - * 根据先序数组的起始位置获得root, - * 再根据root.val算出root在中序数组中的位置,得到root的左子树和右子树 - * 再把左子树和右子树进行重复操作 - * @param pre 前序遍历数组 - * @param in 中序遍历数组 - * @param pStart 前序遍历起始位置 - * @param pEnd 前序遍历结束位置 - * @param iStart 中序遍历起始位置 - * @param iEnd 中序遍历结束位置 - */ - public TreeNode construct(int[] pre, int[] in, int pStart, int pEnd, int iStart, int iEnd) { - // 先序遍历数组中的第一个元素:根结点 - TreeNode root = new TreeNode(pre[pStart]); - // 第一次:pStart=0、pEnd=7;iStart=0、iEnd=7 - // 第二次:pStart=1、pEnd=3;iStart=0、iEnd=2 - // 第三次:pStart=2、pEnd=3;iStart=0、iEnd=1 - // 第四次:pStart=3、pEnd=3;iStart=1、iEnd=1 - // 先序数组和中序数组中只有一个结点 - if (pStart == pEnd && iStart == iEnd) { - if (pre[pStart] != in[iStart]) - //throw new FileNotFoundException("数组不符合规范!"); - throw new RuntimeException("数组不符合规范!"); - return root; - } - int index = iStart; // 用于记录中序遍历序列中根结点的位置 - //第一次:index=3,中序遍历对应root下标 - //第二次:index=2,中序遍历对应root下标 - //第二次:index=0,中序遍历对应root下标 - //根据先序遍历数组得到的根结点,找到该根结点对应中序遍历数组的下标 - while (root.val != in[index] && index <= iEnd) { - index++; - } - if (index > iEnd) - throw new RuntimeException("数组不符合规范!"); - //第一次:leftLength=3,当前root的左子树有三个结点 - //第二次:leftLength=2,当前root的左子树有两个结点 - //第三次:leftLength=0,当前root的左子树有没有结点 - int leftLength = index - iStart;//中序遍历中当前root的左子树结点个数 - //构建左子树 - if (leftLength > 0) { - // [pStart + 1...pStart + leftLength]是先序遍历左子树的范围 - // [iStart..index-1]是中序遍历左子树的范围 - root.left = construct(pre, in, pStart + 1, pStart + leftLength, iStart, index - 1); - } - // 构建右子树 - if (leftLength < iEnd - iStart) { - // [pStart + leftLength + 1...pEnd]是先序遍历右子树的范围 - // [index + 1..iEnd]是中序遍历右子树的范围 - root.right = construct(pre, in, pStart + leftLength + 1, pEnd, index + 1, iEnd); - } - return root; - } - - private void preOrderTraverse(TreeNode node) { - if (node == null) - return; - System.out.print(node.val); - preOrderTraverse(node.left); - preOrderTraverse(node.right); - } - - private void inOrderTraverse(TreeNode node) { - if (node == null) - return; - inOrderTraverse(node.left); - System.out.print(node.val); - inOrderTraverse(node.right); - } - - /** - * 正常二叉树 - */ - public void test1() { - int[] pre = {1, 2, 4, 7, 3, 5, 6, 8}; - int[] in = {4, 7, 2, 1, 5, 3, 8, 6}; - TreeNode root = reConstructBinaryTree(pre, in); - System.out.print("test1:"); - preOrderTraverse(root); - System.out.print("\t"); - inOrderTraverse(root); - System.out.println(); - } - - /** - * 左斜树 - */ - public void test2() { - int[] pre = {1, 2, 3, 4, 5}; - int[] in = {5, 4, 3, 2, 1}; - TreeNode root = reConstructBinaryTree(pre, in); - System.out.print("test2:"); - preOrderTraverse(root); - System.out.print("\t"); - inOrderTraverse(root); - System.out.println(); - } - - /** - * 右斜树 - */ - public void test3() { - int[] pre = {1, 2, 3, 4, 5}; - int[] in = {1, 2, 3, 4, 5}; - TreeNode root = reConstructBinaryTree(pre, in); - System.out.print("test3:"); - preOrderTraverse(root); - System.out.print("\t"); - inOrderTraverse(root); - System.out.println(); - } - - /** - * 单个结点 - */ - public void test4() { - int[] pre = {1}; - int[] in = {1}; - TreeNode root = reConstructBinaryTree(pre, in); - System.out.print("test4:"); - preOrderTraverse(root); - System.out.print("\t"); - inOrderTraverse(root); - System.out.println(); - } - - /** - * 数组为空 - */ - public void test5() { - int[] pre = {}; - int[] in = {}; - TreeNode root = reConstructBinaryTree(pre, in); - System.out.print("test5:"); - preOrderTraverse(root); - System.out.print("\t"); - inOrderTraverse(root); - System.out.println(); - } - - public static void main(String[] args) { - ConstructBinaryTree demo = new ConstructBinaryTree(); - demo.test1(); - //demo.test2(); - //demo.test3(); - //demo.test4(); - //demo.test5(); - } -} \ No newline at end of file diff --git a/algorithms/offer/src/main/java/cn/lastwhisper/offer/interview_7/Solution_7.java b/algorithms/offer/src/main/java/cn/lastwhisper/offer/interview_7/Solution_7.java deleted file mode 100644 index bfd3ae2f..00000000 --- a/algorithms/offer/src/main/java/cn/lastwhisper/offer/interview_7/Solution_7.java +++ /dev/null @@ -1,11 +0,0 @@ -package cn.lastwhisper.offer.interview_7; - -/** - * 面试题7:输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。 - * 假设输入的前序遍历和中序遍历的结果中都不含重复的数字。 - * 例如输入前序遍历序列{1,2, 4, 7, 3, 5, 6, 8}和中序遍历序列{4, 7, 2, 1, 5, 3, 8, 6}, - * 则重建出二叉树并输出它的头结点。 - * @author cn.lastwhisper - */ -public class Solution_7 { -} diff --git a/algorithms/offer/src/main/java/cn/lastwhisper/offer/interview_8/Solution_8.java b/algorithms/offer/src/main/java/cn/lastwhisper/offer/interview_8/Solution_8.java deleted file mode 100644 index dde5ddb5..00000000 --- a/algorithms/offer/src/main/java/cn/lastwhisper/offer/interview_8/Solution_8.java +++ /dev/null @@ -1,122 +0,0 @@ -package cn.lastwhisper.offer.interview_8; - -/** - * 面试题8:二叉树的下一个结点 - * 思路: - * 1.若一个结点有右子树,则它下一个结点就是它右子树的最左子结点 - * 2.若一个结点无右子树 - * 2.1若该结点是它父结点的左子结点,则它下一个结点就是它的父结点 - * 2.2若该结点是它父结点的右子结点,则沿着父结点的指针向上遍历, - * 直到找到一个是它父结点的左子结点的结点,找不到说明没有下一个结点 - * 核心思想:有右子树,找自己右子树的最左子结点 - * 无右子树, - * @author cn.lastwhisper - */ -public class Solution_8 { - public static void main(String[] args) { - Solution_8 solution_8 = new Solution_8(); - TreeNode treeNode = solution_8.construct(); - //TreeNode nextNode = solution_8.GetNext(treeNode); - TreeNode nextNode = solution_8.GetNext1(treeNode); - System.out.println(nextNode.val); - } - - public TreeNode GetNext(TreeNode pNode) { - if (pNode == null) { - System.out.print("结点为null "); - return null; - } - if (pNode.right != null) { - pNode = pNode.right; - while (pNode.left != null) - pNode = pNode.left; - return pNode; - } - while (pNode.parent != null) { - if (pNode == pNode.parent.left) - return pNode.parent; - pNode = pNode.parent; - } - return null; - } - - private TreeNode GetNext1(TreeNode pNode) { - // 数据校验 - if (pNode == null) { - return null; - } - //该结点有右子树 - if (pNode.right != null) { - //若一个结点有右子树,则它下一个结点就是它右子树的最左子结点 - pNode = pNode.right; - while (pNode.left != null) { - pNode = pNode.left; - } - return pNode; - } - else { - TreeNode parentNode = pNode.parent; - if (parentNode.left == pNode) { - //若该结点是它父结点的左子结点,则它下一个结点就是它的父结点 - return parentNode; - } else if (parentNode.right == pNode) { - //若该结点是它父结点的右子结点,则沿着父结点的指针向上遍历, - //直到找到一个是它父结点的左子结点的结点,找不到说明没有下一个结点 - parentNode = pNode; - while (parentNode.parent != null) { - if (parentNode.parent.left == parentNode) { - return parentNode.parent; - } - parentNode = parentNode.parent; - } - } - } - return null; - } - - private TreeNode construct() { - TreeNode treeNode1 = new TreeNode("a"); - TreeNode treeNode2 = new TreeNode("b"); - TreeNode treeNode3 = new TreeNode("c"); - TreeNode treeNode4 = new TreeNode("d"); - TreeNode treeNode5 = new TreeNode("e"); - TreeNode treeNode6 = new TreeNode("f"); - TreeNode treeNode7 = new TreeNode("g"); - TreeNode treeNode8 = new TreeNode("h"); - TreeNode treeNode9 = new TreeNode("i"); - // a,b,c - treeNode1.left = treeNode2; - treeNode1.right = treeNode3; - treeNode2.parent = treeNode1; - treeNode3.parent = treeNode1; - // b,d,e - treeNode2.left = treeNode4; - treeNode2.right = treeNode5; - treeNode4.parent = treeNode2; - treeNode5.parent = treeNode2; - // c,f,g - treeNode3.left = treeNode6; - treeNode3.right = treeNode7; - treeNode6.parent = treeNode3; - treeNode7.parent = treeNode3; - // e,h,i - treeNode5.left = treeNode8; - treeNode5.right = treeNode9; - treeNode8.parent = treeNode5; - treeNode9.parent = treeNode5; - return treeNode1;//情景一 - //return treeNode4;//情景二 - //return treeNode9;//情景三 - } -} - -class TreeNode { - T val; - TreeNode left; - TreeNode right; - TreeNode parent; - - public TreeNode(T val) { - this.val = val; - } -} diff --git a/algorithms/offer/src/main/java/cn/lastwhisper/offer/interview_9/Solution.java b/algorithms/offer/src/main/java/cn/lastwhisper/offer/interview_9/Solution.java deleted file mode 100644 index 04cee0c1..00000000 --- a/algorithms/offer/src/main/java/cn/lastwhisper/offer/interview_9/Solution.java +++ /dev/null @@ -1,27 +0,0 @@ -package cn.lastwhisper.offer.interview_9; - -import java.util.Stack; - -/** - * 牛客提交版本 - */ -public class Solution { - Stack stack1 = new Stack(); - Stack stack2 = new Stack(); - - public void push(int node) { - stack1.push(node); - } - - public int pop() { - if (stack2.isEmpty()) { - while (!stack1.isEmpty()) { - stack2.push(stack1.pop()); - } - } - if (stack2.size() == 0) { - throw new RuntimeException("stack2为空"); - } - return stack2.pop(); - } -} \ No newline at end of file diff --git a/algorithms/offer/src/main/java/cn/lastwhisper/offer/interview_9/Solution_9.java b/algorithms/offer/src/main/java/cn/lastwhisper/offer/interview_9/Solution_9.java deleted file mode 100644 index 5cde467f..00000000 --- a/algorithms/offer/src/main/java/cn/lastwhisper/offer/interview_9/Solution_9.java +++ /dev/null @@ -1,114 +0,0 @@ -package cn.lastwhisper.offer.interview_9; - -import java.util.LinkedList; -import java.util.Queue; -import java.util.Stack; - -/** - * 面试题9:用两个栈实现队列(stack1用于入队,stack2用于出队) - * 入队:将元素push到stack1 - * 出队:出队时stack2不为空,就将stack2栈顶pop - * 如果stack2为空,就将stack1栈顶元素依次push到stack2中,再从stack2栈顶pop - * 扩展:用两个队列实现栈(两个队列都用于入栈、出栈) - * 入栈:queue1不为空,将元素入queue1;queue2不为空,将元素入queue2; - * 都为空入queue1 - * 出栈:queue1和queue2都为空直接RuntimeException - * queue1不为空,将queue1元素依次出队并插入queue2,直到最后一个元素, - * 该元素为待出栈元素,直接将该元素出队返回 - * queue2不为空,将queue2元素依次出队并插入queue1,直到最后一个元素, - * 该元素为待出栈元素,直接将该元素出队返回 - * @author cn.lastwhisper - */ -public class Solution_9 { - public static void main(String[] args) { - // 两个栈实现队列 - //testQueue(); - // 两个队列实现栈 - testStack(); - } - - private static void testStack() { - CStack stack = new CStack<>(); - stack.push("a").push("b").push("c"); - System.out.print(stack.pop() + "\t"); - System.out.print(stack.pop() + "\t"); - stack.push("e"); - System.out.print(stack.pop() + "\t"); - System.out.print(stack.pop() + "\t"); - System.out.print(stack.pop() + "\t"); - } - - private static void testQueue() { - CQueue cQueue = new CQueue<>(); - cQueue.appendTail("a").appendTail("b") - .appendTail("c").appendTail("d"); - System.out.print(cQueue.deleteHead() + "\t"); - System.out.print(cQueue.deleteHead() + "\t"); - cQueue.appendTail("e"); - System.out.print(cQueue.deleteHead() + "\t"); - System.out.print(cQueue.deleteHead() + "\t"); - System.out.print(cQueue.deleteHead() + "\t"); - } -} - -//栈 -class CStack { - private Queue queue1 = new LinkedList<>(); - private Queue queue2 = new LinkedList<>(); - - //入栈 - public CStack push(T t) { - if (!queue1.isEmpty()) { - queue1.add(t); - } else if (!queue2.isEmpty()) { - queue2.add(t); - } else { - queue1.add(t); - } - return this; - } - - //出栈 - public T pop() { - if (queue1.isEmpty() && queue2.isEmpty()) { - throw new RuntimeException("栈空无元素"); - } - if (!queue1.isEmpty()) { - while (queue1.size() > 1) { - queue2.add(queue1.poll()); - } - return queue1.poll(); - } else { - while (queue2.size() > 1) { - queue1.add(queue2.poll()); - } - return queue2.poll(); - } - } -} - -//队列 -class CQueue { - private Stack stack1 = new Stack<>(); - private Stack stack2 = new Stack<>(); - - //入队 - public CQueue appendTail(T t) { - stack1.push(t); - return this; - } - - //出队 - public T deleteHead() { - //stack2为空,将stack1元素push到stack2 - if (stack2.isEmpty()) { - while (!stack1.isEmpty()) { - stack2.push(stack1.pop()); - } - } - if (stack2.size() == 0) { - throw new RuntimeException("stack2为空"); - } - return stack2.pop(); - } -} diff --git "a/algorithms/offer/src/main/java/cn/lastwhisper/offer/\345\215\225\344\276\213/Singleton1.java" "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\345\215\225\344\276\213/Singleton1.java" new file mode 100644 index 00000000..1fc79ebf --- /dev/null +++ "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\345\215\225\344\276\213/Singleton1.java" @@ -0,0 +1,16 @@ +package cn.lastwhisper.offer.单例; + +/** + * 恶汉式之类加载时初始化 + * @author cn.lastwhisper + */ +public class Singleton1 { + // 类属性,所有引用共享一个地址 + private static Singleton1 instance = new Singleton1(); + + private Singleton1() { + } + public static Singleton1 getInstance() { + return instance; + } +} diff --git "a/algorithms/offer/src/main/java/cn/lastwhisper/offer/\345\215\225\344\276\213/Singleton2.java" "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\345\215\225\344\276\213/Singleton2.java" new file mode 100644 index 00000000..f670fb89 --- /dev/null +++ "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\345\215\225\344\276\213/Singleton2.java" @@ -0,0 +1,21 @@ +package cn.lastwhisper.offer.单例; + +/** + * 懒汉式之同步锁 + * @author cn.lastwhisper + */ +public class Singleton2 { + // 类属性,所有引用共享一个地址 + private static Singleton2 instance; + + private Singleton2() { + + } + // + public static synchronized Singleton2 getInstance() { + if (instance == null) { + instance = new Singleton2(); + } + return instance; + } +} diff --git "a/algorithms/offer/src/main/java/cn/lastwhisper/offer/\345\215\225\344\276\213/Singleton3.java" "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\345\215\225\344\276\213/Singleton3.java" new file mode 100644 index 00000000..9d8adc40 --- /dev/null +++ "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\345\215\225\344\276\213/Singleton3.java" @@ -0,0 +1,26 @@ +package cn.lastwhisper.offer.单例; + +/** + * 懒汉式之DCL + * @author cn.lastwhisper + */ +public class Singleton3 { + // 类属性,所有引用共享一个地址 + // volatile保证“可见性”、不保证“原子性”“有序性” + private static volatile Singleton3 instance; + + private Singleton3() { + + } + + private static Singleton3 getInstance() { + if (instance == null) { + synchronized (Singleton3.class) { + if (instance == null) { + instance = new Singleton3(); + } + } + } + return instance; + } +} diff --git "a/algorithms/offer/src/main/java/cn/lastwhisper/offer/\345\215\225\344\276\213/Singleton4.java" "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\345\215\225\344\276\213/Singleton4.java" new file mode 100644 index 00000000..38bef605 --- /dev/null +++ "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\345\215\225\344\276\213/Singleton4.java" @@ -0,0 +1,18 @@ +package cn.lastwhisper.offer.单例; + +/** + * 懒汉式之静态内部类 + * @author cn.lastwhisper + */ +public class Singleton4 { + private Singleton4() { + } + + private static class InnerClass { + private static Singleton4 singleton = new Singleton4(); + } + + private static Singleton4 getInstance() { + return InnerClass.singleton; + } +} diff --git "a/algorithms/offer/src/main/java/cn/lastwhisper/offer/\345\215\225\344\276\213/Singleton5.java" "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\345\215\225\344\276\213/Singleton5.java" new file mode 100644 index 00000000..41bdaa6f --- /dev/null +++ "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\345\215\225\344\276\213/Singleton5.java" @@ -0,0 +1,12 @@ +package cn.lastwhisper.offer.单例; + +/** + * 懒汉式之枚举 + */ +public enum Singleton5 { + INSTANCE; + + public Singleton5 getInstance() { + return INSTANCE; + } +} diff --git a/algorithms/offer/src/main/java/cn/lastwhisper/offer/Interview_2/Singleton6.java "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\345\215\225\344\276\213/Singleton6.java" similarity index 93% rename from algorithms/offer/src/main/java/cn/lastwhisper/offer/Interview_2/Singleton6.java rename to "algorithms/offer/src/main/java/cn/lastwhisper/offer/\345\215\225\344\276\213/Singleton6.java" index 0152837a..ae6e0a63 100644 --- a/algorithms/offer/src/main/java/cn/lastwhisper/offer/Interview_2/Singleton6.java +++ "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\345\215\225\344\276\213/Singleton6.java" @@ -1,4 +1,4 @@ -package cn.lastwhisper.offer.Interview_2; +package cn.lastwhisper.offer.单例; import java.util.concurrent.atomic.AtomicReference; diff --git "a/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23003_\346\225\260\347\273\204\344\270\255\351\207\215\345\244\215\347\232\204\346\225\260\345\255\227_\347\256\200\345\215\225/Solution1.java" "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23003_\346\225\260\347\273\204\344\270\255\351\207\215\345\244\215\347\232\204\346\225\260\345\255\227_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..cc51c62b --- /dev/null +++ "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23003_\346\225\260\347\273\204\344\270\255\351\207\215\345\244\215\347\232\204\346\225\260\345\255\227_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,33 @@ +package cn.lastwhisper.offer.面试题03_数组中重复的数字_简单; + +import java.util.HashSet; +import java.util.Set; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/shu-zu-zhong-zhong-fu-de-shu-zi-lcof/ + * ------------------------------------------------------------------- + * 思考: + * 1、hash查重 + * 2、找规律(桶思想) + * ------------------------------------------------------------------- + * 思路:hash查重 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(n) + */ + public int findRepeatNumber(int[] nums) { + Set hash = new HashSet<>(); + for (int num : nums) { + if (hash.contains(num)) { + return num; + } + hash.add(num); + } + return 0; + } + + public static void main(String[] args) { + System.out.println(new Solution1().findRepeatNumber(new int[]{2, 3, 1, 0, 2, 5, 3})); + } +} \ No newline at end of file diff --git "a/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23003_\346\225\260\347\273\204\344\270\255\351\207\215\345\244\215\347\232\204\346\225\260\345\255\227_\347\256\200\345\215\225/Solution2.java" "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23003_\346\225\260\347\273\204\344\270\255\351\207\215\345\244\215\347\232\204\346\225\260\345\255\227_\347\256\200\345\215\225/Solution2.java" new file mode 100644 index 00000000..343ecccc --- /dev/null +++ "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23003_\346\225\260\347\273\204\344\270\255\351\207\215\345\244\215\347\232\204\346\225\260\345\255\227_\347\256\200\345\215\225/Solution2.java" @@ -0,0 +1,41 @@ +package cn.lastwhisper.offer.面试题03_数组中重复的数字_简单; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/shu-zu-zhong-zhong-fu-de-shu-zi-lcof/ + * ------------------------------------------------------------------- + * 思考: + * 1、hash查重 + * 2、找规律(桶思想) + * ------------------------------------------------------------------- + * 思路:长度n的数组,数字范围0~n-1。无重复:长度4的数组,nums={3,1,0,2} + * 重复:长度4的数组,nums={3,2,0,2} + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(n) + */ + public int findRepeatNumber(int[] nums) { + for (int i = 0; i < nums.length; i++) { + /* + * 内循环 + * 1、将i==nums[i],{3,2,0,2}==》{0,2,2,3} + * 2、检查重复;i=1,nums[i] == nums[nums[i]] + */ + while (i != nums[i]) { + if (nums[i] == nums[nums[i]]) { + return nums[i]; + } else { + int temp = nums[i]; + // 必须用nums[temp],不能用nums[nums[i]] + nums[i] = nums[temp]; + nums[temp] = temp; + } + } + } + return -1; + } + + public static void main(String[] args) { + System.out.println(new Solution2().findRepeatNumber(new int[]{3, 2, 0, 2})); + } +} \ No newline at end of file diff --git a/algorithms/offer/src/main/java/cn/lastwhisper/offer/interview_3/Solution_3_2.java "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23003_\346\225\260\347\273\204\344\270\255\351\207\215\345\244\215\347\232\204\346\225\260\345\255\227_\347\256\200\345\215\225/Solution_3_2.java" similarity index 97% rename from algorithms/offer/src/main/java/cn/lastwhisper/offer/interview_3/Solution_3_2.java rename to "algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23003_\346\225\260\347\273\204\344\270\255\351\207\215\345\244\215\347\232\204\346\225\260\345\255\227_\347\256\200\345\215\225/Solution_3_2.java" index e8b277d9..59f77334 100644 --- a/algorithms/offer/src/main/java/cn/lastwhisper/offer/interview_3/Solution_3_2.java +++ "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23003_\346\225\260\347\273\204\344\270\255\351\207\215\345\244\215\347\232\204\346\225\260\345\255\227_\347\256\200\345\215\225/Solution_3_2.java" @@ -1,4 +1,4 @@ -package cn.lastwhisper.offer.interview_3; +package cn.lastwhisper.offer.面试题03_数组中重复的数字_简单; /** * 数组中重复的数字 diff --git "a/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23004_\344\272\214\347\273\264\346\225\260\347\273\204\344\270\255\347\232\204\346\237\245\346\211\276_\347\256\200\345\215\225/Solution1.java" "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23004_\344\272\214\347\273\264\346\225\260\347\273\204\344\270\255\347\232\204\346\237\245\346\211\276_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..e137efbc --- /dev/null +++ "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23004_\344\272\214\347\273\264\346\225\260\347\273\204\344\270\255\347\232\204\346\237\245\346\211\276_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,57 @@ +package cn.lastwhisper.offer.面试题04_二维数组中的查找_简单; + +class Solution1 { + /** + * 右上角列上最小值与目标值比较 + * 大于时,说明整个列都比目标值大,剔除该列,缩小范围 + * 小于时,说明该列可能有目标值,剔除该行,缩小范围 + * 等于时,找到该值 + * + * @param matrix 规则矩阵 + * @param target 目标值 + * @return boolean + */ + public boolean findNumberIn2DArray(int[][] matrix, int target) { + boolean flag = false; + // 数据校验:防止空数组 + if (matrix == null || matrix.length == 0 || matrix[0].length == 0) { + return false; + } + + // 矩阵行数和列数 + int rows = matrix.length - 1, columns = matrix[0].length - 1; + // 目标值比数组最大值还大 + if (matrix[rows][columns] < target) { + return false; + } + // 从矩阵右上角进行剔除列和行 + int row = 0, column = columns; + while (row <= rows && column >= 0) { + if (matrix[row][column] == target) { + //找到了 + flag = true; + break; + } else if (matrix[row][column] > target) { + //右上角列上最小值大于target,剔除列 + column--; + } else { + //target大于右上角列上最小值,剔除行 + row++; + } + } + return flag; + } + + public static void main(String[] args) { + //int[][] array = { + // {1, 2, 8, 9}, + // {2, 4, 9, 12}, + // {4, 7, 10, 13}, + // {6, 8, 11, 15} + //}; + int[][] array = { + {-5} + }; + System.out.println(new Solution1().findNumberIn2DArray(array, -5)); + } +} \ No newline at end of file diff --git "a/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23005_\346\233\277\346\215\242\347\251\272\346\240\274_\347\256\200\345\215\225/Solution.java" "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23005_\346\233\277\346\215\242\347\251\272\346\240\274_\347\256\200\345\215\225/Solution.java" new file mode 100644 index 00000000..a4d74724 --- /dev/null +++ "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23005_\346\233\277\346\215\242\347\251\272\346\240\274_\347\256\200\345\215\225/Solution.java" @@ -0,0 +1,12 @@ +package cn.lastwhisper.offer.面试题05_替换空格_简单; + +class Solution { + public String replaceSpace(String s) { + StringBuilder sb = new StringBuilder(); + for (char c : s.toCharArray()) { + if (c != ' ') sb.append(c); + else sb.append("%20"); + } + return sb.toString(); + } +} \ No newline at end of file diff --git "a/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23005_\346\233\277\346\215\242\347\251\272\346\240\274_\347\256\200\345\215\225/Solution1.java" "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23005_\346\233\277\346\215\242\347\251\272\346\240\274_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..43b61829 --- /dev/null +++ "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23005_\346\233\277\346\215\242\347\251\272\346\240\274_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,39 @@ +package cn.lastwhisper.offer.面试题05_替换空格_简单; + +class Solution1 { + public String replaceSpace(String s) { + // 校验数据 + if (s == null || s.length() == 0) { + return ""; + } + StringBuilder sb = new StringBuilder(s); + + int spacenum = 0;//spacenum为计算空格数 + for (int i = 0; i < sb.length(); i++) { + if (sb.charAt(i) == ' ') + spacenum++; + } + // 新字符串长度 + int newlength = sb.length() + spacenum * 2; + // 原字符串的尾指针 + int indexOfOrigin = sb.length() - 1; + // 新字符串的尾指针 + int indexOfNew = newlength - 1; + //使str的长度扩大到转换成%20之后的长度,防止下标越界 + sb.setLength(newlength);//底层新建数组后copy元素 + for (; indexOfOrigin >= 0; indexOfOrigin--) { + if (sb.charAt(indexOfOrigin) == ' ') { // + sb.setCharAt(indexOfNew--, '0'); + sb.setCharAt(indexOfNew--, '2'); + sb.setCharAt(indexOfNew--, '%'); + } else { + sb.setCharAt(indexOfNew--, sb.charAt(indexOfOrigin)); + } + } + return sb.toString(); + } + + public static void main(String[] args) { + + } +} \ No newline at end of file diff --git "a/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23006_\344\273\216\345\260\276\345\210\260\345\244\264\346\211\223\345\215\260\351\223\276\350\241\250_\347\256\200\345\215\225/Solution1.java" "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23006_\344\273\216\345\260\276\345\210\260\345\244\264\346\211\223\345\215\260\351\223\276\350\241\250_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..e50bc55b --- /dev/null +++ "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23006_\344\273\216\345\260\276\345\210\260\345\244\264\346\211\223\345\215\260\351\223\276\350\241\250_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,48 @@ +package cn.lastwhisper.offer.面试题06_从尾到头打印链表_简单; + + +import cn.lastwhisper.leetcode.common.linkedlist.ListNode; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static cn.lastwhisper.leetcode.common.linkedlist.LinkedListUtil.createListNode; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/cong-wei-dao-tou-da-yin-lian-biao-lcof/ + * ------------------------------------------------------------------- + * 思考: + * 栈和递归的联系 + * ------------------------------------------------------------------- + * 思路:递归 + * 一、栈(能用栈就要思考能不能用递归) + * 二、递归(能用递归就要思考能不能用栈模拟递归) + * 三、反序链表,然后输出 + * 四、链表正序遍历,数组倒着插入数据 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(n) + */ + public int[] reversePrint(ListNode head) { + List result = new ArrayList<>(); + recursion(head, result); + int[] nums = new int[result.size()]; + for (int i = 0; i < result.size(); i++) { + nums[i] = result.get(i); + } + return nums; + } + + private void recursion(ListNode head, List result) { + if (head != null) { + recursion(head.next, result); + result.add(head.val); + } + } + + public static void main(String[] args) { + System.err.println(Arrays.toString(new Solution1().reversePrint(createListNode(1, 3, 2)))); + } +} \ No newline at end of file diff --git "a/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23007_\351\207\215\345\273\272\344\272\214\345\217\211\346\240\221_\344\270\255\347\255\211/Solution1.java" "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23007_\351\207\215\345\273\272\344\272\214\345\217\211\346\240\221_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..8bdbec40 --- /dev/null +++ "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23007_\351\207\215\345\273\272\344\272\214\345\217\211\346\240\221_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,55 @@ +package cn.lastwhisper.offer.面试题07_重建二叉树_中等; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; +import cn.lastwhisper.leetcode.common.tree.TreeUtil; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/cong-wei-dao-tou-da-yin-lian-biao-lcof/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * 1、找到前序root在中序的位置下标 inRootIndex + * 2、根据(1)算出前序root需要跳过多少左子树结点到下一个root leftLength + * 3、根据inRootIndex和leftLength可以找到左右子树 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(n) + */ + public TreeNode buildTree(int[] preorder, int[] inorder) { + if (preorder == null || inorder == null || preorder.length == 0 || preorder.length != inorder.length) { + return null; + } + return construct(preorder, inorder, 0, preorder.length - 1, 0, inorder.length - 1); + } + + private TreeNode construct(int[] pre, int[] in, int pStart, int pEnd, int iStart, int iEnd) { + // 先序遍历数组中的第一个元素:根节点 + TreeNode root = new TreeNode(pre[pStart]); + // 找到前序root在中序的位置 + int inRootIndex = iStart; + while (root.val != in[inRootIndex]) { + inRootIndex++; + } + // 前序的下一个root结点在哪里?跳过当前左子树结点 + // 需要跳过左子树的多少颗结点? + int leftLength = inRootIndex - iStart; + + // 有左子树 + if (leftLength > 0) { + root.left = construct(pre, in, pStart + 1, pStart + leftLength, iStart, inRootIndex - 1); + } + // 前序root在中序的位置下标不超过iEnd + if (inRootIndex < iEnd) { + root.right = construct(pre, in, pStart + leftLength + 1, pEnd, inRootIndex + 1, iEnd); + } + + return root; + } + + public static void main(String[] args) { + int[] preorder = {3, 9, 20, 15, 7}, inorder = {9, 3, 15, 20, 7}; + TreeUtil.printLevelOrder(new Solution1().buildTree(preorder, inorder)); + } +} \ No newline at end of file diff --git "a/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23008_\344\272\214\345\217\211\346\240\221\347\232\204\344\270\213\344\270\200\344\270\252\350\212\202\347\202\271/Solution_8.java" "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23008_\344\272\214\345\217\211\346\240\221\347\232\204\344\270\213\344\270\200\344\270\252\350\212\202\347\202\271/Solution_8.java" new file mode 100644 index 00000000..b50bc131 --- /dev/null +++ "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23008_\344\272\214\345\217\211\346\240\221\347\232\204\344\270\213\344\270\200\344\270\252\350\212\202\347\202\271/Solution_8.java" @@ -0,0 +1,122 @@ +package cn.lastwhisper.offer.面试题08_二叉树的下一个节点; + +/** + * 面试题8:二叉树的下一个节点 + * 思路: + * 1.若一个节点有右子树,则它下一个节点就是它右子树的最左子节点 + * 2.若一个节点无右子树 + * 2.1若该节点是它父节点的左子节点,则它下一个节点就是它的父节点 + * 2.2若该节点是它父节点的右子节点,则沿着父节点的指针向上遍历, + * 直到找到一个是它父节点的左子节点的节点,找不到说明没有下一个节点 + * 核心思想:有右子树,找自己右子树的最左子节点 + * 无右子树, + * @author cn.lastwhisper + */ +public class Solution_8 { + public static void main(String[] args) { + Solution_8 solution_8 = new Solution_8(); + TreeNode treeNode = solution_8.construct(); + //TreeNode nextNode = solution_8.GetNext(treeNode); + TreeNode nextNode = solution_8.GetNext1(treeNode); + System.out.println(nextNode.val); + } + + public TreeNode GetNext(TreeNode pNode) { + if (pNode == null) { + System.out.print("节点为null "); + return null; + } + if (pNode.right != null) { + pNode = pNode.right; + while (pNode.left != null) + pNode = pNode.left; + return pNode; + } + while (pNode.parent != null) { + if (pNode == pNode.parent.left) + return pNode.parent; + pNode = pNode.parent; + } + return null; + } + + private TreeNode GetNext1(TreeNode pNode) { + // 数据校验 + if (pNode == null) { + return null; + } + //该节点有右子树 + if (pNode.right != null) { + //若一个节点有右子树,则它下一个节点就是它右子树的最左子节点 + pNode = pNode.right; + while (pNode.left != null) { + pNode = pNode.left; + } + return pNode; + } + else { + TreeNode parentNode = pNode.parent; + if (parentNode.left == pNode) { + //若该节点是它父节点的左子节点,则它下一个节点就是它的父节点 + return parentNode; + } else if (parentNode.right == pNode) { + //若该节点是它父节点的右子节点,则沿着父节点的指针向上遍历, + //直到找到一个是它父节点的左子节点的节点,找不到说明没有下一个节点 + parentNode = pNode; + while (parentNode.parent != null) { + if (parentNode.parent.left == parentNode) { + return parentNode.parent; + } + parentNode = parentNode.parent; + } + } + } + return null; + } + + private TreeNode construct() { + TreeNode treeNode1 = new TreeNode("a"); + TreeNode treeNode2 = new TreeNode("b"); + TreeNode treeNode3 = new TreeNode("c"); + TreeNode treeNode4 = new TreeNode("d"); + TreeNode treeNode5 = new TreeNode("e"); + TreeNode treeNode6 = new TreeNode("f"); + TreeNode treeNode7 = new TreeNode("g"); + TreeNode treeNode8 = new TreeNode("h"); + TreeNode treeNode9 = new TreeNode("i"); + // a,b,c + treeNode1.left = treeNode2; + treeNode1.right = treeNode3; + treeNode2.parent = treeNode1; + treeNode3.parent = treeNode1; + // b,d,e + treeNode2.left = treeNode4; + treeNode2.right = treeNode5; + treeNode4.parent = treeNode2; + treeNode5.parent = treeNode2; + // c,f,g + treeNode3.left = treeNode6; + treeNode3.right = treeNode7; + treeNode6.parent = treeNode3; + treeNode7.parent = treeNode3; + // e,h,i + treeNode5.left = treeNode8; + treeNode5.right = treeNode9; + treeNode8.parent = treeNode5; + treeNode9.parent = treeNode5; + return treeNode1;//情景一 + //return treeNode4;//情景二 + //return treeNode9;//情景三 + } +} + +class TreeNode { + T val; + TreeNode left; + TreeNode right; + TreeNode parent; + + public TreeNode(T val) { + this.val = val; + } +} diff --git "a/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23009_\347\224\250\344\270\244\344\270\252\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227_\347\256\200\345\215\225/CQueue1.java" "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23009_\347\224\250\344\270\244\344\270\252\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227_\347\256\200\345\215\225/CQueue1.java" new file mode 100644 index 00000000..cabffa25 --- /dev/null +++ "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23009_\347\224\250\344\270\244\344\270\252\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227_\347\256\200\345\215\225/CQueue1.java" @@ -0,0 +1,63 @@ +package cn.lastwhisper.offer.面试题09_用两个栈实现队列_简单; + +import java.util.LinkedList; + +class CQueue1 { + // 只存数据 + private LinkedList inStack; + // 只出数据 + private LinkedList outStack; + + public CQueue1() { + inStack = new LinkedList<>(); + outStack = new LinkedList<>(); + } + + /** + * outStack非空 + * 1、上一次操作是outStack.pop,需要将outStack都入inStack + * + * 时间复杂度:O(n) + * 空间复杂度:O(n) + */ + public void appendTail(int value) { + while (!outStack.isEmpty()) { + inStack.push(outStack.pop()); + } + inStack.push(value); + } + + /** + * 先将inStack都放入outStack,再outStack.pop + * + * 时间复杂度:O(n) + * 空间复杂度:O(n) + */ + public int deleteHead() { + while (!inStack.isEmpty()) { + outStack.push(inStack.pop()); + } + return !outStack.isEmpty() ? outStack.pop() : -1; + } + + public static void main(String[] args) { + CQueue1 cQueue = new CQueue1(); + System.err.println(cQueue.deleteHead()); + cQueue.appendTail(1); + cQueue.appendTail(2); + cQueue.appendTail(3); + System.err.println(cQueue.deleteHead()); + System.err.println(cQueue.deleteHead()); + cQueue.appendTail(4); + System.err.println(cQueue.deleteHead()); + System.err.println(cQueue.deleteHead()); + System.err.println(cQueue.deleteHead()); + } +} + +/** + * Your CQueue object will be instantiated and called as such: + * CQueue obj = new CQueue(); + * obj.appendTail(value); + * int param_2 = obj.deleteHead(); + */ \ No newline at end of file diff --git "a/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23009_\347\224\250\344\270\244\344\270\252\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227_\347\256\200\345\215\225/CQueue2.java" "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23009_\347\224\250\344\270\244\344\270\252\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227_\347\256\200\345\215\225/CQueue2.java" new file mode 100644 index 00000000..5c810fa1 --- /dev/null +++ "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23009_\347\224\250\344\270\244\344\270\252\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227_\347\256\200\345\215\225/CQueue2.java" @@ -0,0 +1,51 @@ +package cn.lastwhisper.offer.面试题09_用两个栈实现队列_简单; + +import java.util.LinkedList; + +class CQueue2 { + + private LinkedList inStack; + + private LinkedList outStack; + + public CQueue2() { + inStack = new LinkedList<>(); + outStack = new LinkedList<>(); + } + + /** + * 时间复杂度:O(1) + */ + public void appendTail(int value) { + inStack.push(value); + } + + /** + * outStack为空先将inStack都放入outStack,再outStack.pop + * outStack不为空直接pop + * 时间复杂度:O(n) + * 空间复杂度:O(n) + */ + public int deleteHead() { + if (outStack.isEmpty()) { + while (!inStack.isEmpty()) { + outStack.push(inStack.pop()); + } + } + return !outStack.isEmpty() ? outStack.pop() : -1; + } + + public static void main(String[] args) { + CQueue2 cQueue = new CQueue2(); + System.err.println(cQueue.deleteHead()); + cQueue.appendTail(1); + cQueue.appendTail(2); + cQueue.appendTail(3); + System.err.println(cQueue.deleteHead()); + System.err.println(cQueue.deleteHead()); + cQueue.appendTail(4); + System.err.println(cQueue.deleteHead()); + System.err.println(cQueue.deleteHead()); + System.err.println(cQueue.deleteHead()); + } +} \ No newline at end of file diff --git "a/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23010_II_\351\235\222\350\233\231\350\267\263\345\217\260\351\230\266\351\227\256\351\242\230_\347\256\200\345\215\225/Solution.java" "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23010_II_\351\235\222\350\233\231\350\267\263\345\217\260\351\230\266\351\227\256\351\242\230_\347\256\200\345\215\225/Solution.java" new file mode 100644 index 00000000..c79a81a6 --- /dev/null +++ "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23010_II_\351\235\222\350\233\231\350\267\263\345\217\260\351\230\266\351\227\256\351\242\230_\347\256\200\345\215\225/Solution.java" @@ -0,0 +1,18 @@ +package cn.lastwhisper.offer.面试题10_II_青蛙跳台阶问题_简单; + +class Solution { + // cn.lastwhisper.leetcode.dynamic.爬楼梯_70_简单.Solution5 + public int numWays(int n) { + if (n == 0) return 1; + if (n < 2) return n; + int item1 = 1; + int item2 = 1; + int sum = 0; + for (int i = 2; i <= n; i++) { + sum = (item1 + item2) % 1000000007; + item1 = item2; + item2 = sum; + } + return sum; + } +} \ No newline at end of file diff --git "a/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23010_I_\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260\345\210\227_\347\256\200\345\215\225/Solution.java" "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23010_I_\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260\345\210\227_\347\256\200\345\215\225/Solution.java" new file mode 100644 index 00000000..99ecd3ed --- /dev/null +++ "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23010_I_\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260\345\210\227_\347\256\200\345\215\225/Solution.java" @@ -0,0 +1,29 @@ +package cn.lastwhisper.offer.面试题10_I_斐波那契数列_简单; + +class Solution { + // 表示循环斐波那契? + //public int fib(int n) { + // if (n < 2) return n; + // int item1 = 0; + // int item2 = 1; + // int sum = 0; + // for (int i = 2; i <= n; i++) { + // sum = (item1 + item2) % 1000000007; + // item1 = item2; + // item2 = sum; + // } + // return sum; + //} + public int fib(int n) { + if (n < 2) return n; + long item1 = 0; + long item2 = 1; + long sum = 0; + for (int i = 2; i <= n; i++) { + sum = (item1 + item2) % 1000000007; + item1 = item2; + item2 = sum; + } + return (int) sum; + } +} \ No newline at end of file diff --git "a/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23011_\346\227\213\350\275\254\346\225\260\347\273\204\347\232\204\346\234\200\345\260\217\346\225\260\345\255\227_\347\256\200\345\215\225/Solution1.java" "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23011_\346\227\213\350\275\254\346\225\260\347\273\204\347\232\204\346\234\200\345\260\217\346\225\260\345\255\227_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..ccf9cb29 --- /dev/null +++ "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23011_\346\227\213\350\275\254\346\225\260\347\273\204\347\232\204\346\234\200\345\260\217\346\225\260\345\255\227_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,60 @@ +package cn.lastwhisper.offer.面试题11_旋转数组的最小数字_简单; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/xuan-zhuan-shu-zu-de-zui-xiao-shu-zi-lcof/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * 一、遍历 + * 二、二分 + * ------------------------------------------------------------------- + * 时间复杂度:O(logn) + * 空间复杂度:O(n) + */ + public int minArray(int[] numbers) { + int left = 0, right = numbers.length - 1, middle = left; + + while (numbers[left] >= numbers[right]) { + // 找到最小值 + if (right - left == 1) { + middle = right; + break; + } + middle = (right - left) / 2 + left; + + // 无法界定middle属于前数组还是后数组 {1, 0, 1, 1, 1};//01111 + if (numbers[left] == numbers[middle] && numbers[right] == numbers[middle]) { + return sequenceSearch(left, right, numbers); + } + + if (numbers[middle] >= numbers[left]) { + left = middle; + } else if (numbers[middle] <= numbers[right]) { + right = middle; + } + } + return numbers[middle]; + } + + // 顺序查找 + public int sequenceSearch(int left, int right, int[] numbers) { + int min = numbers[left]; + for (int i = left + 1; i <= right; i++) { + if (numbers[i] < min) { + min = numbers[i]; + } + } + return min; + } + + public static void main(String[] args) { + //int[] nums = new int[]{3, 4, 5, 1, 2}; + //int[] nums = new int[]{0,0,0,0}; + //int[] nums = new int[]{1, 0, 1, 1, 1};//01111 + //int[] nums = new int[]{1,1,1,0,1};//01111 + int[] nums = new int[]{ 0, 1, 1, 1,1};//01111 + System.err.println(new Solution1().minArray(nums)); + } +} \ No newline at end of file diff --git "a/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23012_\347\237\251\351\230\265\344\270\255\347\232\204\350\267\257\345\276\204_\344\270\255\347\255\211/Solution1.java" "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23012_\347\237\251\351\230\265\344\270\255\347\232\204\350\267\257\345\276\204_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..5ba13063 --- /dev/null +++ "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23012_\347\237\251\351\230\265\344\270\255\347\232\204\350\267\257\345\276\204_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,95 @@ +package cn.lastwhisper.offer.面试题12_矩阵中的路径_中等; + +import cn.lastwhisper.leetcode.common.array.ArrayUtil; + +class Solution1 { + + /** + * 题目地址:https://leetcode-cn.com/problems/ju-zhen-zhong-de-lu-jing-lcof/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:递归+回溯 + * 递归:在board起始位置上下左右去搜索,每一个位置保证: + * 1.与该index单词字母相同 + * 2.数组不越界 + * 3.未被访问过 + * 4.index+1也满足这1、2、3、4条件 + * 回溯:将当前位置标记为未访问 + * 递归终止:index等于单词长度-1,最后一个字母相同 + * ------------------------------------------------------------------- + * 时间复杂度:O(m*n*m*n) + * 空间复杂度:O(m*n) + */ + private static final int[][] directory = new int[][]{ + {-1, 0},// up + {0, 1},// right + {1, 0},// down + {0, -1},// left + }; + + private int m, n; + + private boolean isValid(int x, int y) { + return x >= 0 && y >= 0 && x < m && y < n; + } + + public boolean exist(char[][] board, String word) { + m = board.length; + if (m == 0) { + return false; + } + n = board[0].length; + + boolean[][] visited = new boolean[m][n]; + + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + // 从word[0]开始搜索board + if (board[i][j] == word.charAt(0) && findWord(board, i, j, word, 0, visited)) { + return true; + } + } + } + + return false; + } + + /** + * @param board 矩阵 + * @param startX x + * @param startY y + * @param word 寻找的单词 + * @param index 当前对比的位置 + * @param visited 已经访问过得坐标 false表示未访问,true表示已访问 + */ + public boolean findWord(char[][] board, int startX, int startY, String word, int index, boolean[][] visited) { + if (word.length() - 1 == index) { + return board[startX][startY] == word.charAt(index); + } + + if (board[startX][startY] == word.charAt(index)) { + // 标记来过 + visited[startX][startY] = true; + + for (int i = 0; i < directory.length; i++) { + int newX = startX + directory[i][0]; + int newY = startY + directory[i][1]; + if (isValid(newX, newY) && !visited[newX][newY] && + findWord(board, newX, newY, word, index + 1, visited)) { + return true; + } + } + visited[startX][startY] = false; + } + return false; + } + + public static void main(String[] args) { + //String[][] board = new String[][]{{"A", "B", "C", "E"}, {"S", "F", "C", "S"}, {"A", "D", "E", "E"}}; + //String word = "ABCCED"; + String[][] board = new String[][]{{"a", "b"}, {"c", "d"}}; + String word = "abcd"; + System.err.println(new Solution1().exist(ArrayUtil.createCharArrays(board), word)); + } +} \ No newline at end of file diff --git "a/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23013_\346\234\272\345\231\250\344\272\272\347\232\204\350\277\220\345\212\250\350\214\203\345\233\264_\344\270\255\347\255\211/Solution1.java" "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23013_\346\234\272\345\231\250\344\272\272\347\232\204\350\277\220\345\212\250\350\214\203\345\233\264_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..ce6ea87e --- /dev/null +++ "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23013_\346\234\272\345\231\250\344\272\272\347\232\204\350\277\220\345\212\250\350\214\203\345\233\264_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,68 @@ +package cn.lastwhisper.offer.面试题13_机器人的运动范围_中等; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/ji-qi-ren-de-yun-dong-fan-wei-lcof/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:递归+回溯 DFS + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + + private static final int[][] directory = new int[][]{ + {-1, 0},// up + {0, 1},// right + {1, 0},// down + {0, -1},// left + }; + + private int m, n, k; + + private boolean isValid(int x, int y, int k) { + return x >= 0 && y >= 0 && x < m && y < n && digitalSum(x) + digitalSum(y) <= k; + } + + private int digitalSum(int num) { + int sum = 0; + while (num != 0) { + sum += num % 10; + num /= 10; + } + return sum; + } + + + private int findCount(int startX, int startY, boolean[][] visited) { + int result = 0; + + visited[startX][startY] = true; + for (int i = 0; i < directory.length; i++) { + int newX = startX + directory[i][0]; + int newY = startY + directory[i][1]; + // 接下来要访问的坐标合法,切未访问过 + if (isValid(newX, newY, k) && !visited[newX][newY]) { + result += findCount(newX, newY, visited); + } + } + + return result + 1; + } + + public int movingCount(int m, int n, int k) { + this.m = m; + this.n = n; + this.k = k; + return findCount(0, 0, new boolean[m][n]); + } + + + public static void main(String[] args) { + //int m = 2, n = 3, k = 1; + //int m = 3, n = 1, k = 0; + int m = 35, n = 38, k = 18; + System.err.println(new Solution1().movingCount(m, n, k)); + } +} \ No newline at end of file diff --git "a/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23013_\346\234\272\345\231\250\344\272\272\347\232\204\350\277\220\345\212\250\350\214\203\345\233\264_\344\270\255\347\255\211/o/Solution1.java" "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23013_\346\234\272\345\231\250\344\272\272\347\232\204\350\277\220\345\212\250\350\214\203\345\233\264_\344\270\255\347\255\211/o/Solution1.java" new file mode 100644 index 00000000..c6b668a2 --- /dev/null +++ "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23013_\346\234\272\345\231\250\344\272\272\347\232\204\350\277\220\345\212\250\350\214\203\345\233\264_\344\270\255\347\255\211/o/Solution1.java" @@ -0,0 +1,30 @@ +package cn.lastwhisper.offer.面试题13_机器人的运动范围_中等.o; + +class Solution1 { + // https://leetcode-cn.com/problems/ji-qi-ren-de-yun-dong-fan-wei-lcof/solution/mian-shi-ti-13-ji-qi-ren-de-yun-dong-fan-wei-dfs-b/ + int m, n, k; + boolean[][] visited; + + public int movingCount(int m, int n, int k) { + this.m = m; + this.n = n; + this.k = k; + this.visited = new boolean[m][n]; + return dfs(0, 0, 0, 0); + } + + public int dfs(int i, int j, int si, int sj) { + if (i < 0 || i >= m || j < 0 || j >= n || k < si + sj || visited[i][j]) return 0; + visited[i][j] = true; + return 1 + dfs(i + 1, j, digitalSum(i + 1), sj) + dfs(i, j + 1, si, digitalSum(j + 1)); + } + + private int digitalSum(int num) { + int sum = 0; + while (num != 0) { + sum += num % 10; + num /= 10; + } + return sum; + } +} \ No newline at end of file diff --git "a/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23013_\346\234\272\345\231\250\344\272\272\347\232\204\350\277\220\345\212\250\350\214\203\345\233\264_\344\270\255\347\255\211/o/Solution2.java" "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23013_\346\234\272\345\231\250\344\272\272\347\232\204\350\277\220\345\212\250\350\214\203\345\233\264_\344\270\255\347\255\211/o/Solution2.java" new file mode 100644 index 00000000..184b9de6 --- /dev/null +++ "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23013_\346\234\272\345\231\250\344\272\272\347\232\204\350\277\220\345\212\250\350\214\203\345\233\264_\344\270\255\347\255\211/o/Solution2.java" @@ -0,0 +1,34 @@ +package cn.lastwhisper.offer.面试题13_机器人的运动范围_中等.o; + +import java.util.LinkedList; +import java.util.Queue; + +class Solution2 { + + public int movingCount(int m, int n, int k) { + boolean[][] visited = new boolean[m][n]; + int res = 0; + Queue queue = new LinkedList(); + queue.add(new int[]{0, 0, 0, 0}); + while (queue.size() > 0) { + int[] x = queue.poll(); + int i = x[0], j = x[1], si = x[2], sj = x[3]; + if (i < 0 || i >= m || j < 0 || j >= n || k < si + sj || visited[i][j]) continue; + visited[i][j] = true; + res++; + queue.add(new int[]{i + 1, j, digitalSum(i + 1), sj}); + queue.add(new int[]{i, j + 1, si, digitalSum(j + 1)}); + } + return res; + } + + private int digitalSum(int num) { + int sum = 0; + while (num != 0) { + sum += num % 10; + num /= 10; + } + return sum; + } + +} \ No newline at end of file diff --git "a/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23014_II_\345\211\252\347\273\263\345\255\220_\344\270\255\347\255\211/Solution1.java" "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23014_II_\345\211\252\347\273\263\345\255\220_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..c7c63897 --- /dev/null +++ "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23014_II_\345\211\252\347\273\263\345\255\220_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,20 @@ +package cn.lastwhisper.offer.面试题14_II_剪绳子_中等; + +class Solution1 { + public int cuttingRope(int n) { + if (n <= 3) return n - 1; + int b = n % 3, p = 1000000007; + long rem = 1, x = 3; + for (int a = n / 3 - 1; a > 0; a /= 2) { + if (a % 2 == 1) rem = (rem * x) % p; + x = (x * x) % p; + } + if (b == 0) return (int) (rem * 3 % p); + if (b == 1) return (int) (rem * 4 % p); + return (int) (rem * 6 % p); + } + + public static void main(String[] args) { + System.err.println(new Solution1().cuttingRope(120)); + } +} \ No newline at end of file diff --git "a/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23014_I_\345\211\252\347\273\263\345\255\220_\344\270\255\347\255\211/Solution1.java" "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23014_I_\345\211\252\347\273\263\345\255\220_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..7d6e27b4 --- /dev/null +++ "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23014_I_\345\211\252\347\273\263\345\255\220_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,40 @@ +package cn.lastwhisper.offer.面试题14_I_剪绳子_中等; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/jian-sheng-zi-lcof/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:动态规划 + * 1、状态定义:dp[n]表示长度为n的绳子剪成若干段后得到的乘积最大值 + * 2、状态分析 + * 初始化: + * n>1 dp[2]=1、dp[3]=2 + * 常规: + * dp[n]=max(i*(n-i),i*dp[n-i]) + * 3、转换方程: + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(n) + */ + public int cuttingRope(int n) { + // 2=>1*1=1 + // 3=>1*2=2 + int[] memo = new int[n + 1]; + memo[1] = 1; + // 外循环将2~n的最大乘积推算出来 + for (int i = 2; i <= n; i++) { + // 内循环分割i(1~i-1),推算i的最大乘积 + for (int j = 1; j < i; j++) { + // + memo[i] = Math.max(memo[i], Math.max(j * (i - j), j * memo[i - j])); + } + } + return memo[n]; + } + + public static void main(String[] args) { + System.err.println(new Solution1().cuttingRope(10)); + } +} \ No newline at end of file diff --git "a/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23014_I_\345\211\252\347\273\263\345\255\220_\344\270\255\347\255\211/Solution2.java" "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23014_I_\345\211\252\347\273\263\345\255\220_\344\270\255\347\255\211/Solution2.java" new file mode 100644 index 00000000..ffe037e6 --- /dev/null +++ "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23014_I_\345\211\252\347\273\263\345\255\220_\344\270\255\347\255\211/Solution2.java" @@ -0,0 +1,41 @@ +package cn.lastwhisper.offer.面试题14_I_剪绳子_中等; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/jian-sheng-zi-lcof/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:贪心算法 + * n>=5时 2(n-2)>n、3(n-3)>n ===》 3(n-3)>2(n-2) + * ------------------------------------------------------------------- + * 时间复杂度:O(1) + * 空间复杂度:O(1) + */ + public int cuttingRope(int n) { + if (n <= 3) return n - 1;// 2 3 + int time0f3 = n / 3, b = n % 3; + if (b == 0) return (int) Math.pow(3, time0f3);//6 9 + if (b == 1) return (int) Math.pow(3, time0f3 - 1) * 4;// 4 7 10 13 + return (int) Math.pow(3, time0f3) * 2;// 5 8 11 + } + // logn + //public int cuttingRope(int n) { + // // 2=>1*1=1 + // // 3=>1*2=2 + // if (n < 4) { + // return n-1; + // } + // + // int sum = 1; + // while (n > 4) { + // sum *= 3; + // n -= 3; + // } + // return sum * n; + //} + + public static void main(String[] args) { + System.err.println(new Solution2().cuttingRope(10)); + } +} \ No newline at end of file diff --git "a/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23015_\344\272\214\350\277\233\345\210\266\344\270\2551\347\232\204\344\270\252\346\225\260_\347\256\200\345\215\225/Solution.java" "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23015_\344\272\214\350\277\233\345\210\266\344\270\2551\347\232\204\344\270\252\346\225\260_\347\256\200\345\215\225/Solution.java" new file mode 100644 index 00000000..1fe6091a --- /dev/null +++ "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23015_\344\272\214\350\277\233\345\210\266\344\270\2551\347\232\204\344\270\252\346\225\260_\347\256\200\345\215\225/Solution.java" @@ -0,0 +1,24 @@ +package cn.lastwhisper.offer.面试题15_二进制中1的个数_简单; + +class Solution { + // you need to treat n as an unsigned value + public int hammingWeight(int n) { + int count = 0; + while (n != 0) { + // n=10011101,n-1=10011100 + // &全1则1,否则0 + // n & (n - 1)=10011101&10011100=10011100 + // n=10011100 + n = n & (n - 1); + count++; + } + return count; + } + + public static void main(String[] args){ + System.err.println(new Solution().hammingWeight(00000000000000000000000000001011)); + System.err.println(new Solution().hammingWeight(00000000000000000000000010000000)); + //System.err.println(new Solution().hammingWeight(11111111111111111111111111111101)); + } + +} \ No newline at end of file diff --git "a/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23016_\346\225\260\345\200\274\347\232\204\346\225\264\346\225\260\346\254\241\346\226\271_\344\270\255\347\255\211/Solution1.java" "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23016_\346\225\260\345\200\274\347\232\204\346\225\264\346\225\260\346\254\241\346\226\271_\344\270\255\347\255\211/Solution1.java" new file mode 100644 index 00000000..37961c76 --- /dev/null +++ "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23016_\346\225\260\345\200\274\347\232\204\346\225\264\346\225\260\346\254\241\346\226\271_\344\270\255\347\255\211/Solution1.java" @@ -0,0 +1,51 @@ +package cn.lastwhisper.offer.面试题16_数值的整数次方_中等; + + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/shu-zhi-de-zheng-shu-ci-fang-lcof/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * 一、n=-2147483648无法处理 + * 二、二分优化n^8=n^4^2=n^2^2^2 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(n) + */ + public double myPow(double x, int n) { + if (x == 0) { + return 0; + } + // x底数 n指数 + double result; + + int absExponent = n; + if (n < 0) absExponent = -n; + result = pow(x, absExponent); + + if (n < 0) { + result = 1.0 / result; + } + + return result; + } + + public double pow(double base, int exponent) { + double result = 1.0; + for (int i = 0; i < exponent; i++) { + result *= base; + } + return result; + } + + public static void main(String[] args) { + //System.err.println(new Solution1().myPow(2.00000, 2)); + //System.err.println(new Solution1().myPow(2.00000, -2)); + //System.err.println(new Solution1().myPow(2.00000, 0)); + System.err.println(new Solution1().myPow(0, 0)); + System.err.println(new Solution1().myPow(-1, 0)); + System.err.println(new Solution1().myPow(2.00000, 10)); + } +} \ No newline at end of file diff --git "a/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23016_\346\225\260\345\200\274\347\232\204\346\225\264\346\225\260\346\254\241\346\226\271_\344\270\255\347\255\211/Solution2.java" "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23016_\346\225\260\345\200\274\347\232\204\346\225\264\346\225\260\346\254\241\346\226\271_\344\270\255\347\255\211/Solution2.java" new file mode 100644 index 00000000..3261f3eb --- /dev/null +++ "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23016_\346\225\260\345\200\274\347\232\204\346\225\264\346\225\260\346\254\241\346\226\271_\344\270\255\347\255\211/Solution2.java" @@ -0,0 +1,34 @@ +package cn.lastwhisper.offer.面试题16_数值的整数次方_中等; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/shu-zhi-de-zheng-shu-ci-fang-lcof/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(n) + */ + public double myPow(double x, int n) { + double res = 1.0; + for (int i = n; i != 0; i /= 2) { + if (i % 2 != 0) { + res *= x; + } + x *= x; + } + return n < 0 ? 1 / res : res; + } + + public static void main(String[] args) { + //System.err.println(new Solution2().myPow(2.00000, 2)); + //System.err.println(new Solution2().myPow(2.00000, -2)); + //System.err.println(new Solution2().myPow(2.00000, 0)); + //System.err.println(new Solution2().myPow(0, 0)); + //System.err.println(new Solution2().myPow(-1, 0)); + //System.err.println(new Solution2().myPow(2.00000, 10)); + System.err.println(new Solution2().myPow(2.00000, -2147483648)); + } +} \ No newline at end of file diff --git "a/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23016_\346\225\260\345\200\274\347\232\204\346\225\264\346\225\260\346\254\241\346\226\271_\344\270\255\347\255\211/Solution3.java" "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23016_\346\225\260\345\200\274\347\232\204\346\225\264\346\225\260\346\254\241\346\226\271_\344\270\255\347\255\211/Solution3.java" new file mode 100644 index 00000000..0cd68a8f --- /dev/null +++ "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23016_\346\225\260\345\200\274\347\232\204\346\225\264\346\225\260\346\254\241\346\226\271_\344\270\255\347\255\211/Solution3.java" @@ -0,0 +1,25 @@ +package cn.lastwhisper.offer.面试题16_数值的整数次方_中等; + +class Solution3 { + public double myPow(double x, int n) { + // 指数-偶数 + if (n == 0) { + return 1; + } + // 指数-奇数 + if (n == 1) { + return x; + } + // 指数-负数 + if (n == -1) { + return 1 / x; + } + double half = myPow(x, n / 2);//n>>1 + double base = myPow(x, n % 2); + return half * half * base; + } + + public static void main(String[] args){ + System.err.println(new Solution3().myPow(34.00515,-3)); + } +} \ No newline at end of file diff --git "a/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23017_\346\211\223\345\215\260\344\273\2161\345\210\260\346\234\200\345\244\247\347\232\204n\344\275\215\346\225\260_\347\256\200\345\215\225/Solution1.java" "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23017_\346\211\223\345\215\260\344\273\2161\345\210\260\346\234\200\345\244\247\347\232\204n\344\275\215\346\225\260_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..46cc3f9e --- /dev/null +++ "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23017_\346\211\223\345\215\260\344\273\2161\345\210\260\346\234\200\345\244\247\347\232\204n\344\275\215\346\225\260_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,39 @@ +package cn.lastwhisper.offer.面试题17_打印从1到最大的n位数_简单; + +import java.util.Arrays; + +class Solution1 { + + /** + * 题目地址:https://leetcode-cn.com/problems/da-yin-cong-1dao-zui-da-de-nwei-shu-lcof/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * 如何构造n个9 + * 一、9循环*10+9 + * 二、pow(10,n)-1 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(1) + */ + public int[] printNumbers(int n) { + + int base = 9; + for (int i = 1; i < n; i++) { + base *= 10; + base += 9; + } + + int[] nums = new int[base]; + for (int i = 0; i < base; i++) { + nums[i] = i + 1; + } + return nums; + } + + public static void main(String[] args) { + System.err.println(Arrays.toString(new Solution1().printNumbers(1))); + System.err.println(Arrays.toString(new Solution1().printNumbers(2))); + } +} \ No newline at end of file diff --git "a/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23018_\345\210\240\351\231\244\351\223\276\350\241\250\347\232\204\350\212\202\347\202\271_\347\256\200\345\215\225/Solution1.java" "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23018_\345\210\240\351\231\244\351\223\276\350\241\250\347\232\204\350\212\202\347\202\271_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..494058bc --- /dev/null +++ "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23018_\345\210\240\351\231\244\351\223\276\350\241\250\347\232\204\350\212\202\347\202\271_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,43 @@ +package cn.lastwhisper.offer.面试题18_删除链表的节点_简单; + +import cn.lastwhisper.leetcode.common.linkedlist.LinkedListUtil; +import cn.lastwhisper.leetcode.common.linkedlist.ListNode; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/shan-chu-lian-biao-de-jie-dian-lcof/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(n) + */ + public ListNode deleteNode(ListNode head, int val) { + ListNode vNode = new ListNode(-1); + vNode.next = head; + + ListNode prev = vNode; + while (head != null) { + if (head.val == val) { + prev.next = head.next; + break; + } + prev = head; + head = head.next; + } + + return vNode.next; + } + + public static void main(String[] args) { + int[] head = {4, 5, 1, 9}; + //int val = 4; + //int val = 1; + int val = 9; + + ListNode listNode = LinkedListUtil.createListNode(head); + LinkedListUtil.printListNode(new Solution1().deleteNode(listNode, val)); + } +} \ No newline at end of file diff --git "a/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23019_\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217\345\214\271\351\205\215/Solution1.java" "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23019_\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217\345\214\271\351\205\215/Solution1.java" new file mode 100644 index 00000000..9105c703 --- /dev/null +++ "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23019_\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217\345\214\271\351\205\215/Solution1.java" @@ -0,0 +1,42 @@ +package cn.lastwhisper.offer.面试题19_正则表达式匹配; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/shan-chu-lian-biao-de-jie-dian-lcof/ + * ------------------------------------------------------------------- + * 思考: + * p的第二个字符是"*" + * 一、p跳过两个字符 + * 二、text和p第一个字符匹配的前提下,text跳过第一个字符 + * ------------------------------------------------------------------- + * 思路: + * ------------------------------------------------------------------- + * 时间复杂度:O() + * 空间复杂度:O() + */ + public boolean isMatch(String text, String pattern) { + if (pattern.isEmpty()) return text.isEmpty(); + // text="a",p="a"或者"."都匹配 + boolean first_match = (!text.isEmpty() && + (pattern.charAt(0) == text.charAt(0) || pattern.charAt(0) == '.')); + // p的第二个字符是"*" + if (pattern.length() >= 2 && pattern.charAt(1) == '*') { + // 一、跳过p第一个字符和第二个"*",因为"*"可以匹配0个字符,示例:text="aaa",p="ab*ac*a" + return (isMatch(text, pattern.substring(2)) || + // 二、text和p第一个字符匹配的前提下,text继续向下匹配,示例:text="aa",p="a" + (first_match && isMatch(text.substring(1), pattern))); + } else { + // text和p第一个字符匹配的前提下,p的第二个字符不是"*",继续匹配 + return first_match && isMatch(text.substring(1), pattern.substring(1)); + } + } + + + public static void main(String[] args) { + String text = "a", pattern = "c*a"; + //String text = "aaa", pattern = "a.a"; + //String text = "aaa", pattern = "ab*ac*a"; + System.err.println(new Solution1().isMatch(text, pattern)); + } + +} \ No newline at end of file diff --git "a/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23020_\350\241\250\347\244\272\346\225\260\345\200\274\347\232\204\345\255\227\347\254\246\344\270\262/Solution1.java" "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23020_\350\241\250\347\244\272\346\225\260\345\200\274\347\232\204\345\255\227\347\254\246\344\270\262/Solution1.java" new file mode 100644 index 00000000..952a91fd --- /dev/null +++ "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23020_\350\241\250\347\244\272\346\225\260\345\200\274\347\232\204\345\255\227\347\254\246\344\270\262/Solution1.java" @@ -0,0 +1,58 @@ +package cn.lastwhisper.offer.面试题20_表示数值的字符串; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/biao-shi-shu-zhi-de-zi-fu-chuan-lcof/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(1) + */ + public boolean isNumber(String s) { + s = s.trim(); + boolean pointScan = false, eScan = false, numberScan = false, numberAfterEScan = true; + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + if (c <= '9' && c >= '0') { + // 出现0~9 + numberScan = true; + numberAfterEScan = true; + } else if (c == 'e') { + // 出现'e',true:1.23e10、0.5e-10、0.5e04、05047e+6 + // e不能出现两次||number出现后e才可以出现 + if (eScan || !numberScan) { + return false; + } + // num之后找到e + numberAfterEScan = false; + eScan = true; + } else if (c == '.') { + // 出现'.',true:0.、123.5、0.5e04、0.5e-10 + // '.'前面不能有点||不能有e + if (eScan || pointScan) { + return false; + } + pointScan = true; + } else if (c == '-' || c == '+') { + // '-'、、'+'必须出现在第一位,同时第二位不能是e + if (i != 0 && s.charAt(i - 1) != 'e') { + return false; + } + } else { + return false; + } + + } + + return numberScan && numberAfterEScan; + } + + public static void main(String[] args) { + String expression = ""; + + System.err.println(new Solution1().isNumber(expression)); + } +} \ No newline at end of file diff --git "a/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23021_\350\260\203\346\225\264\346\225\260\347\273\204\351\241\272\345\272\217\344\275\277\345\245\207\346\225\260\344\275\215\344\272\216\345\201\266\346\225\260\345\211\215\351\235\242/Solution1.java" "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23021_\350\260\203\346\225\264\346\225\260\347\273\204\351\241\272\345\272\217\344\275\277\345\245\207\346\225\260\344\275\215\344\272\216\345\201\266\346\225\260\345\211\215\351\235\242/Solution1.java" new file mode 100644 index 00000000..1fe7ca7e --- /dev/null +++ "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23021_\350\260\203\346\225\264\346\225\260\347\273\204\351\241\272\345\272\217\344\275\277\345\245\207\346\225\260\344\275\215\344\272\216\345\201\266\346\225\260\345\211\215\351\235\242/Solution1.java" @@ -0,0 +1,41 @@ +package cn.lastwhisper.offer.面试题21_调整数组顺序使奇数位于偶数前面; + +import java.util.Arrays; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/diao-zheng-shu-zu-shun-xu-shi-qi-shu-wei-yu-ou-shu-qian-mian-lcof/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:双指针交换奇偶 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(1) + */ + public int[] exchange(int[] nums) { + int left = 0, right = nums.length - 1; + while (left < right) { + // left指向偶数 + while (left < right && nums[left] % 2 == 1) { + left++; + } + // right指向奇数 + while (left < right && nums[right] % 2 == 0) { + right--; + } + if (left < right) { + int temp = nums[left]; + nums[left] = nums[right]; + nums[right] = temp; + } + } + return nums; + } + + + public static void main(String[] args) { + int[] nums = new int[]{1, 2, 3, 4}; + System.out.println(Arrays.toString(new Solution1().exchange(nums))); + } +} \ No newline at end of file diff --git "a/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23021_\350\260\203\346\225\264\346\225\260\347\273\204\351\241\272\345\272\217\344\275\277\345\245\207\346\225\260\344\275\215\344\272\216\345\201\266\346\225\260\345\211\215\351\235\242/Solution2.java" "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23021_\350\260\203\346\225\264\346\225\260\347\273\204\351\241\272\345\272\217\344\275\277\345\245\207\346\225\260\344\275\215\344\272\216\345\201\266\346\225\260\345\211\215\351\235\242/Solution2.java" new file mode 100644 index 00000000..2725166f --- /dev/null +++ "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23021_\350\260\203\346\225\264\346\225\260\347\273\204\351\241\272\345\272\217\344\275\277\345\245\207\346\225\260\344\275\215\344\272\216\345\201\266\346\225\260\345\211\215\351\235\242/Solution2.java" @@ -0,0 +1,75 @@ +package cn.lastwhisper.offer.面试题21_调整数组顺序使奇数位于偶数前面; + +import java.util.Arrays; + +class Solution2 { + // 抽象规则 + public interface Rule { + boolean judge(int num); + } + + // 具体规则 + static class OddEvenRule implements Rule { + @Override + public boolean judge(int num) { + return (num & 1) == 1;//奇数true + } + } + + // 工厂方法 抽象工厂类 + abstract static class RuleFactory { + public abstract Rule getRule(); + } + + // 具体工厂类 + static class OddEvenRuleFactory extends RuleFactory { + @Override + public Rule getRule() { + return new OddEvenRule(); + } + } + + /** + * 题目地址:https://leetcode-cn.com/problems/diao-zheng-shu-zu-shun-xu-shi-qi-shu-wei-yu-ou-shu-qian-mian-lcof/ + * ------------------------------------------------------------------- + * 思考: 适配规则 + * Q:如果问题改成正负数、或者其他分区规则如何适配? + * A:使用工厂方法,需要添加新规则时。 + * 只需实现Rule接口,添加具体规则,以及实现RuleFactory,添加具体规则的创建工厂 + * ------------------------------------------------------------------- + * 思路:双指针交换奇偶 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(1) + */ + public int[] exchange(int[] nums) { + RuleFactory ruleFactory = new OddEvenRuleFactory(); + return exchange(nums, ruleFactory.getRule()); + } + + public int[] exchange(int[] nums, Rule rule) { + int left = 0, right = nums.length - 1; + while (left < right) { + // left找到偶数 + while (left < right && rule.judge(nums[left])) { + left++; + } + // right找到奇数 + while (left < right && !rule.judge(nums[right])) { + right--; + } + // 把奇偶数交换 + if (left < right) { + int temp = nums[left]; + nums[left] = nums[right]; + nums[right] = temp; + } + } + return nums; + } + + public static void main(String[] args) { + int[] nums = new int[]{1, 2, 3, 4}; + System.out.println(Arrays.toString(new Solution2().exchange(nums))); + } +} \ No newline at end of file diff --git "a/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23022_\351\223\276\350\241\250\344\270\255\345\200\222\346\225\260\347\254\254k\344\270\252\350\212\202\347\202\271/Solution1.java" "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23022_\351\223\276\350\241\250\344\270\255\345\200\222\346\225\260\347\254\254k\344\270\252\350\212\202\347\202\271/Solution1.java" new file mode 100644 index 00000000..89fc5fcb --- /dev/null +++ "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23022_\351\223\276\350\241\250\344\270\255\345\200\222\346\225\260\347\254\254k\344\270\252\350\212\202\347\202\271/Solution1.java" @@ -0,0 +1,38 @@ +package cn.lastwhisper.offer.面试题22_链表中倒数第k个节点; + +import cn.lastwhisper.leetcode.common.linkedlist.LinkedListUtil; +import cn.lastwhisper.leetcode.common.linkedlist.ListNode; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/diao-zheng-shu-zu-shun-xu-shi-qi-shu-wei-yu-ou-shu-qian-mian-lcof/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:双指针、快慢指针 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(1) + */ + public ListNode getKthFromEnd(ListNode head, int k) { + + ListNode fastNode = head; + ListNode slowNode = head; + while (k > 0) { + fastNode = fastNode.next; + k--; + } + + while (fastNode != null) { + fastNode = fastNode.next; + slowNode = slowNode.next; + } + + return slowNode; + } + + public static void main(String[] args) { + ListNode listNode = LinkedListUtil.createListNode(1, 2, 3, 4, 5); + LinkedListUtil.printListNode(new Solution1().getKthFromEnd(listNode, 2)); + } +} \ No newline at end of file diff --git "a/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23024_\345\217\215\350\275\254\351\223\276\350\241\250/Solution1.java" "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23024_\345\217\215\350\275\254\351\223\276\350\241\250/Solution1.java" new file mode 100644 index 00000000..491ac833 --- /dev/null +++ "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23024_\345\217\215\350\275\254\351\223\276\350\241\250/Solution1.java" @@ -0,0 +1,35 @@ +package cn.lastwhisper.offer.面试题24_反转链表; + +import cn.lastwhisper.leetcode.common.linkedlist.LinkedListUtil; +import cn.lastwhisper.leetcode.common.linkedlist.ListNode; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/fan-zhuan-lian-biao-lcof/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:循环反转 + * 三个指针prev、curr、next,注意next要在while里面先记录curr.next + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(1) + */ + public ListNode reverseList(ListNode head) { + ListNode prev = null, curr = head, next; + + while (curr != null) { + next = curr.next; + + curr.next = prev; + prev = curr; + curr = next; + } + return prev; + } + + public static void main(String[] args) { + ListNode listNode = LinkedListUtil.createListNode(1, 2, 3, 4, 5); + LinkedListUtil.printListNode(new Solution1().reverseList(listNode)); + } +} \ No newline at end of file diff --git "a/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23024_\345\217\215\350\275\254\351\223\276\350\241\250/Solution2.java" "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23024_\345\217\215\350\275\254\351\223\276\350\241\250/Solution2.java" new file mode 100644 index 00000000..fdd2ec59 --- /dev/null +++ "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23024_\345\217\215\350\275\254\351\223\276\350\241\250/Solution2.java" @@ -0,0 +1,37 @@ +package cn.lastwhisper.offer.面试题24_反转链表; + +import cn.lastwhisper.leetcode.common.linkedlist.LinkedListUtil; +import cn.lastwhisper.leetcode.common.linkedlist.ListNode; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/fan-zhuan-lian-biao-lcof/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:递归反转 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(n) + */ + public ListNode reverseList(ListNode head) { + // 找到链表的最后一个结点 + if (head == null || head.next == null) + return head; + + ListNode rhead = reverseList(head.next); + + // 每次反转链表末尾的两个节点 + // head->next此刻指向head后面的链表的尾节点 + // head->next->next = head把head节点放在了尾部 + head.next.next = head; + head.next = null; + + return rhead; + } + + public static void main(String[] args) { + ListNode listNode = LinkedListUtil.createListNode(1, 2, 3, 4, 5); + LinkedListUtil.printListNode(new Solution2().reverseList(listNode)); + } +} \ No newline at end of file diff --git "a/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23025_\345\220\210\345\271\266\344\270\244\344\270\252\346\216\222\345\272\217\347\232\204\351\223\276\350\241\250/Solution1.java" "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23025_\345\220\210\345\271\266\344\270\244\344\270\252\346\216\222\345\272\217\347\232\204\351\223\276\350\241\250/Solution1.java" new file mode 100644 index 00000000..85a76a6c --- /dev/null +++ "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23025_\345\220\210\345\271\266\344\270\244\344\270\252\346\216\222\345\272\217\347\232\204\351\223\276\350\241\250/Solution1.java" @@ -0,0 +1,44 @@ +package cn.lastwhisper.offer.面试题25_合并两个排序的链表; + +import cn.lastwhisper.leetcode.common.linkedlist.LinkedListUtil; +import cn.lastwhisper.leetcode.common.linkedlist.ListNode; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/fan-zhuan-lian-biao-lcof/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:合并k个链表? + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(1) + */ + public ListNode mergeTwoLists(ListNode l1, ListNode l2) { + ListNode vNode = new ListNode(-1); + ListNode curr = vNode; + + while (l1 != null && l2 != null) { + if (l1.val < l2.val) { + curr.next = l1; + l1 = l1.next; + } else { + curr.next = l2; + l2 = l2.next; + } + curr = curr.next; + } + + curr.next = l1 == null ? l2 : l1; + + return vNode.next; + } + + public static void main(String[] args) { + ListNode l1 = LinkedListUtil.createListNode(1, 2, 4); + ListNode l2 = LinkedListUtil.createListNode(1, 3, 4); + + LinkedListUtil.printListNode(new Solution1().mergeTwoLists(l1, l2)); + + } +} \ No newline at end of file diff --git "a/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23026_\346\240\221\347\232\204\345\255\220\347\273\223\346\236\204/Solution1.java" "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23026_\346\240\221\347\232\204\345\255\220\347\273\223\346\236\204/Solution1.java" new file mode 100644 index 00000000..863b39a9 --- /dev/null +++ "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23026_\346\240\221\347\232\204\345\255\220\347\273\223\346\236\204/Solution1.java" @@ -0,0 +1,56 @@ +package cn.lastwhisper.offer.面试题26_树的子结构; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; +import cn.lastwhisper.leetcode.common.tree.TreeUtil; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/shu-de-zi-jie-gou-lcof/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:写个对比方法 + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public boolean isSubStructure(TreeNode A, TreeNode B) { + // A、B树都为空 true + if (A == null && B == null) { + return true; + } + // A或B为空 false + if (A == null || B == null) { + return false; + } + return compare(A, B) || isSubStructure(A.left, B) || isSubStructure(A.right, B); + } + + // 负责对比两颗树 + private boolean compare(TreeNode root1, TreeNode root2) { + if (root1 == null && root2 == null) { + return true; + } + // A不为空,B为空说明前面都对上了 + if (root2 == null) { + return true; + } + // B不为空,A为空说明对个屁 + if (root1 == null) { + return false; + } + // 相等时继续对比 + if (root1.val == root2.val) { + return compare(root1.left, root2.left) && compare(root1.right, root2.right); + } + return false; + } + + public static void main(String[] args) { + //TreeNode A = TreeUtils.createTree(1, 2, 3); + //TreeNode B = TreeUtils.createTree(3, 1); + TreeNode A = TreeUtil.createTree(3, 4, 5, 1, 2); + TreeNode B = TreeUtil.createTree(4, 1); + System.out.println(new Solution1().isSubStructure(A, B)); + } +} \ No newline at end of file diff --git "a/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23027_\344\272\214\345\217\211\346\240\221\347\232\204\351\225\234\345\203\217/Solution1.java" "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23027_\344\272\214\345\217\211\346\240\221\347\232\204\351\225\234\345\203\217/Solution1.java" new file mode 100644 index 00000000..cf03f38d --- /dev/null +++ "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23027_\344\272\214\345\217\211\346\240\221\347\232\204\351\225\234\345\203\217/Solution1.java" @@ -0,0 +1,33 @@ +package cn.lastwhisper.offer.面试题27_二叉树的镜像; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; +import cn.lastwhisper.leetcode.common.tree.TreeUtil; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/er-cha-shu-de-jing-xiang-lcof/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: cn.lastwhisper.leetcode.binarytree.翻转二叉树_226_简单 + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public TreeNode mirrorTree(TreeNode root) { + if (root == null) { + return null; + } + + TreeNode temp = root.left; + root.left = mirrorTree(root.right); + root.right = mirrorTree(temp); + + return root; + } + + public static void main(String[] args) { + TreeNode tree = TreeUtil.createTree(4, 2, 7, 1, 3, 6, 9); + TreeUtil.printLevelOrder(new Solution1().mirrorTree(tree)); + } +} \ No newline at end of file diff --git "a/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23028_\345\257\271\347\247\260\347\232\204\344\272\214\345\217\211\346\240\221/Solution1.java" "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23028_\345\257\271\347\247\260\347\232\204\344\272\214\345\217\211\346\240\221/Solution1.java" new file mode 100644 index 00000000..e2d01313 --- /dev/null +++ "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23028_\345\257\271\347\247\260\347\232\204\344\272\214\345\217\211\346\240\221/Solution1.java" @@ -0,0 +1,41 @@ +package cn.lastwhisper.offer.面试题28_对称的二叉树; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; +import cn.lastwhisper.leetcode.common.tree.TreeUtil; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/er-cha-shu-de-jing-xiang-lcof/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(n) + */ + public boolean isSymmetric(TreeNode root) { + if (root == null) { + return true; + } + // 对比左右子树是否相等 + return isSymmetric(root.left, root.right); + } + + private boolean isSymmetric(TreeNode root1, TreeNode root2) { + if (root1 == null && root2 == null) { + return true; + } + if (root1 == null || root2 == null) { + return false; + } + if (root1.val == root2.val) { + return isSymmetric(root1.left, root2.right)&&isSymmetric(root1.right, root2.left); + } + return false; + } + + public static void main(String[] args) { + System.out.println(new Solution1().isSymmetric(TreeUtil.createTree(1, 2, 2, 3, 4, 4, 3))); + } +} \ No newline at end of file diff --git "a/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23029_\351\241\272\346\227\266\351\222\210\346\211\223\345\215\260\347\237\251\351\230\265/Solution1.java" "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23029_\351\241\272\346\227\266\351\222\210\346\211\223\345\215\260\347\237\251\351\230\265/Solution1.java" new file mode 100644 index 00000000..624ab770 --- /dev/null +++ "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23029_\351\241\272\346\227\266\351\222\210\346\211\223\345\215\260\347\237\251\351\230\265/Solution1.java" @@ -0,0 +1,54 @@ +package cn.lastwhisper.offer.面试题29_顺时针打印矩阵; + +import java.util.Arrays; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/shun-shi-zhen-da-yin-ju-zhen-lcof/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * ------------------------------------------------------------------- + * 时间复杂度:O(n^2) + * 空间复杂度:O(n^2) + */ + public int[] spiralOrder(int[][] matrix) { + if (matrix == null || matrix.length == 0) return new int[0]; + int[] result = new int[matrix.length * matrix[0].length]; + // nowColumn当前所在列、totalColumn总列数、nowRow当前所在行、totalRow总行数 + int nowColumn = 0, totalColumn = matrix[0].length - 1, nowRow = 0, totalRow = matrix.length - 1; + int index = 0; + // 顺时针遍历 + while (nowColumn <= totalColumn && nowRow <= totalRow) { + //只有一列,不需要从左到右 + for (int i = nowColumn; i <= totalColumn; i++) {//第一步 从左到右 + result[index++] = matrix[nowRow][i]; + } + //只有一行,不需要从上到下 + for (int i = nowRow + 1; i <= totalRow; i++) {//第二步 从上到下 + result[index++] = matrix[i][totalColumn]; + } + if (nowRow != totalRow) {//同行,不需要从右向左遍历 + for (int i = totalColumn - 1; i >= nowColumn; i--) {//第三步 从右向左 + result[index++] = matrix[totalRow][i]; + } + } + if (nowColumn != totalColumn) {//同列,不需要从下到上遍历 + for (int i = totalRow - 1; i > nowRow; i--) {// 第四步 从下到上 + result[index++] = matrix[i][nowColumn]; + } + } + nowColumn++; + nowRow++; + totalColumn--; + totalRow--; + } + return result; + } + + public static void main(String[] args) { + int[][] matrix = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}; + System.out.println(Arrays.toString(new Solution1().spiralOrder(matrix))); + } +} \ No newline at end of file diff --git "a/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23030_\345\214\205\345\220\253min\345\207\275\346\225\260\347\232\204\346\240\210/MinStack.java" "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23030_\345\214\205\345\220\253min\345\207\275\346\225\260\347\232\204\346\240\210/MinStack.java" new file mode 100644 index 00000000..df3d12b0 --- /dev/null +++ "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23030_\345\214\205\345\220\253min\345\207\275\346\225\260\347\232\204\346\240\210/MinStack.java" @@ -0,0 +1,66 @@ +package cn.lastwhisper.offer.面试题30_包含min函数的栈; + +import org.junit.Assert; + +import java.util.LinkedList; + +class MinStack { + /** + * 题目地址:https://leetcode-cn.com/problems/bao-han-minhan-shu-de-zhan-lcof/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + LinkedList dataStack = new LinkedList<>(); + LinkedList minStack = new LinkedList<>(); + + /** initialize your data structure here. */ + public MinStack() { + + } + + // minStack为空,直接插入。不为空,peek栈顶和当前值相比,push最小值 + public void push(int x) { + // 保证minStack栈顶永远是最小值 + if (!minStack.isEmpty()) { + Integer min = minStack.peek(); + if (min > x) { + minStack.push(x); + } else { + minStack.push(min); + } + } else { + minStack.push(x); + } + dataStack.push(x); + } + + public void pop() { + dataStack.pop(); + minStack.pop(); + } + + public int top() { + return dataStack.peek(); + } + + public int min() { + return minStack.peek(); + } + + public static void main(String[] args) { + MinStack minStack = new MinStack(); + minStack.push(-2); + minStack.push(0); + minStack.push(-3); + Assert.assertEquals(-3, minStack.min()); // --> 返回 -3. + minStack.pop(); + Assert.assertEquals(0, minStack.top()); // --> 返回 0. + Assert.assertEquals(-2, minStack.min()); // --> 返回 -2. + } +} + diff --git "a/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23031_\346\240\210\347\232\204\345\216\213\345\205\245\345\274\271\345\207\272\345\272\217\345\210\227/Solution1.java" "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23031_\346\240\210\347\232\204\345\216\213\345\205\245\345\274\271\345\207\272\345\272\217\345\210\227/Solution1.java" new file mode 100644 index 00000000..2e731603 --- /dev/null +++ "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23031_\346\240\210\347\232\204\345\216\213\345\205\245\345\274\271\345\207\272\345\272\217\345\210\227/Solution1.java" @@ -0,0 +1,36 @@ +package cn.lastwhisper.offer.面试题31_栈的压入弹出序列; + +import java.util.LinkedList; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/bao-han-minhan-shu-de-zhan-lcof/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public boolean validateStackSequences(int[] pushed, int[] popped) { + LinkedList stack = new LinkedList<>(); + + int index = 0; + for (int item : pushed) { + stack.push(item); + while (index < popped.length && !stack.isEmpty() && stack.peek() == popped[index]) { + stack.pop(); + index++; + } + } + + return index == popped.length; + } + + public static void main(String[] args) { + //int[] pushed = {1, 2, 3, 4, 5}, popped = {4, 5, 3, 2, 1}; + int[] pushed = {1, 2, 3, 4, 5}, popped = {4, 3, 5, 1, 5}; + System.out.println(new Solution1().validateStackSequences(pushed, popped)); + } +} \ No newline at end of file diff --git "a/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23032_III_\344\273\216\344\270\212\345\210\260\344\270\213\346\211\223\345\215\260\344\272\214\345\217\211\346\240\221III/Solution1.java" "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23032_III_\344\273\216\344\270\212\345\210\260\344\270\213\346\211\223\345\215\260\344\272\214\345\217\211\346\240\221III/Solution1.java" new file mode 100644 index 00000000..d9cab9f4 --- /dev/null +++ "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23032_III_\344\273\216\344\270\212\345\210\260\344\270\213\346\211\223\345\215\260\344\272\214\345\217\211\346\240\221III/Solution1.java" @@ -0,0 +1,52 @@ +package cn.lastwhisper.offer.面试题32_III_从上到下打印二叉树III; + +import cn.lastwhisper.leetcode.common.print.PrintUtil; +import cn.lastwhisper.leetcode.common.tree.TreeNode; +import cn.lastwhisper.leetcode.common.tree.TreeUtil; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/cong-shang-dao-xia-da-yin-er-cha-shu-iii-lcof/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:z字层次遍历 + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public List> levelOrder(TreeNode root) { + List> result = new ArrayList<>(); + // 特判 + if (root == null) return result; + Queue queue = new LinkedList<>(); + queue.add(root); + + while (!queue.isEmpty()) { + int size = queue.size();//记录每层的元素个数 + LinkedList list = new LinkedList<>(); + for (int i = 0; i < size; i++) { + root = queue.poll(); + // result代表层级 + if (result.size() % 2 == 0) {//奇数倒序 + list.add(root.val); + } else { + list.push(root.val); + } + if (root.left != null) queue.add(root.left); + if (root.right != null) queue.add(root.right); + } + result.add(list); + } + return result; + } + + public static void main(String[] args) { + PrintUtil.printLists(new Solution1().levelOrder(TreeUtil.createTree(3, 9, 20, null, null, 15, 7))); + } +} \ No newline at end of file diff --git "a/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23032_II_\344\273\216\344\270\212\345\210\260\344\270\213\346\211\223\345\215\260\344\272\214\345\217\211\346\240\221II/Solution1.java" "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23032_II_\344\273\216\344\270\212\345\210\260\344\270\213\346\211\223\345\215\260\344\272\214\345\217\211\346\240\221II/Solution1.java" new file mode 100644 index 00000000..bb031ef7 --- /dev/null +++ "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23032_II_\344\273\216\344\270\212\345\210\260\344\270\213\346\211\223\345\215\260\344\272\214\345\217\211\346\240\221II/Solution1.java" @@ -0,0 +1,47 @@ +package cn.lastwhisper.offer.面试题32_II_从上到下打印二叉树II; + +import cn.lastwhisper.leetcode.common.print.PrintUtil; +import cn.lastwhisper.leetcode.common.tree.TreeNode; +import cn.lastwhisper.leetcode.common.tree.TreeUtil; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/bao-han-minhan-shu-de-zhan-lcof/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:层次遍历 + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public List> levelOrder(TreeNode root) { + List> result = new ArrayList<>(); + // 特判 + if (root == null) return result; + Queue queue = new LinkedList<>(); + + queue.add(root); + while (!queue.isEmpty()) { + int size = queue.size();//记录每层的元素个数 + List list = new ArrayList<>(); + for (int i = 0; i < size; i++) { + root = queue.poll(); + list.add(root.val); + if (root.left != null) queue.add(root.left); + if (root.right != null) queue.add(root.right); + } + result.add(list); + } + return result; + } + + public static void main(String[] args) { + PrintUtil.printLists(new Solution1().levelOrder(TreeUtil.createTree(3,9,20,null,null,15,7))); + } +} \ No newline at end of file diff --git "a/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23032_I_\344\273\216\344\270\212\345\210\260\344\270\213\346\211\223\345\215\260\344\272\214\345\217\211\346\240\221/Solution1.java" "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23032_I_\344\273\216\344\270\212\345\210\260\344\270\213\346\211\223\345\215\260\344\272\214\345\217\211\346\240\221/Solution1.java" new file mode 100644 index 00000000..af425ebb --- /dev/null +++ "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23032_I_\344\273\216\344\270\212\345\210\260\344\270\213\346\211\223\345\215\260\344\272\214\345\217\211\346\240\221/Solution1.java" @@ -0,0 +1,42 @@ +package cn.lastwhisper.offer.面试题32_I_从上到下打印二叉树; + +import cn.lastwhisper.leetcode.common.tree.TreeNode; +import cn.lastwhisper.leetcode.common.tree.TreeUtil; + +import java.util.*; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/bao-han-minhan-shu-de-zhan-lcof/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:层次遍历 + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(n) + */ + public int[] levelOrder(TreeNode root) { + // 特判 + if (root == null) return new int[0]; + + Queue queue = new LinkedList<>(); + List list = new ArrayList<>(); + queue.add(root); + while (!queue.isEmpty()) { + root = queue.poll(); + list.add(root.val); + if (root.left != null) queue.add(root.left); + if (root.right != null) queue.add(root.right); + } + int[] nums = new int[list.size()]; + for (int i = 0; i < nums.length; i++) { + nums[i] = list.get(i); + } + return nums; + } + + public static void main(String[] args) { + System.out.println(Arrays.toString(new Solution1().levelOrder(TreeUtil.createTree(3, 9, 20, 15, 7)))); + } +} \ No newline at end of file diff --git "a/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23033_\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227/Solution1.java" "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23033_\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227/Solution1.java" new file mode 100644 index 00000000..c106f84b --- /dev/null +++ "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23033_\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227/Solution1.java" @@ -0,0 +1,43 @@ +package cn.lastwhisper.offer.面试题33_二叉搜索树的后序遍历序列; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/er-cha-sou-suo-shu-de-hou-xu-bian-li-xu-lie-lcof/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public boolean verifyPostorder(int[] postorder) { + if (postorder == null || postorder.length == 0) { + return true; + } + return process(postorder, 0, postorder.length - 1); + } + + public boolean process(int[] postorder, int left, int right) { + if (left >= right) { + return true; + } + int i = right - 1; + int root = postorder[right]; + while (i >= left && postorder[i] > root) { + i--; + } + for (int j = left; j <= i; j++) { + if (postorder[j] > root) { + return false; + } + } + return process(postorder, left, i) && process(postorder, i + 1, right - 1); + } + + public static void main(String[] args) { + //int[] nums = new int[]{1, 6, 3, 2, 5}; + int[] nums = new int[]{1, 3, 2, 6, 5}; + System.out.println(new Solution1().verifyPostorder(nums)); + } +} \ No newline at end of file diff --git "a/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23034_\344\272\214\345\217\211\346\240\221\344\270\255\345\222\214\344\270\272\346\237\220\344\270\200\345\200\274\347\232\204\350\267\257\345\276\204/Solution1.java" "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23034_\344\272\214\345\217\211\346\240\221\344\270\255\345\222\214\344\270\272\346\237\220\344\270\200\345\200\274\347\232\204\350\267\257\345\276\204/Solution1.java" new file mode 100644 index 00000000..901418e2 --- /dev/null +++ "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23034_\344\272\214\345\217\211\346\240\221\344\270\255\345\222\214\344\270\272\346\237\220\344\270\200\345\200\274\347\232\204\350\267\257\345\276\204/Solution1.java" @@ -0,0 +1,52 @@ +package cn.lastwhisper.offer.面试题34_二叉树中和为某一值的路径; + +import cn.lastwhisper.leetcode.common.print.PrintUtil; +import cn.lastwhisper.leetcode.common.tree.TreeNode; +import cn.lastwhisper.leetcode.common.tree.TreeUtil; + +import java.util.ArrayList; +import java.util.List; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/er-cha-shu-zhong-he-wei-mou-yi-zhi-de-lu-jing-lcof/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:递归回溯 + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度:O(n^2) + */ + public List> pathSum(TreeNode root, int sum) { + List> result = new ArrayList<>(); + if (root == null) { + return result; + } + pathSumHelper(root, sum, new ArrayList<>(), result); + + return result; + } + + public void pathSumHelper(TreeNode root, int sum, List list, List> result) { + if (root == null) { + return; + } + + list.add(root.val); + sum -= root.val; + if (sum == 0 && root.left == null && root.right == null) { + result.add(new ArrayList<>(list)); + } else { + pathSumHelper(root.left, sum, list, result); + pathSumHelper(root.right, sum, list, result); + } + list.remove(list.size() - 1); + } + + public static void main(String[] args) { + TreeNode tree = TreeUtil.createTree(5, 4, 8, 11, null, 13, 4, 7, 2, null, null, 5, 1); + int sum = 22; + PrintUtil.printLists(new Solution1().pathSum(tree, sum)); + } +} \ No newline at end of file diff --git "a/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23039_\346\225\260\347\273\204\344\270\255\345\207\272\347\216\260\346\254\241\346\225\260\350\266\205\350\277\207\344\270\200\345\215\212\347\232\204\346\225\260\345\255\227/Solution1.java" "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23039_\346\225\260\347\273\204\344\270\255\345\207\272\347\216\260\346\254\241\346\225\260\350\266\205\350\277\207\344\270\200\345\215\212\347\232\204\346\225\260\345\255\227/Solution1.java" new file mode 100644 index 00000000..dd8f69d1 --- /dev/null +++ "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23039_\346\225\260\347\273\204\344\270\255\345\207\272\347\216\260\346\254\241\346\225\260\350\266\205\350\277\207\344\270\200\345\215\212\347\232\204\346\225\260\345\255\227/Solution1.java" @@ -0,0 +1,15 @@ +package cn.lastwhisper.offer.面试题39_数组中出现次数超过一半的数字; + +class Solution1 { + public int majorityElement(int[] nums) { + int candidate = 0; + int count = 0; + for (int num : nums) { + if (count == 0) { + candidate = num; + } + count += candidate == num ? 1 : -1; + } + return candidate; + } +} \ No newline at end of file diff --git "a/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23040_\346\234\200\345\260\217\347\232\204k\344\270\252\346\225\260/Solution1.java" "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23040_\346\234\200\345\260\217\347\232\204k\344\270\252\346\225\260/Solution1.java" new file mode 100644 index 00000000..776ff43a --- /dev/null +++ "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23040_\346\234\200\345\260\217\347\232\204k\344\270\252\346\225\260/Solution1.java" @@ -0,0 +1,44 @@ +package cn.lastwhisper.offer.面试题40_最小的k个数; + +import org.junit.Assert; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/zui-xiao-de-kge-shu-lcof/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public int[] getLeastNumbers(int[] arr, int k) { + // 特判 + if (k == 0 || arr == null || arr.length == 0) { + return new int[0]; + } + // 统计每个数字出现的次数 + int[] counter = new int[10001]; + for (int num : arr) { + counter[num]++; + } + // 根据counter数组从头找出k个数作为返回结果 + int[] res = new int[k]; + int idx = 0; + for (int num = 0; num < counter.length; num++) { + while (counter[num]-- > 0 && idx < k) { + res[idx++] = num; + } + if (idx == k) { + break; + } + } + return res; + } + + public static void main(String[] args) { + Assert.assertArrayEquals(new int[]{1, 2}, new Solution1().getLeastNumbers(new int[]{3, 2, 1}, 2)); + Assert.assertArrayEquals(new int[]{0}, new Solution1().getLeastNumbers(new int[]{0, 1, 2, 1}, 1)); + } +} \ No newline at end of file diff --git "a/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23057_II_\345\222\214\344\270\272s\347\232\204\350\277\236\347\273\255\346\255\243\346\225\260\345\272\217\345\210\227_\347\256\200\345\215\225/Solution1.java" "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23057_II_\345\222\214\344\270\272s\347\232\204\350\277\236\347\273\255\346\255\243\346\225\260\345\272\217\345\210\227_\347\256\200\345\215\225/Solution1.java" new file mode 100644 index 00000000..4a79fce6 --- /dev/null +++ "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23057_II_\345\222\214\344\270\272s\347\232\204\350\277\236\347\273\255\346\255\243\346\225\260\345\272\217\345\210\227_\347\256\200\345\215\225/Solution1.java" @@ -0,0 +1,37 @@ +package cn.lastwhisper.offer.面试题57_II_和为s的连续正数序列_简单; + +import java.util.ArrayList; +import java.util.List; + +class Solution1 { + public int[][] findContinuousSequence(int target) { + List list = new ArrayList<>(); + + //🧠里要有一个区间的概念,这里的区间是(1, 2, 3, ..., target - 1) + //套滑动窗口模板,l是窗口左边界,r是窗口右边界,窗口中的值一定是连续值。 + //当窗口中数字和小于target时,r右移; 大于target时,l右移; 等于target时就获得了一个解 + for (int l = 1, r = 1, sum = 0; r < target; r++) { + sum += r; + while (sum > target) { + sum -= l++; + } + if (sum == target) { + int[] temp = new int[r - l + 1]; + for (int i = 0; i < temp.length; i++) { + temp[i] = l + i; + } + list.add(temp); + } + } + + int[][] res = new int[list.size()][]; + for (int i = 0; i < res.length; i++) { + res[i] = list.get(i); + } + return res; + } + + public static void main(String[] args) { + + } +} \ No newline at end of file diff --git "a/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23059_II_\351\230\237\345\210\227\347\232\204\346\234\200\345\244\247\345\200\274/MaxQueue.java" "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23059_II_\351\230\237\345\210\227\347\232\204\346\234\200\345\244\247\345\200\274/MaxQueue.java" new file mode 100644 index 00000000..deb73970 --- /dev/null +++ "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23059_II_\351\230\237\345\210\227\347\232\204\346\234\200\345\244\247\345\200\274/MaxQueue.java" @@ -0,0 +1,41 @@ +package cn.lastwhisper.offer.面试题59_II_队列的最大值; + +class MaxQueue { + /** + * 题目地址:https://leetcode-cn.com/problems/dui-lie-de-zui-da-zhi-lcof/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public MaxQueue() { + + } + + // 最大值 + public int max_value() { + + return 0; + } + + // 入队 + public void push_back(int value) { + + } + + // 出队 + public int pop_front() { + return 0; + } +} + +/** + * Your MaxQueue object will be instantiated and called as such: + * MaxQueue obj = new MaxQueue(); + * int param_1 = obj.max_value(); + * obj.push_back(value); + * int param_3 = obj.pop_front(); + */ \ No newline at end of file diff --git "a/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23059_I_\346\273\221\345\212\250\347\252\227\345\217\243\347\232\204\346\234\200\345\244\247\345\200\274/Solution.java" "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23059_I_\346\273\221\345\212\250\347\252\227\345\217\243\347\232\204\346\234\200\345\244\247\345\200\274/Solution.java" new file mode 100644 index 00000000..c96621eb --- /dev/null +++ "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23059_I_\346\273\221\345\212\250\347\252\227\345\217\243\347\232\204\346\234\200\345\244\247\345\200\274/Solution.java" @@ -0,0 +1,34 @@ +package cn.lastwhisper.offer.面试题59_I_滑动窗口的最大值; + +import java.util.Arrays; + +class Solution { + /** + * 题目地址:https://leetcode-cn.com/problems/hua-dong-chuang-kou-de-zui-da-zhi-lcof/ + * 编号:面试题59 - I + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:双指针(滑动窗口) + * (1) + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public int[] maxSlidingWindow(int[] nums, int k) { + if (nums == null || nums.length < k) + return nums; + + + + + return null; + } + + + public static void main(String[] args) { + int[] nums = new int[]{1, 3, -1, -3, 5, 3, 6, 7}; + int k = 3; + System.out.println(Arrays.toString(new Solution().maxSlidingWindow(nums, k))); + } +} \ No newline at end of file diff --git "a/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23059_I_\346\273\221\345\212\250\347\252\227\345\217\243\347\232\204\346\234\200\345\244\247\345\200\274/Solution1.java" "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23059_I_\346\273\221\345\212\250\347\252\227\345\217\243\347\232\204\346\234\200\345\244\247\345\200\274/Solution1.java" new file mode 100644 index 00000000..0dd47493 --- /dev/null +++ "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23059_I_\346\273\221\345\212\250\347\252\227\345\217\243\347\232\204\346\234\200\345\244\247\345\200\274/Solution1.java" @@ -0,0 +1,49 @@ +package cn.lastwhisper.offer.面试题59_I_滑动窗口的最大值; + +import java.util.ArrayDeque; +import java.util.Arrays; +import java.util.Deque; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/hua-dong-chuang-kou-de-zui-da-zhi-lcof/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路:单调队列 + * + * + * ------------------------------------------------------------------- + * 时间复杂度: + * 空间复杂度: + */ + public int[] maxSlidingWindow(int[] nums, int k) { + if (nums == null || nums.length == 0) + return nums; + + Deque deque = new ArrayDeque<>(); + int[] ans = new int[nums.length - k + 1]; + + for (int i = 0; i < nums.length; i++) { + int index = i + 1 - k; + if (!deque.isEmpty() && deque.peekFirst() < index) { + deque.removeFirst();//deque最大值不在滑动窗口中 + } + while (!deque.isEmpty() && nums[deque.peekLast()] < nums[i]) { + deque.removeLast();//新进入窗口的值大于deque最小值 + } + deque.addLast(i); + if (index >= 0) {//第一个窗口装满 + ans[index] = nums[deque.peekFirst()]; + } + } + return ans; + } + + + public static void main(String[] args) { + int[] nums = new int[]{1, 3, -1, -3, 5, 3, 6, 7}; + int k = 3; + System.out.println(Arrays.toString(new Solution1().maxSlidingWindow(nums, k))); + } +} \ No newline at end of file diff --git "a/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23062_\345\234\206\345\234\210\344\270\255\346\234\200\345\220\216\345\211\251\344\270\213\347\232\204\346\225\260\345\255\227/Solution1.java" "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23062_\345\234\206\345\234\210\344\270\255\346\234\200\345\220\216\345\211\251\344\270\213\347\232\204\346\225\260\345\255\227/Solution1.java" new file mode 100644 index 00000000..a196364e --- /dev/null +++ "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23062_\345\234\206\345\234\210\344\270\255\346\234\200\345\220\216\345\211\251\344\270\213\347\232\204\346\225\260\345\255\227/Solution1.java" @@ -0,0 +1,39 @@ +package cn.lastwhisper.offer.面试题62_圆圈中最后剩下的数字; + +import org.junit.Assert; + +import java.util.ArrayList; +import java.util.List; + +class Solution1 { + /** + * 题目地址:https://leetcode-cn.com/problems/yuan-quan-zhong-zui-hou-sheng-xia-de-shu-zi-lcof/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * 通过取模模拟环状 + * ------------------------------------------------------------------- + * 时间复杂度:O(mn) + * 空间复杂度:O(n) + */ + public int lastRemaining(int n, int m) { + List list = new ArrayList<>(); + for (int i = 0; i < n; i++) { + list.add(i); + } + int idx = 0; + while (n > 1) { + // 模拟环状,-1是因为移除一个数 + idx = (idx + m - 1) % n; + list.remove(idx); + n--; + } + + return list.get(0); + } + + public static void main(String[] args) { + Assert.assertEquals(3, new Solution1().lastRemaining(5, 3)); + } +} \ No newline at end of file diff --git "a/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23062_\345\234\206\345\234\210\344\270\255\346\234\200\345\220\216\345\211\251\344\270\213\347\232\204\346\225\260\345\255\227/Solution2.java" "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23062_\345\234\206\345\234\210\344\270\255\346\234\200\345\220\216\345\211\251\344\270\213\347\232\204\346\225\260\345\255\227/Solution2.java" new file mode 100644 index 00000000..6e87c9a2 --- /dev/null +++ "b/algorithms/offer/src/main/java/cn/lastwhisper/offer/\351\235\242\350\257\225\351\242\23062_\345\234\206\345\234\210\344\270\255\346\234\200\345\220\216\345\211\251\344\270\213\347\232\204\346\225\260\345\255\227/Solution2.java" @@ -0,0 +1,42 @@ +package cn.lastwhisper.offer.面试题62_圆圈中最后剩下的数字; + +import org.junit.Assert; + +class Solution2 { + /** + * 题目地址:https://leetcode-cn.com/problems/yuan-quan-zhong-zui-hou-sheng-xia-de-shu-zi-lcof/ + * ------------------------------------------------------------------- + * 思考: + * ------------------------------------------------------------------- + * 思路: + * https://leetcode-cn.com/problems/yuan-quan-zhong-zui-hou-sheng-xia-de-shu-zi-lcof/solution/yuan-quan-zhong-zui-hou-sheng-xia-de-shu-zi-by-lee/ + * 将上述问题建模为函数 f(n, m),该函数的返回值为最终留下的元素的序号 + * 长度为n的序列会先删除第m%n个元素,然后剩下一个长度为n-1的序列,递归地求解f(n-1,m),设x=f(n-1,m) + * f(n - 1, m) = (m % n + x) % n = (m + x) % n + * ------------------------------------------------------------------- + * 时间复杂度:O(n) + * 空间复杂度:O(n) + */ + public int lastRemaining(int n, int m) { + //int ans = 0; + //// 最后一轮剩下2个人,所以从2开始反推 + //for (int i = 2; i <= n; i++) { + // ans = (ans + m) % i; + //} + //return ans; + return f(n, m); + } + + private int f(int n, int m) { + // 当序列长度为 1 时,一定会留下唯一的那个元素,它的编号为 0 + if (n == 1){ + return 0; + } + int x = f(n - 1, m); + return (m + x) % n; + } + + public static void main(String[] args) { + Assert.assertEquals(3, new Solution2().lastRemaining(5, 3)); + } +} \ No newline at end of file diff --git a/algorithms/pom.xml b/algorithms/pom.xml index bc8c6ec3..c67bc1b0 100644 --- a/algorithms/pom.xml +++ b/algorithms/pom.xml @@ -14,7 +14,8 @@ interview algorithm leetcode - thread + algorithm-common + niuke diff --git a/algorithms/test/pom.xml b/algorithms/test/pom.xml new file mode 100644 index 00000000..2b1eb3d3 --- /dev/null +++ b/algorithms/test/pom.xml @@ -0,0 +1,16 @@ + + + 4.0.0 + + org.example + test + 1.0-SNAPSHOT + + + 8 + 8 + + + \ No newline at end of file diff --git a/algorithms/test/src/main/java/cn/cunchang/Main.java b/algorithms/test/src/main/java/cn/cunchang/Main.java new file mode 100644 index 00000000..51de18e3 --- /dev/null +++ b/algorithms/test/src/main/java/cn/cunchang/Main.java @@ -0,0 +1,39 @@ +package cn.cunchang; + +import java.util.ArrayList; +import java.util.Scanner; + +/** + * @author cunchang + * @date 2022/7/6 8:12 PM + */ +public class Main { + + /** + * 有n个人围成一圈,顺序排号。 + * 从第1个人开始报数(从1到3报数),凡报到3的人退出圈子,问最后留下的是原来第几号的那位,起始索引位置为0。 + */ + public static void main(String[] args) { + Scanner scanner = new Scanner(System.in); + int n = scanner.nextInt(); + ArrayList list = new ArrayList<>(n); + for (int i = 0; i < n; i++) { + list.add(i + 1); + } + int idx = 0; + int count = 0; + while (list.size() >1) { + if (count == 2) { + list.remove(idx); + idx=-1; + count=0; + } + idx++; + count++; + } + + // 还剩两个人 + System.out.println(list); + } + +} diff --git a/algorithms/test/src/main/java/cn/cunchang/Main2.java b/algorithms/test/src/main/java/cn/cunchang/Main2.java new file mode 100644 index 00000000..8eda3417 --- /dev/null +++ b/algorithms/test/src/main/java/cn/cunchang/Main2.java @@ -0,0 +1,45 @@ +package cn.cunchang; + +import java.util.Scanner; + +/** + * @author cunchang + * @date 2022/7/6 8:12 PM + */ +public class Main2 { + + /** + * 有n个人围成一圈,顺序排号。 + * 从第1个人开始报数(从1到3报数),凡报到3的人退出圈子,问最后留下的是原来第几号的那位,起始索引位置为0。 + */ + public static void main(String[] args) { + Scanner scanner = new Scanner(System.in); + int n = scanner.nextInt(); + + boolean[] visited = new boolean[n];//true表示访问了 + + int outCount = n; + int idx = 0;// 访问下标 + int outIdx = 1;// 剔除计数 + while (outCount > 1) { + if (visited[idx % n]) { + idx++; + continue; + } + if (outIdx == 3) { + visited[idx % n] = true; + outCount--; + outIdx = 0; + } + idx++; + outIdx++; + } + + for (int i = 0; i < visited.length; i++) { + if (!visited[i]) { + System.out.println(i + 1); + } + } + } + +} diff --git a/algorithms/thread/pom.xml b/algorithms/thread/pom.xml deleted file mode 100644 index 765558b2..00000000 --- a/algorithms/thread/pom.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - algorithms - cn.lastwhisper - 1.0-SNAPSHOT - - 4.0.0 - - cn.lastwhisper - thread - - - \ No newline at end of file diff --git "a/algorithms/thread/src/main/java/cn/lastwhisper/thread/\346\214\211\345\272\217\346\211\223\345\215\2601114/Foo.java" "b/algorithms/thread/src/main/java/cn/lastwhisper/thread/\346\214\211\345\272\217\346\211\223\345\215\2601114/Foo.java" deleted file mode 100644 index a075b4a2..00000000 --- "a/algorithms/thread/src/main/java/cn/lastwhisper/thread/\346\214\211\345\272\217\346\211\223\345\215\2601114/Foo.java" +++ /dev/null @@ -1,32 +0,0 @@ -package cn.lastwhisper.thread.按序打印1114; - -import java.util.concurrent.CountDownLatch; - -public class Foo { - private CountDownLatch second = new CountDownLatch(1); - private CountDownLatch third = new CountDownLatch(1); - - public Foo() { - - } - - public void first(Runnable printFirst) throws InterruptedException { - - // printFirst.run() outputs "first". Do not change or remove this line. - printFirst.run(); - second.countDown(); - } - - public void second(Runnable printSecond) throws InterruptedException { - - // printSecond.run() outputs "second". Do not change or remove this line. - printSecond.run(); - third.countDown(); - } - - public void third(Runnable printThird) throws InterruptedException { - third.await(); - // printThird.run() outputs "third". Do not change or remove this line. - printThird.run(); - } -} \ No newline at end of file diff --git a/bigdata/flink-cdc/pom.xml b/bigdata/flink-cdc/pom.xml new file mode 100644 index 00000000..041ae367 --- /dev/null +++ b/bigdata/flink-cdc/pom.xml @@ -0,0 +1,92 @@ + + + 4.0.0 + + cn.cunchang + flink-cdc + 1.0-SNAPSHOT + + + 8 + 8 + 1.13.2 + + + + + + org.apache.flink + flink-java + ${flink-version} + + + + org.apache.flink + flink-streaming-java_2.12 + ${flink-version} + + + + org.apache.flink + flink-clients_2.12 + ${flink-version} + + + + org.apache.hadoop + hadoop-client + 3.1.3 + + + + mysql + mysql-connector-java + 5.1.49 + + + + org.apache.flink + flink-table-planner-blink_2.12 + ${flink-version} + + + + com.ververica + flink-connector-mysql-cdc + 2.0.0 + + + + com.alibaba + fastjson + 1.2.75 + + + + + + + org.apache.maven.plugins + maven-assembly-plugin + 3.0.0 + + + jar-with-dependencies + + + + + make-assembly + package + + single + + + + + + + + \ No newline at end of file diff --git a/bigdata/flink-cdc/src/main/java/cn/cunchang/FlinkCDC.java b/bigdata/flink-cdc/src/main/java/cn/cunchang/FlinkCDC.java new file mode 100644 index 00000000..81ecaeb2 --- /dev/null +++ b/bigdata/flink-cdc/src/main/java/cn/cunchang/FlinkCDC.java @@ -0,0 +1,51 @@ +package cn.cunchang; + +import com.ververica.cdc.connectors.mysql.MySqlSource; +import com.ververica.cdc.connectors.mysql.table.StartupOptions; +import com.ververica.cdc.debezium.DebeziumSourceFunction; +import com.ververica.cdc.debezium.StringDebeziumDeserializationSchema; +import org.apache.flink.runtime.state.hashmap.HashMapStateBackend; +import org.apache.flink.streaming.api.CheckpointingMode; +import org.apache.flink.streaming.api.datastream.DataStreamSource; +import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; + +public class FlinkCDC { + + public static void main(String[] args) throws Exception { + + //1.获取Flink 执行环境 + StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); + env.setParallelism(1); + + //1.1 开启Checkpoint,保存任务中断点,重启从中断点继续执行 +// env.enableCheckpointing(5000); +// env.getCheckpointConfig().setCheckpointTimeout(10000); +// env.getCheckpointConfig().setCheckpointingMode(CheckpointingMode.EXACTLY_ONCE); +// env.getCheckpointConfig().setMaxConcurrentCheckpoints(1); + // 默认ck在内存里,也可以存到hdfs + env.setStateBackend(new HashMapStateBackend()); + // env.setStateBackend(new FsStateBackend("hdfs://localhost:9000/cdc-test/ck")); //过时写法 + // env.getCheckpointConfig().setCheckpointStorage("hdfs://localhost:9000/cdc-test/ck"); + + //2.通过FlinkCDC构建SourceFunction + DebeziumSourceFunction sourceFunction = MySqlSource.builder() + .hostname("localhost") + .port(3306) + .username("root") + .password("123456") + .databaseList("cdc_test") + .tableList("cdc_test.user_info") + .deserializer(new StringDebeziumDeserializationSchema()) + .startupOptions(StartupOptions.initial()) + .build(); + DataStreamSource dataStreamSource = env.addSource(sourceFunction); + + //3.数据打印 + dataStreamSource.print(); + + //4.启动任务 + env.execute("FlinkCDC"); + + } + +} diff --git a/bigdata/flink-cdc/src/main/java/cn/cunchang/FlinkCDC2.java b/bigdata/flink-cdc/src/main/java/cn/cunchang/FlinkCDC2.java new file mode 100644 index 00000000..5bbc1bef --- /dev/null +++ b/bigdata/flink-cdc/src/main/java/cn/cunchang/FlinkCDC2.java @@ -0,0 +1,43 @@ +package cn.cunchang; + +import cn.cunchang.func.CustomerDeserializationSchema; +import com.ververica.cdc.connectors.mysql.MySqlSource; +import com.ververica.cdc.connectors.mysql.table.StartupOptions; +import com.ververica.cdc.debezium.DebeziumSourceFunction; +import org.apache.flink.streaming.api.datastream.DataStreamSource; +import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; + +public class FlinkCDC2 { + + /** + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + + //1.获取Flink 执行环境 + StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); + env.setParallelism(1); + + //2.通过FlinkCDC构建SourceFunction + DebeziumSourceFunction sourceFunction = MySqlSource.builder() + .hostname("localhost") + .port(3306) + .username("root") + .password("123456") + .databaseList("cdc_test") + .tableList("cdc_test.user_info") + .deserializer(new CustomerDeserializationSchema()) + .startupOptions(StartupOptions.initial()) + .build(); + DataStreamSource dataStreamSource = env.addSource(sourceFunction); + + //3.数据打印 + dataStreamSource.print(); + + //4.启动任务 + env.execute("FlinkCDC2"); + + } + +} diff --git a/bigdata/flink-cdc/src/main/java/cn/cunchang/FlinkSQLCDC.java b/bigdata/flink-cdc/src/main/java/cn/cunchang/FlinkSQLCDC.java new file mode 100644 index 00000000..70ae914e --- /dev/null +++ b/bigdata/flink-cdc/src/main/java/cn/cunchang/FlinkSQLCDC.java @@ -0,0 +1,45 @@ +package cn.cunchang; + +import org.apache.flink.api.java.tuple.Tuple2; +import org.apache.flink.streaming.api.datastream.DataStream; +import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; +import org.apache.flink.table.api.Table; +import org.apache.flink.table.api.bridge.java.StreamTableEnvironment; +import org.apache.flink.types.Row; + +public class FlinkSQLCDC { + + public static void main(String[] args) throws Exception { + + //1.获取执行环境 + StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); + env.setParallelism(1); + StreamTableEnvironment tableEnv = StreamTableEnvironment.create(env); + + //2.使用FLINKSQL DDL模式构建CDC 表 + tableEnv.executeSql("CREATE TABLE user_info ( " + + " id STRING primary key, " + + " name STRING, " + + " sex STRING " + + ") WITH ( " + + " 'connector' = 'mysql-cdc', " + + " 'scan.startup.mode' = 'latest-offset', " + + " 'hostname' = 'localhost', " + + " 'port' = '3306', " + + " 'username' = 'root', " + + " 'password' = '123456', " + + " 'database-name' = 'cdc_test', " + + " 'table-name' = 'user_info' " + + ")"); + + //3.查询数据并转换为流输出 + Table table = tableEnv.sqlQuery("select * from user_info"); + DataStream> retractStream = tableEnv.toRetractStream(table, Row.class); + retractStream.print(); + + //4.启动 + env.execute("FlinkSQLCDC"); + + } + +} diff --git a/bigdata/flink-cdc/src/main/java/cn/cunchang/func/CustomerDeserializationSchema.java b/bigdata/flink-cdc/src/main/java/cn/cunchang/func/CustomerDeserializationSchema.java new file mode 100644 index 00000000..99448140 --- /dev/null +++ b/bigdata/flink-cdc/src/main/java/cn/cunchang/func/CustomerDeserializationSchema.java @@ -0,0 +1,82 @@ +package cn.cunchang.func; + +import com.alibaba.fastjson.JSONObject; +import com.ververica.cdc.debezium.DebeziumDeserializationSchema; +import io.debezium.data.Envelope; +import org.apache.flink.api.common.typeinfo.BasicTypeInfo; +import org.apache.flink.api.common.typeinfo.TypeInformation; +import org.apache.flink.util.Collector; +import org.apache.kafka.connect.data.Field; +import org.apache.kafka.connect.data.Schema; +import org.apache.kafka.connect.data.Struct; +import org.apache.kafka.connect.source.SourceRecord; + +import java.util.List; + +public class CustomerDeserializationSchema implements DebeziumDeserializationSchema { + + + /** + * { + * "db":"", + * "tableName":"", + * "before":{"id":"1001","name":""...}, + * "after":{"id":"1001","name":""...}, + * "op":"" + * } + */ + @Override + public void deserialize(SourceRecord sourceRecord, Collector collector) throws Exception { + + //创建JSON对象用于封装结果数据 + JSONObject result = new JSONObject(); + + //获取库名&表名 + String topic = sourceRecord.topic(); + String[] fields = topic.split("\\."); + result.put("db", fields[1]); + result.put("tableName", fields[2]); + + //获取before数据 + Struct value = (Struct) sourceRecord.value(); + Struct before = value.getStruct("before"); + JSONObject beforeJson = new JSONObject(); + if (before != null) { + //获取列信息 + Schema schema = before.schema(); + List fieldList = schema.fields(); + + for (Field field : fieldList) { + beforeJson.put(field.name(), before.get(field)); + } + } + result.put("before", beforeJson); + + //获取after数据 + Struct after = value.getStruct("after"); + JSONObject afterJson = new JSONObject(); + if (after != null) { + //获取列信息 + Schema schema = after.schema(); + List fieldList = schema.fields(); + + for (Field field : fieldList) { + afterJson.put(field.name(), after.get(field)); + } + } + result.put("after", afterJson); + + //获取操作类型 + Envelope.Operation operation = Envelope.operationFor(sourceRecord); + result.put("op", operation); + + //输出数据 + collector.collect(result.toJSONString()); + + } + + @Override + public TypeInformation getProducedType() { + return BasicTypeInfo.STRING_TYPE_INFO; + } +} diff --git a/bigdata/flink/pom.xml b/bigdata/flink/pom.xml new file mode 100644 index 00000000..30a11181 --- /dev/null +++ b/bigdata/flink/pom.xml @@ -0,0 +1,149 @@ + + + 4.0.0 + + cn.cunchang + flink + 1.0-SNAPSHOT + + + 8 + 8 + + + + + org.apache.flink + flink-java + 1.11.1 + + + + org.apache.flink + flink-streaming-java_2.12 + 1.11.1 + + + + + org.apache.flink + flink-streaming-scala_2.12 + 1.11.0 + + + + + org.apache.flink + flink-clients_2.12 + 1.11.1 + + + + + org.slf4j + slf4j-api + 1.7.10 + + + + org.slf4j + slf4j-log4j12 + 1.7.10 + + + + org.apache.hadoop + hadoop-client + 3.2.0 + + + + org.apache.bahir + flink-connector-redis_2.11 + 1.0 + + + + org.apache.flink + flink-table-api-java-bridge_2.12 + 1.11.0 + + + + org.apache.flink + flink-table-api-scala-bridge_2.12 + 1.11.0 + + + + + org.apache.flink + flink-table-planner-blink_2.12 + 1.11.0 + + + + + org.apache.flink + flink-table-planner_2.12 + 1.11.1 + + + + + org.apache.flink + flink-connector-kafka_2.12 + 1.11.1 + + + org.apache.flink + flink-statebackend-rocksdb_2.12 + 1.11.1 + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + 1.8 + 1.8 + UTF-8 + + + + + org.apache.maven.plugins + maven-assembly-plugin + 2.4.1 + + + jar-with-dependencies + + + + + + + + + + + make-assembly + package + + single + + + + + + + + + \ No newline at end of file diff --git a/bigdata/flink/src/main/java/cn/cunchang/README.txt b/bigdata/flink/src/main/java/cn/cunchang/README.txt new file mode 100644 index 00000000..3449dfb0 --- /dev/null +++ b/bigdata/flink/src/main/java/cn/cunchang/README.txt @@ -0,0 +1,57 @@ + +# 入门 +# 一、流处理和批处理程序开发 +stream.SocketWindowWordCountJava 实时处理 +batch.BatchWordCountJava 批处理 + +# 二、Flink核心API之DataStream API +## DataStreamAPI之DataSource +- stream.source.StreamCollectionSourceJava + +## DataStreamAPI之Transformation +- stream.transformation +- 算子 + - union 合并多个流,多个流的数据类型必须一致 + - connect 只能连接两个流,两个流的数据类型可以不同 + - split 根据规则把一个数据流切分为多个流;代码:StreamSplitJava、StreamSideOutputJava +- 算子分区 + - shuffle 随机分区 + - rebalance 对数据集进行再平衡(顺序),重分区,消除数据倾斜 + - rescale 重分区(局部顺序) + - partitionCustom 自定义分区;代码:StreamPartitionOpJava + +## DataStreamAPI之DataSink +- stream.sink.StreamRedisSinkJava + +# 三、Flink核心API之DataSetAPI +## DataSetAPI之Transformation +- batch.transformation +- 算子 + - mapPartition 类似map,一次处理一个分区的数据;代码:BatchMapPartitionJava + - distinct 返回数据集中去重之后的元素 + - join 内连接;代码:BatchJoinJava + - outerJoin 外连接;代码:BatchOuterJoinJava + - cross 获取两个数据集的笛卡尔积;BatchCrossJava + - union 返回多个数据集的总和,数据类型需要一致 + - first-n 获取集合中的前N个元素;BatchFirstNJava + +# 四、Flink核心API之TableAPI和SQL +tablesql + +## Table API 和SQL的使用 +- CreateTableEnvironmentJava 创建一个TableEnvironment对象 +- TableAPIAndSQLOpJava +- DataStreamToTableJava DataStream、DataSet和Table之间的互相转换 + +# 进阶 +# 一、Window +- TimeWindowOpJava +- CountWindowOpJava +- MyTimeWindowJava + + + + + + + diff --git a/bigdata/flink/src/main/java/cn/cunchang/batch/BatchWordCountJava.java b/bigdata/flink/src/main/java/cn/cunchang/batch/BatchWordCountJava.java new file mode 100644 index 00000000..53a727b9 --- /dev/null +++ b/bigdata/flink/src/main/java/cn/cunchang/batch/BatchWordCountJava.java @@ -0,0 +1,44 @@ +package cn.cunchang.batch; + +import org.apache.flink.api.common.functions.FlatMapFunction; +import org.apache.flink.api.java.ExecutionEnvironment; +import org.apache.flink.api.java.operators.AggregateOperator; +import org.apache.flink.api.java.operators.DataSource; +import org.apache.flink.api.java.tuple.Tuple2; +import org.apache.flink.util.Collector; + +/** + * 需求:统计指定文件中单词出现的总次数 + * Created by xuwei + */ +public class BatchWordCountJava { + public static void main(String[] args) throws Exception{ + //获取执行环境 + ExecutionEnvironment env = ExecutionEnvironment.getExecutionEnvironment(); + + String inputPath = "hdfs://localhost:9000/hello.txt"; + String outPath = "hdfs://localhost:9000/out2"; + + //读取文件中的数据 + DataSource text = env.readTextFile(inputPath); + + //处理数据 + AggregateOperator> wordCount = text.flatMap(new FlatMapFunction>() { + public void flatMap(String line, Collector> out) + throws Exception { + String[] words = line.split(" "); + for (String word : words) { + out.collect(new Tuple2(word, 1)); + } + } + }).groupBy(0) + .sum(1) + .setParallelism(1); + + //将结果数据保存到文件中 + wordCount.writeAsCsv(outPath,"\n"," "); + + //执行程序 + env.execute("BatchWordCountJava"); + } +} diff --git a/bigdata/flink/src/main/java/cn/cunchang/batch/transformation/BatchCrossJava.java b/bigdata/flink/src/main/java/cn/cunchang/batch/transformation/BatchCrossJava.java new file mode 100644 index 00000000..1994477c --- /dev/null +++ b/bigdata/flink/src/main/java/cn/cunchang/batch/transformation/BatchCrossJava.java @@ -0,0 +1,24 @@ +package cn.cunchang.batch.transformation; + +import org.apache.flink.api.java.ExecutionEnvironment; +import org.apache.flink.api.java.operators.DataSource; + +import java.util.Arrays; + +/** + * cross:获取两个数据集的笛卡尔积 + * Created by xuwei + */ +public class BatchCrossJava { + public static void main(String[] args) throws Exception{ + ExecutionEnvironment env = ExecutionEnvironment.getExecutionEnvironment(); + + //初始化第一份数据 + DataSource text1 = env.fromCollection(Arrays.asList(1, 2)); + //初始化第二份数据 + DataSource text2 = env.fromCollection(Arrays.asList("a", "b")); + + //执行cross操作 + text1.cross(text2).print(); + } +} diff --git a/bigdata/flink/src/main/java/cn/cunchang/batch/transformation/BatchFirstNJava.java b/bigdata/flink/src/main/java/cn/cunchang/batch/transformation/BatchFirstNJava.java new file mode 100644 index 00000000..47b1959e --- /dev/null +++ b/bigdata/flink/src/main/java/cn/cunchang/batch/transformation/BatchFirstNJava.java @@ -0,0 +1,43 @@ +package cn.cunchang.batch.transformation; + +import org.apache.flink.api.common.operators.Order; +import org.apache.flink.api.java.ExecutionEnvironment; +import org.apache.flink.api.java.operators.DataSource; +import org.apache.flink.api.java.tuple.Tuple2; + +import java.util.ArrayList; + +/** + * first-n:获取集合中的前N个元素 + * Created by xuwei + */ +public class BatchFirstNJava { + public static void main(String[] args) throws Exception{ + ExecutionEnvironment env = ExecutionEnvironment.getExecutionEnvironment(); + + ArrayList> data = new ArrayList<>(); + data.add(new Tuple2(2,"zs")); + data.add(new Tuple2(4,"ls")); + data.add(new Tuple2(3,"ww")); + data.add(new Tuple2(1,"aw")); + data.add(new Tuple2(1,"xw")); + data.add(new Tuple2(1,"mw")); + + //初始化数据 + DataSource> text = env.fromCollection(data); + + //获取前3条数据,按照数据插入的顺序 + text.first(3).print(); + System.out.println("============================================"); + + + //根据数据中的第一列进行分组,获取每组的前2个元素 + text.groupBy(0).first(2).print(); + System.out.println("============================================"); + + //根据数据中的第一列分组,再根据第二列进行组内排序[倒序],获取每组的前2个元素 + //分组排序取TopN + text.groupBy(0).sortGroup(1, Order.DESCENDING).first(2).print(); + System.out.println("============================================"); + } +} diff --git a/bigdata/flink/src/main/java/cn/cunchang/batch/transformation/BatchJoinJava.java b/bigdata/flink/src/main/java/cn/cunchang/batch/transformation/BatchJoinJava.java new file mode 100644 index 00000000..34a2b1c6 --- /dev/null +++ b/bigdata/flink/src/main/java/cn/cunchang/batch/transformation/BatchJoinJava.java @@ -0,0 +1,52 @@ +package cn.cunchang.batch.transformation; + +import org.apache.flink.api.common.functions.JoinFunction; +import org.apache.flink.api.java.ExecutionEnvironment; +import org.apache.flink.api.java.operators.DataSource; +import org.apache.flink.api.java.tuple.Tuple2; +import org.apache.flink.api.java.tuple.Tuple3; + +import java.util.ArrayList; + +/** + * join:内连接 + * Created by xuwei + */ +public class BatchJoinJava { + public static void main(String[] args) throws Exception{ + ExecutionEnvironment env = ExecutionEnvironment.getExecutionEnvironment(); + + //初始化第一份数据 Tuple2<用户id,用户姓名> + ArrayList> data1 = new ArrayList<>(); + data1.add(new Tuple2(1,"jack")); + data1.add(new Tuple2(2,"tom")); + data1.add(new Tuple2(3,"mick")); + DataSource> text1 = env.fromCollection(data1); + + //初始化第二份数据 Tuple2<用户id,用户所在城市> + ArrayList> data2 = new ArrayList<>(); + data2.add(new Tuple2(1,"bj")); + data2.add(new Tuple2(2,"sh")); + data2.add(new Tuple2(4,"gz")); + DataSource> text2 = env.fromCollection(data2); + + //对两份数据集执行join操作 + text1.join(text2) + //注意:这里的where和equalTo实现了类似于on fieldA=fieldB的效果 + //where:指定左边数据集中参与比较的元素角标 + .where(0) + .equalTo(0) + //三个输入参数: + //第一个tuple2是左边数据集的类型, + //第二个tuple2是右边数据集的类型, + //第三个tuple3是此函数返回的数据集类型 + .with(new JoinFunction, Tuple2, Tuple3>() { + @Override + public Tuple3 join(Tuple2 first, Tuple2 second) + throws Exception { + return new Tuple3(first.f0,first.f1,second.f1); + } + }).print(); + + } +} diff --git a/bigdata/flink/src/main/java/cn/cunchang/batch/transformation/BatchMapPartitionJava.java b/bigdata/flink/src/main/java/cn/cunchang/batch/transformation/BatchMapPartitionJava.java new file mode 100644 index 00000000..b532864d --- /dev/null +++ b/bigdata/flink/src/main/java/cn/cunchang/batch/transformation/BatchMapPartitionJava.java @@ -0,0 +1,40 @@ +package cn.cunchang.batch.transformation; + +import org.apache.flink.api.common.functions.MapPartitionFunction; +import org.apache.flink.api.java.ExecutionEnvironment; +import org.apache.flink.api.java.operators.DataSource; +import org.apache.flink.util.Collector; + +import java.util.Arrays; +import java.util.UUID; + +/** + * MapPartition的使用:一次处理一个分区的数据 + * Created by xuwei + */ +public class BatchMapPartitionJava { + public static void main(String[] args) throws Exception { + ExecutionEnvironment env = ExecutionEnvironment.getExecutionEnvironment(); + //生成数据源数据 + DataSource text = env.fromCollection(Arrays.asList("hello you", "hello me")); + + //每次处理一个分区的数据 + text.mapPartition(new MapPartitionFunction() { + @Override + public void mapPartition(Iterable iterable, Collector out) + throws Exception { + String id = UUID.randomUUID().toString(); + // 可以在此处创建数据库连接,建议把这块代码放到try-catch代码块中 + // 注意:此时是每个分区获取一个数据库连接,不需要每处理一条数据就获取一次连接 + for (String line : iterable) { + System.out.println("id:" + id + ",line:" + line); + String[] words = line.split(" "); + for (String word : words) { + out.collect(word); + } + } + //关闭数据库连接 + } + }).print(); + } +} diff --git a/bigdata/flink/src/main/java/cn/cunchang/batch/transformation/BatchOuterJoinJava.java b/bigdata/flink/src/main/java/cn/cunchang/batch/transformation/BatchOuterJoinJava.java new file mode 100644 index 00000000..29e5abb1 --- /dev/null +++ b/bigdata/flink/src/main/java/cn/cunchang/batch/transformation/BatchOuterJoinJava.java @@ -0,0 +1,94 @@ +package cn.cunchang.batch.transformation; + +import org.apache.flink.api.common.functions.JoinFunction; +import org.apache.flink.api.java.ExecutionEnvironment; +import org.apache.flink.api.java.operators.DataSource; +import org.apache.flink.api.java.tuple.Tuple2; +import org.apache.flink.api.java.tuple.Tuple3; + +import java.util.ArrayList; + +/** + * outerJoin:外连接 + * 一共有三种情况 + * 1:leftOuterJoin + * 2:rightOuterJoin + * 3:fullOuterJoin + * Created by xuwei + */ +public class BatchOuterJoinJava { + public static void main(String[] args) throws Exception{ + ExecutionEnvironment env = ExecutionEnvironment.getExecutionEnvironment(); + + //初始化第一份数据 Tuple2<用户id,用户姓名> + ArrayList> data1 = new ArrayList<>(); + data1.add(new Tuple2(1,"jack")); + data1.add(new Tuple2(2,"tom")); + data1.add(new Tuple2(3,"mick")); + DataSource> text1 = env.fromCollection(data1); + + //初始化第二份数据 Tuple2<用户id,用户所在城市> + ArrayList> data2 = new ArrayList<>(); + data2.add(new Tuple2(1,"bj")); + data2.add(new Tuple2(2,"sh")); + data2.add(new Tuple2(4,"gz")); + DataSource> text2 = env.fromCollection(data2); + + System.out.println("==================左外连接===================="); + //对两份数据集执行leftOuterJoin操作 + text1.leftOuterJoin(text2) + .where(0) + .equalTo(0) + .with(new JoinFunction, Tuple2, Tuple3>() { + @Override + public Tuple3 join(Tuple2 first, Tuple2 second) + throws Exception { + if(second==null){ + return new Tuple3(first.f0,first.f1,"null"); + }else{ + return new Tuple3(first.f0,first.f1,second.f1); + } + } + }).print(); + + System.out.println("========================================"); + + System.out.println("==================右外连接===================="); + //对两份数据集执行rightOuterJoin操作 + text1.rightOuterJoin(text2) + .where(0) + .equalTo(0) + .with(new JoinFunction, Tuple2, Tuple3>() { + @Override + public Tuple3 join(Tuple2 first, Tuple2 second) + throws Exception { + if(first==null){ + return new Tuple3(second.f0,"null",second.f1); + }else{ + return new Tuple3(first.f0,first.f1,second.f1); + } + } + }).print(); + + System.out.println("========================================"); + + System.out.println("==================全外连接===================="); + //对两份数据集执行fullOuterJoin操作 + text1.fullOuterJoin(text2) + .where(0) + .equalTo(0) + .with(new JoinFunction, Tuple2, Tuple3>() { + @Override + public Tuple3 join(Tuple2 first, Tuple2 second) + throws Exception { + if(first==null){ + return new Tuple3(second.f0,"null",second.f1); + }else if(second==null){ + return new Tuple3(first.f0,first.f1,"null"); + }else{ + return new Tuple3(first.f0,first.f1,second.f1); + } + } + }).print(); + } +} diff --git a/bigdata/flink/src/main/java/cn/cunchang/kafkaconnector/StreamKafkaSinkJava.java b/bigdata/flink/src/main/java/cn/cunchang/kafkaconnector/StreamKafkaSinkJava.java new file mode 100644 index 00000000..2b7da149 --- /dev/null +++ b/bigdata/flink/src/main/java/cn/cunchang/kafkaconnector/StreamKafkaSinkJava.java @@ -0,0 +1,33 @@ +package cn.cunchang.kafkaconnector; + +import org.apache.flink.api.common.serialization.SimpleStringSchema; +import org.apache.flink.streaming.api.datastream.DataStreamSource; +import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; +import org.apache.flink.streaming.connectors.kafka.FlinkKafkaProducer; +import org.apache.flink.streaming.connectors.kafka.internals.KafkaSerializationSchemaWrapper; + +import java.util.Properties; + +/** + * Flink向Kafka中生产数据 + * Created by xuwei + */ +public class StreamKafkaSinkJava { + public static void main(String[] args) throws Exception{ + StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); + + DataStreamSource text = env.socketTextStream("bigdata04", 9001); + + //指定FlinkKafkaProducer相关配置 + String topic = "t3"; + Properties prop = new Properties(); + prop.setProperty("bootstrap.servers","bigdata01:9092,bigdata02:9092,bigdata03:9092"); + + //指定kafak作为sink + FlinkKafkaProducer kafkaProducer = new FlinkKafkaProducer<>(topic, new KafkaSerializationSchemaWrapper(topic, null, false, new SimpleStringSchema()), prop, FlinkKafkaProducer.Semantic.EXACTLY_ONCE); + text.addSink(kafkaProducer); + + env.execute("StreamKafkaSinkJava"); + + } +} diff --git a/bigdata/flink/src/main/java/cn/cunchang/kafkaconnector/StreamKafkaSourceJava.java b/bigdata/flink/src/main/java/cn/cunchang/kafkaconnector/StreamKafkaSourceJava.java new file mode 100644 index 00000000..6af40e3b --- /dev/null +++ b/bigdata/flink/src/main/java/cn/cunchang/kafkaconnector/StreamKafkaSourceJava.java @@ -0,0 +1,33 @@ +package cn.cunchang.kafkaconnector; + +import org.apache.flink.api.common.serialization.SimpleStringSchema; +import org.apache.flink.streaming.api.datastream.DataStreamSource; +import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; +import org.apache.flink.streaming.connectors.kafka.FlinkKafkaConsumer; + +import java.util.Properties; + +/** + * Flink从kafka中消费数据 + * Created by xuwei + */ +public class StreamKafkaSourceJava { + public static void main(String[] args) throws Exception{ + StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); + + //指定FlinkKafkaConsumer相关配置 + String topic = "t1"; + Properties prop = new Properties(); + prop.setProperty("bootstrap.servers","bigdata01:9092,bigdata02:9092,bigdata03:9092"); + prop.setProperty("group.id","con1"); + FlinkKafkaConsumer kafkaConsumer = new FlinkKafkaConsumer<>(topic, new SimpleStringSchema(), prop); + + //指定kafka作为source + DataStreamSource text = env.addSource(kafkaConsumer); + + //将读取到的数据打印到控制台 + text.print(); + + env.execute("StreamKafkaSourceJava"); + } +} diff --git a/bigdata/flink/src/main/java/cn/cunchang/stream/SocketWindowWordCountJava.java b/bigdata/flink/src/main/java/cn/cunchang/stream/SocketWindowWordCountJava.java new file mode 100644 index 00000000..246c4a52 --- /dev/null +++ b/bigdata/flink/src/main/java/cn/cunchang/stream/SocketWindowWordCountJava.java @@ -0,0 +1,58 @@ +package cn.cunchang.stream; + +import org.apache.flink.api.common.functions.FlatMapFunction; +import org.apache.flink.api.common.functions.MapFunction; +import org.apache.flink.api.java.functions.KeySelector; +import org.apache.flink.api.java.tuple.Tuple2; +import org.apache.flink.streaming.api.datastream.DataStreamSource; +import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator; +import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; +import org.apache.flink.streaming.api.windowing.time.Time; +import org.apache.flink.util.Collector; + +/** + * 需求:通过socket实时产生一些单词 + * 使用Flink实时接收数据 + * 对指定时间窗口内(例如:2秒)的数据进行聚合统计 + * 并且把时间窗口内计算的结果打印出来 + * Created by xuwei + */ +public class SocketWindowWordCountJava { + public static void main(String[] args) throws Exception{ + //获取运行环境 + StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); + + //连接socket获取输入数据 + DataStreamSource text = env.socketTextStream("localhost", 9001); + + //处理数据 + SingleOutputStreamOperator> wordCount = text.flatMap(new FlatMapFunction() { + @Override + public void flatMap(String line, Collector out) throws Exception { + String[] words = line.split(" "); + for (String word : words) { + out.collect(word); + } + } + }).map(new MapFunction>() { + @Override + public Tuple2 map(String word) throws Exception { + return new Tuple2(word, 1); + } + }).keyBy(new KeySelector, String>() { + @Override + public String getKey(Tuple2 tup) throws Exception { + return tup.f0; + } + })//.keyBy(0) + .timeWindow(Time.seconds(2)) + .sum(1); + + //使用一个线程执行打印操作 + wordCount.print().setParallelism(1); + + //执行程序 + env.execute("SocketWindowWordCountJava"); + + } +} diff --git a/bigdata/flink/src/main/java/cn/cunchang/stream/sink/StreamRedisSinkJava.java b/bigdata/flink/src/main/java/cn/cunchang/stream/sink/StreamRedisSinkJava.java new file mode 100644 index 00000000..8a035852 --- /dev/null +++ b/bigdata/flink/src/main/java/cn/cunchang/stream/sink/StreamRedisSinkJava.java @@ -0,0 +1,61 @@ +package cn.cunchang.stream.sink; + +import org.apache.flink.api.common.functions.MapFunction; +import org.apache.flink.api.java.tuple.Tuple2; +import org.apache.flink.streaming.api.datastream.DataStreamSource; +import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator; +import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; +import org.apache.flink.streaming.connectors.redis.RedisSink; +import org.apache.flink.streaming.connectors.redis.common.config.FlinkJedisPoolConfig; +import org.apache.flink.streaming.connectors.redis.common.mapper.RedisCommand; +import org.apache.flink.streaming.connectors.redis.common.mapper.RedisCommandDescription; +import org.apache.flink.streaming.connectors.redis.common.mapper.RedisMapper; + +/** + * 需求:接收socket传输过来的数据,把数据保存到redis的list队列中 + * Created by xuwei + */ +public class StreamRedisSinkJava { + public static void main(String[] args) throws Exception{ + StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); + //连接socket获取输入数据 + DataStreamSource text = env.socketTextStream("localhost", 9008); + + // 组装数据,这里组装的是tuple2类型 + // 第一个元素是指list队列的key名称 + // 第二个元素是指需要向list队列中添加的元素 + SingleOutputStreamOperator> listData = text.map(new MapFunction>() { + @Override + public Tuple2 map(String word) throws Exception { + return new Tuple2("l_words_java", word); + } + }); + + //指定redissink + FlinkJedisPoolConfig conf = new FlinkJedisPoolConfig.Builder().setHost("localhost").setPort(6379).build(); + RedisSink> redisSink = new RedisSink<>(conf, new MyRedisMapper()); + listData.addSink(redisSink); + + env.execute("StreamRedisSinkJava"); + } + + public static class MyRedisMapper implements RedisMapper>{ + + //指定具体的操作命令 + @Override + public RedisCommandDescription getCommandDescription() { + return new RedisCommandDescription(RedisCommand.LPUSH); + } + + //获取key + @Override + public String getKeyFromData(Tuple2 data) { + return data.f0; + } + //获取value + @Override + public String getValueFromData(Tuple2 data) { + return data.f1; + } + } +} diff --git a/bigdata/flink/src/main/java/cn/cunchang/stream/source/StreamCollectionSourceJava.java b/bigdata/flink/src/main/java/cn/cunchang/stream/source/StreamCollectionSourceJava.java new file mode 100644 index 00000000..d1cdde10 --- /dev/null +++ b/bigdata/flink/src/main/java/cn/cunchang/stream/source/StreamCollectionSourceJava.java @@ -0,0 +1,23 @@ +package cn.cunchang.stream.source; + +import org.apache.flink.streaming.api.datastream.DataStreamSource; +import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; + +import java.util.Arrays; + +/** + * 基于collection的source的应用 + * Created by xuwei + */ +public class StreamCollectionSourceJava { + public static void main(String[] args) throws Exception{ + StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); + + //使用collection集合生成DataStream + DataStreamSource text = env.fromCollection(Arrays.asList(1, 2, 3, 4, 5)); + + text.print().setParallelism(1); + + env.execute("StreamCollectionSourceJava"); + } +} diff --git a/bigdata/flink/src/main/java/cn/cunchang/stream/transformation/MyPartitionerJava.java b/bigdata/flink/src/main/java/cn/cunchang/stream/transformation/MyPartitionerJava.java new file mode 100644 index 00000000..4bfcc73f --- /dev/null +++ b/bigdata/flink/src/main/java/cn/cunchang/stream/transformation/MyPartitionerJava.java @@ -0,0 +1,20 @@ +package cn.cunchang.stream.transformation; + +import org.apache.flink.api.common.functions.Partitioner; + +/** + * 自定义分区规则:按照数字的奇偶性进行分区 + * Created by xuwei + */ +public class MyPartitionerJava implements Partitioner { + + @Override + public int partition(Integer key, int numPartitions) { + System.out.println("key:" + key + ",分区总数:" + numPartitions); + if (key % 2 == 0) { + return 0; + } else { + return 1; + } + } +} diff --git a/bigdata/flink/src/main/java/cn/cunchang/stream/transformation/StreamConnectJava.java b/bigdata/flink/src/main/java/cn/cunchang/stream/transformation/StreamConnectJava.java new file mode 100644 index 00000000..bc71e94f --- /dev/null +++ b/bigdata/flink/src/main/java/cn/cunchang/stream/transformation/StreamConnectJava.java @@ -0,0 +1,41 @@ +package cn.cunchang.stream.transformation; + +import org.apache.flink.streaming.api.datastream.ConnectedStreams; +import org.apache.flink.streaming.api.datastream.DataStreamSource; +import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; +import org.apache.flink.streaming.api.functions.co.CoMapFunction; + +/** + * 只能连接两个流,两个流的数据类型可以不同 + * 应用:可以将两种不同格式的数据统一成一种格式 + * Created by xuwei + */ +public class StreamConnectJava { + public static void main(String[] args) throws Exception{ + StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); + + //第1份数据流 + DataStreamSource text1 = env.fromElements("user:tom,age:18"); + //第2份数据流 + DataStreamSource text2 = env.fromElements("user:jack;age:18"); + + //连接两个流 + ConnectedStreams connectStream = text1.connect(text2); + + connectStream.map(new CoMapFunction() { + + //处理第1份数据流中的数据 + @Override + public String map1(String value) throws Exception { + return value.replace(",","-"); + } + //处理第2份数据流中的数据 + @Override + public String map2(String value) throws Exception { + return value.replace(";","-"); + } + }).print().setParallelism(1); + + env.execute("StreamConnectJava"); + } +} diff --git a/bigdata/flink/src/main/java/cn/cunchang/stream/transformation/StreamPartitionOpJava.java b/bigdata/flink/src/main/java/cn/cunchang/stream/transformation/StreamPartitionOpJava.java new file mode 100644 index 00000000..6afff71b --- /dev/null +++ b/bigdata/flink/src/main/java/cn/cunchang/stream/transformation/StreamPartitionOpJava.java @@ -0,0 +1,106 @@ +package cn.cunchang.stream.transformation; + +import org.apache.flink.api.common.functions.MapFunction; +import org.apache.flink.api.java.functions.KeySelector; +import org.apache.flink.streaming.api.datastream.DataStreamSource; +import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; + +import java.util.Arrays; + +/** + * 分区规则的使用 + * Created by xuwei + */ +public class StreamPartitionOpJava { + public static void main(String[] args) throws Exception{ + StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); + // 注意:默认情况下Flink任务中算子的并行度会读取当前机器的CPU个数 + // fromCollection的并行度为1, + DataStreamSource text = env.fromCollection(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)); + + //使用shuffle分区规则 +// shuffleOp(text); + + //使用rebalance分区规则 +// rebalanceOp(text); + + //使用rescale分区规则 + //rescaleOp(text); + + //使用broadcast分区规则 + //broadcastOp(text); + + //自定义分区规则 + custormPartitionOp(text); + + env.execute("StreamPartitionOpJava"); + } + + private static void custormPartitionOp(DataStreamSource text) { + // 自定义分区规则:根据数据的奇偶性进行分区 + // 注意:此时虽然print算子的并行度为4,但是自定义的分区规则只会把数据分发给2个并行度,所以有2个是不干活 + text.map(new MapFunction() { + @Override + public Integer map(Integer value) throws Exception { + return value; + } + }).setParallelism(2) + .partitionCustom(new MyPartitionerJava(), new KeySelector() { + @Override + public Integer getKey(Integer value) throws Exception { + return value; + } + }) + .print() + .setParallelism(4); + } + + private static void broadcastOp(DataStreamSource text) { + text.map(new MapFunction() { + @Override + public Integer map(Integer value) throws Exception { + return value; + } + }).setParallelism(2) + .broadcast() + .print() + .setParallelism(4); + } + + private static void rescaleOp(DataStreamSource text) { + text.map(new MapFunction() { + @Override + public Integer map(Integer value) throws Exception { + return value; + } + }).setParallelism(2) + .rescale() + .print() + .setParallelism(4); + } + + private static void rebalanceOp(DataStreamSource text) { + text.map(new MapFunction() { + @Override + public Integer map(Integer value) throws Exception { + return value; + } + }).setParallelism(2) + .rebalance() + .print() + .setParallelism(4); + } + + private static void shuffleOp(DataStreamSource text) { + // 由于fromCollection已经设置了并行度为1,所以需要再接一个算子才能修改并行度,在这使用map算子 + text.map(new MapFunction() { + @Override + public Integer map(Integer value) throws Exception { + return value; + } + }).setParallelism(2)// 设置map算子的并行度为2 + .shuffle() + .print() + .setParallelism(4);// 设置print算子的并行度为4 + } +} diff --git a/bigdata/flink/src/main/java/cn/cunchang/stream/transformation/StreamSideOutputJava.java b/bigdata/flink/src/main/java/cn/cunchang/stream/transformation/StreamSideOutputJava.java new file mode 100644 index 00000000..8a617f5a --- /dev/null +++ b/bigdata/flink/src/main/java/cn/cunchang/stream/transformation/StreamSideOutputJava.java @@ -0,0 +1,89 @@ +package cn.cunchang.stream.transformation; + +import org.apache.flink.api.common.functions.FilterFunction; +import org.apache.flink.streaming.api.datastream.DataStream; +import org.apache.flink.streaming.api.datastream.DataStreamSource; +import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator; +import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; +import org.apache.flink.streaming.api.functions.ProcessFunction; +import org.apache.flink.util.Collector; +import org.apache.flink.util.OutputTag; + +import java.util.Arrays; + +/** + * 使用sideoutput切分流 + * Created by xuwei + */ +public class StreamSideOutputJava { + public static void main(String[] args) throws Exception { + StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); + + DataStreamSource text = env.fromCollection(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)); + + //按照数据的奇偶性对数据进行分流 + //首先定义两个sideoutput来保存切分出来的数据 + OutputTag outputTag1 = new OutputTag("even") { + };//保存偶数 + OutputTag outputTag2 = new OutputTag("odd") { + };//保存奇数 + + SingleOutputStreamOperator outputStream = text.process(new ProcessFunction() { + + @Override + public void processElement(Integer value, Context ctx, Collector out) + throws Exception { + if (value % 2 == 0) { + ctx.output(outputTag1, value); + } else { + ctx.output(outputTag2, value); + } + } + }); + + //获取偶数数据流 + DataStream evenStream = outputStream.getSideOutput(outputTag1); + + //对evenStream流进行二次切分 + OutputTag outputTag11 = new OutputTag("low") { + }; + OutputTag outputTag12 = new OutputTag("high") { + }; + SingleOutputStreamOperator subOutputStream = evenStream.process(new ProcessFunction() { + + @Override + public void processElement(Integer value, Context ctx, Collector out) + throws Exception { + if (value <= 5) { + ctx.output(outputTag11, value); + } else { + ctx.output(outputTag12, value); + } + } + }); + + //获取小于等于5的数据流 + DataStream lowStream = subOutputStream.getSideOutput(outputTag11); + //获取大于5的数据流 + DataStream highStream = subOutputStream.getSideOutput(outputTag12); +// lowStream.print().setParallelism(1); + + + //获取奇数数据流 + DataStream oddStream = outputStream.getSideOutput(outputTag2); + SingleOutputStreamOperator filterStream = oddStream.filter(new FilterFunction() { + @Override + public boolean filter(Integer value) throws Exception { + if (value <= 5) { + return true; + } else { + return false; + } + } + }); + filterStream.print().setParallelism(1); + + + env.execute("StreamSideOutputJava"); + } +} diff --git a/bigdata/flink/src/main/java/cn/cunchang/stream/transformation/StreamSplitJava.java b/bigdata/flink/src/main/java/cn/cunchang/stream/transformation/StreamSplitJava.java new file mode 100644 index 00000000..54eec61c --- /dev/null +++ b/bigdata/flink/src/main/java/cn/cunchang/stream/transformation/StreamSplitJava.java @@ -0,0 +1,46 @@ +package cn.cunchang.stream.transformation; + +import org.apache.flink.streaming.api.collector.selector.OutputSelector; +import org.apache.flink.streaming.api.datastream.DataStream; +import org.apache.flink.streaming.api.datastream.DataStreamSource; +import org.apache.flink.streaming.api.datastream.SplitStream; +import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; + +import java.util.ArrayList; +import java.util.Arrays; + +/** + * 根据规则把一个数据流切分为多个数据流 + * 注意:split只能分一次流,切分出来的流不能继续切分 + * split需要和select配合使用,选择切分后的流 + * 应用场景:将一份数据流切分为多份,便于针对每一份数据使用不同的处理逻辑 + * Created by xuwei + */ +public class StreamSplitJava { + public static void main(String[] args) throws Exception{ + StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); + + DataStreamSource text = env.fromCollection(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)); + + //按照数据的奇偶性对数据进行分流 + SplitStream splitStream = text.split(new OutputSelector() { + @Override + public Iterable select(Integer value) { + ArrayList list = new ArrayList<>(); + if (value % 2 == 0) { + list.add("even");//偶数 + } else { + list.add("odd");//奇数 + } + return list; + } + }); + + //选择流 + DataStream enevStream = splitStream.select("even"); + + enevStream.print().setParallelism(1); + + env.execute("StreamSplitJava"); + } +} diff --git a/bigdata/flink/src/main/java/cn/cunchang/stream/transformation/StreamUnionJava.java b/bigdata/flink/src/main/java/cn/cunchang/stream/transformation/StreamUnionJava.java new file mode 100644 index 00000000..66b3ef13 --- /dev/null +++ b/bigdata/flink/src/main/java/cn/cunchang/stream/transformation/StreamUnionJava.java @@ -0,0 +1,32 @@ +package cn.cunchang.stream.transformation; + +import org.apache.flink.streaming.api.datastream.DataStream; +import org.apache.flink.streaming.api.datastream.DataStreamSource; +import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; + +import java.util.Arrays; + +/** + * 合并多个流,多个流的数据类型必须一致 + * 应用场景:多种数据源的数据类型一致,数据处理规则也一致 + * + * Created by xuwei + */ +public class StreamUnionJava { + public static void main(String[] args) throws Exception{ + StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); + + //第1份数据流 + DataStreamSource text1 = env.fromCollection(Arrays.asList(1, 2, 3, 4, 5)); + //第2份数据流 + DataStreamSource text2 = env.fromCollection(Arrays.asList(6, 7, 8, 9, 10)); + + //合并流 + DataStream unionStream = text1.union(text2); + + //打印流中的数据 + unionStream.print().setParallelism(1); + + env.execute("StreamUnionJava"); + } +} diff --git a/bigdata/flink/src/main/java/cn/cunchang/tablesql/CreateTableEnvironmentJava.java b/bigdata/flink/src/main/java/cn/cunchang/tablesql/CreateTableEnvironmentJava.java new file mode 100644 index 00000000..f5bb5d27 --- /dev/null +++ b/bigdata/flink/src/main/java/cn/cunchang/tablesql/CreateTableEnvironmentJava.java @@ -0,0 +1,45 @@ +package cn.cunchang.tablesql; + +import org.apache.flink.api.java.ExecutionEnvironment; +import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; +import org.apache.flink.table.api.EnvironmentSettings; +import org.apache.flink.table.api.TableEnvironment; +import org.apache.flink.table.api.bridge.java.BatchTableEnvironment; +import org.apache.flink.table.api.bridge.java.StreamTableEnvironment; + +/** + * 创建TableEnvironment对象 + * Created by xuwei + */ +public class CreateTableEnvironmentJava { + public static void main(String[] args) { + /** + * 注意:如果Table API 和 SQL不需要和DataStream或者DataSet互相转换 + * 则针对stream和batch都可以使用TableEnvironment + */ + //指定底层引擎为Blink,以及数据处理模式-stream + // 从1.11版本开始,Blink引擎成为Table API和SQL的默认执行引擎,在生产环境下 + EnvironmentSettings sSettings = EnvironmentSettings.newInstance().useBlinkPlanner().inStreamingMode().build(); + //创建TableEnvironment对象 + TableEnvironment sTableEnv = TableEnvironment.create(sSettings); + + //指定底层引擎为Blink,以及数据处理模式-batch + EnvironmentSettings bSettings = EnvironmentSettings.newInstance().useBlinkPlanner().inBatchMode().build(); + //创建TableEnvironment对象 + TableEnvironment bTableEnv = TableEnvironment.create(bSettings); + + /** + * 注意:如果Table API和SQL需要和DataStream或者DataSet互相转换 + * 针对stream需要使用StreamTableEnvironment + * 针对batch需要使用BatchTableEnvironment + */ + //创建StreamTableEnvironment + StreamExecutionEnvironment ssEnv = StreamExecutionEnvironment.getExecutionEnvironment(); + EnvironmentSettings ssSettings = EnvironmentSettings.newInstance().useBlinkPlanner().inStreamingMode().build(); + StreamTableEnvironment ssTableEnv = StreamTableEnvironment.create(ssEnv, ssSettings); + + //创建BatchTableEnvironment + ExecutionEnvironment bbEnv = ExecutionEnvironment.getExecutionEnvironment(); + BatchTableEnvironment bbTableEnv = BatchTableEnvironment.create(bbEnv); + } +} diff --git a/bigdata/flink/src/main/java/cn/cunchang/tablesql/DataSetToTableJava.java b/bigdata/flink/src/main/java/cn/cunchang/tablesql/DataSetToTableJava.java new file mode 100644 index 00000000..737f35b3 --- /dev/null +++ b/bigdata/flink/src/main/java/cn/cunchang/tablesql/DataSetToTableJava.java @@ -0,0 +1,41 @@ +package cn.cunchang.tablesql; + +import org.apache.flink.api.java.ExecutionEnvironment; +import org.apache.flink.api.java.operators.DataSource; +import org.apache.flink.api.java.tuple.Tuple2; +import org.apache.flink.streaming.api.datastream.DataStreamSource; +import org.apache.flink.table.api.bridge.java.BatchTableEnvironment; + +import java.util.ArrayList; + +import static org.apache.flink.table.api.Expressions.$; + +/** + * 将DataSet转换为表 + * Created by xuwei + */ +public class DataSetToTableJava { + public static void main(String[] args) { + //获取BatchTableEnvironment + ExecutionEnvironment bbEnv = ExecutionEnvironment.getExecutionEnvironment(); + BatchTableEnvironment bbTableEnv = BatchTableEnvironment.create(bbEnv); + + //获取DataSet + //获取DataStream + ArrayList> data = new ArrayList<>(); + data.add(new Tuple2(1,"jack")); + data.add(new Tuple2(2,"tom")); + data.add(new Tuple2(3,"mick")); + DataSource> set = bbEnv.fromCollection(data); + + //第一种:将DataSet转换为view视图 + bbTableEnv.createTemporaryView("myTable",set,$("id"),$("name")); + bbTableEnv.sqlQuery("select * from myTable where id > 1 ").execute().print(); + + //第二种:将DataSet转换为table对象 + bbTableEnv.fromDataSet(set,$("id"),$("name")) + .filter($("id").isGreater(1)) + .execute() + .print(); + } +} diff --git a/bigdata/flink/src/main/java/cn/cunchang/tablesql/DataStreamToTableJava.java b/bigdata/flink/src/main/java/cn/cunchang/tablesql/DataStreamToTableJava.java new file mode 100644 index 00000000..0a030872 --- /dev/null +++ b/bigdata/flink/src/main/java/cn/cunchang/tablesql/DataStreamToTableJava.java @@ -0,0 +1,43 @@ +package cn.cunchang.tablesql; + +import org.apache.flink.api.java.tuple.Tuple2; +import org.apache.flink.streaming.api.datastream.DataStreamSource; +import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; +import org.apache.flink.table.api.EnvironmentSettings; +import org.apache.flink.table.api.Table; +import org.apache.flink.table.api.bridge.java.StreamTableEnvironment; + +import java.util.ArrayList; + +import static org.apache.flink.table.api.Expressions.$; + +/** + * 将DataStream转换为表 + * Created by xuwei + */ +public class DataStreamToTableJava { + public static void main(String[] args) { + //获取StreamTableEnvironment + StreamExecutionEnvironment ssEnv = StreamExecutionEnvironment.getExecutionEnvironment(); + EnvironmentSettings ssSettings = EnvironmentSettings.newInstance().useBlinkPlanner().inStreamingMode().build(); + StreamTableEnvironment ssTableEnv = StreamTableEnvironment.create(ssEnv, ssSettings); + + //获取DataStream + ArrayList> data = new ArrayList<>(); + data.add(new Tuple2(1,"jack")); + data.add(new Tuple2(2,"tom")); + data.add(new Tuple2(3,"mick")); + DataStreamSource> stream = ssEnv.fromCollection(data); + + //第一种:将DataStream转换为view视图 + ssTableEnv.createTemporaryView("myTable",stream,$("id"),$("name")); + ssTableEnv.sqlQuery("select * from myTable where id > 1 ").execute().print(); + + //第二种:将DataStream转换为table对象 + Table table = ssTableEnv.fromDataStream(stream, $("id"), $("name")); + table.select($("id"),$("name")) + .filter($("id").isGreater(1)) + .execute() + .print(); + } +} diff --git a/bigdata/flink/src/main/java/cn/cunchang/tablesql/TableAPIAndSQLOpJava.java b/bigdata/flink/src/main/java/cn/cunchang/tablesql/TableAPIAndSQLOpJava.java new file mode 100644 index 00000000..f756fbd5 --- /dev/null +++ b/bigdata/flink/src/main/java/cn/cunchang/tablesql/TableAPIAndSQLOpJava.java @@ -0,0 +1,64 @@ +package cn.cunchang.tablesql; + +import org.apache.flink.table.api.EnvironmentSettings; +import org.apache.flink.table.api.Table; +import org.apache.flink.table.api.TableEnvironment; + +import static org.apache.flink.table.api.Expressions.$; + +/** + * TableAPI 和 SQL的使用 + * Created by xuwei + */ +public class TableAPIAndSQLOpJava { + public static void main(String[] args) { + //获取TableEnvironment对象 + EnvironmentSettings sSettings = EnvironmentSettings.newInstance().useBlinkPlanner().inStreamingMode().build(); + TableEnvironment sTableEnv = TableEnvironment.create(sSettings); + + //创建输入表 + /** + * connector.type:指定connector的类型 + * connector.path:指定文件或者目录地址 + * format.type:文件数据格式化类型,现在只支持csv格式 + * 注意:SQL语句如果出现了换行,行的末尾可以添加空格或者\n都可以,最后一行不用添 + * + * 注意:/Users/cunchang/tmp/data/source下面必须要有csv文件,内容:1,jack + */ + sTableEnv.executeSql("" + + "create table myTable(\n" + + "id int,\n" + + "name string\n" + + ") with (\n" + + "'connector.type' = 'filesystem',\n" + + "'connector.path' = '/Users/cunchang/tmp/data/source',\n" + + "'format.type' = 'csv'\n" + + ")"); + + //使用TableAPI实现数据查询和过滤等操作 + /*Table result = sTableEnv.from("myTable") + .select($("id"), $("name")) + .filter($("id").isGreater(1));*/ + + //使用SQL实现数据查询和过滤等操作 + Table result = sTableEnv.sqlQuery("select id,name from myTable where id > 1"); + + //输出结果到控制台 + result.execute().print(); + + //创建输出表 + sTableEnv.executeSql("" + + "create table newTable(\n" + + "id int,\n" + + "name string\n" + + ") with (\n" + + "'connector.type' = 'filesystem',\n" + + "'connector.path' = '/Users/cunchang/tmp/data/res',\n" + + "'format.type' = 'csv'\n" + + ")"); + + //输出结果到表newTable中 + result.executeInsert("newTable"); + + } +} diff --git a/bigdata/flink/src/main/java/cn/cunchang/tablesql/TableToDataSetJava.java b/bigdata/flink/src/main/java/cn/cunchang/tablesql/TableToDataSetJava.java new file mode 100644 index 00000000..12213745 --- /dev/null +++ b/bigdata/flink/src/main/java/cn/cunchang/tablesql/TableToDataSetJava.java @@ -0,0 +1,46 @@ +package cn.cunchang.tablesql; + +import org.apache.flink.api.common.functions.MapFunction; +import org.apache.flink.api.java.DataSet; +import org.apache.flink.api.java.ExecutionEnvironment; +import org.apache.flink.api.java.tuple.Tuple2; +import org.apache.flink.table.api.Table; +import org.apache.flink.table.api.bridge.java.BatchTableEnvironment; +import org.apache.flink.types.Row; + +/** + * 将table转换成DataSet + * Created by xuwei + */ +public class TableToDataSetJava { + public static void main(String[] args) throws Exception{ + //创建BatchTableEnvironment + ExecutionEnvironment bbEnv = ExecutionEnvironment.getExecutionEnvironment(); + BatchTableEnvironment bbTableEnv = BatchTableEnvironment.create(bbEnv); + + //创建输入表 + bbTableEnv.executeSql("" + + "create table myTable(\n" + + "id int,\n" + + "name string\n" + + ") with (\n" + + "'connector.type' = 'filesystem',\n" + + "'connector.path' = 'D:\\data\\source',\n" + + "'format.type' = 'csv'\n" + + ")"); + + //获取table + Table table = bbTableEnv.from("myTable"); + + //将table转换成DataSet + DataSet set = bbTableEnv.toDataSet(table, Row.class); + set.map(new MapFunction>() { + @Override + public Tuple2 map(Row row) throws Exception { + int id = Integer.parseInt(row.getField(0).toString()); + String name = row.getField(1).toString(); + return new Tuple2(id,name); + } + }).print(); + } +} diff --git a/bigdata/flink/src/main/java/cn/cunchang/tablesql/TableToDataStreamJava.java b/bigdata/flink/src/main/java/cn/cunchang/tablesql/TableToDataStreamJava.java new file mode 100644 index 00000000..c877a456 --- /dev/null +++ b/bigdata/flink/src/main/java/cn/cunchang/tablesql/TableToDataStreamJava.java @@ -0,0 +1,65 @@ +package cn.cunchang.tablesql; + +import org.apache.flink.api.common.functions.MapFunction; +import org.apache.flink.api.java.tuple.Tuple2; +import org.apache.flink.api.java.tuple.Tuple3; +import org.apache.flink.streaming.api.datastream.DataStream; +import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; +import org.apache.flink.table.api.EnvironmentSettings; +import org.apache.flink.table.api.Table; +import org.apache.flink.table.api.bridge.java.StreamTableEnvironment; +import org.apache.flink.types.Row; + +/** + * 将table转换成DataStream + * Created by xuwei + */ +public class TableToDataStreamJava { + public static void main(String[] args) throws Exception{ + //获取StreamTableEnvironment + StreamExecutionEnvironment ssEnv = StreamExecutionEnvironment.getExecutionEnvironment(); + EnvironmentSettings ssSettings = EnvironmentSettings.newInstance().useBlinkPlanner().inStreamingMode().build(); + StreamTableEnvironment ssTableEnv = StreamTableEnvironment.create(ssEnv, ssSettings); + + //创建输入表 + ssTableEnv.executeSql("" + + "create table myTable(\n" + + "id int,\n" + + "name string\n" + + ") with (\n" + + "'connector.type' = 'filesystem',\n" + + "'connector.path' = 'D:\\data\\source',\n" + + "'format.type' = 'csv'\n" + + ")"); + + //获取table + Table table = ssTableEnv.from("myTable"); + + //将table转换为DataStream + //如果只有新增(追加)操作,可以使用toAppendStream + DataStream appStream = ssTableEnv.toAppendStream(table, Row.class); + appStream.map(new MapFunction>() { + @Override + public Tuple2 map(Row row) throws Exception { + int id = Integer.parseInt(row.getField(0).toString()); + String name = row.getField(1).toString(); + return new Tuple2(id,name); + } + }).print(); + + //如果有增加操作,还有删除操作,则使用toRetractStream + DataStream> retStream = ssTableEnv.toRetractStream(table, Row.class); + retStream.map(new MapFunction, Tuple3>() { + @Override + public Tuple3 map(Tuple2 tup) throws Exception { + Boolean flag = tup.f0; + int id = Integer.parseInt(tup.f1.getField(0).toString()); + String name = tup.f1.getField(1).toString(); + return new Tuple3(flag,id,name); + } + }).print(); + + //注意:将table转换为DataStream之后,就需要调用StreamExecutionEnvironment中的execute方法了 + ssEnv.execute("TableToDataStreamJava"); + } +} diff --git a/bigdata/flink/src/main/java/cn/cunchang/window/CountWindowOpJava.java b/bigdata/flink/src/main/java/cn/cunchang/window/CountWindowOpJava.java new file mode 100644 index 00000000..941d4d5c --- /dev/null +++ b/bigdata/flink/src/main/java/cn/cunchang/window/CountWindowOpJava.java @@ -0,0 +1,56 @@ +package cn.cunchang.window; + +import org.apache.flink.api.common.functions.FlatMapFunction; +import org.apache.flink.api.java.tuple.Tuple2; +import org.apache.flink.streaming.api.datastream.DataStreamSource; +import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; +import org.apache.flink.util.Collector; + +/** + * CountWindow的使用 + * 1:滚动窗口 + * 2:滑动窗口 + * Created by xuwei + */ +public class CountWindowOpJava { + public static void main(String[] args) throws Exception{ + StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); + DataStreamSource text = env.socketTextStream("localhost", 9001); + + // 注意:由于我们在这里使用keyBy, 会先对数据分组 + // 如果某个分组对应的数据窗口内达到了5个元素,这个窗口才会被触发执行 + //CountWindow之滚动窗口:每隔5个元素计算一次前5个元素 + text.flatMap(new FlatMapFunction>() { + @Override + public void flatMap(String line, Collector> out) + throws Exception { + String[] words = line.split(" "); + for (String word : words) { + out.collect(new Tuple2(word,1)); + } + } + }).keyBy(0) + //窗口大小 + .countWindow(5) + .sum(1) + .print(); + + //CountWindow之滑动窗口:每隔1个元素计算一次前5个元素 +// text.flatMap(new FlatMapFunction>() { +// @Override +// public void flatMap(String line, Collector> out) +// throws Exception { +// String[] words = line.split(" "); +// for (String word : words) { +// out.collect(new Tuple2(word,1)); +// } +// } +// }).keyBy(0) +// //第一个参数:窗口大小,第二个参数:滑动间隔 +// .countWindow(5,1) +// .sum(1) +// .print(); + + env.execute("CountWindowOpJava"); + } +} diff --git a/bigdata/flink/src/main/java/cn/cunchang/window/MyTimeWindowJava.java b/bigdata/flink/src/main/java/cn/cunchang/window/MyTimeWindowJava.java new file mode 100644 index 00000000..08f25ae1 --- /dev/null +++ b/bigdata/flink/src/main/java/cn/cunchang/window/MyTimeWindowJava.java @@ -0,0 +1,39 @@ +package cn.cunchang.window; + +import org.apache.flink.api.common.functions.FlatMapFunction; +import org.apache.flink.api.java.tuple.Tuple2; +import org.apache.flink.streaming.api.datastream.DataStreamSource; +import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; +import org.apache.flink.streaming.api.windowing.assigners.TumblingProcessingTimeWindows; +import org.apache.flink.streaming.api.windowing.time.Time; +import org.apache.flink.util.Collector; + +/** + * 需求:自定义MyTimeWindow + * Created by xuwei + */ +public class MyTimeWindowJava { + public static void main(String[] args) throws Exception{ + StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); + DataStreamSource text = env.socketTextStream("localhost", 9001); + + // timewindow和countwindow底层都用的 window + //自定义MyTimeWindow滚动窗口:每隔10秒计算一次前10秒时间窗口内的数据 + text.flatMap(new FlatMapFunction>() { + @Override + public void flatMap(String line, Collector> out) + throws Exception { + String[] words = line.split(" "); + for (String word : words) { + out.collect(new Tuple2(word,1)); + } + } + }).keyBy(0) + //窗口大小 + .window(TumblingProcessingTimeWindows.of(Time.seconds(10))) + .sum(1) + .print(); + + env.execute("MyTimeWindowJava"); + } +} diff --git a/bigdata/flink/src/main/java/cn/cunchang/window/TimeWindowOpJava.java b/bigdata/flink/src/main/java/cn/cunchang/window/TimeWindowOpJava.java new file mode 100644 index 00000000..c72fbc6a --- /dev/null +++ b/bigdata/flink/src/main/java/cn/cunchang/window/TimeWindowOpJava.java @@ -0,0 +1,55 @@ +package cn.cunchang.window; + +import org.apache.flink.api.common.functions.FlatMapFunction; +import org.apache.flink.api.java.tuple.Tuple2; +import org.apache.flink.streaming.api.datastream.DataStreamSource; +import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; +import org.apache.flink.streaming.api.windowing.time.Time; +import org.apache.flink.util.Collector; + +/** + * TimeWindow的使用 + * 1:滚动窗口 + * 2:滑动窗口 + * hello + */ +public class TimeWindowOpJava { + public static void main(String[] args) throws Exception { + StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); + DataStreamSource text = env.socketTextStream("localhost", 9001); + + //TimeWindow之滚动窗口:每隔10秒计算一次前10秒时间窗口内的数据 +// text.flatMap(new FlatMapFunction>() { +// @Override +// public void flatMap(String line, Collector> out) +// throws Exception { +// String[] words = line.split(" "); +// for (String word : words) { +// out.collect(new Tuple2(word, 1)); +// } +// } +// }).keyBy(0) +// //窗口大小 +// .timeWindow(Time.seconds(10)) +// .sum(1) +// .print(); + + //TimeWindow之滑动窗口:每隔5秒计算一次前10秒时间窗口内的数据 + text.flatMap(new FlatMapFunction>() { + @Override + public void flatMap(String line, Collector> out) + throws Exception { + String[] words = line.split(" "); + for (String word: words) { + out.collect(new Tuple2(word,1)); + } + } + }).keyBy(0) + //第一个参数:窗口大小,第二个参数:滑动间隔 + .timeWindow(Time.seconds(10),Time.seconds(5)) + .sum(1) + .print(); + + env.execute("TimeWindowOpJava"); + } +} diff --git a/bigdata/flink/src/main/java/cn/cunchang/window/WatermarkOpJava.java b/bigdata/flink/src/main/java/cn/cunchang/window/WatermarkOpJava.java new file mode 100644 index 00000000..0930a442 --- /dev/null +++ b/bigdata/flink/src/main/java/cn/cunchang/window/WatermarkOpJava.java @@ -0,0 +1,19 @@ +package cn.cunchang.window; + +import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; + +/** + * 水位线 + * + * @author cunchang + * @date 2021/10/6 3:55 下午 + */ +public class WatermarkOpJava { + + public static void main(String[] args) { + StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); + + + } + +} diff --git a/bigdata/flink/src/main/resources/log4j.properties b/bigdata/flink/src/main/resources/log4j.properties new file mode 100644 index 00000000..cdb2da93 --- /dev/null +++ b/bigdata/flink/src/main/resources/log4j.properties @@ -0,0 +1,9 @@ +log4j.rootLogger=warn,stdout + +log4j.appender.stdout = org.apache.log4j.ConsoleAppender +log4j.appender.stdout.Target = System.out +log4j.appender.stdout.layout=org.apache.log4j.PatternLayout +log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} [%t] [%c] [%p] - %m%n + + + diff --git a/bigdata/flink/src/main/scala/com/imooc/scala/batch/BatchWordCountScala.scala b/bigdata/flink/src/main/scala/com/imooc/scala/batch/BatchWordCountScala.scala new file mode 100644 index 00000000..47b537c3 --- /dev/null +++ b/bigdata/flink/src/main/scala/com/imooc/scala/batch/BatchWordCountScala.scala @@ -0,0 +1,36 @@ +package com.imooc.scala.batch + +import org.apache.flink.api.scala.ExecutionEnvironment + +/** + * 需求:统计指定文件中单词出现的总次数 + * Created by xuwei + */ +object BatchWordCountScala { + def main(args: Array[String]): Unit = { + //获取执行环境 + val env = ExecutionEnvironment.getExecutionEnvironment + + val inputPath = "hdfs://bigdata01:9000/hello.txt" + val outPath = "hdfs://bigdata01:9000/out" + + //读取文件中的数据 + val text = env.readTextFile(inputPath) + + //处理数据 + import org.apache.flink.api.scala._ + val wordCount = text.flatMap(_.split(" ")) + .map((_, 1)) + .groupBy(0) + .sum(1) + .setParallelism(1)//这里面设置并行度为1是为了将所有数据写到一个文件里面,查看结果比较方便 + + //将结果数据保存到文件中 + wordCount.writeAsCsv(outPath,"\n"," ") + + //执行程序 + env.execute("BatchWordCountScala") + + } + +} diff --git a/bigdata/flink/src/main/scala/com/imooc/scala/batch/transformation/BatchCrossScala.scala b/bigdata/flink/src/main/scala/com/imooc/scala/batch/transformation/BatchCrossScala.scala new file mode 100644 index 00000000..6b0375af --- /dev/null +++ b/bigdata/flink/src/main/scala/com/imooc/scala/batch/transformation/BatchCrossScala.scala @@ -0,0 +1,23 @@ +package com.imooc.scala.batch.transformation + +import org.apache.flink.api.scala.ExecutionEnvironment + +/** + * cross:获取两个数据集的笛卡尔积 + * Created by xuwei + */ +object BatchCrossScala { + def main(args: Array[String]): Unit = { + val env = ExecutionEnvironment.getExecutionEnvironment + + import org.apache.flink.api.scala._ + //初始化第一份数据 + val text1 = env.fromCollection(Array(1, 2)) + //初始化第二份数据 + val text2 = env.fromCollection(Array("a", "b")) + + //执行cross操作 + text1.cross(text2).print() + } + +} diff --git a/bigdata/flink/src/main/scala/com/imooc/scala/batch/transformation/BatchFirstNScala.scala b/bigdata/flink/src/main/scala/com/imooc/scala/batch/transformation/BatchFirstNScala.scala new file mode 100644 index 00000000..4092c85b --- /dev/null +++ b/bigdata/flink/src/main/scala/com/imooc/scala/batch/transformation/BatchFirstNScala.scala @@ -0,0 +1,41 @@ +package com.imooc.scala.batch.transformation + +import org.apache.flink.api.common.operators.Order +import org.apache.flink.api.scala.ExecutionEnvironment + +import scala.collection.mutable.ListBuffer + +/** + * first-n:获取集合中的前N个元素 + * Created by xuwei + */ +object BatchFirstNScala { + def main(args: Array[String]): Unit = { + val env = ExecutionEnvironment.getExecutionEnvironment + val data = ListBuffer[Tuple2[Int,String]]() + data.append((2,"zs")) + data.append((4,"ls")) + data.append((3,"ww")) + data.append((1,"aw")) + data.append((1,"xw")) + data.append((1,"mw")) + + import org.apache.flink.api.scala._ + //初始化数据 + val text = env.fromCollection(data) + + //获取前3条数据,按照数据插入的顺序 + text.first(3).print() + println("===========================") + + //根据数据中的第一列进行分组,获取每组的前2个元素 + text.groupBy(0).first(2).print() + println("===========================") + + + //根据数据中的第一列分组,再根据第二列进行组内排序[倒序],获取每组的前2个元素 + //分组排序取TopN + text.groupBy(0).sortGroup(1,Order.DESCENDING).first(2).print() + } + +} diff --git a/bigdata/flink/src/main/scala/com/imooc/scala/batch/transformation/BatchJoinScala.scala b/bigdata/flink/src/main/scala/com/imooc/scala/batch/transformation/BatchJoinScala.scala new file mode 100644 index 00000000..dc302d2c --- /dev/null +++ b/bigdata/flink/src/main/scala/com/imooc/scala/batch/transformation/BatchJoinScala.scala @@ -0,0 +1,31 @@ +package com.imooc.scala.batch.transformation + +import org.apache.flink.api.scala.ExecutionEnvironment + +/** + * join:内连接 + * Created by xuwei + */ +object BatchJoinScala { + def main(args: Array[String]): Unit = { + val env = ExecutionEnvironment.getExecutionEnvironment + + import org.apache.flink.api.scala._ + //初始化第一份数据 Tuple2<用户id,用户姓名> + val text1 = env.fromCollection(Array((1, "jack"), (2, "tom"), (3, "mick"))) + //初始化第二份数据 Tuple2<用户id,用户所在城市> + val text2 = env.fromCollection(Array((1, "bj"), (2, "sh"), (4, "gz"))) + + //对两份数据集执行join操作 + text1.join(text2) + //注意:这里的where和equalsTo实现类似于on fieldA=fieldB的效果 + //where:指定左边数据集中参与比较的元素角标 + .where(0) + //equalTo:指定右边数据集中参与比较的元素角标 + .equalTo(0){(first,second)=>{ + (first._1,first._2,second._2) + }}.print() + + } + +} diff --git a/bigdata/flink/src/main/scala/com/imooc/scala/batch/transformation/BatchMapPartitionScala.scala b/bigdata/flink/src/main/scala/com/imooc/scala/batch/transformation/BatchMapPartitionScala.scala new file mode 100644 index 00000000..e697ac26 --- /dev/null +++ b/bigdata/flink/src/main/scala/com/imooc/scala/batch/transformation/BatchMapPartitionScala.scala @@ -0,0 +1,40 @@ +package com.imooc.scala.batch.transformation + +import org.apache.flink.api.scala.ExecutionEnvironment + +import scala.collection.mutable.ListBuffer + +/** + * MapPartition的使用:一次处理一个分区的数据 + * Created by xuwei + */ +object BatchMapPartitionScala { + def main(args: Array[String]): Unit = { + val env = ExecutionEnvironment.getExecutionEnvironment + + import org.apache.flink.api.scala._ + //生成数据源数据 + val text = env.fromCollection(Array("hello you", "hello me")) + + //每次处理一个分区的数据 + text.mapPartition(it=>{ + //可以在此处创建数据库连接,建议把这块代码放到try-catch代码块中 + //注意:此时是每个分区获取一次数据库连接,不需要每处理一条数据就获取一次连接,性能较高 + val res = ListBuffer[String]() + it.foreach(line=>{ + val words = line.split(" ") + for(word <- words){ + res.append(word) + } + }) + res + //关闭数据库连接 + }).print() + + //No new data sinks have been defined since the last execution. + //The last execution refers to the latest call to 'execute()', 'count()', 'collect()', or 'print()'. + //注意:这对DataSetAPI,如果在后面调用的是count、collect、print,则最后不需要指定execute即可 + //env.execute("BatchMapPartitionScala") + } + +} diff --git a/bigdata/flink/src/main/scala/com/imooc/scala/batch/transformation/BatchOuterJoinScala.scala b/bigdata/flink/src/main/scala/com/imooc/scala/batch/transformation/BatchOuterJoinScala.scala new file mode 100644 index 00000000..4e8b9710 --- /dev/null +++ b/bigdata/flink/src/main/scala/com/imooc/scala/batch/transformation/BatchOuterJoinScala.scala @@ -0,0 +1,67 @@ +package com.imooc.scala.batch.transformation + +import org.apache.flink.api.scala.ExecutionEnvironment + +/** + * outerJoin:外连接 + * 一共有三种情况 + * 1:leftOuterJoin + * 2:rightOuterJoin + * 3:fullOuterJoin + * Created by xuwei + */ +object BatchOuterJoinScala { + def main(args: Array[String]): Unit = { + val env = ExecutionEnvironment.getExecutionEnvironment + + import org.apache.flink.api.scala._ + //初始化第一份数据 Tuple2<用户id,用户姓名> + val text1 = env.fromCollection(Array((1, "jack"), (2, "tom"), (3, "mick"))) + //初始化第二份数据 Tuple2<用户id,用户所在城市> + val text2 = env.fromCollection(Array((1, "bj"), (2, "sh"), (4, "gz"))) + + //对两份数据集执行leftOuterJoin操作 + text1.leftOuterJoin(text2) + .where(0) + .equalTo(0){(first,second)=>{ + //注意:second中的元素可能为null + if(second==null){ + (first._1,first._2,"null") + }else{ + (first._1,first._2,second._2) + } + }}.print() + + println("========================================") + + //对两份数据集执行rightOuterJoin操作 + text1.rightOuterJoin(text2) + .where(0) + .equalTo(0){(first,second)=>{ + //注意:first中的元素可能为null + if(first==null){ + (second._1,"null",second._2) + }else{ + (first._1,first._2,second._2) + } + }}.print() + + println("========================================") + + //对两份数据集执行fullOuterJoin操作 + text1.fullOuterJoin(text2) + .where(0) + .equalTo(0){(first,second)=>{ + //注意:first和second中的元素都有可能为null + if(first==null){ + (second._1,"null",second._2) + }else if(second==null){ + (first._1,first._2,"null") + }else{ + (first._1,first._2,second._2) + } + }}.print() + + } + +} diff --git a/bigdata/flink/src/main/scala/com/imooc/scala/kafkaconnector/StreamKafkaSinkScala.scala b/bigdata/flink/src/main/scala/com/imooc/scala/kafkaconnector/StreamKafkaSinkScala.scala new file mode 100644 index 00000000..8902da11 --- /dev/null +++ b/bigdata/flink/src/main/scala/com/imooc/scala/kafkaconnector/StreamKafkaSinkScala.scala @@ -0,0 +1,48 @@ +package com.imooc.scala.kafkaconnector + +import java.util.Properties + +import org.apache.flink.api.common.serialization.SimpleStringSchema +import org.apache.flink.streaming.api.scala.StreamExecutionEnvironment +import org.apache.flink.streaming.connectors.kafka.FlinkKafkaProducer +import org.apache.flink.streaming.connectors.kafka.internals.KafkaSerializationSchemaWrapper +import org.apache.flink.streaming.connectors.kafka.partitioner.FlinkFixedPartitioner + +/** + * Flink向Kafka中生产数据 + * Created by xuwei + */ +object StreamKafkaSinkScala { + def main(args: Array[String]): Unit = { + val env = StreamExecutionEnvironment.getExecutionEnvironment + + //开启checkpoint + env.enableCheckpointing(5000) + + + val text = env.socketTextStream("bigdata04", 9001) + + //指定FlinkKafkaProducer的相关配置 + val topic = "t3" + val prop = new Properties() + prop.setProperty("bootstrap.servers","bigdata01:9092,bigdata02:9092,bigdata03:9092") + + //指定kafka作为sink + /* + KafkaSerializationSchemaWrapper的几个参数 + 1:topic:指定需要写入的topic名称即可 + 2:partitioner,通过自定义分区器实现将数据写入到指定topic的具体分区中 + 默认会使用FlinkFixedPartitioner,它表示会将所有的数据都写入指定topic的一个分区里面 + 如果不想自定义分区器,也不想使用默认的,可以直接使用null即可 + 3:writeTimeStamp,向topic中写入数据的时候,是否写入时间戳 + 如果写入了,那么在watermark的案例中,使用extractTimestamp()提起时间戳的时候 + 就可以直接使用recordTimestamp即可,它表示的就是我们在这里写入的数据对应的timestamp + */ + val kafkaProducer = new FlinkKafkaProducer[String](topic, new KafkaSerializationSchemaWrapper[String](topic, null, false, new SimpleStringSchema()), prop, FlinkKafkaProducer.Semantic.EXACTLY_ONCE) + text.addSink(kafkaProducer) + + env.execute("StreamKafkaSinkScala") + + } + +} diff --git a/bigdata/flink/src/main/scala/com/imooc/scala/kafkaconnector/StreamKafkaSourceScala.scala b/bigdata/flink/src/main/scala/com/imooc/scala/kafkaconnector/StreamKafkaSourceScala.scala new file mode 100644 index 00000000..1d4635d8 --- /dev/null +++ b/bigdata/flink/src/main/scala/com/imooc/scala/kafkaconnector/StreamKafkaSourceScala.scala @@ -0,0 +1,66 @@ +package com.imooc.scala.kafkaconnector + +import java.util.Properties + +import org.apache.flink.api.common.serialization.SimpleStringSchema +import org.apache.flink.contrib.streaming.state.RocksDBStateBackend +import org.apache.flink.streaming.api.CheckpointingMode +import org.apache.flink.streaming.api.environment.CheckpointConfig +import org.apache.flink.streaming.api.scala.StreamExecutionEnvironment +import org.apache.flink.streaming.connectors.kafka.FlinkKafkaConsumer + +/** + * Flink从kafka中消费数据 + * Created by xuwei + */ +object StreamKafkaSourceScala { + def main(args: Array[String]): Unit = { + val env = StreamExecutionEnvironment.getExecutionEnvironment + + //每隔5000 ms执行一次checkpoint(设置checkpoint的周期) + env.enableCheckpointing(5000) + + //针对checkpoint的相关配置 + //设置模式为.EXACTLY_ONCE (这是默认值) ,还可以设置为AT_LEAST_ONCE + env.getCheckpointConfig.setCheckpointingMode(CheckpointingMode.EXACTLY_ONCE) + //确保两次Checkpoint之间有至少多少 ms的间隔(checkpoint最小间隔) + env.getCheckpointConfig.setMinPauseBetweenCheckpoints(500) + //Checkpoint必须在一分钟内完成,或者被丢弃(checkpoint的超时时间) + env.getCheckpointConfig.setCheckpointTimeout(60000) + //同一时间只允许执行一个Checkpoint + env.getCheckpointConfig.setMaxConcurrentCheckpoints(1) + //表示一旦Flink处理程序被cancel后,会保留Checkpoint数据,以便根据实际需要恢复到指定的Checkpoint + env.getCheckpointConfig.enableExternalizedCheckpoints(CheckpointConfig.ExternalizedCheckpointCleanup.RETAIN_ON_CANCELLATION) + //设置状态数据存储的位置 + env.setStateBackend(new RocksDBStateBackend("hdfs://bigdata01:9000/flink/checkpoints",true)) + + + //指定FlinkKafkaConsumer相关配置 + val topic = "t1" + val prop = new Properties() + prop.setProperty("bootstrap.servers","bigdata01:9092,bigdata02:9092,bigdata03:9092") + prop.setProperty("group.id","con1") + val kafkaConsumer = new FlinkKafkaConsumer[String](topic, new SimpleStringSchema(), prop) + + //kafka consumer的消费策略设置 + //默认策略,读取group.id对应保存的offset开始消费数据,读取不到则根据kafka中auto.offset.reset参数的值开始消费数据 + kafkaConsumer.setStartFromGroupOffsets() + //从最早的记录开始消费数据,忽略已提交的offset信息 + //kafkaConsumer.setStartFromEarliest() + //从最新的记录开始消费数据,忽略已提交的offset信息 + //kafkaConsumer.setStartFromLatest() + //从指定的时间戳开始消费数据,对于每个分区,其时间戳大于或等于指定时间戳的记录将被作为起始位置 + //kafkaConsumer.setStartFromTimestamp(176288819) + + + //指定kafka作为source + import org.apache.flink.api.scala._ + val text = env.addSource(kafkaConsumer) + + //将读取到的数据打印到控制台上 + text.print() + + env.execute("StreamKafkaSourceScala") + } + +} diff --git a/bigdata/flink/src/main/scala/com/imooc/scala/stream/SocketWindowWordCountScala.scala b/bigdata/flink/src/main/scala/com/imooc/scala/stream/SocketWindowWordCountScala.scala new file mode 100644 index 00000000..05bb74bc --- /dev/null +++ b/bigdata/flink/src/main/scala/com/imooc/scala/stream/SocketWindowWordCountScala.scala @@ -0,0 +1,40 @@ +package com.imooc.scala.stream + +import org.apache.flink.streaming.api.scala.StreamExecutionEnvironment +import org.apache.flink.streaming.api.windowing.time.Time + +/** + * 需求:通过socket实时产生一些单词 + * 使用Flink实时接收数据 + * 对指定时间窗口内(例如:2秒)的数据进行聚合统计 + * 并且把时间窗口内计算的结果打印出来 + * Created by xuwei + */ +object SocketWindowWordCountScala { + def main(args: Array[String]): Unit = { + //获取运行环境 + val env = StreamExecutionEnvironment.getExecutionEnvironment + + //连接socket获取输入数据 + val text = env.socketTextStream("bigdata04", 9001) + + //处理数据 + //注意:必须要添加这一行隐式转换的代码,否则下面的flatMap方法会报错 + import org.apache.flink.api.scala._ + val wordCount = text.flatMap(_.split(" "))//将每一行数据根据空格切分单词 + .map((_,1))//每一个单词转换为tuple2的形式(单词,1) + //.keyBy(0)//根据tuple2中的第一列进行分组 + .keyBy(tup=>tup._1)//官方推荐使用keySelector选择器选择数据 + .timeWindow(Time.seconds(2))//时间窗口为2秒,表示每隔2秒钟计算一次接收到的数据 + .sum(1)//使用sum或者reduce都可以 + //.reduce((t1,t2)=>(t1._1,t1._2+t2._2)) + + //使用一个线程执行打印操作 + wordCount.print().setParallelism(1) + + //执行程序 + env.execute("SocketWindowWordCountScala") + + } + +} diff --git a/bigdata/flink/src/main/scala/com/imooc/scala/stream/sink/StreamRedisSinkScala.scala b/bigdata/flink/src/main/scala/com/imooc/scala/stream/sink/StreamRedisSinkScala.scala new file mode 100644 index 00000000..6a697503 --- /dev/null +++ b/bigdata/flink/src/main/scala/com/imooc/scala/stream/sink/StreamRedisSinkScala.scala @@ -0,0 +1,49 @@ +package com.imooc.scala.stream.sink + +import org.apache.flink.streaming.api.scala.StreamExecutionEnvironment +import org.apache.flink.streaming.connectors.redis.RedisSink +import org.apache.flink.streaming.connectors.redis.common.config.FlinkJedisPoolConfig +import org.apache.flink.streaming.connectors.redis.common.mapper.{RedisCommand, RedisCommandDescription, RedisMapper} + +/** + * 需求:接收socket传输过来的数据,把数据保存到redis的list队列中 + * Created by xuwei + */ +object StreamRedisSinkScala { + def main(args: Array[String]): Unit = { + val env = StreamExecutionEnvironment.getExecutionEnvironment + + //连接socket获取输入数据 + val text = env.socketTextStream("bigdata04", 9001) + + import org.apache.flink.api.scala._ + //组装数据,这里组装的是tuple2类型 + //第一个元素是指list队列的key名称 + //第二个元素是指需要向list队列中添加的元素 + val listData = text.map(word => ("l_words_scala", word)) + + //指定redissink + val conf = new FlinkJedisPoolConfig.Builder().setHost("bigdata04").setPort(6379).build() + val redisSink = new RedisSink[Tuple2[String, String]](conf, new MyRedisMapper) + listData.addSink(redisSink) + + env.execute("StreamRedisSinkScala") + } + + class MyRedisMapper extends RedisMapper[Tuple2[String,String]]{ + //指定具体的操作命令 + override def getCommandDescription: RedisCommandDescription = { + new RedisCommandDescription(RedisCommand.LPUSH) + } + + //获取key + override def getKeyFromData(data: (String, String)): String = { + data._1 + } + //获取value + override def getValueFromData(data: (String, String)): String = { + data._2 + } + } + +} diff --git a/bigdata/flink/src/main/scala/com/imooc/scala/stream/source/StreamCollectionSourceScala.scala b/bigdata/flink/src/main/scala/com/imooc/scala/stream/source/StreamCollectionSourceScala.scala new file mode 100644 index 00000000..40424017 --- /dev/null +++ b/bigdata/flink/src/main/scala/com/imooc/scala/stream/source/StreamCollectionSourceScala.scala @@ -0,0 +1,22 @@ +package com.imooc.scala.stream.source + +import org.apache.flink.streaming.api.scala.StreamExecutionEnvironment + +/** + * 基于collection的source的应用 + * 注意:这个source的主要应用场景是模拟测试代码流程的时候使用 + * Created by xuwei + */ +object StreamCollectionSourceScala { + def main(args: Array[String]): Unit = { + val env = StreamExecutionEnvironment.getExecutionEnvironment + + //使用collection集合生成DataStream + import org.apache.flink.api.scala._ + val text = env.fromCollection(Array(1, 2, 3, 4, 5)) + + text.print().setParallelism(1) + + env.execute("StreamCollectionSourceScala") + } +} diff --git a/bigdata/flink/src/main/scala/com/imooc/scala/stream/transformation/MyPartitionerScala.scala b/bigdata/flink/src/main/scala/com/imooc/scala/stream/transformation/MyPartitionerScala.scala new file mode 100644 index 00000000..c0a61dcf --- /dev/null +++ b/bigdata/flink/src/main/scala/com/imooc/scala/stream/transformation/MyPartitionerScala.scala @@ -0,0 +1,18 @@ +package com.imooc.scala.stream.transformation + +import org.apache.flink.api.common.functions.Partitioner + +/** + * 自定义分区规则:按照数字的奇偶性进行分区 + * Created by xuwei + */ +class MyPartitionerScala extends Partitioner[Int]{ + override def partition(key: Int, numPartitions: Int): Int = { + println("分区总数:"+numPartitions) + if(key % 2 == 0){//偶数分到0号分区 + 0 + }else{//奇数分到1号分区 + 1 + } + } +} diff --git a/bigdata/flink/src/main/scala/com/imooc/scala/stream/transformation/StreamConnectScala.scala b/bigdata/flink/src/main/scala/com/imooc/scala/stream/transformation/StreamConnectScala.scala new file mode 100644 index 00000000..3f49c263 --- /dev/null +++ b/bigdata/flink/src/main/scala/com/imooc/scala/stream/transformation/StreamConnectScala.scala @@ -0,0 +1,37 @@ +package com.imooc.scala.stream.transformation + +import org.apache.flink.streaming.api.functions.co.CoMapFunction +import org.apache.flink.streaming.api.scala.StreamExecutionEnvironment + +/** + * 只能连接两个流,两个流的数据类型可以不同 + * 应用:可以将两种不同格式的数据统一成一种格式 + * Created by xuwei + */ +object StreamConnectScala { + def main(args: Array[String]): Unit = { + val env = StreamExecutionEnvironment.getExecutionEnvironment + + import org.apache.flink.api.scala._ + //第1份数据流 + val text1 = env.fromElements("user:tom,age:18") + //第2份数据流 + val text2 = env.fromElements("user:jack_age:20") + + //连接两个流 + val connectStream = text1.connect(text2) + + connectStream.map(new CoMapFunction[String,String,String] { + //处理第1份数据流中的数据 + override def map1(value: String): String = { + value.replace(",","-") + } + //处理第2份数据流中的数据 + override def map2(value: String): String = { + value.replace("_","-") + } + }).print().setParallelism(1) + + env.execute("StreamConnectScala") + } +} diff --git a/bigdata/flink/src/main/scala/com/imooc/scala/stream/transformation/StreamPartitionOpScala.scala b/bigdata/flink/src/main/scala/com/imooc/scala/stream/transformation/StreamPartitionOpScala.scala new file mode 100644 index 00000000..84920ca4 --- /dev/null +++ b/bigdata/flink/src/main/scala/com/imooc/scala/stream/transformation/StreamPartitionOpScala.scala @@ -0,0 +1,82 @@ +package com.imooc.scala.stream.transformation + +import org.apache.flink.streaming.api.scala.{DataStream, StreamExecutionEnvironment} +import org.apache.flink.api.scala._ +/** + * 分区规则的使用 + * Created by xuwei + */ +object StreamPartitionOpScala { + def main(args: Array[String]): Unit = { + val env = StreamExecutionEnvironment.getExecutionEnvironment + + //注意:在这里将这个隐式转换代码放到类上面 + //因为默认它只在main函数生效,针对下面提取的shuffleOp是无效,否则也需要在shuffleOp添加这行代码 + //import org.apache.flink.api.scala._ + + //注意:默认情况下Flink任务中算子的并行度会读取当前机器的CPU个数 + //fromCollection的并行度为1, + val text = env.fromCollection(Array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)) + + //使用shuffle分区规则 + //shuffleOp(text) + + //使用rebalance分区规则 + //rebalanceOp(text) + + //使用rescale分区规则 + //rescaleOp(text) + + //使用broadcast分区规则 + //broadcastOp(text) + + //自定义分区规则:根据数据的奇偶性进行分区 + //注意:此时虽然print算子的并行度为4,但是自定义的分区规则只会把数据分发给2个并行度,所以有2个是不干活 + //custormPartitionOp(text) + + env.execute("StreamPartitionOpScala") + + } + + private def custormPartitionOp(text: DataStream[Int]) = { + text.map(num => num) + .setParallelism(2) //设置map算子的并行度为2 + //.partitionCustom(new MyPartitionerScala,0)//这种写法已经过期 + .partitionCustom(new MyPartitionerScala, num => num) //官方建议使用keySelector + .print() + .setParallelism(4) //设置print算子的并行度为4 + } + + private def broadcastOp(text: DataStream[Int]) = { + text.map(num => num) + .setParallelism(2) //设置map算子的并行度为2 + .broadcast + .print() + .setParallelism(4) //设置print算子的并行度为4 + } + + private def rescaleOp(text: DataStream[Int]) = { + text.map(num => num) + .setParallelism(2) //设置map算子的并行度为2 + .rescale + .print() + .setParallelism(4) //设置print算子的并行度为4 + } + + private def rebalanceOp(text: DataStream[Int]) = { + text.map(num => num) + .setParallelism(2) //设置map算子的并行度为2 + .rebalance + .print() + .setParallelism(4) //设置print算子的并行度为4 + } + + private def shuffleOp(text: DataStream[Int]) = { + //由于fromCollection已经设置了并行度为1,所以需要再接一个算子才能修改并行度,在这使用map算子 + text.map(num => num) + .setParallelism(2) //设置map算子的并行度为2 + .shuffle + .print() + .setParallelism(4) //设置print算子的并行度为4 + } +} diff --git a/bigdata/flink/src/main/scala/com/imooc/scala/stream/transformation/StreamSideOutputScala.scala b/bigdata/flink/src/main/scala/com/imooc/scala/stream/transformation/StreamSideOutputScala.scala new file mode 100644 index 00000000..a1e036e0 --- /dev/null +++ b/bigdata/flink/src/main/scala/com/imooc/scala/stream/transformation/StreamSideOutputScala.scala @@ -0,0 +1,65 @@ +package com.imooc.scala.stream.transformation + +import org.apache.flink.streaming.api.functions.ProcessFunction +import org.apache.flink.streaming.api.scala.{OutputTag, StreamExecutionEnvironment} +import org.apache.flink.util.Collector + +/** + * 使用sideoutput切分流 + * Created by xuwei + */ +object StreamSideOutputScala { + def main(args: Array[String]): Unit = { + val env = StreamExecutionEnvironment.getExecutionEnvironment + + import org.apache.flink.api.scala._ + val text = env.fromCollection(Array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)) + + //按照数据的奇偶性对数据进行分流 + //首先定义两个sideoutput来准备保存切分出来的数据 + val outputTag1 = new OutputTag[Int]("even")//保存偶数 + val outputTag2 = new OutputTag[Int]("odd")//保存奇数 + + //注意:process属于Flink中的低级api + val outputStream = text.process(new ProcessFunction[Int, Int] { + override def processElement(value: Int, ctx: ProcessFunction[Int, Int]#Context, out: Collector[Int]): Unit = { + if (value % 2 == 0) { + ctx.output(outputTag1, value) + } else { + ctx.output(outputTag2, value) + } + } + }) + + //获取偶数数据流 + val evenStream = outputStream.getSideOutput(outputTag1) + //获取奇数数据流 + val oddStream = outputStream.getSideOutput(outputTag2) + //evenStream.print().setParallelism(1) + + //对evenStream流进行二次切分 + val outputTag11 = new OutputTag[Int]("low")//保存小于等于5的数字 + val outputTag12 = new OutputTag[Int]("high")//保存大于5的数字 + + val subOutputStream = evenStream.process(new ProcessFunction[Int, Int] { + override def processElement(value: Int, ctx: ProcessFunction[Int, Int]#Context, out: Collector[Int]): Unit = { + if (value <= 5) { + ctx.output(outputTag11, value) + } else { + ctx.output(outputTag12, value) + } + } + }) + + //获取小于等于5的数据流 + val lowStream = subOutputStream.getSideOutput(outputTag11) + //获取大于5的数据流 + val highStream = subOutputStream.getSideOutput(outputTag12) + + lowStream.print().setParallelism(1) + + env.execute("StreamSideOutputScala") + + } + +} diff --git a/bigdata/flink/src/main/scala/com/imooc/scala/stream/transformation/StreamSplitScala.scala b/bigdata/flink/src/main/scala/com/imooc/scala/stream/transformation/StreamSplitScala.scala new file mode 100644 index 00000000..8f4870e8 --- /dev/null +++ b/bigdata/flink/src/main/scala/com/imooc/scala/stream/transformation/StreamSplitScala.scala @@ -0,0 +1,59 @@ +package com.imooc.scala.stream.transformation + +import java.{lang, util} + +import org.apache.flink.streaming.api.collector.selector.OutputSelector +import org.apache.flink.streaming.api.scala.StreamExecutionEnvironment + +/** + * 根据规则把一个数据流切分为多个数据流 + * 注意:split只能分一次流,切分出来的流不能继续切分 + * split需要和select配合使用,选择切分后的流 + * 应用场景:将一份数据流切分为多份,便于针对每一份数据使用不同的处理逻辑 + * Created by xuwei + */ +object StreamSplitScala { + def main(args: Array[String]): Unit = { + val env = StreamExecutionEnvironment.getExecutionEnvironment + + import org.apache.flink.api.scala._ + //初始化数据 + val text = env.fromCollection(Array(1, 2, 4, 5, 6, 7, 8, 9, 10)) + + //按照数据的奇偶性对数据进行分流 + val splitStream = text.split(new OutputSelector[Int] { + override def select(value: Int): lang.Iterable[String] = { + val list = new util.ArrayList[String]() + if(value % 2 == 0){ + list.add("even")//偶数 + }else{ + list.add("odd")//奇数 + } + list + } + }) + + //选择流 + val evenStream = splitStream.select("even") + evenStream.print().setParallelism(1) + + //二次切流会报错 + //Consecutive multiple splits are not supported. Splits are deprecated. Please use side-outputs. + /*val lowHighStream = evenStream.split(new OutputSelector[Int] { + override def select(value: Int): lang.Iterable[String] = { + val list = new util.ArrayList[String]() + if(value <= 5){ + list.add("low") + }else{ + list.add("high") + } + list + } + }) + val lowStream = lowHighStream.select("low") + lowStream.print().setParallelism(1)*/ + + + env.execute("StreamSplitScala") + } +} diff --git a/bigdata/flink/src/main/scala/com/imooc/scala/stream/transformation/StreamUnionScala.scala b/bigdata/flink/src/main/scala/com/imooc/scala/stream/transformation/StreamUnionScala.scala new file mode 100644 index 00000000..867e80ae --- /dev/null +++ b/bigdata/flink/src/main/scala/com/imooc/scala/stream/transformation/StreamUnionScala.scala @@ -0,0 +1,29 @@ +package com.imooc.scala.stream.transformation + +import org.apache.flink.streaming.api.scala.StreamExecutionEnvironment + +/** + * 合并多个流,多个流的数据类型必须一致 + * 应用场景:多种数据源的数据类型一致,数据处理规则也一致 + * Created by xuwei + */ +object StreamUnionScala { + def main(args: Array[String]): Unit = { + val env = StreamExecutionEnvironment.getExecutionEnvironment + + import org.apache.flink.api.scala._ + //第1份数据流 + val text1 = env.fromCollection(Array(1, 2, 3, 4, 5)) + //第2份数据流 + val text2 = env.fromCollection(Array(6, 7, 8, 9, 10)) + + //合并流 + val unionStream = text1.union(text2) + + //打印流中的数据 + unionStream.print().setParallelism(1) + + env.execute("StreamUnionScala") + + } +} diff --git a/bigdata/flink/src/main/scala/com/imooc/scala/tablesql/CreateTableEnvironmentScala.scala b/bigdata/flink/src/main/scala/com/imooc/scala/tablesql/CreateTableEnvironmentScala.scala new file mode 100644 index 00000000..c5294be3 --- /dev/null +++ b/bigdata/flink/src/main/scala/com/imooc/scala/tablesql/CreateTableEnvironmentScala.scala @@ -0,0 +1,46 @@ +package com.imooc.scala.tablesql + +import org.apache.flink.api.scala.ExecutionEnvironment +import org.apache.flink.streaming.api.scala.StreamExecutionEnvironment +import org.apache.flink.table.api.bridge.scala.{BatchTableEnvironment, StreamTableEnvironment} +import org.apache.flink.table.api.{EnvironmentSettings, TableEnvironment} + +/** + * 创建TableEnvironment对象 + * Created by xuwei + */ +object CreateTableEnvironmentScala { + def main(args: Array[String]): Unit = { + + /** + * 注意:如果Table API 和 SQL不需要和DataStream或者DataSet互相转换 + * 则针对stream和batch都可以使用TableEnvironment + */ + //指定底层引擎为Blink,以及数据处理模式-stream + val sSettings = EnvironmentSettings.newInstance().useBlinkPlanner().inStreamingMode().build() + //创建TableEnvironment对象 + val sTableEnv = TableEnvironment.create(sSettings) + + + //指定底层引擎为Blink,以及数据处理模式-batch + val bSettings = EnvironmentSettings.newInstance().useBlinkPlanner().inBatchMode().build() + //创建TableEnvironment对象 + val bTableEnv = TableEnvironment.create(bSettings) + + /** + * 注意:如果Table API和SQL需要和DataStream或者DataSet互相转换 + * 针对stream需要使用StreamTableEnvironment + * 针对batch需要使用BatchTableEnvironment + */ + //创建StreamTableEnvironment + val ssEnv = StreamExecutionEnvironment.getExecutionEnvironment + val ssSettings = EnvironmentSettings.newInstance().useBlinkPlanner().inStreamingMode().build() + val ssTableEnv = StreamTableEnvironment.create(ssEnv, ssSettings) + + //创建BatchTableEnvironment + //注意:此时只能使用旧的执行引擎,新的Blink执行引擎不支持和DataSet转换 + val bbEnv = ExecutionEnvironment.getExecutionEnvironment + val bbTableEnv = BatchTableEnvironment.create(bbEnv) + + } +} diff --git a/bigdata/flink/src/main/scala/com/imooc/scala/tablesql/DataSetToTableScala.scala b/bigdata/flink/src/main/scala/com/imooc/scala/tablesql/DataSetToTableScala.scala new file mode 100644 index 00000000..a8908acc --- /dev/null +++ b/bigdata/flink/src/main/scala/com/imooc/scala/tablesql/DataSetToTableScala.scala @@ -0,0 +1,33 @@ +package com.imooc.scala.tablesql + +import org.apache.flink.api.scala.ExecutionEnvironment +import org.apache.flink.table.api.bridge.scala.BatchTableEnvironment + +/** + * 将DataSet转换为表 + * Created by xuwei + */ +object DataSetToTableScala { + def main(args: Array[String]): Unit = { + //获取BatchTableEnvironment + val bbEnv = ExecutionEnvironment.getExecutionEnvironment + val bbTableEnv = BatchTableEnvironment.create(bbEnv) + + //获取DataSet + import org.apache.flink.api.scala._ + val set = bbEnv.fromCollection(Array((1, "jack"), (2, "tom"), (3, "mack"))) + + //第一种:将DataSet转换为view视图 + import org.apache.flink.table.api._ + bbTableEnv.createTemporaryView("myTable",set,'id,'name) + bbTableEnv.sqlQuery("select * from myTable where id > 1").execute().print() + + //第二种:将DataSet转换为table对象 + val table = bbTableEnv.fromDataSet(set, 'id, 'name) + table.select($"id",$"name") + .filter($"id" > 1 ) + .execute() + .print() + } + +} diff --git a/bigdata/flink/src/main/scala/com/imooc/scala/tablesql/DataStreamToTableScala.scala b/bigdata/flink/src/main/scala/com/imooc/scala/tablesql/DataStreamToTableScala.scala new file mode 100644 index 00000000..a7935ef7 --- /dev/null +++ b/bigdata/flink/src/main/scala/com/imooc/scala/tablesql/DataStreamToTableScala.scala @@ -0,0 +1,37 @@ +package com.imooc.scala.tablesql + +import org.apache.flink.streaming.api.scala.StreamExecutionEnvironment +import org.apache.flink.table.api.EnvironmentSettings +import org.apache.flink.table.api.bridge.scala.StreamTableEnvironment + +/** + * 将DataStream转换为表 + * Created by xuwei + */ +object DataStreamToTableScala { + def main(args: Array[String]): Unit = { + //获取StreamTableEnvironment + val ssEnv = StreamExecutionEnvironment.getExecutionEnvironment + val ssSettings = EnvironmentSettings.newInstance().useBlinkPlanner().inStreamingMode().build() + val ssTableEnv = StreamTableEnvironment.create(ssEnv, ssSettings) + + //获取DataStream + import org.apache.flink.api.scala._ + val stream = ssEnv.fromCollection(Array((1, "jack"), (2, "tom"), (3, "mack"))) + + //第一种:将DataStream转换为view视图 + import org.apache.flink.table.api._ + ssTableEnv.createTemporaryView("myTable",stream,'id,'name) + ssTableEnv.sqlQuery("select * from myTable where id > 1").execute().print() + + + //第二种:将DataStream转换为Table对象 + val table = ssTableEnv.fromDataStream(stream, $"id", $"name") + table.select($"id",$"name") + .filter($"id" > 1) + .execute() + .print() + + //注意:'id,'name 和 $"id", $"name" 这两种写法是一样的效果 + } +} diff --git a/bigdata/flink/src/main/scala/com/imooc/scala/tablesql/TableAPIAndSQLOpScala.scala b/bigdata/flink/src/main/scala/com/imooc/scala/tablesql/TableAPIAndSQLOpScala.scala new file mode 100644 index 00000000..5e4086ab --- /dev/null +++ b/bigdata/flink/src/main/scala/com/imooc/scala/tablesql/TableAPIAndSQLOpScala.scala @@ -0,0 +1,58 @@ +package com.imooc.scala.tablesql + +import org.apache.flink.table.api.{EnvironmentSettings, TableEnvironment} + +/** + * TableAPI 和 SQL的使用 + * Created by xuwei + */ +object TableAPIAndSQLOpScala { + def main(args: Array[String]): Unit = { + //获取TableEnvironment + val sSettings = EnvironmentSettings.newInstance().useBlinkPlanner().inStreamingMode().build() + val sTableEnv = TableEnvironment.create(sSettings) + + //创建输入表 + /** + * connector.type:指定connector的类型 + * connector.path:指定文件或者目录地址 + * format.type:文件数据格式化类型,现在只支持csv格式 + * 注意:SQL语句中如果出现了换行,行尾末尾可以添加空格或者\n都可以,最后一行不用添加 + */ + sTableEnv.executeSql("" + + "create table myTable(\n" + + "id int,\n" + + "name string\n" + + ") with (\n" + + "'connector.type' = 'filesystem',\n" + + "'connector.path' = 'D:\\data\\source',\n" + + "'format.type' = 'csv'\n" + + ")") + + //使用TableAPI实现数据查询和过滤等操作 + import org.apache.flink.table.api._ + /*val result = sTableEnv.from("myTable") + .select($"id", $"name") + .filter($"id" > 1)*/ + + //使用SQL实现数据查询和过滤等操作 + val result = sTableEnv.sqlQuery("select id,name from myTable where id > 1") + + //输出结果到控制台 + result.execute().print() + + //创建输出表 + sTableEnv.executeSql("" + + "create table newTable(\n" + + "id int,\n" + + "name string\n" + + ") with (\n" + + "'connector.type' = 'filesystem',\n" + + "'connector.path' = 'D:\\data\\res',\n" + + "'format.type' = 'csv'\n" + + ")") + + //输出结果到表newTable中 + result.executeInsert("newTable") + } +} diff --git a/bigdata/flink/src/main/scala/com/imooc/scala/tablesql/TableToDataSetScala.scala b/bigdata/flink/src/main/scala/com/imooc/scala/tablesql/TableToDataSetScala.scala new file mode 100644 index 00000000..58bf9c60 --- /dev/null +++ b/bigdata/flink/src/main/scala/com/imooc/scala/tablesql/TableToDataSetScala.scala @@ -0,0 +1,38 @@ +package com.imooc.scala.tablesql + +import org.apache.flink.api.scala.ExecutionEnvironment +import org.apache.flink.table.api.bridge.scala.BatchTableEnvironment +import org.apache.flink.types.Row + +/** + * 将table转换成DataSet + * Created by xuwei + */ +object TableToDataSetScala { + def main(args: Array[String]): Unit = { + //获取BatchTableEnvironment + val bbEnv = ExecutionEnvironment.getExecutionEnvironment + val bbTableEnv = BatchTableEnvironment.create(bbEnv) + + //创建输入表 + bbTableEnv.executeSql("" + + "create table myTable(\n" + + "id int,\n" + + "name string\n" + + ") with (\n" + + "'connector.type' = 'filesystem',\n" + + "'connector.path' = 'D:\\data\\source',\n" + + "'format.type' = 'csv'\n" + + ")") + + //获取table + val table = bbTableEnv.from("myTable") + + //将table转换成DataSet + import org.apache.flink.api.scala._ + val set = bbTableEnv.toDataSet[Row](table) + set.map(row=>(row.getField(0).toString.toInt,row.getField(1).toString)) + .print() + + } +} diff --git a/bigdata/flink/src/main/scala/com/imooc/scala/tablesql/TableToDataStreamScala.scala b/bigdata/flink/src/main/scala/com/imooc/scala/tablesql/TableToDataStreamScala.scala new file mode 100644 index 00000000..9fb90b16 --- /dev/null +++ b/bigdata/flink/src/main/scala/com/imooc/scala/tablesql/TableToDataStreamScala.scala @@ -0,0 +1,54 @@ +package com.imooc.scala.tablesql + +import org.apache.flink.streaming.api.scala.StreamExecutionEnvironment +import org.apache.flink.table.api.EnvironmentSettings +import org.apache.flink.table.api.bridge.scala.StreamTableEnvironment +import org.apache.flink.types.Row + +/** + * 将table转换成DataStream + * Created by xuwei + */ +object TableToDataStreamScala { + def main(args: Array[String]): Unit = { + //获取StreamTableEnvironment + val ssEnv = StreamExecutionEnvironment.getExecutionEnvironment + val ssSettings = EnvironmentSettings.newInstance().useBlinkPlanner().inStreamingMode().build() + val ssTableEnv = StreamTableEnvironment.create(ssEnv, ssSettings) + + //创建输入表 + ssTableEnv.executeSql("" + + "create table myTable(\n" + + "id int,\n" + + "name string\n" + + ") with (\n" + + "'connector.type' = 'filesystem',\n" + + "'connector.path' = 'D:\\data\\source',\n" + + "'format.type' = 'csv'\n" + + ")") + + //获取table + val table = ssTableEnv.from("myTable") + + //将table转换为DataStream + //如果只有新增(追加)操作,可以使用toAppendStream + import org.apache.flink.api.scala._ + val appStream = ssTableEnv.toAppendStream[Row](table) + appStream.map(row=>(row.getField(0).toString.toInt,row.getField(1).toString)) + .print() + + + //如果有增加操作,还有删除操作,则使用toRetractStream + val retStream = ssTableEnv.toRetractStream[Row](table) + retStream.map(tup=>{ + val flag = tup._1 + val row = tup._2 + val id = row.getField(0).toString.toInt + val name = row.getField(1).toString + (flag,id,name) + }).print() + + //注意:将table转换为DataStream之后,就需要调用StreamExecutionEnvironment中的execute方法了 + ssEnv.execute("TableToDataStreamScala") + } +} diff --git a/bigdata/flink/src/main/scala/com/imooc/scala/window/CountWindowOpScala.scala b/bigdata/flink/src/main/scala/com/imooc/scala/window/CountWindowOpScala.scala new file mode 100644 index 00000000..47d463ab --- /dev/null +++ b/bigdata/flink/src/main/scala/com/imooc/scala/window/CountWindowOpScala.scala @@ -0,0 +1,43 @@ +package com.imooc.scala.window + +import org.apache.flink.streaming.api.scala.StreamExecutionEnvironment + +/** + * CountWindow的使用 + * 1:滚动窗口 + * 2:滑动窗口 + * Created by xuwei + */ +object CountWindowOpScala { + def main(args: Array[String]): Unit = { + val env = StreamExecutionEnvironment.getExecutionEnvironment + val text = env.socketTextStream("bigdata04", 9001) + + import org.apache.flink.api.scala._ + /** + * 注意:由于我们在这里使用keyBy,会先对数据分组 + * 如果某个分组对应的数据窗口内达到了5个元素,这个窗口才会被触发执行 + */ + //CountWindow之滚动窗口:每隔5个元素计算一次前5个元素 + /*text.flatMap(_.split(" ")) + .map((_,1)) + .keyBy(0) + //指定窗口大小 + .countWindow(5) + .sum(1) + .print()*/ + + + //CountWindow之滑动窗口:每隔1个元素计算一次前5个元素 + text.flatMap(_.split(" ")) + .map((_,1)) + .keyBy(0) + //第一个参数:窗口大小,第二个参数:滑动间隔 + .countWindow(5,1) + .sum(1) + .print() + + env.execute("CountWindowOpScala") + + } +} diff --git a/bigdata/flink/src/main/scala/com/imooc/scala/window/MyTimeWindowScala.scala b/bigdata/flink/src/main/scala/com/imooc/scala/window/MyTimeWindowScala.scala new file mode 100644 index 00000000..845bceeb --- /dev/null +++ b/bigdata/flink/src/main/scala/com/imooc/scala/window/MyTimeWindowScala.scala @@ -0,0 +1,29 @@ +package com.imooc.scala.window + +import org.apache.flink.streaming.api.scala.StreamExecutionEnvironment +import org.apache.flink.streaming.api.windowing.assigners.TumblingProcessingTimeWindows +import org.apache.flink.streaming.api.windowing.time.Time + +/** + * 需求:自定义MyTimeWindow + * Created by xuwei + */ +object MyTimeWindowScala { + def main(args: Array[String]): Unit = { + val env = StreamExecutionEnvironment.getExecutionEnvironment + val text = env.socketTextStream("bigdata04", 9001) + + import org.apache.flink.api.scala._ + + //自定义MyTimeWindow滚动窗口:每隔10秒计算一次前10秒时间窗口内的数据 + text.flatMap(_.split(" ")) + .map((_,1)) + .keyBy(0) + //窗口大小 + .window(TumblingProcessingTimeWindows.of(Time.seconds(10))) + .sum(1) + .print() + + env.execute("MyTimeWindowScala") + } +} diff --git a/bigdata/flink/src/main/scala/com/imooc/scala/window/TimeWindowOpScala.scala b/bigdata/flink/src/main/scala/com/imooc/scala/window/TimeWindowOpScala.scala new file mode 100644 index 00000000..23b1a71e --- /dev/null +++ b/bigdata/flink/src/main/scala/com/imooc/scala/window/TimeWindowOpScala.scala @@ -0,0 +1,41 @@ +package com.imooc.scala.window + +import org.apache.flink.streaming.api.scala.StreamExecutionEnvironment +import org.apache.flink.streaming.api.windowing.time.Time + +/** + * TimeWindow的使用 + * 1:滚动窗口 + * 2:滑动窗口 + * Created by xuwei + */ +object TimeWindowOpScala { + def main(args: Array[String]): Unit = { + val env = StreamExecutionEnvironment.getExecutionEnvironment + val text = env.socketTextStream("bigdata04", 9001) + + import org.apache.flink.api.scala._ + + //TimeWindow之滚动窗口:每隔10秒计算一次前10秒时间窗口内的数据 + /*text.flatMap(_.split(" ")) + .map((_,1)) + .keyBy(0) + //窗口大小 + .timeWindow(Time.seconds(10)) + .sum(1) + .print()*/ + + //TimeWindow之滑动窗口:每隔5秒计算一次前10秒时间窗口内的数据 + text.flatMap(_.split(" ")) + .map((_,1)) + .keyBy(0) + //第一个参数:窗口大小,第二个参数:滑动间隔 + .timeWindow(Time.seconds(10),Time.seconds(5)) + .sum(1) + .print() + + env.execute("TimeWindowOpScala") + + } + +} diff --git a/bigdata/flink/src/main/scala/com/imooc/scala/window/WatermarkOpForAllowedLatenessScala.scala b/bigdata/flink/src/main/scala/com/imooc/scala/window/WatermarkOpForAllowedLatenessScala.scala new file mode 100644 index 00000000..48fcc062 --- /dev/null +++ b/bigdata/flink/src/main/scala/com/imooc/scala/window/WatermarkOpForAllowedLatenessScala.scala @@ -0,0 +1,91 @@ +package com.imooc.scala.window + +import java.text.SimpleDateFormat +import java.time.Duration + +import org.apache.flink.api.common.eventtime.{SerializableTimestampAssigner, WatermarkStrategy} +import org.apache.flink.api.java.tuple.Tuple +import org.apache.flink.streaming.api.TimeCharacteristic +import org.apache.flink.streaming.api.scala.StreamExecutionEnvironment +import org.apache.flink.streaming.api.scala.function.WindowFunction +import org.apache.flink.streaming.api.windowing.assigners.TumblingEventTimeWindows +import org.apache.flink.streaming.api.windowing.time.Time +import org.apache.flink.streaming.api.windowing.windows.TimeWindow +import org.apache.flink.util.Collector + +import scala.collection.mutable.ArrayBuffer +import scala.util.Sorting + +/** + * Watermark+EventTime解决数据乱序问题 + * Created by xuwei + */ +object WatermarkOpForAllowedLatenessScala { + def main(args: Array[String]): Unit = { + val env = StreamExecutionEnvironment.getExecutionEnvironment + //设置使用数据产生的时间:EventTime + env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime) + //设置全局并行度为1 + env.setParallelism(1) + + //设置自动周期性的产生watermark,默认值为200毫秒 + env.getConfig.setAutoWatermarkInterval(200) + + + val text = env.socketTextStream("bigdata04", 9001) + import org.apache.flink.api.scala._ + //将数据转换为tuple2的形式 + //第一列表示具体的数据,第二列表示是数据产生的时间戳 + val tupStream = text.map(line => { + val arr = line.split(",") + (arr(0), arr(1).toLong) + }) + + //分配(提取)时间戳和watermark + val waterMarkStream = tupStream.assignTimestampsAndWatermarks(WatermarkStrategy.forBoundedOutOfOrderness(Duration.ofSeconds(10)) //最大允许的数据乱序时间 10s + .withTimestampAssigner(new SerializableTimestampAssigner[Tuple2[String, Long]] { + val sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss") + var currentMaxTimstamp = 0L + + //从数据流中抽取时间戳作为EventTime + override def extractTimestamp(element: (String, Long), recordTimestamp: Long): Long = { + val timestamp = element._2 + currentMaxTimstamp = Math.max(timestamp, currentMaxTimstamp) + //计算当前watermark,为了打印出来方便观察数据,没有别的作用,watermark=currentMaxTimstamp-OutOfOrderness + val currentWatermark = currentMaxTimstamp - 10000L + //此print语句仅仅是为了在学习阶段观察数据的变化 + println("key:" + element._1 + "," + "eventtime:[" + element._2 + "|" + sdf.format(element._2) + "],currentMaxTimstamp:[" + currentWatermark + "|" + sdf.format(currentMaxTimstamp) + "],watermark:[" + currentWatermark + "|" + sdf.format(currentWatermark) + "]") + element._2 + } + }) + ) + + waterMarkStream.keyBy(0) + //按照消息的EventTime分配窗口,和调用TimeWindow效果一样 + .window(TumblingEventTimeWindows.of(Time.seconds(3))) + //允许数据迟到2秒 + .allowedLateness(Time.seconds(2)) + //使用全量聚合的方式处理window中的数据 + .apply(new WindowFunction[Tuple2[String,Long],String,Tuple,TimeWindow] { + override def apply(key: Tuple, window: TimeWindow, input: Iterable[(String, Long)], out: Collector[String]): Unit = { + val keyStr = key.toString + //将window中的数据保存到arrBuff中 + val arrBuff = ArrayBuffer[Long]() + input.foreach(tup=>{ + arrBuff.append(tup._2) + }) + //将arrBuff转换为arr + val arr = arrBuff.toArray + //对arr中的数据进行排序 + Sorting.quickSort(arr) + + val sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss") + //将目前window内排序后的数据,以及window的开始时间和window的结束时间打印出来,便于观察 + val result = keyStr+","+arr.length+","+sdf.format(arr.head)+","+sdf.format(arr.last)+","+sdf.format(window.getStart)+","+sdf.format(window.getEnd) + out.collect(result) + } + }).print() + + env.execute("WatermarkOpScala") + } +} diff --git a/bigdata/flink/src/main/scala/com/imooc/scala/window/WatermarkOpForSideOutputLateDataScala.scala b/bigdata/flink/src/main/scala/com/imooc/scala/window/WatermarkOpForSideOutputLateDataScala.scala new file mode 100644 index 00000000..d6636cb3 --- /dev/null +++ b/bigdata/flink/src/main/scala/com/imooc/scala/window/WatermarkOpForSideOutputLateDataScala.scala @@ -0,0 +1,101 @@ +package com.imooc.scala.window + +import java.text.SimpleDateFormat +import java.time.Duration + +import org.apache.flink.api.common.eventtime.{SerializableTimestampAssigner, WatermarkStrategy} +import org.apache.flink.api.java.tuple.Tuple +import org.apache.flink.streaming.api.TimeCharacteristic +import org.apache.flink.streaming.api.scala.{OutputTag, StreamExecutionEnvironment} +import org.apache.flink.streaming.api.scala.function.WindowFunction +import org.apache.flink.streaming.api.windowing.assigners.TumblingEventTimeWindows +import org.apache.flink.streaming.api.windowing.time.Time +import org.apache.flink.streaming.api.windowing.windows.TimeWindow +import org.apache.flink.util.Collector + +import scala.collection.mutable.ArrayBuffer +import scala.util.Sorting + +/** + * Watermark+EventTime解决数据乱序问题 + * Created by xuwei + */ +object WatermarkOpForSideOutputLateDataScala { + def main(args: Array[String]): Unit = { + val env = StreamExecutionEnvironment.getExecutionEnvironment + //设置使用数据产生的时间:EventTime + env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime) + //设置全局并行度为1 + env.setParallelism(1) + + //设置自动周期性的产生watermark,默认值为200毫秒 + env.getConfig.setAutoWatermarkInterval(200) + + + val text = env.socketTextStream("bigdata04", 9001) + import org.apache.flink.api.scala._ + //将数据转换为tuple2的形式 + //第一列表示具体的数据,第二列表示是数据产生的时间戳 + val tupStream = text.map(line => { + val arr = line.split(",") + (arr(0), arr(1).toLong) + }) + + //分配(提取)时间戳和watermark + val waterMarkStream = tupStream.assignTimestampsAndWatermarks(WatermarkStrategy.forBoundedOutOfOrderness(Duration.ofSeconds(10)) //最大允许的数据乱序时间 10s + .withTimestampAssigner(new SerializableTimestampAssigner[Tuple2[String, Long]] { + val sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss") + var currentMaxTimstamp = 0L + + //从数据流中抽取时间戳作为EventTime + override def extractTimestamp(element: (String, Long), recordTimestamp: Long): Long = { + val timestamp = element._2 + currentMaxTimstamp = Math.max(timestamp, currentMaxTimstamp) + //计算当前watermark,为了打印出来方便观察数据,没有别的作用,watermark=currentMaxTimstamp-OutOfOrderness + val currentWatermark = currentMaxTimstamp - 10000L + //此print语句仅仅是为了在学习阶段观察数据的变化 + println("key:" + element._1 + "," + "eventtime:[" + element._2 + "|" + sdf.format(element._2) + "],currentMaxTimstamp:[" + currentWatermark + "|" + sdf.format(currentMaxTimstamp) + "],watermark:[" + currentWatermark + "|" + sdf.format(currentWatermark) + "]") + element._2 + } + }) + ) + + //保存被丢弃的数据 + val outputTag = new OutputTag[Tuple2[String,Long]]("late-data") + + val resStream = waterMarkStream.keyBy(0) + //按照消息的EventTime分配窗口,和调用TimeWindow效果一样 + .window(TumblingEventTimeWindows.of(Time.seconds(3))) + //保存被丢弃的数据 + .sideOutputLateData(outputTag) + //使用全量聚合的方式处理window中的数据 + .apply(new WindowFunction[Tuple2[String, Long], String, Tuple, TimeWindow] { + override def apply(key: Tuple, window: TimeWindow, input: Iterable[(String, Long)], out: Collector[String]): Unit = { + val keyStr = key.toString + //将window中的数据保存到arrBuff中 + val arrBuff = ArrayBuffer[Long]() + input.foreach(tup => { + arrBuff.append(tup._2) + }) + //将arrBuff转换为arr + val arr = arrBuff.toArray + //对arr中的数据进行排序 + Sorting.quickSort(arr) + + val sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss") + //将目前window内排序后的数据,以及window的开始时间和window的结束时间打印出来,便于观察 + val result = keyStr + "," + arr.length + "," + sdf.format(arr.head) + "," + sdf.format(arr.last) + "," + sdf.format(window.getStart) + "," + sdf.format(window.getEnd) + out.collect(result) + } + }) + + //把迟到的数据取出来,暂时打印到控制台,实际工作中可以选择存储到其它存储介质中 + //例如:redis,kafka + val sideOutput = resStream.getSideOutput(outputTag) + sideOutput.print() + + //将流中的结果数据也打印到控制台 + resStream.print() + env.execute("WatermarkOpScala") + } +} diff --git a/bigdata/flink/src/main/scala/com/imooc/scala/window/WatermarkOpMoreParallelismScala.scala b/bigdata/flink/src/main/scala/com/imooc/scala/window/WatermarkOpMoreParallelismScala.scala new file mode 100644 index 00000000..d7156ab0 --- /dev/null +++ b/bigdata/flink/src/main/scala/com/imooc/scala/window/WatermarkOpMoreParallelismScala.scala @@ -0,0 +1,90 @@ +package com.imooc.scala.window + +import java.text.SimpleDateFormat +import java.time.Duration + +import org.apache.flink.api.common.eventtime.{SerializableTimestampAssigner, WatermarkStrategy} +import org.apache.flink.api.java.tuple.Tuple +import org.apache.flink.streaming.api.TimeCharacteristic +import org.apache.flink.streaming.api.scala.StreamExecutionEnvironment +import org.apache.flink.streaming.api.scala.function.WindowFunction +import org.apache.flink.streaming.api.windowing.assigners.TumblingEventTimeWindows +import org.apache.flink.streaming.api.windowing.time.Time +import org.apache.flink.streaming.api.windowing.windows.TimeWindow +import org.apache.flink.util.Collector + +import scala.collection.mutable.ArrayBuffer +import scala.util.Sorting + +/** + * Watermark+EventTime解决数据乱序问题 + * Created by xuwei + */ +object WatermarkOpMoreParallelismScala { + def main(args: Array[String]): Unit = { + val env = StreamExecutionEnvironment.getExecutionEnvironment + //设置使用数据产生的时间:EventTime + env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime) + //设置全局并行度为1 + env.setParallelism(2) + + //设置自动周期性的产生watermark,默认值为200毫秒 + env.getConfig.setAutoWatermarkInterval(200) + + + val text = env.socketTextStream("bigdata04", 9001) + import org.apache.flink.api.scala._ + //将数据转换为tuple2的形式 + //第一列表示具体的数据,第二列表示是数据产生的时间戳 + val tupStream = text.map(line => { + val arr = line.split(",") + (arr(0), arr(1).toLong) + }) + + //分配(提取)时间戳和watermark + val waterMarkStream = tupStream.assignTimestampsAndWatermarks(WatermarkStrategy.forBoundedOutOfOrderness(Duration.ofSeconds(10)) //最大允许的数据乱序时间 10s + .withTimestampAssigner(new SerializableTimestampAssigner[Tuple2[String, Long]] { + val sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss") + var currentMaxTimstamp = 0L + + //从数据流中抽取时间戳作为EventTime + override def extractTimestamp(element: (String, Long), recordTimestamp: Long): Long = { + val timestamp = element._2 + currentMaxTimstamp = Math.max(timestamp, currentMaxTimstamp) + //计算当前watermark,为了打印出来方便观察数据,没有别的作用,watermark=currentMaxTimstamp-OutOfOrderness + val currentWatermark = currentMaxTimstamp - 10000L + val threadId = Thread.currentThread().getId + //此print语句仅仅是为了在学习阶段观察数据的变化 + println("threadId:"+threadId+",key:" + element._1 + "," + "eventtime:[" + element._2 + "|" + sdf.format(element._2) + "],currentMaxTimstamp:[" + currentWatermark + "|" + sdf.format(currentMaxTimstamp) + "],watermark:[" + currentWatermark + "|" + sdf.format(currentWatermark) + "]") + element._2 + } + }) + ) + + waterMarkStream.keyBy(0) + //按照消息的EventTime分配窗口,和调用TimeWindow效果一样 + .window(TumblingEventTimeWindows.of(Time.seconds(3))) + //使用全量聚合的方式处理window中的数据 + .apply(new WindowFunction[Tuple2[String,Long],String,Tuple,TimeWindow] { + override def apply(key: Tuple, window: TimeWindow, input: Iterable[(String, Long)], out: Collector[String]): Unit = { + val keyStr = key.toString + //将window中的数据保存到arrBuff中 + val arrBuff = ArrayBuffer[Long]() + input.foreach(tup=>{ + arrBuff.append(tup._2) + }) + //将arrBuff转换为arr + val arr = arrBuff.toArray + //对arr中的数据进行排序 + Sorting.quickSort(arr) + + val sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss") + //将目前window内排序后的数据,以及window的开始时间和window的结束时间打印出来,便于观察 + val result = keyStr+","+arr.length+","+sdf.format(arr.head)+","+sdf.format(arr.last)+","+sdf.format(window.getStart)+","+sdf.format(window.getEnd) + out.collect(result) + } + }).print() + + env.execute("WatermarkOpScala") + } +} diff --git a/bigdata/flink/src/main/scala/com/imooc/scala/window/WatermarkOpScala.scala b/bigdata/flink/src/main/scala/com/imooc/scala/window/WatermarkOpScala.scala new file mode 100644 index 00000000..cb2b18b4 --- /dev/null +++ b/bigdata/flink/src/main/scala/com/imooc/scala/window/WatermarkOpScala.scala @@ -0,0 +1,89 @@ +package com.imooc.scala.window + +import java.text.SimpleDateFormat +import java.time.Duration + +import org.apache.flink.api.common.eventtime.{SerializableTimestampAssigner, WatermarkStrategy} +import org.apache.flink.api.java.tuple.Tuple +import org.apache.flink.streaming.api.TimeCharacteristic +import org.apache.flink.streaming.api.scala.StreamExecutionEnvironment +import org.apache.flink.streaming.api.scala.function.WindowFunction +import org.apache.flink.streaming.api.windowing.assigners.TumblingEventTimeWindows +import org.apache.flink.streaming.api.windowing.time.Time +import org.apache.flink.streaming.api.windowing.windows.TimeWindow +import org.apache.flink.util.Collector + +import scala.collection.mutable.ArrayBuffer +import scala.util.Sorting + +/** + * Watermark+EventTime解决数据乱序问题 + * Created by xuwei + */ +object WatermarkOpScala { + def main(args: Array[String]): Unit = { + val env = StreamExecutionEnvironment.getExecutionEnvironment + //设置使用数据产生的时间:EventTime + env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime) + //设置全局并行度为1 + env.setParallelism(1) + + //设置自动周期性的产生watermark,默认值为200毫秒 + env.getConfig.setAutoWatermarkInterval(200) + + + val text = env.socketTextStream("bigdata04", 9001) + import org.apache.flink.api.scala._ + //将数据转换为tuple2的形式 + //第一列表示具体的数据,第二列表示是数据产生的时间戳 + val tupStream = text.map(line => { + val arr = line.split(",") + (arr(0), arr(1).toLong) + }) + + //分配(提取)时间戳和watermark + val waterMarkStream = tupStream.assignTimestampsAndWatermarks(WatermarkStrategy.forBoundedOutOfOrderness(Duration.ofSeconds(10)) //最大允许的数据乱序时间 10s + .withTimestampAssigner(new SerializableTimestampAssigner[Tuple2[String, Long]] { + val sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss") + var currentMaxTimstamp = 0L + + //从数据流中抽取时间戳作为EventTime + override def extractTimestamp(element: (String, Long), recordTimestamp: Long): Long = { + val timestamp = element._2 + currentMaxTimstamp = Math.max(timestamp, currentMaxTimstamp) + //计算当前watermark,为了打印出来方便观察数据,没有别的作用,watermark=currentMaxTimstamp-OutOfOrderness + val currentWatermark = currentMaxTimstamp - 10000L + //此print语句仅仅是为了在学习阶段观察数据的变化 + println("key:" + element._1 + "," + "eventtime:[" + element._2 + "|" + sdf.format(element._2) + "],currentMaxTimstamp:[" + currentWatermark + "|" + sdf.format(currentMaxTimstamp) + "],watermark:[" + currentWatermark + "|" + sdf.format(currentWatermark) + "]") + element._2 + } + }) + ) + + waterMarkStream.keyBy(0) + //按照消息的EventTime分配窗口,和调用TimeWindow效果一样 + .window(TumblingEventTimeWindows.of(Time.seconds(3))) + //使用全量聚合的方式处理window中的数据 + .apply(new WindowFunction[Tuple2[String,Long],String,Tuple,TimeWindow] { + override def apply(key: Tuple, window: TimeWindow, input: Iterable[(String, Long)], out: Collector[String]): Unit = { + val keyStr = key.toString + //将window中的数据保存到arrBuff中 + val arrBuff = ArrayBuffer[Long]() + input.foreach(tup=>{ + arrBuff.append(tup._2) + }) + //将arrBuff转换为arr + val arr = arrBuff.toArray + //对arr中的数据进行排序 + Sorting.quickSort(arr) + + val sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss") + //将目前window内排序后的数据,以及window的开始时间和window的结束时间打印出来,便于观察 + val result = keyStr+","+arr.length+","+sdf.format(arr.head)+","+sdf.format(arr.last)+","+sdf.format(window.getStart)+","+sdf.format(window.getEnd) + out.collect(result) + } + }).print() + + env.execute("WatermarkOpScala") + } +} diff --git a/bigdata/hadoop/hdfs/pom.xml b/bigdata/hadoop/hdfs/pom.xml new file mode 100644 index 00000000..52c6b311 --- /dev/null +++ b/bigdata/hadoop/hdfs/pom.xml @@ -0,0 +1,40 @@ + + + 4.0.0 + + hdfs + cn.cunchang + 1.0-SNAPSHOT + + + 8 + 8 + + + + + + + org.apache.hadoop + hadoop-client + 3.2.0 + + + + + + org.slf4j + slf4j-api + 1.7.10 + + + org.slf4j + slf4j-log4j12 + 1.7.10 + + + + + \ No newline at end of file diff --git a/bigdata/hadoop/hdfs/src/main/java/cn/cunchang/HdfsOp.java b/bigdata/hadoop/hdfs/src/main/java/cn/cunchang/HdfsOp.java new file mode 100644 index 00000000..6550c40f --- /dev/null +++ b/bigdata/hadoop/hdfs/src/main/java/cn/cunchang/HdfsOp.java @@ -0,0 +1,83 @@ +package cn.cunchang; + +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.fs.FSDataInputStream; +import org.apache.hadoop.fs.FSDataOutputStream; +import org.apache.hadoop.fs.FileSystem; +import org.apache.hadoop.fs.Path; +import org.apache.hadoop.io.IOUtils; + +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; + +/** + * Java代码操作HDFS + * 文件操作:上传文件,下载文件,删除文件 + * + */ +public class HdfsOp { + + public static void main(String[] args) throws Exception{ + //创建一个配置对象 + Configuration conf = new Configuration(); + //指定HDFS的地址 + conf.set("fs.defaultFS","hdfs://localhost:9000"); + //获取操作HDFS的对象 + FileSystem fileSystem = FileSystem.get(conf); + + //上传文件 + put(fileSystem); + //下载文件 +// get(fileSystem); + //删除文件 +// delete(fileSystem); + + } + + /** + * 删除文件或者目录 + * @param fileSystem + * @throws IOException + */ + private static void delete(FileSystem fileSystem) throws IOException { + //删除文件,目录也可以删除 + //如果要递归删除目录,则第二个参数需要设置为true + //如果删除的是文件或者空目录,第二个参数会被忽略 + boolean flag = fileSystem.delete(new Path("/README.txt"),true); + if(flag){ + System.out.println("删除成功!"); + }else{ + System.out.println("删除失败!"); + } + } + + /** + * 下载文件 + * @param fileSystem + * @throws IOException + */ + private static void get(FileSystem fileSystem) throws IOException { + //获取HDFS文件系统中的输入流 + FSDataInputStream fis = fileSystem.open(new Path("/README.txt")); + //获取本地文件的输出流 + FileOutputStream fos = new FileOutputStream("/Users/cunchang/workspace/github/code/bigdata/hadoop/README.txt"); + //下载文件 + IOUtils.copyBytes(fis,fos,1024,true); + } + + /** + * 上传文件 + * @param fileSystem + * @throws IOException + */ + private static void put(FileSystem fileSystem) throws IOException { + //获取本地文件的输入流 + FileInputStream fis = new FileInputStream("/data/soft/hadoop-3.2.0/README.txt"); + //获取HDFS文件系统的输出流 + FSDataOutputStream fos = fileSystem.create(new Path("/README.txt")); + //上传文件:通过工具类把输入流拷贝到输出流里面,实现本地文件上传到HDFS + IOUtils.copyBytes(fis,fos,1024,true); + } + +} diff --git a/bigdata/hadoop/hdfs/src/main/resources/log4j.properties b/bigdata/hadoop/hdfs/src/main/resources/log4j.properties new file mode 100644 index 00000000..ddf8c805 --- /dev/null +++ b/bigdata/hadoop/hdfs/src/main/resources/log4j.properties @@ -0,0 +1,9 @@ +log4j.rootLogger=info,stdout + +log4j.appender.stdout = org.apache.log4j.ConsoleAppender +log4j.appender.stdout.Target = System.out +log4j.appender.stdout.layout=org.apache.log4j.PatternLayout +log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} [%t] [%c] [%p] - %m%n + + + diff --git a/bigdata/hadoop/mapreduce/pom.xml b/bigdata/hadoop/mapreduce/pom.xml new file mode 100644 index 00000000..672940ae --- /dev/null +++ b/bigdata/hadoop/mapreduce/pom.xml @@ -0,0 +1,81 @@ + + + 4.0.0 + + cn.cunchang + mapreduce + 1.0-SNAPSHOT + + + 8 + 8 + + + + + + org.apache.hadoop + hadoop-client + 3.2.0 + + provided + + + + + org.slf4j + slf4j-api + 1.7.10 + provided + + + org.slf4j + slf4j-log4j12 + 1.7.10 + provided + + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.1 + + UTF-8 + 1.8 + 1.8 + true + + + + maven-assembly-plugin + + + jar-with-dependencies + + + + + + + + + + make-assembly + package + + single + + + + + + + + \ No newline at end of file diff --git a/bigdata/hadoop/mapreduce/src/main/java/cn/cunchang/mr/GenerateDat.java b/bigdata/hadoop/mapreduce/src/main/java/cn/cunchang/mr/GenerateDat.java new file mode 100644 index 00000000..66f2e660 --- /dev/null +++ b/bigdata/hadoop/mapreduce/src/main/java/cn/cunchang/mr/GenerateDat.java @@ -0,0 +1,57 @@ +package cn.cunchang.mr; + +import java.io.BufferedWriter; +import java.io.FileWriter; +import java.io.IOException; + +/** + * 生成测试数据 + * 1: + * Created by xuwei + */ +public class GenerateDat { + public static void main(String[] args) throws Exception{ + generate_140M(); + generate_141M(); + } + + /** + * 生成141M文件 + * @throws IOException + */ + private static void generate_141M() throws IOException { + String fileName = "D:\\s_name_141.dat"; + System.out.println("start: 开始生成141M文件->"+fileName); + BufferedWriter bfw = new BufferedWriter(new FileWriter(fileName)); + int num = 0; + while(num<8221592){ + bfw.write("zhangsan beijing"); + bfw.newLine(); + num ++; + if(num%10000==0){ + bfw.flush(); + } + } + System.out.println("end: 141M文件已生成"); + } + + /** + * 生成140M文件 + * @throws IOException + */ + private static void generate_140M() throws IOException { + String fileName = "D:\\s_name_140.dat"; + System.out.println("start: 开始生成140M文件->"+fileName); + BufferedWriter bfw = new BufferedWriter(new FileWriter(fileName)); + int num = 0; + while(num<8201592){ + bfw.write("zhangsan beijing"); + bfw.newLine(); + num ++; + if(num%10000==0){ + bfw.flush(); + } + } + System.out.println("end: 140M文件已生成"); + } +} diff --git a/bigdata/hadoop/mapreduce/src/main/java/cn/cunchang/mr/HadoopSerialize.java b/bigdata/hadoop/mapreduce/src/main/java/cn/cunchang/mr/HadoopSerialize.java new file mode 100644 index 00000000..655d4f83 --- /dev/null +++ b/bigdata/hadoop/mapreduce/src/main/java/cn/cunchang/mr/HadoopSerialize.java @@ -0,0 +1,58 @@ +package cn.cunchang.mr; + +import org.apache.hadoop.io.Writable; + +import java.io.*; + +/** + * Hadoop序列化机制 + * Created by xuwei + */ +public class HadoopSerialize { + public static void main(String[] args) throws Exception{ + //创建Student对象,并设置id和name属性 + StudentWritable studentWritable = new StudentWritable(); + studentWritable.setId(1L); + studentWritable.setName("Hadoop"); + + //将Student对象的当前状态写入本地文件中 + FileOutputStream fos = new FileOutputStream("D:\\student_hadoop.txt"); + ObjectOutputStream oos = new ObjectOutputStream(fos); + studentWritable.write(oos); + oos.close(); + fos.close(); + } +} + +class StudentWritable implements Writable{ + private Long id; + private String name; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @Override + public void write(DataOutput out) throws IOException { + out.writeLong(this.id); + out.writeUTF(this.name); + } + + @Override + public void readFields(DataInput in) throws IOException { + this.id = in.readLong(); + this.name = in.readUTF(); + } +} diff --git a/bigdata/hadoop/mapreduce/src/main/java/cn/cunchang/mr/JavaSerialize.java b/bigdata/hadoop/mapreduce/src/main/java/cn/cunchang/mr/JavaSerialize.java new file mode 100644 index 00000000..43915042 --- /dev/null +++ b/bigdata/hadoop/mapreduce/src/main/java/cn/cunchang/mr/JavaSerialize.java @@ -0,0 +1,47 @@ +package cn.cunchang.mr; + +import java.io.FileOutputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; + +/** + * Java中的序列化 + * Created by xuwei + */ +public class JavaSerialize { + public static void main(String[] args) throws Exception{ + //创建Student对象,并设置id和name属性 + StudentJava studentJava = new StudentJava(); + studentJava.setId(1L); + studentJava.setName("Hadoop"); + + //将Student对象的当前状态写入本地文件中 + FileOutputStream fos = new FileOutputStream("D:\\student_java.txt"); + ObjectOutputStream oos = new ObjectOutputStream(fos); + oos.writeObject(studentJava); + oos.close(); + fos.close(); + } +} + +class StudentJava implements Serializable{ + private static final long serialVersionUID = 1L; + private Long id; + private String name; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} \ No newline at end of file diff --git a/bigdata/hadoop/mapreduce/src/main/java/cn/cunchang/mr/README.md b/bigdata/hadoop/mapreduce/src/main/java/cn/cunchang/mr/README.md new file mode 100644 index 00000000..8aff41fa --- /dev/null +++ b/bigdata/hadoop/mapreduce/src/main/java/cn/cunchang/mr/README.md @@ -0,0 +1,11 @@ + +# mapreduce +mapreduce模块下的类,都要放到hadoop上执行 + +WordCountJob +JavaSerialize、HadoopSerialize + + +# yarn +WordCountJobQueue + diff --git a/bigdata/hadoop/mapreduce/src/main/java/cn/cunchang/mr/SmallFileMap.java b/bigdata/hadoop/mapreduce/src/main/java/cn/cunchang/mr/SmallFileMap.java new file mode 100644 index 00000000..542bf740 --- /dev/null +++ b/bigdata/hadoop/mapreduce/src/main/java/cn/cunchang/mr/SmallFileMap.java @@ -0,0 +1,101 @@ +package cn.cunchang.mr; + +import org.apache.commons.io.FileUtils; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.fs.FileSystem; +import org.apache.hadoop.fs.Path; +import org.apache.hadoop.io.MapFile; +import org.apache.hadoop.io.SequenceFile; +import org.apache.hadoop.io.Text; + +import java.io.File; + +/** + * 小文件解决方案之MapFile + * Created by xuwei + */ +public class SmallFileMap { + + public static void main(String[] args) throws Exception{ + //生成MapFile文件 + write("D:\\smallFile","/mapFile"); + //读取MapFile文件 + read("/mapFile"); + } + + /** + * 生成MapFile文件 + * @param inputDir 输入目录-windows目录 + * @param outputDir 输出目录-hdfs目录 + * @throws Exception + */ + private static void write(String inputDir,String outputDir) throws Exception{ + //创建一个配置对象 + Configuration conf = new Configuration(); + //指定HDFS的地址 + conf.set("fs.defaultFS","hdfs://bigdata01:9000"); + + //获取操作HDFD的对象 + FileSystem fileSystem = FileSystem.get(conf); + + //删除HDFS上的输出文件 + fileSystem.delete(new Path(outputDir),true); + + //构造opts数组,有两个元素 + /* + 第一个是key的类型 + 第二个是value的类型 + */ + SequenceFile.Writer.Option[] opts = new SequenceFile.Writer.Option[]{ + MapFile.Writer.keyClass(Text.class), + MapFile.Writer.valueClass(Text.class) + }; + //创建了一个writer实例 + MapFile.Writer writer = new MapFile.Writer(conf, new Path(outputDir), opts); + + //指定需要压缩的文件的目录 + File inputDirPath = new File(inputDir); + if(inputDirPath.isDirectory()){ + //获取目录中的文件 + File[] files = inputDirPath.listFiles(); + //迭代文件 + for (File file: files) { + //获取文件的全部内容 + String content = FileUtils.readFileToString(file, "UTF-8"); + //获取文件名 + String fileName = file.getName(); + Text key = new Text(fileName); + Text value = new Text(content); + //向SequenceFile中写入数据 + writer.append(key,value); + } + } + writer.close(); + } + + /** + * 读取MapFile文件 + * @param inputDir MapFile文件路径 + * @throws Exception + */ + private static void read(String inputDir)throws Exception{ + //创建一个配置对象 + Configuration conf = new Configuration(); + //指定HDFS的地址 + conf.set("fs.defaultFS","hdfs://bigdata01:9000"); + //创建阅读器 + MapFile.Reader reader = new MapFile.Reader(new Path(inputDir),conf); + Text key = new Text(); + Text value = new Text(); + //循环读取数据 + while(reader.next(key,value)){ + //输出文件名称 + System.out.print("文件名:"+key.toString()+","); + //输出文件内容 + System.out.println("文件内容:"+value.toString()+""); + } + reader.close(); + } + + +} diff --git a/bigdata/hadoop/mapreduce/src/main/java/cn/cunchang/mr/SmallFileSeq.java b/bigdata/hadoop/mapreduce/src/main/java/cn/cunchang/mr/SmallFileSeq.java new file mode 100644 index 00000000..d5b68b61 --- /dev/null +++ b/bigdata/hadoop/mapreduce/src/main/java/cn/cunchang/mr/SmallFileSeq.java @@ -0,0 +1,102 @@ +package cn.cunchang.mr; + +import org.apache.commons.io.FileUtils; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.fs.FileSystem; +import org.apache.hadoop.fs.Path; +import org.apache.hadoop.io.SequenceFile; +import org.apache.hadoop.io.Text; + +import java.io.File; + +/** + * 小文件解决方案之SequenceFile + * Created by xuwei + */ +public class SmallFileSeq { + + public static void main(String[] args) throws Exception{ + //生成SequenceFile文件 + write("D:\\smallFile","/seqFile"); + //读取SequenceFile文件 + read("/seqFile"); + } + + + /** + * 生成SequenceFile文件 + * @param inputDir 输入目录-windows目录 + * @param outputFile 输出文件-hdfs文件 + * @throws Exception + */ + private static void write(String inputDir,String outputFile) throws Exception{ + //创建一个配置对象 + Configuration conf = new Configuration(); + //指定HDFS的地址 + conf.set("fs.defaultFS","hdfs://bigdata01:9000"); + + //获取操作HDFD的对象 + FileSystem fileSystem = FileSystem.get(conf); + + //删除HDFS上的输出文件 + fileSystem.delete(new Path(outputFile),true); + + //构造opts数组,有三个元素 + /* + 第一个是输出路径【文件】 + 第二个是key的类型 + 第三个是value的类型 + */ + SequenceFile.Writer.Option[] opts = new SequenceFile.Writer.Option[]{ + SequenceFile.Writer.file(new Path(outputFile)), + SequenceFile.Writer.keyClass(Text.class), + SequenceFile.Writer.valueClass(Text.class) + }; + //创建了一个writer实例 + SequenceFile.Writer writer = SequenceFile.createWriter(conf, opts); + + //指定需要压缩的文件的目录 + File inputDirPath = new File(inputDir); + if(inputDirPath.isDirectory()){ + //获取目录中的文件 + File[] files = inputDirPath.listFiles(); + //迭代文件 + for (File file: files) { + //获取文件的全部内容 + String content = FileUtils.readFileToString(file, "UTF-8"); + //获取文件名 + String fileName = file.getName(); + Text key = new Text(fileName); + Text value = new Text(content); + //向SequenceFile中写入数据 + writer.append(key,value); + } + } + writer.close(); + } + + /** + * 读取SequenceFile文件 + * @param inputFile SequenceFile文件路径 + * @throws Exception + */ + private static void read(String inputFile) throws Exception{ + //创建一个配置对象 + Configuration conf = new Configuration(); + //指定HDFS的地址 + conf.set("fs.defaultFS","hdfs://bigdata01:9000"); + //创建阅读器 + SequenceFile.Reader reader = new SequenceFile.Reader(conf, SequenceFile.Reader.file(new Path(inputFile))); + Text key = new Text(); + Text value = new Text(); + //循环读取数据 + while(reader.next(key,value)){ + //输出文件名称 + System.out.print("文件名:"+key.toString()+","); + //输出文件内容 + System.out.println("文件内容:"+value.toString()+""); + } + reader.close(); + } + +} diff --git a/bigdata/hadoop/mapreduce/src/main/java/cn/cunchang/mr/WordCountJob.java b/bigdata/hadoop/mapreduce/src/main/java/cn/cunchang/mr/WordCountJob.java new file mode 100644 index 00000000..912021b5 --- /dev/null +++ b/bigdata/hadoop/mapreduce/src/main/java/cn/cunchang/mr/WordCountJob.java @@ -0,0 +1,152 @@ +package cn.cunchang.mr; + +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.fs.Path; +import org.apache.hadoop.io.LongWritable; +import org.apache.hadoop.io.Text; +import org.apache.hadoop.mapreduce.Job; +import org.apache.hadoop.mapreduce.Mapper; +import org.apache.hadoop.mapreduce.Reducer; +import org.apache.hadoop.mapreduce.lib.input.FileInputFormat; +import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; + +/** + * 需求:读取hdfs上的hello.txt文件,计算文件中每个单词出现的总次数 + *

+ * 原始文件hello.txt内容如下: + * hello you + * hello me + *

+ * 最终需要的结果形式如下: + * hello 2 + * me 1 + * you 1 + *

+ * Created by xuwei + */ +public class WordCountJob { + /** + * Map阶段 + */ + public static class MyMapper extends Mapper { + Logger logger = LoggerFactory.getLogger(MyMapper.class); + + /** + * 需要实现map函数 + * 这个map函数就是可以接收,产生 + * + * @param k1 + * @param v1 + * @param context + * @throws IOException + * @throws InterruptedException + */ + @Override + protected void map(LongWritable k1, Text v1, Context context) + throws IOException, InterruptedException { + //输出k1,v1的值 + logger.info("=<"+k1.get()+","+v1.toString()+">"); + //k1 代表的是每一行数据的行首偏移量,v1代表的是每一行内容 + //对获取到的每一行数据进行切割,把单词切割出来 + String[] words = v1.toString().split(" "); + //迭代切割出来的单词数据 + for (String word : words) { + //把迭代出来的单词封装成的形式 + Text k2 = new Text(word); + LongWritable v2 = new LongWritable(1L); + //把写出去 + context.write(k2, v2); + } + } + } + + + /** + * Reduce阶段 + */ + public static class MyReducer extends Reducer { + Logger logger = LoggerFactory.getLogger(MyReducer.class); + + /** + * 针对的数据进行累加求和,并且最终把数据转化为k3,v3写出去 + * + * @param k2 + * @param v2s + * @param context + * @throws IOException + * @throws InterruptedException + */ + @Override + protected void reduce(Text k2, Iterable v2s, Context context) + throws IOException, InterruptedException { + //创建一个sum变量,保存v2s的和 + long sum = 0L; + //对v2s中的数据进行累加求和 + for (LongWritable v2 : v2s) { + //输出k2,v2的值 + logger.info("=<"+k2.toString()+","+v2.get()+">"); + sum += v2.get(); + } + + //组装k3,v3 + Text k3 = k2; + LongWritable v3 = new LongWritable(sum); + //输出k3,v3的值 + logger.info("=<"+k3.toString()+","+v3.get()+">"); + // 把结果写出去 + context.write(k3, v3); + } + } + + /** + * 组装Job=Map+Reduce + */ + public static void main(String[] args) { + try { + if (args.length != 2) { + //如果传递的参数不够,程序直接退出 + System.exit(100); + } + + //指定Job需要的配置参数 + Configuration conf = new Configuration(); + //创建一个Job + Job job = Job.getInstance(conf); + + //注意了:这一行必须设置,否则在集群中执行的时候是找不到WordCountJob这个类的 + job.setJarByClass(WordCountJob.class); + + //指定输入路径(可以是文件,也可以是目录) + FileInputFormat.setInputPaths(job, new Path(args[0])); + //指定输出路径(只能指定一个不存在的目录) + FileOutputFormat.setOutputPath(job, new Path(args[1])); + + //指定map相关的代码 + job.setMapperClass(MyMapper.class); + //指定k2的类型 + job.setMapOutputKeyClass(Text.class); + //指定v2的类型 + job.setMapOutputValueClass(LongWritable.class); + + + //指定reduce相关的代码 + job.setReducerClass(MyReducer.class); + //指定k3的类型 + job.setOutputKeyClass(Text.class); + //指定v3的类型 + job.setOutputValueClass(LongWritable.class); + + //提交job + job.waitForCompletion(true); + } catch (Exception e) { + e.printStackTrace(); + } + + } + + +} diff --git a/bigdata/hadoop/mapreduce/src/main/java/cn/cunchang/mr/WordCountJobNoReduce.java b/bigdata/hadoop/mapreduce/src/main/java/cn/cunchang/mr/WordCountJobNoReduce.java new file mode 100644 index 00000000..7db549e8 --- /dev/null +++ b/bigdata/hadoop/mapreduce/src/main/java/cn/cunchang/mr/WordCountJobNoReduce.java @@ -0,0 +1,101 @@ +package cn.cunchang.mr; + +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.fs.Path; +import org.apache.hadoop.io.LongWritable; +import org.apache.hadoop.io.Text; +import org.apache.hadoop.mapreduce.Job; +import org.apache.hadoop.mapreduce.Mapper; +import org.apache.hadoop.mapreduce.Reducer; +import org.apache.hadoop.mapreduce.lib.input.FileInputFormat; +import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; + +/** + * 只有Map阶段,不包含Reduce阶段 + * + * Created by xuwei + */ +public class WordCountJobNoReduce { + /** + * Map阶段 + */ + public static class MyMapper extends Mapper{ + Logger logger = LoggerFactory.getLogger(MyMapper.class); + /** + * 需要实现map函数 + * 这个map函数就是可以接收,产生 + * @param k1 + * @param v1 + * @param context + * @throws IOException + * @throws InterruptedException + */ + @Override + protected void map(LongWritable k1, Text v1, Context context) + throws IOException, InterruptedException { + //输出k1,v1的值 + logger.info("=<"+k1.get()+","+v1.toString()+">"); + //k1 代表的是每一行数据的行首偏移量,v1代表的是每一行内容 + //对获取到的每一行数据进行切割,把单词切割出来 + String[] words = v1.toString().split(" "); + //迭代切割出来的单词数据 + for (String word : words) { + //把迭代出来的单词封装成的形式 + Text k2 = new Text(word); + LongWritable v2 = new LongWritable(1L); + //把写出去 + context.write(k2,v2); + } + } + } + + + + + /** + * 组装Job=Map+Reduce + */ + public static void main(String[] args) { + try{ + if(args.length!=2){ + //如果传递的参数不够,程序直接退出 + System.exit(100); + } + + //指定Job需要的配置参数 + Configuration conf = new Configuration(); + //创建一个Job + Job job = Job.getInstance(conf); + + //注意了:这一行必须设置,否则在集群中执行的时候是找不到WordCountJob这个类的 + job.setJarByClass(WordCountJobNoReduce.class); + + //指定输入路径(可以是文件,也可以是目录) + FileInputFormat.setInputPaths(job,new Path(args[0])); + //指定输出路径(只能指定一个不存在的目录) + FileOutputFormat.setOutputPath(job,new Path(args[1])); + + //指定map相关的代码 + job.setMapperClass(MyMapper.class); + //指定k2的类型 + job.setMapOutputKeyClass(Text.class); + //指定v2的类型 + job.setMapOutputValueClass(LongWritable.class); + + //禁用Reduce + job.setNumReduceTasks(0); + + //提交job + job.waitForCompletion(true); + }catch(Exception e){ + e.printStackTrace(); + } + + } + + +} diff --git a/bigdata/hadoop/mapreduce/src/main/java/cn/cunchang/mr/WordCountJobQueue.java b/bigdata/hadoop/mapreduce/src/main/java/cn/cunchang/mr/WordCountJobQueue.java new file mode 100644 index 00000000..6f3c7638 --- /dev/null +++ b/bigdata/hadoop/mapreduce/src/main/java/cn/cunchang/mr/WordCountJobQueue.java @@ -0,0 +1,139 @@ +package cn.cunchang.mr; + +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.fs.Path; +import org.apache.hadoop.io.LongWritable; +import org.apache.hadoop.io.Text; +import org.apache.hadoop.mapreduce.Job; +import org.apache.hadoop.mapreduce.Mapper; +import org.apache.hadoop.mapreduce.Reducer; +import org.apache.hadoop.mapreduce.lib.input.FileInputFormat; +import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; +import org.apache.hadoop.util.GenericOptionsParser; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; + +/** + * 指定队列名称 + * + * Created by xuwei + */ +public class WordCountJobQueue { + /** + * Map阶段 + */ + public static class MyMapper extends Mapper{ + Logger logger = LoggerFactory.getLogger(MyMapper.class); + /** + * 需要实现map函数 + * 这个map函数就是可以接收,产生 + * @param k1 + * @param v1 + * @param context + * @throws IOException + * @throws InterruptedException + */ + @Override + protected void map(LongWritable k1, Text v1, Context context) + throws IOException, InterruptedException { + //输出k1,v1的值 + logger.info("=<"+k1.get()+","+v1.toString()+">"); + //k1 代表的是每一行数据的行首偏移量,v1代表的是每一行内容 + //对获取到的每一行数据进行切割,把单词切割出来 + String[] words = v1.toString().split(" "); + //迭代切割出来的单词数据 + for (String word : words) { + //把迭代出来的单词封装成的形式 + Text k2 = new Text(word); + LongWritable v2 = new LongWritable(1L); + //把写出去 + context.write(k2,v2); + } + } + } + + + /** + * Reduce阶段 + */ + public static class MyReducer extends Reducer{ + Logger logger = LoggerFactory.getLogger(MyReducer.class); + /** + * 针对的数据进行累加求和,并且最终把数据转化为k3,v3写出去 + * @param k2 + * @param v2s + * @param context + * @throws IOException + * @throws InterruptedException + */ + @Override + protected void reduce(Text k2, Iterable v2s, Context context) + throws IOException, InterruptedException { + //创建一个sum变量,保存v2s的和 + long sum = 0L; + //对v2s中的数据进行累加求和 + for(LongWritable v2: v2s){ + //输出k2,v2的值 + logger.info("=<"+k2.toString()+","+v2.get()+">"); + sum += v2.get(); + } + + //组装k3,v3 + Text k3 = k2; + LongWritable v3 = new LongWritable(sum); + //输出k3,v3的值 + logger.info("=<"+k3.toString()+","+v3.get()+">"); + // 把结果写出去 + context.write(k3,v3); + } + } + + /** + * 组装Job=Map+Reduce + */ + public static void main(String[] args) { + try{ + + //指定Job需要的配置参数 + Configuration conf = new Configuration(); + //解析命令行中通过-D传递过来的参数,添加到conf中 + String[] remainingArgs = new GenericOptionsParser(conf, args).getRemainingArgs(); + + //创建一个Job + Job job = Job.getInstance(conf); + + //注意了:这一行必须设置,否则在集群中执行的时候是找不到WordCountJob这个类的 + job.setJarByClass(WordCountJobQueue.class); + + //指定输入路径(可以是文件,也可以是目录) + FileInputFormat.setInputPaths(job,new Path(remainingArgs[0])); + //指定输出路径(只能指定一个不存在的目录) + FileOutputFormat.setOutputPath(job,new Path(remainingArgs[1])); + + //指定map相关的代码 + job.setMapperClass(MyMapper.class); + //指定k2的类型 + job.setMapOutputKeyClass(Text.class); + //指定v2的类型 + job.setMapOutputValueClass(LongWritable.class); + + + //指定reduce相关的代码 + job.setReducerClass(MyReducer.class); + //指定k3的类型 + job.setOutputKeyClass(Text.class); + //指定v3的类型 + job.setOutputValueClass(LongWritable.class); + + //提交job + job.waitForCompletion(true); + }catch(Exception e){ + e.printStackTrace(); + } + + } + + +} diff --git a/bigdata/hadoop/mapreduce/src/main/java/cn/cunchang/mr/WordCountJobSeq.java b/bigdata/hadoop/mapreduce/src/main/java/cn/cunchang/mr/WordCountJobSeq.java new file mode 100644 index 00000000..6d359f7e --- /dev/null +++ b/bigdata/hadoop/mapreduce/src/main/java/cn/cunchang/mr/WordCountJobSeq.java @@ -0,0 +1,146 @@ +package cn.cunchang.mr; + +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.fs.Path; +import org.apache.hadoop.io.LongWritable; +import org.apache.hadoop.io.Text; +import org.apache.hadoop.mapreduce.Job; +import org.apache.hadoop.mapreduce.Mapper; +import org.apache.hadoop.mapreduce.Reducer; +import org.apache.hadoop.mapreduce.lib.input.FileInputFormat; +import org.apache.hadoop.mapreduce.lib.input.SequenceFileInputFormat; +import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; + +/** + * 需求:读取SequenceFile文件 + * + * Created by xuwei + */ +public class WordCountJobSeq { + /** + * Map阶段 + */ + public static class MyMapper extends Mapper{ + Logger logger = LoggerFactory.getLogger(MyMapper.class); + /** + * 需要实现map函数 + * 这个map函数就是可以接收,产生 + * @param k1 + * @param v1 + * @param context + * @throws IOException + * @throws InterruptedException + */ + @Override + protected void map(Text k1, Text v1, Context context) + throws IOException, InterruptedException { + //输出k1,v1的值 + System.out.println("=<"+k1.toString()+","+v1.toString()+">"); + //logger.info("=<"+k1.get()+","+v1.toString()+">"); + //k1 代表的是每一行数据的行首偏移量,v1代表的是每一行内容 + //对获取到的每一行数据进行切割,把单词切割出来 + String[] words = v1.toString().split(" "); + //迭代切割出来的单词数据 + for (String word : words) { + //把迭代出来的单词封装成的形式 + Text k2 = new Text(word); + LongWritable v2 = new LongWritable(1L); + //把写出去 + context.write(k2,v2); + } + } + } + + + /** + * Reduce阶段 + */ + public static class MyReducer extends Reducer{ + Logger logger = LoggerFactory.getLogger(MyReducer.class); + /** + * 针对的数据进行累加求和,并且最终把数据转化为k3,v3写出去 + * @param k2 + * @param v2s + * @param context + * @throws IOException + * @throws InterruptedException + */ + @Override + protected void reduce(Text k2, Iterable v2s, Context context) + throws IOException, InterruptedException { + //创建一个sum变量,保存v2s的和 + long sum = 0L; + //对v2s中的数据进行累加求和 + for(LongWritable v2: v2s){ + //输出k2,v2的值 + //System.out.println("=<"+k2.toString()+","+v2.get()+">"); + //logger.info("=<"+k2.toString()+","+v2.get()+">"); + sum += v2.get(); + } + + //组装k3,v3 + Text k3 = k2; + LongWritable v3 = new LongWritable(sum); + //输出k3,v3的值 + //System.out.println("=<"+k3.toString()+","+v3.get()+">"); + //logger.info("=<"+k3.toString()+","+v3.get()+">"); + // 把结果写出去 + context.write(k3,v3); + } + } + + /** + * 组装Job=Map+Reduce + */ + public static void main(String[] args) { + try{ + if(args.length!=2){ + //如果传递的参数不够,程序直接退出 + System.exit(100); + } + + //指定Job需要的配置参数 + Configuration conf = new Configuration(); + //创建一个Job + Job job = Job.getInstance(conf); + + //注意了:这一行必须设置,否则在集群中执行的时候是找不到WordCountJob这个类的 + job.setJarByClass(WordCountJobSeq.class); + + //指定输入路径(可以是文件,也可以是目录) + FileInputFormat.setInputPaths(job,new Path(args[0])); + //指定输出路径(只能指定一个不存在的目录) + FileOutputFormat.setOutputPath(job,new Path(args[1])); + + //指定map相关的代码 + job.setMapperClass(MyMapper.class); + //指定k2的类型 + job.setMapOutputKeyClass(Text.class); + //指定v2的类型 + job.setMapOutputValueClass(LongWritable.class); + + //设置输入数据处理类 + job.setInputFormatClass(SequenceFileInputFormat.class); + + + //指定reduce相关的代码 + job.setReducerClass(MyReducer.class); + //指定k3的类型 + job.setOutputKeyClass(Text.class); + //指定v3的类型 + job.setOutputValueClass(LongWritable.class); + + //提交job + job.waitForCompletion(true); + }catch(Exception e){ + e.printStackTrace(); + } + + } + + +} diff --git a/bigdata/hadoop/mapreduce/src/main/java/cn/cunchang/mr/WordCountJobSkew.java b/bigdata/hadoop/mapreduce/src/main/java/cn/cunchang/mr/WordCountJobSkew.java new file mode 100644 index 00000000..6512784c --- /dev/null +++ b/bigdata/hadoop/mapreduce/src/main/java/cn/cunchang/mr/WordCountJobSkew.java @@ -0,0 +1,146 @@ +package cn.cunchang.mr; + +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.fs.Path; +import org.apache.hadoop.io.LongWritable; +import org.apache.hadoop.io.Text; +import org.apache.hadoop.mapreduce.Job; +import org.apache.hadoop.mapreduce.Mapper; +import org.apache.hadoop.mapreduce.Reducer; +import org.apache.hadoop.mapreduce.lib.input.FileInputFormat; +import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; + +/** + * 数据倾斜-增加Reduce任务个数 + * + * Created by xuwei + */ +public class WordCountJobSkew { + /** + * Map阶段 + */ + public static class MyMapper extends Mapper{ + Logger logger = LoggerFactory.getLogger(MyMapper.class); + /** + * 需要实现map函数 + * 这个map函数就是可以接收,产生 + * @param k1 + * @param v1 + * @param context + * @throws IOException + * @throws InterruptedException + */ + @Override + protected void map(LongWritable k1, Text v1, Context context) + throws IOException, InterruptedException { + //输出k1,v1的值 + //System.out.println("=<"+k1.get()+","+v1.toString()+">"); + //logger.info("=<"+k1.get()+","+v1.toString()+">"); + //k1 代表的是每一行数据的行首偏移量,v1代表的是每一行内容 + //对获取到的每一行数据进行切割,把单词切割出来 + String[] words = v1.toString().split(" "); + //把迭代出来的单词封装成的形式 + Text k2 = new Text(words[0]); + LongWritable v2 = new LongWritable(1L); + //把写出去 + context.write(k2,v2); + } + } + + + /** + * Reduce阶段 + */ + public static class MyReducer extends Reducer{ + Logger logger = LoggerFactory.getLogger(MyReducer.class); + /** + * 针对的数据进行累加求和,并且最终把数据转化为k3,v3写出去 + * @param k2 + * @param v2s + * @param context + * @throws IOException + * @throws InterruptedException + */ + @Override + protected void reduce(Text k2, Iterable v2s, Context context) + throws IOException, InterruptedException { + //创建一个sum变量,保存v2s的和 + long sum = 0L; + //对v2s中的数据进行累加求和 + for(LongWritable v2: v2s){ + //输出k2,v2的值 + //System.out.println("=<"+k2.toString()+","+v2.get()+">"); + //logger.info("=<"+k2.toString()+","+v2.get()+">"); + sum += v2.get(); + //模拟Reduce的复杂计算消耗的时间 + if(sum%200 == 0){ + Thread.sleep(1); + } + } + + //组装k3,v3 + Text k3 = k2; + LongWritable v3 = new LongWritable(sum); + //输出k3,v3的值 + //System.out.println("=<"+k3.toString()+","+v3.get()+">"); + //logger.info("=<"+k3.toString()+","+v3.get()+">"); + // 把结果写出去 + context.write(k3,v3); + } + } + + /** + * 组装Job=Map+Reduce + */ + public static void main(String[] args) { + try{ + if(args.length!=3){ + //如果传递的参数不够,程序直接退出 + System.exit(100); + } + + //指定Job需要的配置参数 + Configuration conf = new Configuration(); + //创建一个Job + Job job = Job.getInstance(conf); + + //注意了:这一行必须设置,否则在集群中执行的时候是找不到WordCountJob这个类的 + job.setJarByClass(WordCountJobSkew.class); + + //指定输入路径(可以是文件,也可以是目录) + FileInputFormat.setInputPaths(job,new Path(args[0])); + //指定输出路径(只能指定一个不存在的目录) + FileOutputFormat.setOutputPath(job,new Path(args[1])); + + //指定map相关的代码 + job.setMapperClass(MyMapper.class); + //指定k2的类型 + job.setMapOutputKeyClass(Text.class); + //指定v2的类型 + job.setMapOutputValueClass(LongWritable.class); + + + //指定reduce相关的代码 + job.setReducerClass(MyReducer.class); + //指定k3的类型 + job.setOutputKeyClass(Text.class); + //指定v3的类型 + job.setOutputValueClass(LongWritable.class); + + //设置Reduce任务个数 + job.setNumReduceTasks(Integer.parseInt(args[2])); + + //提交job + job.waitForCompletion(true); + }catch(Exception e){ + e.printStackTrace(); + } + + } + + +} diff --git a/bigdata/hadoop/mapreduce/src/main/java/cn/cunchang/mr/WordCountJobSkewRandKey.java b/bigdata/hadoop/mapreduce/src/main/java/cn/cunchang/mr/WordCountJobSkewRandKey.java new file mode 100644 index 00000000..a5c7609c --- /dev/null +++ b/bigdata/hadoop/mapreduce/src/main/java/cn/cunchang/mr/WordCountJobSkewRandKey.java @@ -0,0 +1,153 @@ +package cn.cunchang.mr; + +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.fs.Path; +import org.apache.hadoop.io.LongWritable; +import org.apache.hadoop.io.Text; +import org.apache.hadoop.mapreduce.Job; +import org.apache.hadoop.mapreduce.Mapper; +import org.apache.hadoop.mapreduce.Reducer; +import org.apache.hadoop.mapreduce.lib.input.FileInputFormat; +import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.util.Random; + +/** + * 数据倾斜-把倾斜的数据打散 + * + * Created by xuwei + */ +public class WordCountJobSkewRandKey { + /** + * Map阶段 + */ + public static class MyMapper extends Mapper{ + Logger logger = LoggerFactory.getLogger(MyMapper.class); + Random random = new Random(); + /** + * 需要实现map函数 + * 这个map函数就是可以接收,产生 + * @param k1 + * @param v1 + * @param context + * @throws IOException + * @throws InterruptedException + */ + @Override + protected void map(LongWritable k1, Text v1, Context context) + throws IOException, InterruptedException { + //输出k1,v1的值 + //System.out.println("=<"+k1.get()+","+v1.toString()+">"); + //logger.info("=<"+k1.get()+","+v1.toString()+">"); + //k1 代表的是每一行数据的行首偏移量,v1代表的是每一行内容 + //对获取到的每一行数据进行切割,把单词切割出来 + String[] words = v1.toString().split(" "); + //把迭代出来的单词封装成的形式 + String key = words[0]; + if("5".equals(key)){ + //把倾斜的key打散,分成10份 + key= "5"+"_"+random.nextInt(10); + } + Text k2 = new Text(key); + LongWritable v2 = new LongWritable(1L); + //把写出去 + context.write(k2,v2); + } + } + + + /** + * Reduce阶段 + */ + public static class MyReducer extends Reducer{ + Logger logger = LoggerFactory.getLogger(MyReducer.class); + /** + * 针对的数据进行累加求和,并且最终把数据转化为k3,v3写出去 + * @param k2 + * @param v2s + * @param context + * @throws IOException + * @throws InterruptedException + */ + @Override + protected void reduce(Text k2, Iterable v2s, Context context) + throws IOException, InterruptedException { + //创建一个sum变量,保存v2s的和 + long sum = 0L; + //对v2s中的数据进行累加求和 + for(LongWritable v2: v2s){ + //输出k2,v2的值 + //System.out.println("=<"+k2.toString()+","+v2.get()+">"); + //logger.info("=<"+k2.toString()+","+v2.get()+">"); + sum += v2.get(); + //模拟Reduce的复杂计算消耗的时间 + if(sum%200 == 0){ + Thread.sleep(1); + } + } + + //组装k3,v3 + Text k3 = k2; + LongWritable v3 = new LongWritable(sum); + //输出k3,v3的值 + //System.out.println("=<"+k3.toString()+","+v3.get()+">"); + //logger.info("=<"+k3.toString()+","+v3.get()+">"); + // 把结果写出去 + context.write(k3,v3); + } + } + + /** + * 组装Job=Map+Reduce + */ + public static void main(String[] args) { + try{ + if(args.length!=3){ + //如果传递的参数不够,程序直接退出 + System.exit(100); + } + + //指定Job需要的配置参数 + Configuration conf = new Configuration(); + //创建一个Job + Job job = Job.getInstance(conf); + + //注意了:这一行必须设置,否则在集群中执行的时候是找不到WordCountJob这个类的 + job.setJarByClass(WordCountJobSkewRandKey.class); + + //指定输入路径(可以是文件,也可以是目录) + FileInputFormat.setInputPaths(job,new Path(args[0])); + //指定输出路径(只能指定一个不存在的目录) + FileOutputFormat.setOutputPath(job,new Path(args[1])); + + //指定map相关的代码 + job.setMapperClass(MyMapper.class); + //指定k2的类型 + job.setMapOutputKeyClass(Text.class); + //指定v2的类型 + job.setMapOutputValueClass(LongWritable.class); + + + //指定reduce相关的代码 + job.setReducerClass(MyReducer.class); + //指定k3的类型 + job.setOutputKeyClass(Text.class); + //指定v3的类型 + job.setOutputValueClass(LongWritable.class); + + //设置Reduce任务个数 + job.setNumReduceTasks(Integer.parseInt(args[2])); + + //提交job + job.waitForCompletion(true); + }catch(Exception e){ + e.printStackTrace(); + } + + } + + +} diff --git a/bigdata/hadoop/mapreduce/src/main/resources/log4j.properties b/bigdata/hadoop/mapreduce/src/main/resources/log4j.properties new file mode 100644 index 00000000..ddf8c805 --- /dev/null +++ b/bigdata/hadoop/mapreduce/src/main/resources/log4j.properties @@ -0,0 +1,9 @@ +log4j.rootLogger=info,stdout + +log4j.appender.stdout = org.apache.log4j.ConsoleAppender +log4j.appender.stdout.Target = System.out +log4j.appender.stdout.layout=org.apache.log4j.PatternLayout +log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} [%t] [%c] [%p] - %m%n + + + diff --git a/bigdata/hadoop/pom.xml b/bigdata/hadoop/pom.xml new file mode 100644 index 00000000..db28f7b5 --- /dev/null +++ b/bigdata/hadoop/pom.xml @@ -0,0 +1,17 @@ + + + 4.0.0 + + cn.cunchang + hadoop + jar + 1.0-SNAPSHOT + + + 8 + 8 + + + \ No newline at end of file diff --git a/bigdata/imooc-flink/data/access.json b/bigdata/imooc-flink/data/access.json new file mode 100644 index 00000000..a13328ff --- /dev/null +++ b/bigdata/imooc-flink/data/access.json @@ -0,0 +1,10007 @@ +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"startup","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"startup","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"startup","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"startup","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"startup","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"startup","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"startup","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195061,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195061,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195061,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195061,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195061,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195062,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195062,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195062,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195062,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195062,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"宝马"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"cart","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"户外","name":"运动包"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"华为商城","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-4444-89a7-ee7558603cfd","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_6","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"pay","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"实战Spark3实时处理掌握两套企业级处理方案"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"华为商城","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奔驰"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"pay","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"525a230a-aebd-4999-89a7-ee7558603cfc","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"车","name":"奥迪"},"time":1647195063,"uid":"user_5","version":"V1.2.4"} +{"channel":"Appstore","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"视频饮料","name":"咖啡"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df","deviceType":"iPhone 10","event":"cart","ip":"114.247.50.2","net":"5G","nu":1,"os":"iOS","product":{"category":"车","name":"保时捷"},"time":1647195063,"uid":"user_1","version":"V1.2.2"} +{"channel":"Appstore","device":"525a230a-aebd-3333-89a7-ee7558603cfe","deviceType":"小米11 Ultra","event":"cart","ip":"114.247.50.2","net":"5G","nu":0,"os":"Android","product":{"category":"户外","name":"帆布鞋"},"time":1647195063,"uid":"user_7","version":"V1.2.3"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 8","event":"browse","ip":"114.247.50.2","net":"4G","nu":0,"os":"iOS","product":{"category":"大数据实战","name":"Spark进阶大数据离线与实时项目开发"},"time":1647195063,"uid":"user_3","version":"V1.2.4"} +{"channel":"华为商城","device":"c041bc98-55c2-4fad-b4a4-ad0c79a11b78","deviceType":"iPhone 10","event":"browse","ip":"114.247.50.2","net":"5G","nu":0,"os":"iOS","product":{"category":"视频饮料","name":"五子"},"time":1647195063,"uid":"user_2","version":"V1.2.4"} +{"channel":"Appstore","device":"cad4d506-1552-4137-8c9a-067156791777","deviceType":"小米10","event":"browse","ip":"114.247.50.2","net":"5G","nu":1,"os":"Android","product":{"category":"食品饮料","name":"矿泉水"},"time":1647195063,"uid":"user_4","version":"V1.2.3"} \ No newline at end of file diff --git a/bigdata/imooc-flink/data/access.log b/bigdata/imooc-flink/data/access.log new file mode 100644 index 00000000..4ad1ae20 --- /dev/null +++ b/bigdata/imooc-flink/data/access.log @@ -0,0 +1,5 @@ +202512120010,imooc.com,2000 +202512120010,a.com,6000 +202512120010,b.com,5000 +202512120010,imooc.com,4000 +202512120010,a.com,1000 \ No newline at end of file diff --git a/bigdata/imooc-flink/data/nest/1/a.txt b/bigdata/imooc-flink/data/nest/1/a.txt new file mode 100644 index 00000000..1d5782d2 --- /dev/null +++ b/bigdata/imooc-flink/data/nest/1/a.txt @@ -0,0 +1,3 @@ +a +a +a \ No newline at end of file diff --git a/bigdata/imooc-flink/data/nest/1/b.txt b/bigdata/imooc-flink/data/nest/1/b.txt new file mode 100644 index 00000000..30ed1225 --- /dev/null +++ b/bigdata/imooc-flink/data/nest/1/b.txt @@ -0,0 +1,3 @@ +b +b +b \ No newline at end of file diff --git a/bigdata/imooc-flink/data/nest/2/c.txt b/bigdata/imooc-flink/data/nest/2/c.txt new file mode 100644 index 00000000..1cc8fc36 --- /dev/null +++ b/bigdata/imooc-flink/data/nest/2/c.txt @@ -0,0 +1,2 @@ +c +c \ No newline at end of file diff --git a/bigdata/imooc-flink/data/nest/2/d.txt b/bigdata/imooc-flink/data/nest/2/d.txt new file mode 100644 index 00000000..c59d9b63 --- /dev/null +++ b/bigdata/imooc-flink/data/nest/2/d.txt @@ -0,0 +1 @@ +d \ No newline at end of file diff --git a/bigdata/imooc-flink/data/nest/wc.txt b/bigdata/imooc-flink/data/nest/wc.txt new file mode 100644 index 00000000..6e32fced --- /dev/null +++ b/bigdata/imooc-flink/data/nest/wc.txt @@ -0,0 +1,2 @@ +pk,pk,pk +flink,flink \ No newline at end of file diff --git a/bigdata/imooc-flink/data/people.csv b/bigdata/imooc-flink/data/people.csv new file mode 100644 index 00000000..116efcd3 --- /dev/null +++ b/bigdata/imooc-flink/data/people.csv @@ -0,0 +1,3 @@ +name;age;job +Jorge;30;Developer +Bob;32;Developer \ No newline at end of file diff --git a/bigdata/imooc-flink/data/wc.data b/bigdata/imooc-flink/data/wc.data new file mode 100644 index 00000000..28d9e00f --- /dev/null +++ b/bigdata/imooc-flink/data/wc.data @@ -0,0 +1,2 @@ +pk,pk,pk,flink,flink +pk,pk,pk,flink,flink \ No newline at end of file diff --git a/bigdata/imooc-flink/data/wc.txt b/bigdata/imooc-flink/data/wc.txt new file mode 100644 index 00000000..6e32fced --- /dev/null +++ b/bigdata/imooc-flink/data/wc.txt @@ -0,0 +1,2 @@ +pk,pk,pk +flink,flink \ No newline at end of file diff --git a/bigdata/imooc-flink/imooc-clickhouse/pom.xml b/bigdata/imooc-flink/imooc-clickhouse/pom.xml new file mode 100644 index 00000000..f53174fc --- /dev/null +++ b/bigdata/imooc-flink/imooc-clickhouse/pom.xml @@ -0,0 +1,22 @@ + + + + imooc-flink + com.imooc.flink + 1.0 + + 4.0.0 + + imooc-clickhouse + + + + ru.yandex.clickhouse + clickhouse-jdbc + 0.1.54 + + + + \ No newline at end of file diff --git a/bigdata/imooc-flink/imooc-flink-basic/pom.xml b/bigdata/imooc-flink/imooc-flink-basic/pom.xml new file mode 100644 index 00000000..b62d0937 --- /dev/null +++ b/bigdata/imooc-flink/imooc-flink-basic/pom.xml @@ -0,0 +1,26 @@ + + + + imooc-flink + com.imooc.flink + 1.0 + + 4.0.0 + + imooc-flink-basic + + + + + org.apache.flink + flink-streaming-java_${scala.binary.version} + + + + org.apache.flink + flink-clients_${scala.binary.version} + + + \ No newline at end of file diff --git a/bigdata/imooc-flink/imooc-flink-basic/src/main/java/com/imooc/flink/basic/BatchWCApp.java b/bigdata/imooc-flink/imooc-flink-basic/src/main/java/com/imooc/flink/basic/BatchWCApp.java new file mode 100644 index 00000000..3c2b07ad --- /dev/null +++ b/bigdata/imooc-flink/imooc-flink-basic/src/main/java/com/imooc/flink/basic/BatchWCApp.java @@ -0,0 +1,45 @@ +package com.imooc.flink.basic; + +import org.apache.flink.api.common.functions.FlatMapFunction; +import org.apache.flink.api.common.functions.MapFunction; +import org.apache.flink.api.java.ExecutionEnvironment; +import org.apache.flink.api.java.operators.DataSource; +import org.apache.flink.api.java.tuple.Tuple2; +import org.apache.flink.util.Collector; + +/** + * 第一个基于Flink批处理快速入门案例 + */ +public class BatchWCApp { + + public static void main(String[] args) throws Exception { + ExecutionEnvironment environment = ExecutionEnvironment.getExecutionEnvironment(); + + DataSource source = environment.readTextFile("data/wc.data"); + + source.flatMap(new PKFlatMapFunction()) + .map(new PKMapFunction()) + .groupBy(0) + .sum(1) + .print(); + + } +} + +class PKFlatMapFunction implements FlatMapFunction { + + @Override + public void flatMap(String value, Collector out) throws Exception { + String[] words = value.split(","); + for(String word : words) { + out.collect(word.toLowerCase().trim()); + } + } +} + +class PKMapFunction implements MapFunction> { + @Override + public Tuple2 map(String value) throws Exception { + return new Tuple2<>(value, 1); + } +} \ No newline at end of file diff --git a/bigdata/imooc-flink/imooc-flink-basic/src/main/java/com/imooc/flink/basic/StreamingWCApp.java b/bigdata/imooc-flink/imooc-flink-basic/src/main/java/com/imooc/flink/basic/StreamingWCApp.java new file mode 100644 index 00000000..1a2f0c7e --- /dev/null +++ b/bigdata/imooc-flink/imooc-flink-basic/src/main/java/com/imooc/flink/basic/StreamingWCApp.java @@ -0,0 +1,54 @@ +package com.imooc.flink.basic; + +import org.apache.commons.lang3.StringUtils; +import org.apache.flink.api.common.functions.FilterFunction; +import org.apache.flink.api.common.functions.FlatMapFunction; +import org.apache.flink.api.common.functions.MapFunction; +import org.apache.flink.api.java.functions.KeySelector; +import org.apache.flink.api.java.tuple.Tuple2; +import org.apache.flink.streaming.api.datastream.DataStreamSource; +import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; +import org.apache.flink.util.Collector; + +/** + * 第一个基于Flink实时处理快速入门案例 + */ +public class StreamingWCApp { + public static void main(String[] args) throws Exception { + + // 创建上下文 + StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); + + // 对接数据源的数据 + DataStreamSource source = env.socketTextStream("localhost", 9527); + + // 业务逻辑处理: transformation + source.flatMap(new FlatMapFunction() { + @Override + public void flatMap(String value, Collector out) throws Exception { + String[] words = value.split(","); + for(String word : words) { + out.collect(word.toLowerCase().trim()); + } + } + }).filter(new FilterFunction() { + @Override + public boolean filter(String value) throws Exception { + return StringUtils.isNotEmpty(value); + } + }).map(new MapFunction>() { + @Override + public Tuple2 map(String value) throws Exception { + return new Tuple2<>(value, 1); + } + }).keyBy(new KeySelector, String>() { + @Override + public String getKey(Tuple2 value) throws Exception { + return value.f0; + } + }).sum(1) + .print(); + + env.execute("StreamgingWCApp"); + } +} diff --git a/bigdata/imooc-flink/imooc-flink-dataset/pom.xml b/bigdata/imooc-flink/imooc-flink-dataset/pom.xml new file mode 100644 index 00000000..32391353 --- /dev/null +++ b/bigdata/imooc-flink/imooc-flink-dataset/pom.xml @@ -0,0 +1,26 @@ + + + + imooc-flink + com.imooc.flink + 1.0 + + 4.0.0 + + imooc-flink-dataset + + + + org.apache.flink + flink-streaming-java_${scala.binary.version} + + + + org.apache.flink + flink-clients_${scala.binary.version} + + + + \ No newline at end of file diff --git a/bigdata/imooc-flink/imooc-flink-datastream/README.md b/bigdata/imooc-flink/imooc-flink-datastream/README.md new file mode 100644 index 00000000..654ffdce --- /dev/null +++ b/bigdata/imooc-flink/imooc-flink-datastream/README.md @@ -0,0 +1,49 @@ +# 1、source +数据源 +SourceApp +- test01,官方提供数据源实现,socketTextStream数据源 +- test02,官方提供数据源实现,数值序列迭代器数据源 +- test03,自定义数据源,SourceFunction、ParallelSourceFunction +- test04,自定义数据源,RichSourceFunction +- test05,官方提供数据源实现,kafka + + +# 2、transformation +算子处理数据源 +TransformationApp + + +# 3、partitioner +分区,让某个并行度只处理某个分区数据 +PartitionerApp + +# 4、sink +输出算子处理结果 +SinkApp +- PKMySQLSink,输出到mysql +- PKRedisSink,输出到redis + + +# 5、windows +无界流按窗口拆成有界流 + +WindowApp +- test01 window实例 +- test02 窗口函数,增量 reduce +- test03 窗口函数,全量 ProcessWindowFunction + +# 6、wm +watermark + +EventTimeWMApp,延迟窗口,以及对延迟数据处理 + +# 7、state +状态 +- Keyed State +- 算子状态 (Operator State) ,Kafka consumer 每个并行实例维护了 topic partitions 和偏移量的 map 作为它的算子状态。 + +StateApp,state使用 + + + + diff --git a/bigdata/imooc-flink/imooc-flink-datastream/pom.xml b/bigdata/imooc-flink/imooc-flink-datastream/pom.xml new file mode 100644 index 00000000..e5f11979 --- /dev/null +++ b/bigdata/imooc-flink/imooc-flink-datastream/pom.xml @@ -0,0 +1,51 @@ + + + + imooc-flink + com.imooc.flink + 1.0 + + 4.0.0 + + imooc-flink-datastream + + + + org.apache.flink + flink-streaming-java_${scala.binary.version} + + + + org.apache.flink + flink-clients_${scala.binary.version} + + + + org.apache.logging.log4j + log4j-core + ${log4j.version} + + + + mysql + mysql-connector-java + 5.1.47 + + + + org.apache.bahir + flink-connector-redis_2.11 + 1.0 + + + + org.apache.flink + flink-connector-kafka_${scala.binary.version} + ${flink.version} + + + + + \ No newline at end of file diff --git a/bigdata/imooc-flink/imooc-flink-datastream/src/main/java/com/imooc/flink/partitioner/PKPartitioner.java b/bigdata/imooc-flink/imooc-flink-datastream/src/main/java/com/imooc/flink/partitioner/PKPartitioner.java new file mode 100644 index 00000000..0490f196 --- /dev/null +++ b/bigdata/imooc-flink/imooc-flink-datastream/src/main/java/com/imooc/flink/partitioner/PKPartitioner.java @@ -0,0 +1,19 @@ +package com.imooc.flink.partitioner; + +import org.apache.flink.api.common.functions.Partitioner; + +public class PKPartitioner implements Partitioner{ + @Override + public int partition(String key, int numPartitions) { + + System.out.println("numPartitions:" + numPartitions); + + if("imooc.com".equals(key)) { + return 0; + } else if("a.com".equals(key)) { + return 1; + } else { + return 2; + } + } +} diff --git a/bigdata/imooc-flink/imooc-flink-datastream/src/main/java/com/imooc/flink/partitioner/PartitionerApp.java b/bigdata/imooc-flink/imooc-flink-datastream/src/main/java/com/imooc/flink/partitioner/PartitionerApp.java new file mode 100644 index 00000000..973f890c --- /dev/null +++ b/bigdata/imooc-flink/imooc-flink-datastream/src/main/java/com/imooc/flink/partitioner/PartitionerApp.java @@ -0,0 +1,36 @@ +package com.imooc.flink.partitioner; + +import com.imooc.flink.source.AccessSourceV2; +import com.imooc.flink.transformation.Access; +import org.apache.flink.api.common.functions.MapFunction; +import org.apache.flink.api.java.tuple.Tuple2; +import org.apache.flink.streaming.api.datastream.DataStreamSource; +import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; + +public class PartitionerApp { + public static void main(String[] args) throws Exception{ + StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); + env.setParallelism(3); + DataStreamSource source = env.addSource(new AccessSourceV2()); + System.out.println(source.getParallelism()); + + source.map(new MapFunction>() { + @Override + public Tuple2 map(Access value) throws Exception { + return Tuple2.of(value.getDomain(), value); + } + }).partitionCustom(new PKPartitioner(), 0) + .map(new MapFunction, Access>() { + @Override + public Access map(Tuple2 value) throws Exception { + + System.out.println("current thread id is:" + Thread.currentThread().getId()+ ", value is:" + value.f1); + + return value.f1; + } + }).print(); + + + env.execute("PartitionerApp"); + } +} diff --git a/bigdata/imooc-flink/imooc-flink-datastream/src/main/java/com/imooc/flink/sink/PKMySQLSink.java b/bigdata/imooc-flink/imooc-flink-datastream/src/main/java/com/imooc/flink/sink/PKMySQLSink.java new file mode 100644 index 00000000..a268ce3f --- /dev/null +++ b/bigdata/imooc-flink/imooc-flink-datastream/src/main/java/com/imooc/flink/sink/PKMySQLSink.java @@ -0,0 +1,61 @@ +package com.imooc.flink.sink; + +import com.imooc.flink.utils.MySQLUtils; +import org.apache.flink.api.java.tuple.Tuple2; +import org.apache.flink.configuration.Configuration; +import org.apache.flink.streaming.api.functions.sink.RichSinkFunction; +import org.apache.flink.streaming.api.functions.sink.SinkFunction; + +import java.sql.Connection; +import java.sql.PreparedStatement; + +/** + * domain traffic + */ +public class PKMySQLSink extends RichSinkFunction> { + + + Connection connection; + PreparedStatement insertPstmt; + PreparedStatement updatePstmt; + + + @Override + public void open(Configuration parameters) throws Exception { + super.open(parameters); + + connection = MySQLUtils.getConnection(); + insertPstmt = connection.prepareStatement("insert into pk_traffic(domain,traffic) values (?,?)"); + updatePstmt = connection.prepareStatement("update pk_traffic set traffic=? where domain=?"); + + } + + @Override + public void close() throws Exception { + super.close(); + if(insertPstmt != null) insertPstmt.close(); + if(updatePstmt != null) updatePstmt.close(); + if(connection != null) connection.close(); + } + + /** + * 来一条数据就执行一次 + * + * 1000w的数据 1000w次 + */ + @Override + public void invoke(Tuple2 value, Context context) throws Exception { + System.out.println("=====invoke======" + value.f0 + "-->" + value.f1); + + updatePstmt.setDouble(1, value.f1); + updatePstmt.setString(2 , value.f0); + updatePstmt.execute(); + + if(updatePstmt.getUpdateCount() == 0) { + insertPstmt.setString(1, value.f0); + insertPstmt.setDouble(2, value.f1); + insertPstmt.execute(); + } + + } +} diff --git a/bigdata/imooc-flink/imooc-flink-datastream/src/main/java/com/imooc/flink/sink/PKRedisSink.java b/bigdata/imooc-flink/imooc-flink-datastream/src/main/java/com/imooc/flink/sink/PKRedisSink.java new file mode 100644 index 00000000..a02910d7 --- /dev/null +++ b/bigdata/imooc-flink/imooc-flink-datastream/src/main/java/com/imooc/flink/sink/PKRedisSink.java @@ -0,0 +1,36 @@ +package com.imooc.flink.sink; + +import org.apache.flink.api.java.tuple.Tuple2; +import org.apache.flink.streaming.connectors.redis.common.mapper.RedisCommand; +import org.apache.flink.streaming.connectors.redis.common.mapper.RedisCommandDescription; +import org.apache.flink.streaming.connectors.redis.common.mapper.RedisMapper; + +/** + * 在生产环境中, + * + * 软件的版本做了升级 + * 代码有了很大变化 + * + * ==> diff + * + * + */ +public class PKRedisSink implements RedisMapper> { + + @Override + public RedisCommandDescription getCommandDescription() { + return new RedisCommandDescription(RedisCommand.HSET, "pk-traffic"); + } + + @Override + public String getKeyFromData(Tuple2 data) { + return data.f0; + } + + @Override + public String getValueFromData(Tuple2 data) { + return data.f1 +""; + } +} + + diff --git a/bigdata/imooc-flink/imooc-flink-datastream/src/main/java/com/imooc/flink/sink/SinkApp.java b/bigdata/imooc-flink/imooc-flink-datastream/src/main/java/com/imooc/flink/sink/SinkApp.java new file mode 100644 index 00000000..a411fccd --- /dev/null +++ b/bigdata/imooc-flink/imooc-flink-datastream/src/main/java/com/imooc/flink/sink/SinkApp.java @@ -0,0 +1,75 @@ +package com.imooc.flink.sink; + +import com.imooc.flink.transformation.Access; +import org.apache.flink.api.common.functions.MapFunction; +import org.apache.flink.api.java.functions.KeySelector; +import org.apache.flink.api.java.tuple.Tuple2; +import org.apache.flink.streaming.api.datastream.DataStreamSource; +import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator; +import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; +import org.apache.flink.streaming.connectors.redis.RedisSink; +import org.apache.flink.streaming.connectors.redis.common.config.FlinkJedisPoolConfig; + +public class SinkApp { + + public static void main(String[] args) throws Exception { + StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); + + + toMySQL(env); + + env.execute("SinkApp"); + } + + public static void toMySQL(StreamExecutionEnvironment env) { + + DataStreamSource source = env.readTextFile("data/access.log"); + + SingleOutputStreamOperator mapStream = source.map(new MapFunction() { + @Override + public Access map(String value) throws Exception { + String[] splits = value.split(","); + Long time = Long.parseLong(splits[0].trim()); + String domain = splits[1].trim(); + Double traffic = Double.parseDouble(splits[2].trim()); + + return new Access(time, domain, traffic); + } + }); + + SingleOutputStreamOperator result = mapStream.keyBy(new KeySelector() { + @Override + public String getKey(Access value) throws Exception { + return value.getDomain(); + } + }).sum("traffic"); + + result.print(); + + // mysql + result.map(new MapFunction>() { + @Override + public Tuple2 map(Access value) throws Exception { + return Tuple2.of(value.getDomain(), value.getTraffic()); + } + }).addSink(new PKMySQLSink()); + + // redis +// FlinkJedisPoolConfig conf = new FlinkJedisPoolConfig.Builder().setHost("127.0.0.1").build(); +// result.map(new MapFunction>() { +// @Override +// public Tuple2 map(Access value) throws Exception { +// return Tuple2.of(value.getDomain(), value.getTraffic()); +// } +// }).addSink(new RedisSink>(conf, new PKRedisSink())); + } + + + public static void print(StreamExecutionEnvironment env) { + DataStreamSource source = env.socketTextStream("localhost", 9527); + + System.out.println("source:" + source.getParallelism()); + + source.print().setParallelism(2); + } +} diff --git a/bigdata/imooc-flink/imooc-flink-datastream/src/main/java/com/imooc/flink/source/AccessSource.java b/bigdata/imooc-flink/imooc-flink-datastream/src/main/java/com/imooc/flink/source/AccessSource.java new file mode 100644 index 00000000..8a3553d9 --- /dev/null +++ b/bigdata/imooc-flink/imooc-flink-datastream/src/main/java/com/imooc/flink/source/AccessSource.java @@ -0,0 +1,37 @@ +package com.imooc.flink.source; + +import com.imooc.flink.transformation.Access; +import org.apache.flink.streaming.api.functions.source.SourceFunction; + +import java.util.Random; + +public class AccessSource implements SourceFunction { + + boolean running = true; + + @Override + public void run(SourceContext ctx) throws Exception { + + String[] domains = {"imooc.com", "a.com","b.com"}; + + Random random = new Random(); + + while (running) { + for (int i = 0; i < 10 ; i++) { + Access access = new Access(); + access.setTime(1234567L); + access.setDomain(domains[random.nextInt(domains.length)]); + access.setTraffic(random.nextDouble() + 1000); + + ctx.collect(access); + } + + Thread.sleep(5000); + } + } + + @Override + public void cancel() { + running = false; + } +} diff --git a/bigdata/imooc-flink/imooc-flink-datastream/src/main/java/com/imooc/flink/source/AccessSourceV2.java b/bigdata/imooc-flink/imooc-flink-datastream/src/main/java/com/imooc/flink/source/AccessSourceV2.java new file mode 100644 index 00000000..d8504e6e --- /dev/null +++ b/bigdata/imooc-flink/imooc-flink-datastream/src/main/java/com/imooc/flink/source/AccessSourceV2.java @@ -0,0 +1,38 @@ +package com.imooc.flink.source; + +import com.imooc.flink.transformation.Access; +import org.apache.flink.streaming.api.functions.source.ParallelSourceFunction; +import org.apache.flink.streaming.api.functions.source.SourceFunction; + +import java.util.Random; + +public class AccessSourceV2 implements ParallelSourceFunction { + + boolean running = true; + + @Override + public void run(SourceContext ctx) throws Exception { + + String[] domains = {"imooc.com", "a.com","b.com"}; + + Random random = new Random(); + + while (running) { + for (int i = 0; i < 10 ; i++) { + Access access = new Access(); + access.setTime(1234567L); + access.setDomain(domains[random.nextInt(domains.length)]); + access.setTraffic(random.nextDouble() + 1000); + + ctx.collect(access); + } + + Thread.sleep(5000); + } + } + + @Override + public void cancel() { + running = false; + } +} diff --git a/bigdata/imooc-flink/imooc-flink-datastream/src/main/java/com/imooc/flink/source/SourceApp.java b/bigdata/imooc-flink/imooc-flink-datastream/src/main/java/com/imooc/flink/source/SourceApp.java new file mode 100644 index 00000000..ba1a74bb --- /dev/null +++ b/bigdata/imooc-flink/imooc-flink-datastream/src/main/java/com/imooc/flink/source/SourceApp.java @@ -0,0 +1,106 @@ +package com.imooc.flink.source; + +import com.imooc.flink.transformation.Access; +import org.apache.flink.api.common.functions.FilterFunction; +import org.apache.flink.api.common.serialization.SimpleStringSchema; +import org.apache.flink.streaming.api.datastream.DataStream; +import org.apache.flink.streaming.api.datastream.DataStreamSource; +import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator; +import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; +import org.apache.flink.streaming.connectors.kafka.FlinkKafkaConsumer; +import org.apache.flink.util.NumberSequenceIterator; + +import java.util.Properties; + +public class SourceApp { + + public static void main(String[] args) throws Exception { + // 创建上下文 + StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); + +// test01(env); +// test02(env); +// test03(env); + test04(env); +// test05(env); + env.execute("SourceApp"); + } + + public static void test05(StreamExecutionEnvironment env) { + + Properties properties = new Properties(); + properties.setProperty("bootstrap.servers", "localhost:9092"); + properties.setProperty("group.id", "test"); + DataStream stream = env + .addSource(new FlinkKafkaConsumer<>("flinktopic", new SimpleStringSchema(), properties)); + + System.out.println(stream.getParallelism()); + stream.print(); + } + + public static void test04(StreamExecutionEnvironment env) { + DataStreamSource source = env.addSource(new StudentSource()).setParallelism(1); + System.out.println(source.getParallelism()); + source.print(); + } + + public static void test03(StreamExecutionEnvironment env) { + + DataStreamSource source = env.addSource(new AccessSource()).setParallelism(1); +// DataStreamSource source = env.addSource(new AccessSourceV2()).setParallelism(3); + System.out.println(source.getParallelism()); + source.print(); + } + + public static void test02(StreamExecutionEnvironment env) { + + env.setParallelism(5); // 对于env设置的并行度 是一个全局的概念 + + DataStreamSource source = env.fromParallelCollection( + new NumberSequenceIterator(1, 10), Long.class + );//.setParallelism(4); + + System.out.println("source:" + source.getParallelism()); + + SingleOutputStreamOperator filterStream = source.filter(new FilterFunction() { + @Override + public boolean filter(Long value) throws Exception { + return value >= 5; + } + }).setParallelism(3); // 对于算子层面的并行度,如果全局设置,以本算子的并行度为准 + System.out.println("filterStream:" + filterStream.getParallelism()); + + filterStream.print(); + + } + + + public static void test01(StreamExecutionEnvironment env) { + + env.setParallelism(5); + +// StreamExecutionEnvironment.createLocalEnvironment(); +// StreamExecutionEnvironment.createLocalEnvironment(3); +// StreamExecutionEnvironment.createLocalEnvironment(new Configuration()); +// StreamExecutionEnvironment.createLocalEnvironmentWithWebUI(new Configuration()); +// StreamExecutionEnvironment.createRemoteEnvironment() + + DataStreamSource source = env.socketTextStream("localhost", 9527); + System.out.println("source...." + source.getParallelism()); // ? 1 + + // 接收socket过来的数据,一行一个单词, 把pk的过滤掉 + SingleOutputStreamOperator filterStream = source.filter(new FilterFunction() { + @Override + public boolean filter(String value) throws Exception { + return !"pk".equals(value); + } +// }); + }).setParallelism(6); + + + System.out.println("filter...." + filterStream.getParallelism()); + + + filterStream.print(); + } +} diff --git a/bigdata/imooc-flink/imooc-flink-datastream/src/main/java/com/imooc/flink/source/Student.java b/bigdata/imooc-flink/imooc-flink-datastream/src/main/java/com/imooc/flink/source/Student.java new file mode 100644 index 00000000..720df946 --- /dev/null +++ b/bigdata/imooc-flink/imooc-flink-datastream/src/main/java/com/imooc/flink/source/Student.java @@ -0,0 +1,49 @@ +package com.imooc.flink.source; + +public class Student { + private int id; + private String name; + private int age; + + public Student() { + } + + @Override + public String toString() { + return "Student{" + + "id=" + id + + ", name='" + name + '\'' + + ", age=" + age + + '}'; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + public Student(int id, String name, int age) { + this.id = id; + this.name = name; + this.age = age; + } +} diff --git a/bigdata/imooc-flink/imooc-flink-datastream/src/main/java/com/imooc/flink/source/StudentSource.java b/bigdata/imooc-flink/imooc-flink-datastream/src/main/java/com/imooc/flink/source/StudentSource.java new file mode 100644 index 00000000..7316606b --- /dev/null +++ b/bigdata/imooc-flink/imooc-flink-datastream/src/main/java/com/imooc/flink/source/StudentSource.java @@ -0,0 +1,43 @@ +package com.imooc.flink.source; + +import com.imooc.flink.utils.MySQLUtils; +import org.apache.flink.configuration.Configuration; +import org.apache.flink.streaming.api.functions.source.RichSourceFunction; +import org.apache.flink.streaming.api.functions.source.SourceFunction; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; + +public class StudentSource extends RichSourceFunction { + + Connection connection; + PreparedStatement psmt; + + @Override + public void open(Configuration parameters) throws Exception { + connection = MySQLUtils.getConnection(); + psmt = connection.prepareStatement("select * from student"); + } + + @Override + public void close() throws Exception { + MySQLUtils.close(connection, psmt); + } + + @Override + public void run(SourceContext ctx) throws Exception { + ResultSet rs = psmt.executeQuery(); + while (rs.next()) { + int id = rs.getInt("id"); + String name = rs.getString("name"); + int age = rs.getInt("age"); + ctx.collect(new Student(id, name, age)); + } + } + + @Override + public void cancel() { + + } +} diff --git a/bigdata/imooc-flink/imooc-flink-datastream/src/main/java/com/imooc/flink/state/CheckpointApp.java b/bigdata/imooc-flink/imooc-flink-datastream/src/main/java/com/imooc/flink/state/CheckpointApp.java new file mode 100644 index 00000000..17d3b7e4 --- /dev/null +++ b/bigdata/imooc-flink/imooc-flink-datastream/src/main/java/com/imooc/flink/state/CheckpointApp.java @@ -0,0 +1,99 @@ +package com.imooc.flink.state; + +import org.apache.flink.api.common.functions.FlatMapFunction; +import org.apache.flink.api.common.functions.MapFunction; +import org.apache.flink.api.common.restartstrategy.RestartStrategies; +import org.apache.flink.api.common.time.Time; +import org.apache.flink.api.java.tuple.Tuple2; +import org.apache.flink.runtime.state.filesystem.FsStateBackend; +import org.apache.flink.streaming.api.datastream.DataStreamSource; +import org.apache.flink.streaming.api.environment.CheckpointConfig; +import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; +import org.apache.flink.util.Collector; + +import java.util.concurrent.TimeUnit; + +public class CheckpointApp { + public static void main(String[] args) throws Exception { +// System.setProperty("HADOOP_USER_NAME", "hadoop"); + + StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); +// test1(env); + test2(env); + + env.execute("CheckpointApp"); + } + + private static void test1(StreamExecutionEnvironment env) { + + env.enableCheckpointing(5000); + + DataStreamSource streamSource = env.socketTextStream("localhost", 9527); + + streamSource + .print(); + + } + + private static void test2(StreamExecutionEnvironment env) { + /** + * 不开启checkpoint:不重启 + * + * 开启了checkpoint + * 1) 没有配置重启策略:Integer.MAX_VALUE + * 2) 如果配置了重启策略,就使用我们配置的重启策略覆盖默认的 + * + * 重启策略的配置: + * 1) code + * 2) yaml + * + */ + env.enableCheckpointing(5000); +// env.enableCheckpointing(5000, CheckpointingMode.EXACTLY_ONCE); + + // 是否保留Checkpoint; + env.getCheckpointConfig().enableExternalizedCheckpoints(CheckpointConfig.ExternalizedCheckpointCleanup.RETAIN_ON_CANCELLATION); + + // 设置StateBackend + env.setStateBackend(new FsStateBackend("file:///D:\\tmp\\imooc-flink\\checkpoints")); + + +// env.setStateBackend(new FsStateBackend("hdfs://ruozedata001:8020/imooc-flink-checkpoints")); + + // 自定义设置我们需要的重启策略 + env.setRestartStrategy(RestartStrategies.fixedDelayRestart( + 3, // 尝试重启的次数 + Time.of(5, TimeUnit.SECONDS) // 间隔 + )); + + + DataStreamSource source = env.socketTextStream("localhost", 9527); + source.map(new MapFunction() { + @Override + public String map(String value) throws Exception { + if (value.contains("pk")) { + throw new RuntimeException("PK哥来了,快跑.."); + } else { + return value.toLowerCase(); + } + } + }) + .flatMap(new FlatMapFunction() { + @Override + public void flatMap(String value, Collector out) throws Exception { + String[] splits = value.split(","); + for (String split : splits) { + out.collect(split); + } + } + }).map(new MapFunction>() { + @Override + public Tuple2 map(String value) throws Exception { + return Tuple2.of(value, 1); + } + }).keyBy(x -> x.f0) + .sum(1) + + .print(); + } +} diff --git a/bigdata/imooc-flink/imooc-flink-datastream/src/main/java/com/imooc/flink/state/StateApp.java b/bigdata/imooc-flink/imooc-flink-datastream/src/main/java/com/imooc/flink/state/StateApp.java new file mode 100644 index 00000000..4760b5b1 --- /dev/null +++ b/bigdata/imooc-flink/imooc-flink-datastream/src/main/java/com/imooc/flink/state/StateApp.java @@ -0,0 +1,123 @@ +package com.imooc.flink.state; + +import org.apache.flink.api.common.functions.RichFlatMapFunction; +import org.apache.flink.api.common.state.MapState; +import org.apache.flink.api.common.state.MapStateDescriptor; +import org.apache.flink.api.common.state.ValueState; +import org.apache.flink.api.common.state.ValueStateDescriptor; +import org.apache.flink.api.common.typeinfo.Types; +import org.apache.flink.api.java.tuple.Tuple2; +import org.apache.flink.configuration.Configuration; +import org.apache.flink.shaded.guava18.com.google.common.collect.Lists; +import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; +import org.apache.flink.util.Collector; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +public class StateApp { + + public static void main(String[] args) throws Exception { + StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); + + + test01(env); + + env.execute("SourceApp"); + } + + /** + * 使用ValueState实现平均数 + */ + public static void test01(StreamExecutionEnvironment env) throws Exception { + List> list = new ArrayList<>(); + list.add(Tuple2.of(1L, 3L)); + list.add(Tuple2.of(1L, 7L)); + list.add(Tuple2.of(2L, 4L)); + list.add(Tuple2.of(1L, 5L)); + list.add(Tuple2.of(1L, 15L)); + list.add(Tuple2.of(2L, 2L)); + list.add(Tuple2.of(2L, 5L)); + + env.fromCollection(list) + .keyBy(x -> x.f0) +// .flatMap(new AvgWithValueState()) + .flatMap(new AvgWithMapState()) + .print(); + + } +} + + +class AvgWithMapState extends RichFlatMapFunction ,Tuple2> { + + private transient MapState mapState; + + @Override + public void open(Configuration parameters) throws Exception { + MapStateDescriptor descriptor = new MapStateDescriptor("avg", String.class, Long.class); + mapState = getRuntimeContext().getMapState(descriptor); + } + + @Override + public void flatMap(Tuple2 value, Collector> out) throws Exception { + mapState.put(UUID.randomUUID().toString(), value.f1); + + ArrayList elements = Lists.newArrayList(mapState.values()); + + if(elements.size() == 3) { + Long count = 0L; + Long sum = 0L; + + for (Long element : elements) { + count += 1; + sum += element; + } + + Double avg = sum / count.doubleValue(); + out.collect(Tuple2.of(value.f0, avg)); + + mapState.clear(); + } + } +} + +class AvgWithValueState extends RichFlatMapFunction,Tuple2> { + + // 求平均数:记录条数 总和 + private transient ValueState> sum; + + @Override + public void open(Configuration parameters) throws Exception { + + ValueStateDescriptor> descriptor + = new ValueStateDescriptor<>("avg", Types.TUPLE(Types.LONG, Types.LONG)); + + sum = getRuntimeContext().getState(descriptor); + } + + @Override + public void flatMap(Tuple2 value, Collector> out) throws Exception { + // TODO... ==> state 次数 和 总和 + + Tuple2 currentState = sum.value(); + + if(null == currentState) { + currentState = Tuple2.of(0L,0L); + } + + currentState.f0 += 1; // 次数 + currentState.f1 += value.f1; // 求和 + + + sum.update(currentState); + + // 达到3条数据 ==> 求平均数 clear + if(currentState.f0 >=3 ){ + // key,平均数 + out.collect(Tuple2.of(value.f0, currentState.f1/currentState.f0.doubleValue())); + sum.clear(); + } + } +} diff --git a/bigdata/imooc-flink/imooc-flink-datastream/src/main/java/com/imooc/flink/transformation/Access.java b/bigdata/imooc-flink/imooc-flink-datastream/src/main/java/com/imooc/flink/transformation/Access.java new file mode 100644 index 00000000..d9301d5e --- /dev/null +++ b/bigdata/imooc-flink/imooc-flink-datastream/src/main/java/com/imooc/flink/transformation/Access.java @@ -0,0 +1,49 @@ +package com.imooc.flink.transformation; + +public class Access { + private Long time; + private String domain; + private Double traffic; + + public Access() { + } + + public Access(Long time, String domain, Double traffic) { + this.time = time; + this.domain = domain; + this.traffic = traffic; + } + + @Override + public String toString() { + return "Access{" + + "time=" + time + + ", domain='" + domain + '\'' + + ", traffic=" + traffic + + '}'; + } + + public Long getTime() { + return time; + } + + public void setTime(Long time) { + this.time = time; + } + + public String getDomain() { + return domain; + } + + public void setDomain(String domain) { + this.domain = domain; + } + + public Double getTraffic() { + return traffic; + } + + public void setTraffic(Double traffic) { + this.traffic = traffic; + } +} diff --git a/bigdata/imooc-flink/imooc-flink-datastream/src/main/java/com/imooc/flink/transformation/PKMapFunction.java b/bigdata/imooc-flink/imooc-flink-datastream/src/main/java/com/imooc/flink/transformation/PKMapFunction.java new file mode 100644 index 00000000..49e5ef7a --- /dev/null +++ b/bigdata/imooc-flink/imooc-flink-datastream/src/main/java/com/imooc/flink/transformation/PKMapFunction.java @@ -0,0 +1,46 @@ +package com.imooc.flink.transformation; + +import org.apache.flink.api.common.functions.RichMapFunction; +import org.apache.flink.api.common.functions.RuntimeContext; +import org.apache.flink.configuration.Configuration; + +public class PKMapFunction extends RichMapFunction { + + /** + * 初始化操作;初始化几次与并行度有关 + * Connection + */ + @Override + public void open(Configuration parameters) throws Exception { + super.open(parameters); + System.out.println("~~~~open~~~~"); + } + + /** + * 清理操作 + */ + @Override + public void close() throws Exception { + super.close(); + System.out.println("~~~~close~~~~"); + } + + @Override + public RuntimeContext getRuntimeContext() { + return super.getRuntimeContext(); + } + + /** + * 每条数据执行一次 + */ + @Override + public Access map(String value) throws Exception { + System.out.println("=====map====="); + + String[] splits = value.split(","); + Long time = Long.parseLong(splits[0].trim()); + String domain = splits[1].trim(); + Double traffic = Double.parseDouble(splits[2].trim()); + return new Access(time, domain, traffic); + } +} \ No newline at end of file diff --git a/bigdata/imooc-flink/imooc-flink-datastream/src/main/java/com/imooc/flink/transformation/TransformationApp.java b/bigdata/imooc-flink/imooc-flink-datastream/src/main/java/com/imooc/flink/transformation/TransformationApp.java new file mode 100644 index 00000000..f6314588 --- /dev/null +++ b/bigdata/imooc-flink/imooc-flink-datastream/src/main/java/com/imooc/flink/transformation/TransformationApp.java @@ -0,0 +1,317 @@ +package com.imooc.flink.transformation; + +import com.imooc.flink.source.AccessSource; +import org.apache.flink.api.common.functions.FilterFunction; +import org.apache.flink.api.common.functions.FlatMapFunction; +import org.apache.flink.api.common.functions.MapFunction; +import org.apache.flink.api.common.functions.ReduceFunction; +import org.apache.flink.api.java.functions.KeySelector; +import org.apache.flink.api.java.tuple.Tuple2; +import org.apache.flink.streaming.api.datastream.*; +import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; +import org.apache.flink.streaming.api.functions.co.CoFlatMapFunction; +import org.apache.flink.streaming.api.functions.co.CoMapFunction; +import org.apache.flink.util.Collector; + +import java.util.ArrayList; + +public class TransformationApp { + + public static void main(String[] args) throws Exception { + StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); + + +// map(env); +// filter(env); +// flatMap(env); +// keyBy(env); +// reduce(env); + +// richMap(env); +// union(env); +// connect(env); +// coMap(env); + coFlatMap(env); + + env.execute("SourceApp"); + } + + public static void coFlatMap(StreamExecutionEnvironment env) { + DataStreamSource stream1 = env.fromElements("a b c", "d e f"); + DataStreamSource stream2 = env.fromElements("1,2,3", "4,5,6"); + + stream1.connect(stream2) + .flatMap(new CoFlatMapFunction() { + @Override + public void flatMap1(String value, Collector out) throws Exception { + String[] splits = value.split(" "); + for(String split : splits) { + out.collect(split); + } + } + + @Override + public void flatMap2(String value, Collector out) throws Exception { + String[] splits = value.split(","); + for(String split : splits) { + out.collect(split); + } + } + }).print(); + } + + public static void coMap(StreamExecutionEnvironment env) { + DataStreamSource stream1 = env.socketTextStream("localhost", 9527); + SingleOutputStreamOperator stream2 = env.socketTextStream("localhost", 9528) // 数值类型 + .map(new MapFunction() { + @Override + public Integer map(String value) throws Exception { + return Integer.parseInt(value); + } + }); + + // 将2个流连接在一起 + stream1.connect(stream2).map(new CoMapFunction() { + + // 处理第一个流的业务逻辑 + @Override + public String map1(String value) throws Exception { + return value.toUpperCase(); + } + + // 处理第二个流的业务逻辑 + @Override + public String map2(Integer value) throws Exception { + return value * 10 + ""; + } + }).print(); + } + + /** + * union 多流合并 数据结构必须相同 + * connect 双流 数据结构可以不同, 更加灵活 + */ + public static void connect(StreamExecutionEnvironment env) { + + DataStreamSource stream1 = env.addSource(new AccessSource()); + DataStreamSource stream2 = env.addSource(new AccessSource()); + + SingleOutputStreamOperator> stream2new = stream2.map(new MapFunction>() { + @Override + public Tuple2 map(Access value) throws Exception { + return Tuple2.of("pk", value); + } + }); + + stream1.connect(stream2new).map(new CoMapFunction, String>() { + @Override + public String map1(Access value) throws Exception { + return value.toString(); + } + + @Override + public String map2(Tuple2 value) throws Exception { + return value.f0 + "==>" + value.f1.toString(); + } + }).print(); + +// ConnectedStreams connect = stream1.connect(stream2); +// +// connect.map(new CoMapFunction() { +// @Override +// public Access map1(Access value) throws Exception { +// return value; +// } +// +// @Override +// public Access map2(Access value) throws Exception { +// return value; +// } +// }).print(); + + } + + + public static void union(StreamExecutionEnvironment env) { + + DataStreamSource stream1 = env.socketTextStream("localhost", 9527); + DataStreamSource stream2 = env.socketTextStream("localhost", 9528); + + DataStream union = stream1.union(stream2); +// stream1.union(stream2).print(); + stream1.union(stream1).print(); + } + + public static void richMap(StreamExecutionEnvironment env) { + env.setParallelism(3); + DataStreamSource source = env.readTextFile("data/access.log"); + + SingleOutputStreamOperator mapStream = source.map(new PKMapFunction()); + mapStream.print(); + + } + + /** + * wc: socket + * + * 进来的数据:pk,pk,flink pk,spark,spark + * + * + * wc需求分析: + * 1) 读进来数据 + * 2) 按照指定分隔符进行拆分 pk pk flink pk spark spark + * 3) 为每个单词赋上一个出现次数为1的值 (pk,1) (pk,1) ... + * 4) 按照单词进行keyBy + * 5) 分组求和 + * + */ + public static void reduce(StreamExecutionEnvironment env) { + + DataStreamSource source = env.socketTextStream("localhost", 9527); + + source.flatMap(new FlatMapFunction() { + @Override + public void flatMap(String value, Collector out) throws Exception { + String[] splits = value.split(","); + for(String word : splits) { + out.collect(word); + } + } + }).map(new MapFunction>() { + @Override + public Tuple2 map(String value) throws Exception { + return Tuple2.of(value, 1); + } + }).keyBy(x -> x.f0) // word相同的都会分到一个task中去执行 + .reduce(new ReduceFunction>() { + @Override + public Tuple2 reduce(Tuple2 value1, Tuple2 value2) throws Exception { + return Tuple2.of(value1.f0, value1.f1 + value2.f1); + } + }).print(); + } + + /** + * 按照domain分组,求traffic和 + */ + public static void keyBy(StreamExecutionEnvironment env) { + DataStreamSource source = env.readTextFile("data/access.log"); + + SingleOutputStreamOperator mapStream = source.map(new MapFunction() { + @Override + public Access map(String value) throws Exception { + String[] splits = value.split(","); + Long time = Long.parseLong(splits[0].trim()); + String domain = splits[1].trim(); + Double traffic = Double.parseDouble(splits[2].trim()); + + return new Access(time, domain, traffic); + } + }); + + mapStream.keyBy("domain").sum("traffic").print(); +// mapStream.keyBy(new KeySelector() { +// @Override +// public String getKey(Access value) throws Exception { +// return value.getDomain(); +// } +// }).sum("traffic").print(); +// KeyedStream keyedStream = mapStream.keyBy(Access::getDomain); +// keyedStream.sum("traffic").print(); + } + + /** + * 进来是一行行的数据: pk,pk,flink pk,spark,spark + * 需求: + * 1) 把一行数据按照逗号进行分割 + * 2) 过滤掉pk + */ + public static void flatMap(StreamExecutionEnvironment env) { + DataStreamSource source = env.socketTextStream("localhost", 9527); + source.flatMap(new FlatMapFunction() { + @Override + public void flatMap(String value, Collector out) throws Exception { + String[] splits = value.split(","); + for(String split : splits) { + out.collect(split); + } + } + }).filter(new FilterFunction() { + @Override + public boolean filter(String value) throws Exception { + return !"pk".equals(value); + } + }).print(); + } + /** + * filter 就是对DataStream中的数据进行过滤操作 + * 保留true + */ + public static void filter(StreamExecutionEnvironment env) { + DataStreamSource source = env.readTextFile("data/access.log"); + + SingleOutputStreamOperator mapStream = source.map(new MapFunction() { + @Override + public Access map(String value) throws Exception { + String[] splits = value.split(","); + Long time = Long.parseLong(splits[0].trim()); + String domain = splits[1].trim(); + Double traffic = Double.parseDouble(splits[2].trim()); + + return new Access(time, domain, traffic); + } + }); + + SingleOutputStreamOperator filterStream = mapStream.filter(new FilterFunction() { + @Override + public boolean filter(Access value) throws Exception { + return value.getTraffic() > 4000; + } + }); + + filterStream.print(); + } + + /** + * 读进来的数据是一行行的,也字符串类型 + * + * 每一行数据 ==> Access + * + * 将map算子对应的函数作用到DataStream,产生一个新的DataStream + * + * map会作用到已有的DataStream这个数据集中的每一个元素上 + * + */ + public static void map(StreamExecutionEnvironment env) { + +// DataStreamSource source = env.readTextFile("data/access.log"); +// +// SingleOutputStreamOperator mapStream = source.map(new MapFunction() { +// @Override +// public Access map(String value) throws Exception { +// String[] splits = value.split(","); +// Long time = Long.parseLong(splits[0].trim()); +// String domain = splits[1].trim(); +// Double traffic = Double.parseDouble(splits[2].trim()); +// +// return new Access(time, domain, traffic); +// } +// }); +// +// mapStream.print(); + + ArrayList list = new ArrayList<>(); + list.add(1); // map * 2 = 2 + list.add(2); // map * 2 = 4 + list.add(3); // map * 2 = 6 + DataStreamSource source = env.fromCollection(list); + + source.map(new MapFunction() { + @Override + public Integer map(Integer value) throws Exception { + return value * 2; + } + }).print(); + + } +} diff --git a/bigdata/imooc-flink/imooc-flink-datastream/src/main/java/com/imooc/flink/utils/MySQLUtils.java b/bigdata/imooc-flink/imooc-flink-datastream/src/main/java/com/imooc/flink/utils/MySQLUtils.java new file mode 100644 index 00000000..201901b6 --- /dev/null +++ b/bigdata/imooc-flink/imooc-flink-datastream/src/main/java/com/imooc/flink/utils/MySQLUtils.java @@ -0,0 +1,43 @@ +package com.imooc.flink.utils; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.SQLException; + +public class MySQLUtils { + + public static Connection getConnection() { + + try { + Class.forName("com.mysql.jdbc.Driver"); + return DriverManager.getConnection("jdbc:mysql://localhost:3306/pk_flink_imooc?useSSL=false", "root", "123456"); + } catch (Exception e) { + e.printStackTrace(); + } + + return null; + } + + public static void close(Connection connection, PreparedStatement pstmt) { + if(null != pstmt) { + try { + pstmt.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + + if(null != connection) { + try { + connection.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + } + + public static void main(String[] args) { + System.out.println(getConnection()); + } +} diff --git a/bigdata/imooc-flink/imooc-flink-datastream/src/main/java/com/imooc/flink/window/PKProcessWindowFunction.java b/bigdata/imooc-flink/imooc-flink-datastream/src/main/java/com/imooc/flink/window/PKProcessWindowFunction.java new file mode 100644 index 00000000..aecfe085 --- /dev/null +++ b/bigdata/imooc-flink/imooc-flink-datastream/src/main/java/com/imooc/flink/window/PKProcessWindowFunction.java @@ -0,0 +1,27 @@ +package com.imooc.flink.window; + +import org.apache.flink.api.java.tuple.Tuple2; +import org.apache.flink.streaming.api.functions.windowing.ProcessWindowFunction; +import org.apache.flink.streaming.api.windowing.windows.TimeWindow; +import org.apache.flink.util.Collector; + +/** + * IN:待处理DataStream中每个元素的类型 + * OUT:结果DataStream中每个元素的类型 + * KEY:keyBy中指定key的类型 + * W extends Window: TimeWindow + */ +public class PKProcessWindowFunction extends ProcessWindowFunction, String, String, TimeWindow> { + @Override + public void process(String s, Context context, Iterable> elements, Collector out) throws Exception { + + System.out.println("----process invoked...----"); + + int maxValue = Integer.MIN_VALUE; + for (Tuple2 element : elements) { + maxValue = Math.max(element.f1, maxValue); + } + + out.collect("当前窗口的最大值是:" + maxValue); + } +} diff --git a/bigdata/imooc-flink/imooc-flink-datastream/src/main/java/com/imooc/flink/window/WindowApp.java b/bigdata/imooc-flink/imooc-flink-datastream/src/main/java/com/imooc/flink/window/WindowApp.java new file mode 100644 index 00000000..03a4f6c5 --- /dev/null +++ b/bigdata/imooc-flink/imooc-flink-datastream/src/main/java/com/imooc/flink/window/WindowApp.java @@ -0,0 +1,95 @@ +package com.imooc.flink.window; + +import org.apache.flink.api.common.functions.MapFunction; +import org.apache.flink.api.common.functions.ReduceFunction; +import org.apache.flink.api.java.tuple.Tuple2; +import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; +import org.apache.flink.streaming.api.windowing.assigners.TumblingProcessingTimeWindows; +import org.apache.flink.streaming.api.windowing.time.Time; + +public class WindowApp { + + public static void main(String[] args) throws Exception { + StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); + + test01(env); + +// test02(env); +// test03(env); + env.execute("WindowApp"); + } + + public static void test03(StreamExecutionEnvironment env) { + env.socketTextStream("localhost", 9527) + .map(new MapFunction>() { + @Override + public Tuple2 map(String value) throws Exception { + return Tuple2.of("pk", Integer.parseInt(value)); + } + }).keyBy(x -> x.f0) + .window(TumblingProcessingTimeWindows.of(Time.seconds(5))) + .process(new PKProcessWindowFunction()) + .print(); + } + + + public static void test02(StreamExecutionEnvironment env) { + env.socketTextStream("localhost", 9527) + .map(new MapFunction>() { + @Override + public Tuple2 map(String value) throws Exception { + String[] splits = value.split(","); + return Tuple2.of(splits[0].trim(), Integer.parseInt(splits[1].trim())); + } + }).keyBy(x -> x.f0) + .window(TumblingProcessingTimeWindows.of(Time.seconds(5))) + .reduce(new ReduceFunction>() { + @Override + public Tuple2 reduce(Tuple2 value1, Tuple2 value2) throws Exception { + + System.out.println("value1 = [" + value1 + "], value2 = [" + value2 + "]"); + return Tuple2.of(value1.f0, value1.f1+value2.f1); + } + }) + .print(); + } + + + public static void test01(StreamExecutionEnvironment env) { + env.socketTextStream("localhost", 9527) + .map(new MapFunction() { + @Override + public Integer map(String value) throws Exception { + return Integer.parseInt(value); + } + }) + .windowAll(TumblingProcessingTimeWindows.of(Time.seconds(5))) + .sum(0) + .print(); + +// env.socketTextStream("localhost", 9527) +// .map(new MapFunction() { +// @Override +// public Integer map(String value) throws Exception { +// return Integer.parseInt(value); +// } +// }) +// .windowAll(TumblingProcessingTimeWindows.of(Time.seconds(5))) +// .sum(0) +// .print(); + + + // hadoop,1 spark,1 +// env.socketTextStream("localhost", 9527) +// .map(new MapFunction>() { +// @Override +// public Tuple2 map(String value) throws Exception { +// String[] splits = value.split(","); +// return Tuple2.of(splits[0].trim(), Integer.parseInt(splits[1].trim())); +// } +// }).keyBy(x -> x.f0) +// .window(TumblingProcessingTimeWindows.of(Time.seconds(5))) +// .sum(1) +// .print(); + } +} diff --git a/bigdata/imooc-flink/imooc-flink-datastream/src/main/java/com/imooc/flink/wm/EventTimeWMApp.java b/bigdata/imooc-flink/imooc-flink-datastream/src/main/java/com/imooc/flink/wm/EventTimeWMApp.java new file mode 100644 index 00000000..9feb0a5f --- /dev/null +++ b/bigdata/imooc-flink/imooc-flink-datastream/src/main/java/com/imooc/flink/wm/EventTimeWMApp.java @@ -0,0 +1,85 @@ +package com.imooc.flink.wm; + +import org.apache.commons.lang3.time.FastDateFormat; +import org.apache.flink.api.common.functions.MapFunction; +import org.apache.flink.api.common.functions.ReduceFunction; +import org.apache.flink.api.java.tuple.Tuple2; +import org.apache.flink.streaming.api.datastream.DataStream; +import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator; +import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; +import org.apache.flink.streaming.api.functions.timestamps.BoundedOutOfOrdernessTimestampExtractor; +import org.apache.flink.streaming.api.functions.windowing.ProcessWindowFunction; +import org.apache.flink.streaming.api.windowing.assigners.TumblingEventTimeWindows; +import org.apache.flink.streaming.api.windowing.time.Time; +import org.apache.flink.streaming.api.windowing.windows.TimeWindow; +import org.apache.flink.util.Collector; +import org.apache.flink.util.OutputTag; + +/** + * EventTime结合WM的使用 + * + * 输入数据的格式:时间字段,单词,次数 + */ +public class EventTimeWMApp { + public static void main(String[] args) throws Exception { + StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); + + test01(env); + env.execute("EventTimeWMApp"); + } + + public static void test01(StreamExecutionEnvironment env) { + OutputTag> outputTag = new OutputTag>("late-data"){ + + }; + + SingleOutputStreamOperator lines = env.socketTextStream("localhost", 9527) + .assignTimestampsAndWatermarks( + new BoundedOutOfOrdernessTimestampExtractor(Time.seconds(0)) { + @Override + public long extractTimestamp(String element) { + return Long.parseLong(element.split(",")[0]); + } + } + ); + SingleOutputStreamOperator> mapStream = lines.map(new MapFunction>() { + @Override + public Tuple2 map(String value) throws Exception { + String[] splits = value.split(","); + return Tuple2.of(splits[1].trim(), Integer.parseInt(splits[2].trim())); + } + }); + + // [0000,5000) [5000,10000) + SingleOutputStreamOperator window = mapStream.keyBy(x -> x.f0) + .window(TumblingEventTimeWindows.of(Time.seconds(5))) + .sideOutputLateData(outputTag) + .reduce(new ReduceFunction>() { + @Override + public Tuple2 reduce(Tuple2 value1, Tuple2 value2) throws Exception { + System.out.println("-----reduce invoked----" + value1.f0 + "==>" + (value1.f1 + value2.f1)); + return Tuple2.of(value1.f0, value1.f1 + value2.f1); + } + }, new ProcessWindowFunction, String, String, TimeWindow>() { + + FastDateFormat format = FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss"); + + @Override + public void process(String s, Context context, Iterable> elements, Collector out) throws Exception { + for (Tuple2 element : elements) { + out.collect("[" + format.format(context.window().getStart()) + "==>" + format.format(context.window().getEnd()) + "], " + element.f0 + "==>" + element.f1); + } + } + }); + window.print(); + DataStream> sideOutput = window.getSideOutput(outputTag); + sideOutput.printToErr(); + + /** + * WM其实就是延迟触发的一种机制 + * WM = 数据所携带的时间(窗口中最大的时间) - 延迟执行的时间 + * WM >= 上一个窗口的结束边界 就会触发窗口的执行 + * 6999 - 2000 = 4999 >= 上一个窗口的结束边界 + */ + } +} diff --git a/bigdata/imooc-flink/imooc-flink-datastream/src/main/resources/log4j.properties b/bigdata/imooc-flink/imooc-flink-datastream/src/main/resources/log4j.properties new file mode 100644 index 00000000..dcecfce2 --- /dev/null +++ b/bigdata/imooc-flink/imooc-flink-datastream/src/main/resources/log4j.properties @@ -0,0 +1,15 @@ +# 指定 RootLogger 顶级父元素默认配置信息 +# 指定日志级别=trace,使用的 apeender 为=console +log4j.rootLogger = console + +# 自定义 logger 对象设置 +log4j.logger.com.imooc.flink = info,console +log4j.logger.org.apache.flink = warn,console + +# 指定控制台日志输出的 appender +log4j.appender.console = org.apache.log4j.ConsoleAppender +# 指定消息格式 layout +log4j.appender.console.layout = org.apache.log4j.PatternLayout +# 指定消息格式的内容 +log4j.appender.console.layout.conversionPattern = %d{yyyy-MM-dd HH:mm:ss.SSS} %m%n + diff --git a/bigdata/imooc-flink/imooc-flink-datastream/test.sql b/bigdata/imooc-flink/imooc-flink-datastream/test.sql new file mode 100644 index 00000000..ad8f988e --- /dev/null +++ b/bigdata/imooc-flink/imooc-flink-datastream/test.sql @@ -0,0 +1,16 @@ +CREATE TABLE pk_flink_imooc.student +( + id int NOT NULL DEFAULT '0', + name varchar(255) NOT NULL DEFAULT '', + age int NOT NULL DEFAULT '0', + PRIMARY KEY (id) +); + +CREATE TABLE `pk_flink_imooc`.`pk_traffic` +( + `domain` varchar(255) NOT NULL DEFAULT '', + `traffic` double NOT NULL DEFAULT '0.0', + PRIMARY KEY (domain) +); + + diff --git a/bigdata/imooc-flink/imooc-flink-project/README.md b/bigdata/imooc-flink/imooc-flink-project/README.md new file mode 100644 index 00000000..e69de29b diff --git a/bigdata/imooc-flink/imooc-flink-project/pom.xml b/bigdata/imooc-flink/imooc-flink-project/pom.xml new file mode 100644 index 00000000..fa1d86e8 --- /dev/null +++ b/bigdata/imooc-flink/imooc-flink-project/pom.xml @@ -0,0 +1,66 @@ + + + + imooc-flink + com.imooc.flink + 1.0 + + 4.0.0 + + imooc-flink-project + + + + org.apache.flink + flink-streaming-java_${scala.binary.version} + + + + org.apache.flink + flink-clients_${scala.binary.version} + + + + com.alibaba + fastjson + 1.2.57 + + + + + mysql + mysql-connector-java + 5.1.47 + + + + + org.apache.httpcomponents + httpclient + 4.5.6 + + + + + org.apache.httpcomponents + httpasyncclient + 4.1.4 + + + + + org.apache.bahir + flink-connector-redis_2.11 + 1.0 + + + + org.apache.flink + flink-connector-kafka_${scala.binary.version} + ${flink.version} + + + + \ No newline at end of file diff --git a/bigdata/imooc-flink/imooc-flink-project/src/main/java/com/imooc/flink/app/GaodeApp.java b/bigdata/imooc-flink/imooc-flink-project/src/main/java/com/imooc/flink/app/GaodeApp.java new file mode 100644 index 00000000..f9118d56 --- /dev/null +++ b/bigdata/imooc-flink/imooc-flink-project/src/main/java/com/imooc/flink/app/GaodeApp.java @@ -0,0 +1,55 @@ +package com.imooc.flink.app; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.imooc.flink.utils.StringUtils; +import org.apache.http.HttpEntity; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.util.EntityUtils; + +import java.io.IOException; + +public class GaodeApp { + + public static void main(String[] args) { + String ip = "114.247.50.2"; + + + String province = "-"; + String city = "-"; + + String url = "https://restapi.amap.com/v3/ip?ip="+ip+"&output=json&key="+ StringUtils.GAODE_KEY; + + CloseableHttpClient httpClient = HttpClients.createDefault(); + + CloseableHttpResponse response = null; + + try { + HttpGet httpGet = new HttpGet(url); + response = httpClient.execute(httpGet); + int statusCode = response.getStatusLine().getStatusCode(); + if(statusCode == 200) { + HttpEntity entity = response.getEntity(); + String result = EntityUtils.toString(entity, "UTF-8"); + + + JSONObject jsonObject = JSON.parseObject(result); + province = jsonObject.getString("province"); + city = jsonObject.getString("city"); + + System.out.println(province + "\t" + city); + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + if(null != response) try { + response.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } +} diff --git a/bigdata/imooc-flink/imooc-flink-project/src/main/java/com/imooc/flink/app/OsUserCntAppV1.java b/bigdata/imooc-flink/imooc-flink-project/src/main/java/com/imooc/flink/app/OsUserCntAppV1.java new file mode 100644 index 00000000..14d004a5 --- /dev/null +++ b/bigdata/imooc-flink/imooc-flink-project/src/main/java/com/imooc/flink/app/OsUserCntAppV1.java @@ -0,0 +1,99 @@ +package com.imooc.flink.app; + +import com.alibaba.fastjson.JSON; +import com.imooc.flink.domain.Access; +import org.apache.flink.api.common.functions.FilterFunction; +import org.apache.flink.api.common.functions.MapFunction; +import org.apache.flink.api.java.functions.KeySelector; +import org.apache.flink.api.java.tuple.Tuple2; +import org.apache.flink.api.java.tuple.Tuple3; +import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator; +import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; +import org.apache.flink.streaming.connectors.redis.RedisSink; +import org.apache.flink.streaming.connectors.redis.common.config.FlinkJedisPoolConfig; +import org.apache.flink.streaming.connectors.redis.common.mapper.RedisCommand; +import org.apache.flink.streaming.connectors.redis.common.mapper.RedisCommandDescription; +import org.apache.flink.streaming.connectors.redis.common.mapper.RedisMapper; + +import java.util.Objects; + +/** + * 按照操作系统维度进行新老用户的统计分析 + */ +public class OsUserCntAppV1 { + + public static void main(String[] args) throws Exception { + + StreamExecutionEnvironment environment = StreamExecutionEnvironment.getExecutionEnvironment(); + + SingleOutputStreamOperator cleanStream = environment.readTextFile("data/access.json") + .map(new MapFunction() { + @Override + public Access map(String value) throws Exception { + // TODO... json ==> Access + + // 注意事项:一定要考虑解析的容错性 + try { + return JSON.parseObject(value, Access.class); + } catch (Exception e) { + e.printStackTrace(); // 写到某个地方 + return null; + } + + } + }).filter(Objects::nonNull) + .filter(new FilterFunction() { + @Override + public boolean filter(Access value) throws Exception { + return "startup".equals(value.event); + } + }); + + // 操作系统维度 新老用户 ==> wc + SingleOutputStreamOperator> result = cleanStream.map(new MapFunction>() { + @Override + public Tuple3 map(Access value) throws Exception { + return Tuple3.of(value.os, value.nu, 1); + } + }).keyBy(new KeySelector, Tuple2>() { + @Override + public Tuple2 getKey(Tuple3 value) throws Exception { + return Tuple2.of(value.f0, value.f1); + } + }).sum(2);// .print().setParallelism(1); + + /** + * (iOS,1,38) + * (Android,1,29) + * (iOS,0,17) + * (Android,0,16) + */ + + FlinkJedisPoolConfig conf = new FlinkJedisPoolConfig.Builder().setHost("127.0.0.1").build(); + + result.addSink(new RedisSink>(conf, new RedisExampleMapper())); + + environment.execute("OsUserCntAppV1"); + + } + + + static class RedisExampleMapper implements RedisMapper> { + + @Override + public RedisCommandDescription getCommandDescription() { + return new RedisCommandDescription(RedisCommand.HSET, "os-user-cnt:20301002"); + } + + @Override + public String getKeyFromData(Tuple3 data) { + return data.f0 + "_" + data.f1; + } + + @Override + public String getValueFromData(Tuple3 data) { + return data.f2+""; + } + + } +} diff --git a/bigdata/imooc-flink/imooc-flink-project/src/main/java/com/imooc/flink/app/OsUserCntAppV2.java b/bigdata/imooc-flink/imooc-flink-project/src/main/java/com/imooc/flink/app/OsUserCntAppV2.java new file mode 100644 index 00000000..1b2a1d80 --- /dev/null +++ b/bigdata/imooc-flink/imooc-flink-project/src/main/java/com/imooc/flink/app/OsUserCntAppV2.java @@ -0,0 +1,72 @@ +package com.imooc.flink.app; + +import com.alibaba.fastjson.JSON; +import com.imooc.flink.domain.Access; +import org.apache.flink.api.common.functions.FilterFunction; +import org.apache.flink.api.common.functions.MapFunction; +import org.apache.flink.api.java.functions.KeySelector; +import org.apache.flink.api.java.tuple.Tuple2; +import org.apache.flink.api.java.tuple.Tuple3; +import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator; +import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; +import org.apache.flink.streaming.connectors.redis.RedisSink; +import org.apache.flink.streaming.connectors.redis.common.config.FlinkJedisPoolConfig; +import org.apache.flink.streaming.connectors.redis.common.mapper.RedisCommand; +import org.apache.flink.streaming.connectors.redis.common.mapper.RedisCommandDescription; +import org.apache.flink.streaming.connectors.redis.common.mapper.RedisMapper; + +/** + * 新老用户的统计分析 + */ +public class OsUserCntAppV2 { + + public static void main(String[] args) throws Exception { + + StreamExecutionEnvironment environment = StreamExecutionEnvironment.getExecutionEnvironment(); + + SingleOutputStreamOperator cleanStream = environment.readTextFile("data/access.json") + .map(new MapFunction() { + @Override + public Access map(String value) throws Exception { + // TODO... json ==> Access + + try { + return JSON.parseObject(value, Access.class); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + + } + }).filter(x -> x != null) + .filter(new FilterFunction() { + @Override + public boolean filter(Access value) throws Exception { + return "startup".equals(value.event); + } + }); + + cleanStream.map(new MapFunction>() { + @Override + public Tuple2 map(Access value) throws Exception { + return Tuple2.of(value.nu, 1); + } + }).keyBy(x -> x.f0) + .sum(1).print("总的新老用户:").setParallelism(1); + + + /** + * (iOS,1,38) + * (Android,1,29) + * (iOS,0,17) + * (Android,0,16) + * + * ==> + * (1, 67) + * (0, 33) + */ + + environment.execute("OsUserCntAppV2"); + + } +} diff --git a/bigdata/imooc-flink/imooc-flink-project/src/main/java/com/imooc/flink/app/OsUserCntAppV3.java b/bigdata/imooc-flink/imooc-flink-project/src/main/java/com/imooc/flink/app/OsUserCntAppV3.java new file mode 100644 index 00000000..f6e3997a --- /dev/null +++ b/bigdata/imooc-flink/imooc-flink-project/src/main/java/com/imooc/flink/app/OsUserCntAppV3.java @@ -0,0 +1,92 @@ +package com.imooc.flink.app; + +import com.alibaba.fastjson.JSON; +import com.imooc.flink.domain.Access; +import org.apache.flink.api.common.functions.FilterFunction; +import org.apache.flink.api.common.functions.MapFunction; +import org.apache.flink.api.common.state.ValueState; +import org.apache.flink.api.common.state.ValueStateDescriptor; +import org.apache.flink.api.common.typeinfo.TypeHint; +import org.apache.flink.api.common.typeinfo.TypeInformation; +import org.apache.flink.configuration.Configuration; +import org.apache.flink.shaded.guava18.com.google.common.hash.BloomFilter; +import org.apache.flink.shaded.guava18.com.google.common.hash.Funnels; +import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator; +import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; +import org.apache.flink.streaming.api.functions.KeyedProcessFunction; +import org.apache.flink.util.Collector; + +/** + * 新老用户的统计分析 + * + * 原来是根据数据中的某个字段 + * 现在我们是根据每个device来进行判断是否是新老用户 + * + * 思考:device放到state里面去呢 + * + * 我们的实现:状态 + 布隆过滤器 + * + */ +public class OsUserCntAppV3 { + + public static void main(String[] args) throws Exception { + + StreamExecutionEnvironment environment = StreamExecutionEnvironment.getExecutionEnvironment(); + + SingleOutputStreamOperator cleanStream = environment.readTextFile("data/access.json") + .map(new MapFunction() { + @Override + public Access map(String value) throws Exception { + // TODO... json ==> Access + + try { + return JSON.parseObject(value, Access.class); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + + } + }).filter(x -> x != null) + .filter(new FilterFunction() { + @Override + public boolean filter(Access value) throws Exception { + return "startup".equals(value.event); + } + }); + + + cleanStream.keyBy(x -> x.deviceType) + .process(new KeyedProcessFunction() { + + private transient ValueState> state; + + @Override + public void open(Configuration parameters) throws Exception { + ValueStateDescriptor> descriptor = new ValueStateDescriptor<>("s", TypeInformation.of(new TypeHint>() {})); + state = getRuntimeContext().getState(descriptor); + } + + @Override + public void processElement(Access value, Context ctx, Collector out) throws Exception { + String device = value.device; + BloomFilter bloomFilter = state.value(); + if(null == bloomFilter) { + bloomFilter = BloomFilter.create(Funnels.unencodedCharsFunnel(), 100000); + } + + if(!bloomFilter.mightContain(device)) { + bloomFilter.put(device); + value.nu2 = 1; + state.update(bloomFilter); + } + + out.collect(value); + } + }).print(); + + + environment.execute("OsUserCntAppV3"); + + } +} diff --git a/bigdata/imooc-flink/imooc-flink-project/src/main/java/com/imooc/flink/app/OsUserCntAppV4.java b/bigdata/imooc-flink/imooc-flink-project/src/main/java/com/imooc/flink/app/OsUserCntAppV4.java new file mode 100644 index 00000000..e8bc28d9 --- /dev/null +++ b/bigdata/imooc-flink/imooc-flink-project/src/main/java/com/imooc/flink/app/OsUserCntAppV4.java @@ -0,0 +1,81 @@ +package com.imooc.flink.app; + +import com.alibaba.fastjson.JSON; +import com.imooc.flink.domain.Access; +import org.apache.flink.api.common.functions.FilterFunction; +import org.apache.flink.api.common.functions.MapFunction; +import org.apache.flink.api.common.state.ValueState; +import org.apache.flink.api.common.state.ValueStateDescriptor; +import org.apache.flink.api.common.typeinfo.TypeHint; +import org.apache.flink.api.common.typeinfo.TypeInformation; +import org.apache.flink.configuration.Configuration; +import org.apache.flink.shaded.guava18.com.google.common.hash.BloomFilter; +import org.apache.flink.shaded.guava18.com.google.common.hash.Funnels; +import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator; +import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; +import org.apache.flink.streaming.api.functions.KeyedProcessFunction; +import org.apache.flink.util.Collector; + +public class OsUserCntAppV4 { + + public static void main(String[] args) throws Exception { + + StreamExecutionEnvironment environment = StreamExecutionEnvironment.getExecutionEnvironment(); + + SingleOutputStreamOperator cleanStream = environment.socketTextStream("localhost", 9527) + .map(new MapFunction() { + @Override + public Access map(String value) throws Exception { + // TODO... json ==> Access + + try { + return JSON.parseObject(value, Access.class); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + + } + }).filter(x -> x != null) + .filter(new FilterFunction() { + @Override + public boolean filter(Access value) throws Exception { + return "startup".equals(value.event); + } + }); + + + cleanStream.keyBy(x -> x.deviceType) + .process(new KeyedProcessFunction() { + + private transient ValueState> state; + + @Override + public void open(Configuration parameters) throws Exception { + ValueStateDescriptor> descriptor = new ValueStateDescriptor<>("s", TypeInformation.of(new TypeHint>() {})); + state = getRuntimeContext().getState(descriptor); + } + + @Override + public void processElement(Access value, Context ctx, Collector out) throws Exception { + String device = value.device; + BloomFilter bloomFilter = state.value(); + if(null == bloomFilter) { + bloomFilter = BloomFilter.create(Funnels.unencodedCharsFunnel(), 100000); + } + + if(!bloomFilter.mightContain(device)) { + bloomFilter.put(device); + value.nu2 = 1; + state.update(bloomFilter); + } + + out.collect(value); + } + }).print(); + + + environment.execute("OsUserCntAppV2"); + + } +} diff --git a/bigdata/imooc-flink/imooc-flink-project/src/main/java/com/imooc/flink/app/ProvinceUserCntAppV1.java b/bigdata/imooc-flink/imooc-flink-project/src/main/java/com/imooc/flink/app/ProvinceUserCntAppV1.java new file mode 100644 index 00000000..76abcca1 --- /dev/null +++ b/bigdata/imooc-flink/imooc-flink-project/src/main/java/com/imooc/flink/app/ProvinceUserCntAppV1.java @@ -0,0 +1,91 @@ +package com.imooc.flink.app; + +import com.alibaba.fastjson.JSON; +import com.imooc.flink.domain.Access; +import com.imooc.flink.udf.GaodeLocationMapFunction; +import org.apache.flink.api.common.functions.FilterFunction; +import org.apache.flink.api.common.functions.MapFunction; +import org.apache.flink.api.java.functions.KeySelector; +import org.apache.flink.api.java.tuple.Tuple2; +import org.apache.flink.api.java.tuple.Tuple3; +import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator; +import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; +import org.apache.flink.streaming.connectors.redis.RedisSink; +import org.apache.flink.streaming.connectors.redis.common.config.FlinkJedisPoolConfig; +import org.apache.flink.streaming.connectors.redis.common.mapper.RedisCommand; +import org.apache.flink.streaming.connectors.redis.common.mapper.RedisCommandDescription; +import org.apache.flink.streaming.connectors.redis.common.mapper.RedisMapper; + +/** + * 按照省份维度进行新老用户的统计分析 + */ +public class ProvinceUserCntAppV1 { + + public static void main(String[] args) throws Exception { + + StreamExecutionEnvironment environment = StreamExecutionEnvironment.getExecutionEnvironment(); + + SingleOutputStreamOperator cleanStream = environment.readTextFile("data/access.json") + .map(new MapFunction() { + @Override + public Access map(String value) throws Exception { + // TODO... json ==> Access + + try { + return JSON.parseObject(value, Access.class); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + + } + }).filter(x -> x != null) + .filter(new FilterFunction() { + @Override + public boolean filter(Access value) throws Exception { + return "startup".equals(value.event); + } + }) + .map(new GaodeLocationMapFunction()); + + SingleOutputStreamOperator> result = cleanStream.map(new MapFunction>() { + @Override + public Tuple3 map(Access value) throws Exception { + return Tuple3.of(value.province, value.nu, 1); + } + }).keyBy(new KeySelector, Tuple2>() { + @Override + public Tuple2 getKey(Tuple3 value) throws Exception { + return Tuple2.of(value.f0, value.f1); + } + }).sum(2);//.print("省份维度统计新老用户:").setParallelism(1); + + + FlinkJedisPoolConfig conf = new FlinkJedisPoolConfig.Builder().setHost("127.0.0.1").build(); + + result.addSink(new RedisSink>(conf, new RedisExampleMapper())); + + + environment.execute("ProvinceUserCntAppV1"); + + } + + static class RedisExampleMapper implements RedisMapper> { + + @Override + public RedisCommandDescription getCommandDescription() { + return new RedisCommandDescription(RedisCommand.HSET, "province-user-cnt:20301002"); + } + + @Override + public String getKeyFromData(Tuple3 data) { + return data.f0 + "_" + data.f1; + } + + @Override + public String getValueFromData(Tuple3 data) { + return data.f2+""; + } + + } +} diff --git a/bigdata/imooc-flink/imooc-flink-project/src/main/java/com/imooc/flink/app/TopNAppV1.java b/bigdata/imooc-flink/imooc-flink-project/src/main/java/com/imooc/flink/app/TopNAppV1.java new file mode 100644 index 00000000..b26463f9 --- /dev/null +++ b/bigdata/imooc-flink/imooc-flink-project/src/main/java/com/imooc/flink/app/TopNAppV1.java @@ -0,0 +1,125 @@ +package com.imooc.flink.app; + +import com.alibaba.fastjson.JSON; +import com.imooc.flink.domain.Access; +import com.imooc.flink.domain.EventCatagoryProductCount; +import com.imooc.flink.udf.TopNAggregateFunction; +import com.imooc.flink.udf.TopNWindowFunction; +import org.apache.flink.api.common.functions.FilterFunction; +import org.apache.flink.api.common.functions.MapFunction; +import org.apache.flink.api.common.state.ListState; +import org.apache.flink.api.common.state.ListStateDescriptor; +import org.apache.flink.api.java.functions.KeySelector; +import org.apache.flink.api.java.tuple.Tuple2; +import org.apache.flink.api.java.tuple.Tuple3; +import org.apache.flink.api.java.tuple.Tuple4; +import org.apache.flink.configuration.Configuration; +import org.apache.flink.shaded.guava18.com.google.common.collect.Lists; +import org.apache.flink.streaming.api.datastream.KeyedStream; +import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator; +import org.apache.flink.streaming.api.datastream.WindowedStream; +import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; +import org.apache.flink.streaming.api.functions.KeyedProcessFunction; +import org.apache.flink.streaming.api.functions.timestamps.BoundedOutOfOrdernessTimestampExtractor; +import org.apache.flink.streaming.api.windowing.assigners.SlidingEventTimeWindows; +import org.apache.flink.streaming.api.windowing.time.Time; +import org.apache.flink.streaming.api.windowing.windows.TimeWindow; +import org.apache.flink.streaming.connectors.redis.RedisSink; +import org.apache.flink.streaming.connectors.redis.common.config.FlinkJedisPoolConfig; +import org.apache.flink.streaming.connectors.redis.common.mapper.RedisCommand; +import org.apache.flink.streaming.connectors.redis.common.mapper.RedisCommandDescription; +import org.apache.flink.streaming.connectors.redis.common.mapper.RedisMapper; +import org.apache.flink.util.Collector; + +import java.util.ArrayList; +import java.util.List; + +public class TopNAppV1 { + public static void main(String[] args) throws Exception { + StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); + + + SingleOutputStreamOperator cleanStream = env.readTextFile("data/access.json") + .map(new MapFunction() { + @Override + public Access map(String value) throws Exception { + // json ==> 自定义对象 + try { + return JSON.parseObject(value, Access.class); + } catch (Exception e) { + e.printStackTrace(); + // TODO... 把这些异常的数据记录到某个地方去 + return null; + } + } + }).filter(x -> x != null) + .assignTimestampsAndWatermarks( + new BoundedOutOfOrdernessTimestampExtractor(Time.seconds(20)) { + @Override + public long extractTimestamp(Access element) { + return element.time; + } + } + ).filter(new FilterFunction() { + @Override + public boolean filter(Access value) throws Exception { + return !"startup".equals(value.event); + } + }); + + WindowedStream, TimeWindow> windowStream = cleanStream.keyBy(new KeySelector>() { + @Override + public Tuple3 getKey(Access value) throws Exception { + return Tuple3.of(value.event, value.product.category, value.product.name); + } + }).window(SlidingEventTimeWindows.of(Time.minutes(5), Time.minutes(1))); + + // 作用上WindowFunction + + SingleOutputStreamOperator aggStream = windowStream.aggregate(new TopNAggregateFunction(), new TopNWindowFunction()); + + aggStream.keyBy(new KeySelector>() { + @Override + public Tuple4 getKey(EventCatagoryProductCount value) throws Exception { + return Tuple4.of(value.event, value.catagory, value.start, value.end); + } + }).process(new KeyedProcessFunction, EventCatagoryProductCount, List>() { + + private transient ListState listState; + + @Override + public void open(Configuration parameters) throws Exception { + listState = getRuntimeContext().getListState(new ListStateDescriptor("cnt-state", EventCatagoryProductCount.class)); + } + + @Override + public void processElement(EventCatagoryProductCount value, Context ctx, Collector> out) throws Exception { + listState.add(value); + + // 注册一个定时器 + ctx.timerService().registerEventTimeTimer(value.end + 1); + } + + + // 在这里完成TopN操作 + @Override + public void onTimer(long timestamp, OnTimerContext ctx, Collector> out) throws Exception { + ArrayList list = Lists.newArrayList(listState.get()); + + list.sort((x,y) -> Long.compare(y.count, x.count)); + + ArrayList sorted = new ArrayList<>(); + + for (int i = 0; i < Math.min(3, list.size()); i++) { + EventCatagoryProductCount bean = list.get(i); + sorted.add(bean); + } + + out.collect(sorted); + } + }).print().setParallelism(1); + + env.execute(); + } + +} diff --git a/bigdata/imooc-flink/imooc-flink-project/src/main/java/com/imooc/flink/app/TopNTest.java b/bigdata/imooc-flink/imooc-flink-project/src/main/java/com/imooc/flink/app/TopNTest.java new file mode 100644 index 00000000..f733506e --- /dev/null +++ b/bigdata/imooc-flink/imooc-flink-project/src/main/java/com/imooc/flink/app/TopNTest.java @@ -0,0 +1,133 @@ +package com.imooc.flink.app; + +import com.alibaba.fastjson.JSON; +import com.imooc.flink.domain.Access; +import com.imooc.flink.domain.EventCatagoryProductCount; +import com.imooc.flink.udf.TopNAggregateFunction; +import com.imooc.flink.udf.TopNWindowFunction; +import org.apache.flink.api.common.functions.FilterFunction; +import org.apache.flink.api.common.functions.MapFunction; +import org.apache.flink.api.common.state.ListState; +import org.apache.flink.api.common.state.ListStateDescriptor; +import org.apache.flink.api.java.functions.KeySelector; +import org.apache.flink.api.java.tuple.Tuple3; +import org.apache.flink.api.java.tuple.Tuple4; +import org.apache.flink.configuration.Configuration; +import org.apache.flink.shaded.guava18.com.google.common.collect.Lists; +import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator; +import org.apache.flink.streaming.api.datastream.WindowedStream; +import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; +import org.apache.flink.streaming.api.functions.KeyedProcessFunction; +import org.apache.flink.streaming.api.functions.timestamps.BoundedOutOfOrdernessTimestampExtractor; +import org.apache.flink.streaming.api.windowing.assigners.SlidingEventTimeWindows; +import org.apache.flink.streaming.api.windowing.time.Time; +import org.apache.flink.streaming.api.windowing.windows.TimeWindow; +import org.apache.flink.util.Collector; +import redis.clients.jedis.Tuple; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +public class TopNTest { + + /** + * 统计五分钟内的不同event(加购物车、浏览...)类型、类别、商品的TOPN + *

+ * {"channel":"华为商城","device":"8fe721d6-cd41-4869-a14d-23b4fbfc70df", + * "deviceType":"iPhone 10","event":"startup","ip":"114.247.50.2","net":"5G", + * "nu":1,"os":"iOS","time":1647195061,"uid":"user_1","version":"V1.2.2"} + */ + public static void main(String[] args) throws Exception { + + // 五分钟内,用window实现,滚动窗口 + + StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); + + + SingleOutputStreamOperator cleanStream = env.readTextFile("data/access.json") + .map(new MapFunction() { + @Override + public Access map(String value) throws Exception { + // json ==> 自定义对象 + try { + return JSON.parseObject(value, Access.class); + } catch (Exception e) { + e.printStackTrace(); + // TODO... 把这些异常的数据记录到某个地方去 + return null; + } + } + }).filter(Objects::nonNull) + .assignTimestampsAndWatermarks( + new BoundedOutOfOrdernessTimestampExtractor(Time.seconds(20)) { + @Override + public long extractTimestamp(Access element) { + return element.time; + } + } + ).filter(new FilterFunction() { + @Override + public boolean filter(Access value) throws Exception { + return !"startup".equals(value.event); + } + }); + + // 窗口按“类型、类别、商品”划分 + WindowedStream, TimeWindow> windowStream = cleanStream.keyBy(new KeySelector>() { + @Override + public Tuple3 getKey(Access access) throws Exception { + return Tuple3.of(access.event, access.product.category, access.product.name); + } + }).window(SlidingEventTimeWindows.of(Time.minutes(5), Time.minutes(1))); + + // 同窗口汇总 + SingleOutputStreamOperator aggStream = windowStream.aggregate(new TopNAggregateFunction(), new TopNWindowFunction()); + + // 汇总后排序 + + aggStream.keyBy(new KeySelector>() { + @Override + public Tuple4 getKey(EventCatagoryProductCount value) throws Exception { + return Tuple4.of(value.event, value.catagory, value.start, value.end); + } + }).process(new KeyedProcessFunction, EventCatagoryProductCount, List>() { + + private transient ListState listState; + + @Override + public void open(Configuration parameters) throws Exception { + listState = getRuntimeContext().getListState(new ListStateDescriptor("cnt-state", EventCatagoryProductCount.class)); + } + + @Override + public void processElement(EventCatagoryProductCount value, Context ctx, Collector> out) throws Exception { + listState.add(value); + + // 注册一个定时器 + ctx.timerService().registerEventTimeTimer(value.end + 1); + } + + // 在这里完成TopN操作 + @Override + public void onTimer(long timestamp, OnTimerContext ctx, Collector> out) throws Exception { + ArrayList list = Lists.newArrayList(listState.get()); + + list.sort((x,y) -> Long.compare(y.count, x.count)); + + ArrayList sorted = new ArrayList<>(); + + for (int i = 0; i < Math.min(3, list.size()); i++) { + EventCatagoryProductCount bean = list.get(i); + sorted.add(bean); + } + + out.collect(sorted); + } + }).print().setParallelism(1); + + env.execute(); + } + + +} diff --git a/bigdata/imooc-flink/imooc-flink-project/src/main/java/com/imooc/flink/domain/Access.java b/bigdata/imooc-flink/imooc-flink-project/src/main/java/com/imooc/flink/domain/Access.java new file mode 100644 index 00000000..a0548e7e --- /dev/null +++ b/bigdata/imooc-flink/imooc-flink-project/src/main/java/com/imooc/flink/domain/Access.java @@ -0,0 +1,43 @@ +package com.imooc.flink.domain; + +public class Access { + + public String device; + public String deviceType; + public String os; + // startup启动; + public String event; + public String net; + public String channel; + public String uid; + public int nu; // 1新 + public int nu2; + public String ip; // ==> ip去解析 + public long time; + public String version; + public String province; + public String city; + + public Product product; + + @Override + public String toString() { + return "Access{" + + "device='" + device + '\'' + + ", deviceType='" + deviceType + '\'' + + ", os='" + os + '\'' + + ", event='" + event + '\'' + + ", net='" + net + '\'' + + ", channel='" + channel + '\'' + + ", uid='" + uid + '\'' + + ", nu=" + nu + + ", nu2=" + nu2 + + ", ip='" + ip + '\'' + + ", time=" + time + + ", version='" + version + '\'' + + ", province='" + province + '\'' + + ", city='" + city + '\'' + + ", product=" + product + + '}'; + } +} diff --git a/bigdata/imooc-flink/imooc-flink-project/src/main/java/com/imooc/flink/domain/EventCatagoryProductCount.java b/bigdata/imooc-flink/imooc-flink-project/src/main/java/com/imooc/flink/domain/EventCatagoryProductCount.java new file mode 100644 index 00000000..0d70a1bf --- /dev/null +++ b/bigdata/imooc-flink/imooc-flink-project/src/main/java/com/imooc/flink/domain/EventCatagoryProductCount.java @@ -0,0 +1,28 @@ +package com.imooc.flink.domain; + +public class EventCatagoryProductCount { + + public String event; + public String catagory; + public String product; + public long count; + public long start; + public long end; + + public EventCatagoryProductCount() { + } + + public EventCatagoryProductCount(String event, String catagory, String product, long count, long start, long end) { + this.event = event; + this.catagory = catagory; + this.product = product; + this.count = count; + this.start = start; + this.end = end; + } + + @Override + public String toString() { + return event + "\t" + catagory + "\t" + product + "\t" + count + "\t" + start + "\t" + end; + } +} diff --git a/bigdata/imooc-flink/imooc-flink-project/src/main/java/com/imooc/flink/domain/Product.java b/bigdata/imooc-flink/imooc-flink-project/src/main/java/com/imooc/flink/domain/Product.java new file mode 100644 index 00000000..47a7a957 --- /dev/null +++ b/bigdata/imooc-flink/imooc-flink-project/src/main/java/com/imooc/flink/domain/Product.java @@ -0,0 +1,15 @@ +package com.imooc.flink.domain; + +public class Product { + + public String category; + public String name; + + @Override + public String toString() { + return "Product{" + + "category='" + category + '\'' + + ", name='" + name + '\'' + + '}'; + } +} diff --git a/bigdata/imooc-flink/imooc-flink-project/src/main/java/com/imooc/flink/udf/GaodeLocationMapFunction.java b/bigdata/imooc-flink/imooc-flink-project/src/main/java/com/imooc/flink/udf/GaodeLocationMapFunction.java new file mode 100644 index 00000000..44f60b39 --- /dev/null +++ b/bigdata/imooc-flink/imooc-flink-project/src/main/java/com/imooc/flink/udf/GaodeLocationMapFunction.java @@ -0,0 +1,65 @@ +package com.imooc.flink.udf; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.imooc.flink.domain.Access; +import com.imooc.flink.utils.StringUtils; +import com.mysql.jdbc.AbandonedConnectionCleanupThread; +import org.apache.flink.api.common.functions.RichMapFunction; +import org.apache.flink.configuration.Configuration; +import org.apache.http.HttpEntity; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.util.EntityUtils; + +import java.io.IOException; + +public class GaodeLocationMapFunction extends RichMapFunction { + + CloseableHttpClient httpClient; + + @Override + public void open(Configuration parameters) throws Exception { + httpClient = HttpClients.createDefault(); + } + + @Override + public void close() throws Exception { + if(httpClient != null) httpClient.close(); + } + + @Override + public Access map(Access value) throws Exception { + String url = "https://restapi.amap.com/v3/ip?ip="+value.ip+"&output=json&key="+ StringUtils.GAODE_KEY; + + CloseableHttpResponse response = null; + + String province = "-"; + String city = "-"; + + try { + HttpGet httpGet = new HttpGet(url); + response = httpClient.execute(httpGet); + int statusCode = response.getStatusLine().getStatusCode(); + if(statusCode == 200) { + HttpEntity entity = response.getEntity(); + String result = EntityUtils.toString(entity, "UTF-8"); + + + JSONObject jsonObject = JSON.parseObject(result); + province = jsonObject.getString("province"); + city = jsonObject.getString("city"); + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + response.close(); + value.province = province; + value.city = city; + } + + return value; + } +} diff --git a/bigdata/imooc-flink/imooc-flink-project/src/main/java/com/imooc/flink/udf/TopNAggregateFunction.java b/bigdata/imooc-flink/imooc-flink-project/src/main/java/com/imooc/flink/udf/TopNAggregateFunction.java new file mode 100644 index 00000000..ac9a20b0 --- /dev/null +++ b/bigdata/imooc-flink/imooc-flink-project/src/main/java/com/imooc/flink/udf/TopNAggregateFunction.java @@ -0,0 +1,26 @@ +package com.imooc.flink.udf; + +import com.imooc.flink.domain.Access; +import org.apache.flink.api.common.functions.AggregateFunction; + +public class TopNAggregateFunction implements AggregateFunction { + @Override + public Long createAccumulator() { + return 0L; + } + + @Override + public Long add(Access value, Long accumulator) { + return accumulator + 1; + } + + @Override + public Long getResult(Long accumulator) { + return accumulator; + } + + @Override + public Long merge(Long a, Long b) { + return null; + } +} diff --git a/bigdata/imooc-flink/imooc-flink-project/src/main/java/com/imooc/flink/udf/TopNWindowFunction.java b/bigdata/imooc-flink/imooc-flink-project/src/main/java/com/imooc/flink/udf/TopNWindowFunction.java new file mode 100644 index 00000000..4b427d0b --- /dev/null +++ b/bigdata/imooc-flink/imooc-flink-project/src/main/java/com/imooc/flink/udf/TopNWindowFunction.java @@ -0,0 +1,22 @@ +package com.imooc.flink.udf; + +import com.imooc.flink.domain.EventCatagoryProductCount; +import org.apache.flink.api.java.tuple.Tuple3; +import org.apache.flink.streaming.api.functions.windowing.WindowFunction; +import org.apache.flink.streaming.api.windowing.windows.TimeWindow; +import org.apache.flink.util.Collector; + +public class TopNWindowFunction implements WindowFunction, TimeWindow> { + @Override + public void apply(Tuple3 value, TimeWindow window, Iterable input, Collector out) throws Exception { + + String event = value.f0; + String category = value.f1; + String product = value.f2; + Long count = input.iterator().next(); + long start = window.getStart(); + long end = window.getEnd(); + + out.collect(new EventCatagoryProductCount(event, category, product,count,start, end)); + } +} diff --git a/bigdata/imooc-flink/imooc-flink-project/src/main/java/com/imooc/flink/utils/StringUtils.java b/bigdata/imooc-flink/imooc-flink-project/src/main/java/com/imooc/flink/utils/StringUtils.java new file mode 100644 index 00000000..cf785a3d --- /dev/null +++ b/bigdata/imooc-flink/imooc-flink-project/src/main/java/com/imooc/flink/utils/StringUtils.java @@ -0,0 +1,6 @@ +package com.imooc.flink.utils; + +public class StringUtils { + + public static final String GAODE_KEY = "6d5be617aa12cd42f6c7421cbfa8883a"; +} diff --git a/bigdata/imooc-flink/imooc-flink-sql/pom.xml b/bigdata/imooc-flink/imooc-flink-sql/pom.xml new file mode 100644 index 00000000..64b5f783 --- /dev/null +++ b/bigdata/imooc-flink/imooc-flink-sql/pom.xml @@ -0,0 +1,52 @@ + + + + imooc-flink + com.imooc.flink + 1.0 + + 4.0.0 + + imooc-flink-sql + + + + org.apache.flink + flink-table-api-java-bridge_${scala.binary.version} + ${flink.version} + + + + + org.apache.flink + flink-csv + ${flink.version} + + + + org.apache.flink + flink-clients_${scala.binary.version} + + + + org.apache.flink + flink-table-planner-blink_${scala.binary.version} + ${flink.version} + + + org.apache.flink + flink-streaming-scala_${scala.binary.version} + ${flink.version} + + + + com.fasterxml.jackson.core + jackson-databind + 2.6.7 + compile + + + + \ No newline at end of file diff --git a/bigdata/imooc-flink/imooc-flink-upgrade/pom.xml b/bigdata/imooc-flink/imooc-flink-upgrade/pom.xml new file mode 100644 index 00000000..783c13aa --- /dev/null +++ b/bigdata/imooc-flink/imooc-flink-upgrade/pom.xml @@ -0,0 +1,67 @@ + + + + imooc-flink + com.imooc.flink + 1.0 + + 4.0.0 + + imooc-flink-upgrade + + + + UTF-8 + + 1.10.0 + 2.12 + 1.8 + ${target.java.version} + ${target.java.version} + 2.12.1 + + + + + org.apache.flink + flink-streaming-java_${scala.binary.version} + ${flink.version} + + + + org.apache.flink + flink-clients_${scala.binary.version} + ${flink.version} + + + + org.apache.flink + flink-table-planner_${scala.binary.version} + ${flink.version} + + + + + + + + + + org.apache.logging.log4j + log4j-slf4j-impl + ${log4j.version} + + + org.apache.logging.log4j + log4j-api + ${log4j.version} + + + org.apache.logging.log4j + log4j-core + ${log4j.version} + + + \ No newline at end of file diff --git a/bigdata/imooc-flink/pom.xml b/bigdata/imooc-flink/pom.xml new file mode 100644 index 00000000..2eeea636 --- /dev/null +++ b/bigdata/imooc-flink/pom.xml @@ -0,0 +1,49 @@ + + + 4.0.0 + + com.imooc.flink + imooc-flink + pom + 1.0 + + + imooc-flink-datastream + imooc-flink-sql + imooc-flink-dataset + imooc-flink-basic + imooc-flink-project + imooc-clickhouse + imooc-flink-upgrade + + + + + UTF-8 + 1.12.1 + 2.12 + 1.8 + ${target.java.version} + ${target.java.version} + 2.12.1 + + + + + + org.apache.flink + flink-streaming-java_${scala.binary.version} + ${flink.version} + + + + org.apache.flink + flink-clients_${scala.binary.version} + ${flink.version} + + + + + diff --git a/database/elasticsearch/pom.xml b/database/elasticsearch/pom.xml deleted file mode 100644 index 7e7ceae8..00000000 --- a/database/elasticsearch/pom.xml +++ /dev/null @@ -1,60 +0,0 @@ - - - 4.0.0 - - cn.lastwhisper - elasticsearch - 1.0-SNAPSHOT - - - - - org.elasticsearch.client - elasticsearch-rest-high-level-client - 6.5.3 - - - - - mysql - mysql-connector-java - 5.1.48 - - - - - - commons-dbutils - commons-dbutils - 1.7 - - - - - com.alibaba - fastjson - 1.2.62 - - - - org.apache.logging.log4j - log4j-core - 2.9.1 - - - - org.apache.logging.log4j - log4j-api - 2.9.1 - - - - junit - junit - 4.12 - test - - - \ No newline at end of file diff --git a/database/elasticsearch/src/main/java/cn/lastwhisper/elasticsearch/operation/EsDataAdapter.java b/database/elasticsearch/src/main/java/cn/lastwhisper/elasticsearch/operation/EsDataAdapter.java deleted file mode 100644 index 068ae92b..00000000 --- a/database/elasticsearch/src/main/java/cn/lastwhisper/elasticsearch/operation/EsDataAdapter.java +++ /dev/null @@ -1,155 +0,0 @@ -package cn.lastwhisper.elasticsearch.operation; - -import cn.lastwhisper.elasticsearch.operation.entity.Sku; -import cn.lastwhisper.elasticsearch.operation.enums.DbConfig; -import cn.lastwhisper.elasticsearch.operation.utils.DateUtils; -import com.alibaba.fastjson.JSON; -import org.apache.commons.dbutils.QueryRunner; -import org.apache.commons.dbutils.handlers.BeanListHandler; -import org.apache.commons.dbutils.handlers.ScalarHandler; -import org.apache.http.HttpHost; -import org.elasticsearch.action.bulk.BulkRequest; -import org.elasticsearch.action.bulk.BulkResponse; -import org.elasticsearch.action.index.IndexRequest; -import org.elasticsearch.client.RequestOptions; -import org.elasticsearch.client.RestClient; -import org.elasticsearch.client.RestClientBuilder; -import org.elasticsearch.client.RestHighLevelClient; - -import java.io.IOException; -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.SQLException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * 青橙商城数据导入 - * @author lastwhisper - * @date 2019/12/1 - */ -public class EsDataAdapter { - - private static Connection conn; - private static QueryRunner queryRunner; - - private static RestHighLevelClient restHighLevelClient; - - static { - try { - // 初始化mysql连接 - Class.forName(DbConfig.DB_DRIVER.getValue()); - conn = DriverManager.getConnection(DbConfig.DB_URL.getValue(), DbConfig.DB_USERNAME.getValue(), DbConfig.DB_PASSWORD.getValue()); - // dbutils - queryRunner = new QueryRunner(); - // 初始化es连接 - HttpHost http = new HttpHost(DbConfig.ES_HOSTNAME.getValue(), 9200, DbConfig.ES_SCHEMA.getValue()); - RestClientBuilder builder = RestClient.builder(http); - restHighLevelClient = new RestHighLevelClient(builder); - } catch (Exception e) { - e.printStackTrace(); - } - - - } - - public static void main(String[] args) throws SQLException, IOException { - long beginTime = System.currentTimeMillis(); - - // http:200 耗时:22.1s - // 总耗时:25910 - fullImport(); - - // 总耗时:26995 - //batchImport(); - - long endTime = System.currentTimeMillis(); - System.out.println("总耗时:" + (endTime - beginTime)); - } - - - public static void fullImport() throws SQLException, IOException { - try { - List skuList = fetchData(); - BulkResponse response = bulkImport(skuList); - System.out.println("http:" + response.status().getStatus() - + " 耗时:" + response.getTook()); - if (response.hasFailures()) System.out.println("失败原因:" + response.buildFailureMessage()); - } catch (SQLException e) { - e.printStackTrace(); - } finally { - conn.close(); - restHighLevelClient.close(); - } - } - - public static void batchImport() throws SQLException, IOException { - try { - int frequency = 0; - Long total = total();//导入数据的总数 - Long basicTotal = 10000L;//每次导入的量 - Long start = 0L, end = basicTotal; - while (total > 0L) { - List skuList = fetchData(start, end); - BulkResponse response = bulkImport(skuList); - System.out.println("http:" + response.status().getStatus() - + " 耗时:" + response.getTook()); - - if (response.hasFailures()) System.out.println("失败原因:" + response.buildFailureMessage()); - - if (total <= basicTotal) { - basicTotal = total; - } - total -= basicTotal; - start += basicTotal; - end += basicTotal; - frequency++; - } - System.out.println("分批次数:" + frequency); - } catch (SQLException e) { - e.printStackTrace(); - } finally { - conn.close(); - restHighLevelClient.close(); - } - } - - public static Long total() throws SQLException { - String sql = "SELECT COUNT(*) FROM tb_sku"; - return queryRunner.query(conn, sql, new ScalarHandler<>()); - } - - public static List fetchData(Long start, Long end) throws SQLException { - String sql = "SELECT id skuId,name,price,image,create_time createTime,category_name categoryName,brand_name brandName,spec,comment_num commentNum,sale_num saleNum,spu_id spuId FROM tb_sku limit ?,?"; - return queryRunner.query(conn, sql, new BeanListHandler<>(Sku.class), start, end); - } - - public static List fetchData() throws SQLException { - String sql = "SELECT id skuId,name,price,image,create_time createTime,category_name categoryName,brand_name brandName,spec,comment_num commentNum,sale_num saleNum,spu_id spuId FROM tb_sku"; - return queryRunner.query(conn, sql, new BeanListHandler<>(Sku.class)); - } - - public static BulkResponse bulkImport(List skuList) throws IOException { - BulkRequest bulkRequest = new BulkRequest(); - for (Sku sku : skuList) { - Map skuMap = new HashMap(); - IndexRequest indexRequest = new IndexRequest("sku", "doc", sku.getSkuId()); - skuMap.put("name", sku.getName()); - skuMap.put("price", sku.getPrice()); - skuMap.put("image", sku.getImage()); - skuMap.put("createTime", DateUtils.dateFormat(sku.getCreateTime())); - skuMap.put("categoryName", sku.getCategoryName()); - skuMap.put("brandName", sku.getBrandName()); - // "{'颜色': '红色', '版本': '8GB+128GB'}" - Map spec = JSON.parseObject(sku.getSpec()); - skuMap.put("spec", spec); - skuMap.put("commentNum", sku.getCommentNum()); - skuMap.put("saleNum", sku.getSaleNum()); - skuMap.put("spuId", sku.getSpuId()); - indexRequest.source(skuMap); - bulkRequest.add(indexRequest); - } - return restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT); - } -} diff --git a/database/elasticsearch/src/main/java/cn/lastwhisper/elasticsearch/operation/entity/Sku.java b/database/elasticsearch/src/main/java/cn/lastwhisper/elasticsearch/operation/entity/Sku.java deleted file mode 100644 index 1fe9ffaa..00000000 --- a/database/elasticsearch/src/main/java/cn/lastwhisper/elasticsearch/operation/entity/Sku.java +++ /dev/null @@ -1,111 +0,0 @@ -package cn.lastwhisper.elasticsearch.operation.entity; - -import java.util.Date; - -/** - * - * @author lastwhisper - * @date 2019/12/1 - */ -public class Sku { - private String skuId; - private String name; - private Integer price; - private String image; - private Date createTime; - private String categoryName; - private String brandName; - private String spec; - private Integer commentNum; - private Integer saleNum; - private String spuId; - - public String getSkuId() { - return skuId; - } - - public void setSkuId(String skuId) { - this.skuId = skuId; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public Integer getPrice() { - return price; - } - - public void setPrice(Integer price) { - this.price = price; - } - - public String getImage() { - return image; - } - - public void setImage(String image) { - this.image = image; - } - - public Date getCreateTime() { - return createTime; - } - - public void setCreateTime(Date createTime) { - this.createTime = createTime; - } - - public String getCategoryName() { - return categoryName; - } - - public void setCategoryName(String categoryName) { - this.categoryName = categoryName; - } - - public String getBrandName() { - return brandName; - } - - public void setBrandName(String brandName) { - this.brandName = brandName; - } - - public String getSpec() { - return spec; - } - - public void setSpec(String spec) { - this.spec = spec; - } - - public Integer getCommentNum() { - return commentNum; - } - - public void setCommentNum(Integer commentNum) { - this.commentNum = commentNum; - } - - public Integer getSaleNum() { - return saleNum; - } - - public void setSaleNum(Integer saleNum) { - this.saleNum = saleNum; - } - - public String getSpuId() { - return spuId; - } - - public void setSpuId(String spuId) { - this.spuId = spuId; - } - -} diff --git a/database/elasticsearch/src/main/java/cn/lastwhisper/elasticsearch/operation/enums/DbConfig.java b/database/elasticsearch/src/main/java/cn/lastwhisper/elasticsearch/operation/enums/DbConfig.java deleted file mode 100644 index b04757cf..00000000 --- a/database/elasticsearch/src/main/java/cn/lastwhisper/elasticsearch/operation/enums/DbConfig.java +++ /dev/null @@ -1,22 +0,0 @@ -package cn.lastwhisper.elasticsearch.operation.enums; - -public enum DbConfig { - DB_DRIVER("com.mysql.jdbc.Driver"), - DB_URL("jdbc:mysql://127.0.0.1:3306/qingcheng_goods?useUnicode=true&characterEncoding=utf8&useSSL=true"), - DB_USERNAME("root"), - DB_PASSWORD("root"), - - ES_HOSTNAME("127.0.0.1"), - ES_SCHEMA("http"), - ; - - String value; - - DbConfig(String value) { - this.value = value; - } - - public String getValue() { - return value; - } -} \ No newline at end of file diff --git a/database/elasticsearch/src/main/java/cn/lastwhisper/elasticsearch/operation/utils/DateUtils.java b/database/elasticsearch/src/main/java/cn/lastwhisper/elasticsearch/operation/utils/DateUtils.java deleted file mode 100644 index fc942509..00000000 --- a/database/elasticsearch/src/main/java/cn/lastwhisper/elasticsearch/operation/utils/DateUtils.java +++ /dev/null @@ -1,19 +0,0 @@ -package cn.lastwhisper.elasticsearch.operation.utils; - -import java.text.SimpleDateFormat; -import java.util.Date; - -/** - * 时间工具类 - * @author lastwhisper - * @date 2019/12/1 - */ -public class DateUtils { - - static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); - - public static String dateFormat(Date date) { - return sdf.format(date); - } - -} diff --git a/database/elasticsearch/src/test/java/cn/lastwhisper/elasticsearch/operation/BulkSave.java b/database/elasticsearch/src/test/java/cn/lastwhisper/elasticsearch/operation/BulkSave.java deleted file mode 100644 index a6ebea53..00000000 --- a/database/elasticsearch/src/test/java/cn/lastwhisper/elasticsearch/operation/BulkSave.java +++ /dev/null @@ -1,57 +0,0 @@ -package cn.lastwhisper.elasticsearch.operation; - -import org.apache.http.HttpHost; -import org.elasticsearch.action.bulk.BulkRequest; -import org.elasticsearch.action.bulk.BulkResponse; -import org.elasticsearch.action.index.IndexRequest; -import org.elasticsearch.client.RequestOptions; -import org.elasticsearch.client.RestClient; -import org.elasticsearch.client.RestClientBuilder; -import org.elasticsearch.client.RestHighLevelClient; - -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; - - -/** - * - * @author lastwhisper - * @date 2019/12/1 - */ -public class BulkSave { - - public static void main(String[] args) throws IOException { - //1.连接rest接口 - HttpHost http = new HttpHost("127.0.0.1", 9200, "http"); - RestClientBuilder builder = RestClient.builder(http);//rest构建器 - RestHighLevelClient restHighLevelClient = new - RestHighLevelClient(builder);//高级客户端对象 - //2.封装请求对象 - BulkRequest bulkRequest = new BulkRequest(); - IndexRequest indexRequest = new IndexRequest("sku", "doc", "4"); - Map skuMap = new HashMap(); - skuMap.put("name", "华为p30pro 火爆上市"); - skuMap.put("brandName", "华为"); - skuMap.put("categoryName", "手机"); - skuMap.put("price", 1010221); - skuMap.put("createTime", "2019‐05‐01"); - skuMap.put("saleNum", 101021); - skuMap.put("commentNum", 10102321); - Map spec = new HashMap(); - spec.put("网络制式", "移动4G"); - spec.put("屏幕尺寸", "5"); - skuMap.put("spec", spec); - indexRequest.source(skuMap); - bulkRequest.add(indexRequest);//可以多次添加 - //3.获取响应结果 - BulkResponse response = - restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT); - int status = response.status().getStatus(); - System.out.println(status); - String message = response.buildFailureMessage(); - System.out.println(message); - restHighLevelClient.close(); - } - -} diff --git a/database/elasticsearch/src/test/java/cn/lastwhisper/elasticsearch/operation/Save.java b/database/elasticsearch/src/test/java/cn/lastwhisper/elasticsearch/operation/Save.java deleted file mode 100644 index 9c7aeb92..00000000 --- a/database/elasticsearch/src/test/java/cn/lastwhisper/elasticsearch/operation/Save.java +++ /dev/null @@ -1,57 +0,0 @@ -package cn.lastwhisper.elasticsearch.operation; - -import org.apache.http.HttpHost; -import org.elasticsearch.action.index.IndexRequest; -import org.elasticsearch.action.index.IndexResponse; -import org.elasticsearch.client.RequestOptions; -import org.elasticsearch.client.RestClient; -import org.elasticsearch.client.RestClientBuilder; -import org.elasticsearch.client.RestHighLevelClient; - -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; - -/** - * 新增或修改数据 - * @author lastwhisper - * @date 2019/11/26 - */ -public class Save { - /** - * HttpHost : url地址封装 - * RestClientBuilder: rest客户端构建器 - * RestHighLevelClient: rest高级客户端 - * IndexRequest: 新增或修改请求 - * IndexResponse:新增或修改的响应结果 - */ - public static void main(String[] args) throws IOException { - //1.连接rest接口 - HttpHost http = new HttpHost("127.0.0.1", 9200, "http"); - // rest构建器 - RestClientBuilder builder = RestClient.builder(http); - // 高级客户端对象 - RestHighLevelClient restHighLevelClient = new RestHighLevelClient(builder); - //2.封装请求对象 - IndexRequest indexRequest = new IndexRequest("sku", "doc", "3"); - Map skuMap = new HashMap(); - skuMap.put("name", "华为p30pro"); - skuMap.put("brandName", "华为"); - skuMap.put("categoryName", "手机"); - skuMap.put("price", 1010221); - skuMap.put("createTime", "2019-05-01"); - skuMap.put("saleNum", 101021); - skuMap.put("commentNum", 10102321); - Map spec = new HashMap(); - spec.put("网络制式", "移动4G"); - spec.put("屏幕尺寸", "5"); - skuMap.put("spec", spec); - indexRequest.source(skuMap); - //3.获取响应结果 - IndexResponse response = restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT); - int status = response.status().getStatus(); - System.out.println("响应状态:" + status); - restHighLevelClient.close(); - } - -} diff --git a/database/elasticsearch/src/test/java/cn/lastwhisper/elasticsearch/operation/Select.java b/database/elasticsearch/src/test/java/cn/lastwhisper/elasticsearch/operation/Select.java deleted file mode 100644 index 22ce706a..00000000 --- a/database/elasticsearch/src/test/java/cn/lastwhisper/elasticsearch/operation/Select.java +++ /dev/null @@ -1,219 +0,0 @@ -package cn.lastwhisper.elasticsearch.operation; - -import org.apache.http.HttpHost; -import org.elasticsearch.action.search.SearchRequest; -import org.elasticsearch.action.search.SearchResponse; -import org.elasticsearch.client.RequestOptions; -import org.elasticsearch.client.RestClient; -import org.elasticsearch.client.RestClientBuilder; -import org.elasticsearch.client.RestHighLevelClient; -import org.elasticsearch.common.unit.TimeValue; -import org.elasticsearch.index.query.BoolQueryBuilder; -import org.elasticsearch.index.query.MatchQueryBuilder; -import org.elasticsearch.index.query.QueryBuilders; -import org.elasticsearch.index.query.TermQueryBuilder; -import org.elasticsearch.search.SearchHit; -import org.elasticsearch.search.SearchHits; -import org.elasticsearch.search.aggregations.Aggregation; -import org.elasticsearch.search.aggregations.AggregationBuilders; -import org.elasticsearch.search.aggregations.Aggregations; -import org.elasticsearch.search.aggregations.bucket.terms.Terms; -import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder; -import org.elasticsearch.search.builder.SearchSourceBuilder; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -import java.io.IOException; -import java.util.List; -import java.util.Map; - -/** - * 各种查询 - * @author lastwhisper - * @date 2019/11/26 - */ -public class Select { - - private RestHighLevelClient restHighLevelClient = null; - private SearchRequest searchRequest = null; - - @Before - public void init() { - //1.连接rest接口 - HttpHost http = new HttpHost("127.0.0.1", 9200, "http"); - RestClientBuilder builder = RestClient.builder(http);//rest构建器 - restHighLevelClient = new - RestHighLevelClient(builder);//高级客户端对象 - //2.封装查询请求 - searchRequest = new SearchRequest("sku"); - searchRequest.types("doc"); //设置查询的类型 - } - - //@After - public void after() throws IOException { - //3.获取查询结果 - SearchResponse searchResponse = restHighLevelClient.search(searchRequest, - RequestOptions.DEFAULT); - - // 查询花费时间,单位是毫秒 - TimeValue took = searchResponse.getTook(); - // 分片信息 - int total = searchResponse.getTotalShards(); - int success = searchResponse.getSuccessfulShards(); - int skipped = searchResponse.getSkippedShards(); - int failed = searchResponse.getFailedShards(); - // 搜索结果总览对象 - SearchHits searchHits = searchResponse.getHits(); - // 搜索到的总条数 - long totalHits = searchHits.getTotalHits(); - // 所有结果中文档得分的最高分 - float maxScore = searchHits.getMaxScore(); - - System.out.println("took:" + took); - System.out.println("_shards:"); - System.out.println(" total:" + total); - System.out.println(" success:" + success); - System.out.println(" skipped:" + skipped); - System.out.println(" failed:" + failed); - System.out.println("hits:"); - System.out.println(" total:" + totalHits); - System.out.println(" max_score:" + maxScore); - System.out.println(" hits:"); - // 搜索结果的文档对象数组,每个元素是一条搜索到的文档信息 - SearchHit[] hits = searchHits.getHits(); - for (SearchHit hit : hits) { - // 索引库 - String index = hit.getIndex(); - // 文档类型 - String type = hit.getType(); - // 文档id - String id = hit.getId(); - // 文档得分 - float score = hit.getScore(); - // 文档的源数据 - String source = hit.getSourceAsString(); - System.out.println(" _index:" + index); - System.out.println(" _type:" + type); - System.out.println(" _id:" + id); - System.out.println(" _score:" + score); - System.out.println(" _source:" + source); - } - restHighLevelClient.close(); - } - - - /** - * 匹配查询 - * 语法: - * SearchRequest: 查询请求对象 - * SearchResponse:查询响应对象 - * SearchSourceBuilder:查询源构建器 - * MatchQueryBuilder:匹配查询构建器 - * 示例: - * 查询商品名称包含手机的记录。 - */ - @Test - public void test1() throws IOException { - SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); - MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("name", "小米电视"); - searchSourceBuilder.query(matchQueryBuilder); - searchRequest.source(searchSourceBuilder); - } - - /** - * 布尔与词条查询 - * 语法: - * QueryBuilders:查询构建器工厂 - * BoolQueryBuilder:布尔查询构建器 - * TermQueryBuilder:词条查询构建器 - * 示例: - * 查询名称包含手机的,并且品牌为小米的记录 - */ - @Test - public void test2() throws IOException { - //2.封装查询请求 - SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); - // 布尔查询构建器 - BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery(); - MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("name", "手机"); - // 词条查询构建器 - TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("brandName", "小米"); - - boolQueryBuilder.must(matchQueryBuilder); - boolQueryBuilder.must(termQueryBuilder); - - searchSourceBuilder.query(boolQueryBuilder); - searchRequest.source(searchSourceBuilder); - - } - - /** - * 过滤查询 - * 示例:筛选品牌为小米的记录 - */ - @Test - public void test3() throws IOException { - //2.封装查询请求 - SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); - // 布尔查询构建器 - BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery(); - // 词条查询构建器 - TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("brandName", "小米"); - - boolQueryBuilder.filter(termQueryBuilder); - - searchSourceBuilder.query(boolQueryBuilder); - searchRequest.source(searchSourceBuilder); - } - - /** - * 分组(聚合)查询 - * 语法: - * AggregationBuilders:聚合构建器工厂 - * TermsAggregationBuilder:词条聚合构建器 - * Aggregations:分组结果封装 - * Terms.Bucket: 桶 - * 示例: - * 按商品分类分组查询,求出每个分类的文档数 - */ - @Test - public void test4() throws IOException { - //1.连接rest接口 - HttpHost http = new HttpHost("127.0.0.1", 9200, "http"); - RestClientBuilder builder = RestClient.builder(http);//rest构建器 - RestHighLevelClient restHighLevelClient = new - RestHighLevelClient(builder);//高级客户端对象 - //2.封装查询请求 - SearchRequest searchRequest = new SearchRequest("sku"); - searchRequest.types("doc"); //设置查询的类型 - SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); - - TermsAggregationBuilder termsAggregationBuilder = AggregationBuilders - .terms("sku_category").field("categoryName"); - searchSourceBuilder.aggregation(termsAggregationBuilder); - searchSourceBuilder.size(0); - searchRequest.source(searchSourceBuilder); - - //3.获取查询结果 - SearchResponse searchResponse = restHighLevelClient.search(searchRequest, - RequestOptions.DEFAULT); - Aggregations aggregations = searchResponse.getAggregations(); - - Map asMap = aggregations.getAsMap(); - Terms terms = (Terms) asMap.get("sku_category"); - List buckets = terms.getBuckets(); - for (Terms.Bucket bucket : buckets) { - System.out.println(bucket.getKeyAsString() + ":" + bucket.getDocCount() - ); - } - restHighLevelClient.close(); - } - - /** - * 范围查询 - * RangeQueryBuilder rangeQueryBuilder = - * QueryBuilders.rangeQuery("price").gte(10000).lte(20000); - */ - -} diff --git a/database/elasticsearch/target/classes/META-INF/elasticsearch.kotlin_module b/database/elasticsearch/target/classes/META-INF/elasticsearch.kotlin_module deleted file mode 100644 index 2983af70..00000000 Binary files a/database/elasticsearch/target/classes/META-INF/elasticsearch.kotlin_module and /dev/null differ diff --git a/database/elasticsearch/target/classes/cn/lastwhisper/elasticsearch/operation/QingChengESData.class b/database/elasticsearch/target/classes/cn/lastwhisper/elasticsearch/operation/QingChengESData.class deleted file mode 100644 index e1eab8ba..00000000 Binary files a/database/elasticsearch/target/classes/cn/lastwhisper/elasticsearch/operation/QingChengESData.class and /dev/null differ diff --git a/database/elasticsearch/target/classes/cn/lastwhisper/elasticsearch/operation/entity/Sku.class b/database/elasticsearch/target/classes/cn/lastwhisper/elasticsearch/operation/entity/Sku.class deleted file mode 100644 index 04a4fac4..00000000 Binary files a/database/elasticsearch/target/classes/cn/lastwhisper/elasticsearch/operation/entity/Sku.class and /dev/null differ diff --git a/database/elasticsearch/target/classes/cn/lastwhisper/elasticsearch/operation/enums/DbConfig.class b/database/elasticsearch/target/classes/cn/lastwhisper/elasticsearch/operation/enums/DbConfig.class deleted file mode 100644 index 48e84f0e..00000000 Binary files a/database/elasticsearch/target/classes/cn/lastwhisper/elasticsearch/operation/enums/DbConfig.class and /dev/null differ diff --git a/database/elasticsearch/target/classes/cn/lastwhisper/elasticsearch/operation/utils/DateUtils.class b/database/elasticsearch/target/classes/cn/lastwhisper/elasticsearch/operation/utils/DateUtils.class deleted file mode 100644 index 95088880..00000000 Binary files a/database/elasticsearch/target/classes/cn/lastwhisper/elasticsearch/operation/utils/DateUtils.class and /dev/null differ diff --git a/database/elasticsearch/target/test-classes/META-INF/elasticsearch.kotlin_module b/database/elasticsearch/target/test-classes/META-INF/elasticsearch.kotlin_module deleted file mode 100644 index 2983af70..00000000 Binary files a/database/elasticsearch/target/test-classes/META-INF/elasticsearch.kotlin_module and /dev/null differ diff --git a/database/elasticsearch/target/test-classes/cn/lastwhisper/elasticsearch/operation/BulkSave.class b/database/elasticsearch/target/test-classes/cn/lastwhisper/elasticsearch/operation/BulkSave.class deleted file mode 100644 index 0a3381e2..00000000 Binary files a/database/elasticsearch/target/test-classes/cn/lastwhisper/elasticsearch/operation/BulkSave.class and /dev/null differ diff --git a/database/elasticsearch/target/test-classes/cn/lastwhisper/elasticsearch/operation/Save.class b/database/elasticsearch/target/test-classes/cn/lastwhisper/elasticsearch/operation/Save.class deleted file mode 100644 index 8e871867..00000000 Binary files a/database/elasticsearch/target/test-classes/cn/lastwhisper/elasticsearch/operation/Save.class and /dev/null differ diff --git a/database/elasticsearch/target/test-classes/cn/lastwhisper/elasticsearch/operation/Select.class b/database/elasticsearch/target/test-classes/cn/lastwhisper/elasticsearch/operation/Select.class deleted file mode 100644 index ce3be4fd..00000000 Binary files a/database/elasticsearch/target/test-classes/cn/lastwhisper/elasticsearch/operation/Select.class and /dev/null differ diff --git a/database/mysql/mysql1/pom.xml b/database/mysql/mysql1/pom.xml deleted file mode 100644 index 186c2480..00000000 --- a/database/mysql/mysql1/pom.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - mysql - cn.lastwhisper - 1.0-SNAPSHOT - - 4.0.0 - - cn.lastwhisper - mysql1 - mysql主从复制,读写分离,java实现多数据源 - - \ No newline at end of file diff --git a/database/mysql/mysql1/src/main/java/cn/lastwhisper/v1/db/DbContextHolder.java b/database/mysql/mysql1/src/main/java/cn/lastwhisper/v1/db/DbContextHolder.java deleted file mode 100644 index f1149802..00000000 --- a/database/mysql/mysql1/src/main/java/cn/lastwhisper/v1/db/DbContextHolder.java +++ /dev/null @@ -1,21 +0,0 @@ -package cn.lastwhisper.v1.db; - -/** - * @author lastwhisper - */ -public class DbContextHolder { - - public static final String MASTER = "master"; - public static final String SLAVE = "slave"; - - private static ThreadLocal datasource = new ThreadLocal<>(); - - public static void set(String name) { - datasource.set(name); - } - - public static String get() { - return datasource.get(); - } - -} diff --git a/database/mysql/mysql1/src/main/java/cn/lastwhisper/v1/db/DynamicDataSource.java b/database/mysql/mysql1/src/main/java/cn/lastwhisper/v1/db/DynamicDataSource.java deleted file mode 100644 index f7dd831d..00000000 --- a/database/mysql/mysql1/src/main/java/cn/lastwhisper/v1/db/DynamicDataSource.java +++ /dev/null @@ -1,16 +0,0 @@ -package cn.lastwhisper.v1.db; - -import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; - -/** - * @author lastwhisper - */ -public class DynamicDataSource extends AbstractRoutingDataSource { - - @Override - protected Object determineCurrentLookupKey() { - - return DbContextHolder.get(); - } - -} diff --git a/database/mysql/mysql1/src/main/java/cn/lastwhisper/v1/mapper/AppMapper.java b/database/mysql/mysql1/src/main/java/cn/lastwhisper/v1/mapper/AppMapper.java deleted file mode 100644 index 62404507..00000000 --- a/database/mysql/mysql1/src/main/java/cn/lastwhisper/v1/mapper/AppMapper.java +++ /dev/null @@ -1,10 +0,0 @@ -package cn.lastwhisper.v1.mapper; - -import org.apache.ibatis.annotations.Param; - -import java.util.List; -import java.util.Map; - -public interface AppMapper { - List> executeQuery(@Param("sql") String sql); -} diff --git a/database/mysql/mysql1/src/main/java/cn/lastwhisper/v1/mapper/AppMapper.xml b/database/mysql/mysql1/src/main/java/cn/lastwhisper/v1/mapper/AppMapper.xml deleted file mode 100644 index 2ddeb064..00000000 --- a/database/mysql/mysql1/src/main/java/cn/lastwhisper/v1/mapper/AppMapper.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/database/mysql/mysql1/src/main/java/cn/lastwhisper/v1/test/Main.java b/database/mysql/mysql1/src/main/java/cn/lastwhisper/v1/test/Main.java deleted file mode 100644 index 49340d67..00000000 --- a/database/mysql/mysql1/src/main/java/cn/lastwhisper/v1/test/Main.java +++ /dev/null @@ -1,21 +0,0 @@ -package cn.lastwhisper.v1.test; - -import cn.lastwhisper.v1.db.DbContextHolder; -import cn.lastwhisper.v1.mapper.AppMapper; -import org.springframework.context.support.ClassPathXmlApplicationContext; - -/** - * @author lastwhisper - */ -public class Main { - - public static void main(String[] args){ - ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml"); - AppMapper mapper = context.getBean(AppMapper.class); - //DbContextHolder.set(DbContextHolder.MASTER); - DbContextHolder.set(DbContextHolder.SLAVE); - System.out.println(mapper.executeQuery("select * from user")); - context.close(); - } - -} diff --git a/database/mysql/mysql1/src/main/resources/applicationContext.xml b/database/mysql/mysql1/src/main/resources/applicationContext.xml deleted file mode 100644 index 27ccb43a..00000000 --- a/database/mysql/mysql1/src/main/resources/applicationContext.xml +++ /dev/null @@ -1,82 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/database/mysql/mysql1/src/main/resources/db.properties b/database/mysql/mysql1/src/main/resources/db.properties deleted file mode 100644 index fbe66283..00000000 --- a/database/mysql/mysql1/src/main/resources/db.properties +++ /dev/null @@ -1,8 +0,0 @@ -master.jdbc.driver=com.mysql.jdbc.Driver -master.jdbc.url=jdbc:mysql://192.168.108.66:3306/mytest -master.jdbc.username=root -master.jdbc.password=root -slave.jdbc.driver=com.mysql.jdbc.Driver -slave.jdbc.url=jdbc:mysql://192.168.108.67:3306/mytest -slave.jdbc.username=root -slave.jdbc.password=root \ No newline at end of file diff --git a/database/mysql/mysql1/src/main/resources/log4j.properties b/database/mysql/mysql1/src/main/resources/log4j.properties deleted file mode 100644 index ef7157ce..00000000 --- a/database/mysql/mysql1/src/main/resources/log4j.properties +++ /dev/null @@ -1,11 +0,0 @@ -# Global logging configuration\uff0c\u5efa\u8bae\u5f00\u53d1\u73af\u5883\u4e2d\u8981\u7528debug -log4j.rootLogger=DEBUG, stdout -# Console output... -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n -[java] view plain copy -log4j.rootLogger = ${log.level},Console,default,allfile -log4j.logger.com.ibatis=debug -log4j.logger.java.sql=debug -log4j.logger.com.sf.egmas.dcn.web.mapper=debug \ No newline at end of file diff --git a/database/mysql/mysql1/src/main/resources/sqlMapConfig.xml b/database/mysql/mysql1/src/main/resources/sqlMapConfig.xml deleted file mode 100644 index 40055365..00000000 --- a/database/mysql/mysql1/src/main/resources/sqlMapConfig.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - diff --git a/database/mysql/mysql2/pom.xml b/database/mysql/mysql2/pom.xml deleted file mode 100644 index 0947f570..00000000 --- a/database/mysql/mysql2/pom.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - mysql - cn.lastwhisper - 1.0-SNAPSHOT - - 4.0.0 - - cn.lastwhisper - mysql2 - mysql主从复制,读写分离,SpringAop实现多数据源 - - \ No newline at end of file diff --git a/database/mysql/mysql2/src/main/java/cn/lastwhisper/v2/annotation/DataSource.java b/database/mysql/mysql2/src/main/java/cn/lastwhisper/v2/annotation/DataSource.java deleted file mode 100644 index 8da48f14..00000000 --- a/database/mysql/mysql2/src/main/java/cn/lastwhisper/v2/annotation/DataSource.java +++ /dev/null @@ -1,12 +0,0 @@ -package cn.lastwhisper.v2.annotation; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Retention(RetentionPolicy.RUNTIME) -@Target({ElementType.METHOD,ElementType.FIELD}) -public @interface DataSource { - String value(); -} diff --git a/database/mysql/mysql2/src/main/java/cn/lastwhisper/v2/aop/DataSourceAspect.java b/database/mysql/mysql2/src/main/java/cn/lastwhisper/v2/aop/DataSourceAspect.java deleted file mode 100644 index 9263bb77..00000000 --- a/database/mysql/mysql2/src/main/java/cn/lastwhisper/v2/aop/DataSourceAspect.java +++ /dev/null @@ -1,31 +0,0 @@ -package cn.lastwhisper.v2.aop; - -import cn.lastwhisper.v2.annotation.DataSource; -import cn.lastwhisper.v2.db.DbContextHolder; -import org.aspectj.lang.JoinPoint; -import org.aspectj.lang.reflect.MethodSignature; - -import java.lang.reflect.Method; - -/** - * @author lastwhisper - */ -public class DataSourceAspect { - - public void before(JoinPoint point) { - MethodSignature signature = (MethodSignature) point.getSignature(); - Method method = signature.getMethod(); - - DataSource dataSource = method.getAnnotation(DataSource.class); - - String source = dataSource.value(); - System.out.println(source); - // 设置数据源 - DbContextHolder.set(source); - } - - public void after() { - DbContextHolder.clear(); - } - -} diff --git a/database/mysql/mysql2/src/main/java/cn/lastwhisper/v2/db/DbContextHolder.java b/database/mysql/mysql2/src/main/java/cn/lastwhisper/v2/db/DbContextHolder.java deleted file mode 100644 index 22f218bb..00000000 --- a/database/mysql/mysql2/src/main/java/cn/lastwhisper/v2/db/DbContextHolder.java +++ /dev/null @@ -1,26 +0,0 @@ -package cn.lastwhisper.v2.db; - -/** - * @author lastwhisper - */ -public class DbContextHolder { - - public static final String MASTER = "master"; - public static final String SLAVE = "slave"; - - private static ThreadLocal datasource = new ThreadLocal<>(); - - public static void set(String name) { - datasource.set(name); - } - - public static String get() { - String source = datasource.get() == null ? DbContextHolder.MASTER : datasource.get(); - return source; - } - - // 清空数据类型 - public static void clear() { - datasource.remove(); - } -} diff --git a/database/mysql/mysql2/src/main/java/cn/lastwhisper/v2/db/DynamicDataSource.java b/database/mysql/mysql2/src/main/java/cn/lastwhisper/v2/db/DynamicDataSource.java deleted file mode 100644 index 710ce078..00000000 --- a/database/mysql/mysql2/src/main/java/cn/lastwhisper/v2/db/DynamicDataSource.java +++ /dev/null @@ -1,16 +0,0 @@ -package cn.lastwhisper.v2.db; - -import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; - -/** - * @author lastwhisper - */ -public class DynamicDataSource extends AbstractRoutingDataSource { - - @Override - protected Object determineCurrentLookupKey() { - String source = DbContextHolder.get(); - return source; - } - -} diff --git a/database/mysql/mysql2/src/main/java/cn/lastwhisper/v2/mapper/AppMapper.java b/database/mysql/mysql2/src/main/java/cn/lastwhisper/v2/mapper/AppMapper.java deleted file mode 100644 index 3f9ffc16..00000000 --- a/database/mysql/mysql2/src/main/java/cn/lastwhisper/v2/mapper/AppMapper.java +++ /dev/null @@ -1,17 +0,0 @@ -package cn.lastwhisper.v2.mapper; - -import cn.lastwhisper.v2.annotation.DataSource; -import cn.lastwhisper.v2.db.DbContextHolder; -import org.apache.ibatis.annotations.Param; - -import java.util.List; -import java.util.Map; - -public interface AppMapper { - - @DataSource(value = DbContextHolder.MASTER) - List> executeQuery(@Param("sql") String sql); - - @DataSource(value = DbContextHolder.SLAVE) - List> executeQuery2(@Param("sql") String sql); -} diff --git a/database/mysql/mysql2/src/main/java/cn/lastwhisper/v2/mapper/AppMapper.xml b/database/mysql/mysql2/src/main/java/cn/lastwhisper/v2/mapper/AppMapper.xml deleted file mode 100644 index daa963fe..00000000 --- a/database/mysql/mysql2/src/main/java/cn/lastwhisper/v2/mapper/AppMapper.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/database/mysql/mysql2/src/main/java/cn/lastwhisper/v2/test/Main.java b/database/mysql/mysql2/src/main/java/cn/lastwhisper/v2/test/Main.java deleted file mode 100644 index 25d331ea..00000000 --- a/database/mysql/mysql2/src/main/java/cn/lastwhisper/v2/test/Main.java +++ /dev/null @@ -1,22 +0,0 @@ -package cn.lastwhisper.v2.test; - -import cn.lastwhisper.v2.db.DbContextHolder; -import cn.lastwhisper.v2.mapper.AppMapper; -import org.springframework.context.support.ClassPathXmlApplicationContext; - -/** - * @author lastwhisper - */ -public class Main { - - public static void main(String[] args){ - ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml"); - AppMapper mapper = context.getBean(AppMapper.class); - //DbContextHolder.set(DbContextHolder.MASTER); - System.out.println(mapper.executeQuery("select * from user")); - //DbContextHolder.set(DbContextHolder.SLAVE); - System.out.println(mapper.executeQuery2("select * from user")); - context.close(); - } - -} diff --git a/database/mysql/mysql2/src/main/resources/applicationContext.xml b/database/mysql/mysql2/src/main/resources/applicationContext.xml deleted file mode 100644 index 8a49b1de..00000000 --- a/database/mysql/mysql2/src/main/resources/applicationContext.xml +++ /dev/null @@ -1,95 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/database/mysql/mysql2/src/main/resources/db.properties b/database/mysql/mysql2/src/main/resources/db.properties deleted file mode 100644 index fbe66283..00000000 --- a/database/mysql/mysql2/src/main/resources/db.properties +++ /dev/null @@ -1,8 +0,0 @@ -master.jdbc.driver=com.mysql.jdbc.Driver -master.jdbc.url=jdbc:mysql://192.168.108.66:3306/mytest -master.jdbc.username=root -master.jdbc.password=root -slave.jdbc.driver=com.mysql.jdbc.Driver -slave.jdbc.url=jdbc:mysql://192.168.108.67:3306/mytest -slave.jdbc.username=root -slave.jdbc.password=root \ No newline at end of file diff --git a/database/mysql/mysql2/src/main/resources/log4j.properties b/database/mysql/mysql2/src/main/resources/log4j.properties deleted file mode 100644 index 70cce320..00000000 --- a/database/mysql/mysql2/src/main/resources/log4j.properties +++ /dev/null @@ -1,11 +0,0 @@ -# Global logging configuration\uff0c\u5efa\u8bae\u5f00\u53d1\u73af\u5883\u4e2d\u8981\u7528debug -log4j.rootLogger=DEBUG, stdout -# Console output... -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n -[java] view plain copy -log4j.rootLogger = ${log.level},Console,default,allfile -log4j.logger.com.ibatis=debug -log4j.logger.java.sql=debug -log4j.logger.cn.lastwhisper.v2.mapper=debug \ No newline at end of file diff --git a/database/mysql/mysql2/src/main/resources/sqlMapConfig.xml b/database/mysql/mysql2/src/main/resources/sqlMapConfig.xml deleted file mode 100644 index 1ad521f4..00000000 --- a/database/mysql/mysql2/src/main/resources/sqlMapConfig.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/database/mysql/mysql3/pom.xml b/database/mysql/mysql3/pom.xml deleted file mode 100644 index 9a9898b9..00000000 --- a/database/mysql/mysql3/pom.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - mysql - cn.lastwhisper - 1.0-SNAPSHOT - - 4.0.0 - - cn.lastwhisper - mysql3 - mysql逻辑分表,水平分表 - - \ No newline at end of file diff --git a/database/mysql/mysql3/src/main/java/cn/lastwhisper/v3/domain/Archievement.java b/database/mysql/mysql3/src/main/java/cn/lastwhisper/v3/domain/Archievement.java deleted file mode 100644 index ca6c865a..00000000 --- a/database/mysql/mysql3/src/main/java/cn/lastwhisper/v3/domain/Archievement.java +++ /dev/null @@ -1,25 +0,0 @@ -package cn.lastwhisper.v3.domain; - -/** - * @author lastwhisper - */ -public class Archievement { - private Integer id; - private String name; - - public Integer getId() { - return id; - } - - public void setId(Integer id) { - this.id = id; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } -} diff --git a/database/mysql/mysql3/src/main/java/cn/lastwhisper/v3/mapper/AppMapper.java b/database/mysql/mysql3/src/main/java/cn/lastwhisper/v3/mapper/AppMapper.java deleted file mode 100644 index f0bbffe7..00000000 --- a/database/mysql/mysql3/src/main/java/cn/lastwhisper/v3/mapper/AppMapper.java +++ /dev/null @@ -1,12 +0,0 @@ -package cn.lastwhisper.v3.mapper; - -import org.apache.ibatis.annotations.Param; - -import java.util.List; -import java.util.Map; - -public interface AppMapper { - List> executeQuery(@Param("sql") String sql); - - List> executeQuery2(@Param("sql") String sql); -} diff --git a/database/mysql/mysql3/src/main/java/cn/lastwhisper/v3/mapper/AppMapper.xml b/database/mysql/mysql3/src/main/java/cn/lastwhisper/v3/mapper/AppMapper.xml deleted file mode 100644 index 9d44a2df..00000000 --- a/database/mysql/mysql3/src/main/java/cn/lastwhisper/v3/mapper/AppMapper.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/database/mysql/mysql3/src/main/java/cn/lastwhisper/v3/test/Main.java b/database/mysql/mysql3/src/main/java/cn/lastwhisper/v3/test/Main.java deleted file mode 100644 index 380471e7..00000000 --- a/database/mysql/mysql3/src/main/java/cn/lastwhisper/v3/test/Main.java +++ /dev/null @@ -1,26 +0,0 @@ -package cn.lastwhisper.v3.test; - -import cn.lastwhisper.v3.mapper.AppMapper; -import org.springframework.context.support.ClassPathXmlApplicationContext; - -import java.util.Calendar; - -/** - * 水平分表 - * @author lastwhisper - */ -public class Main { - - public static void main(String[] args) { - ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml"); - AppMapper mapper = context.getBean(AppMapper.class); - - String currYear = "2016"; - //String sql = "insert into t_archievement_" + currYear + "(name) values('second')"; - String sql = "select * from t_archievement_" + currYear; - System.out.println(mapper.executeQuery(sql));; - - context.close(); - } - -} diff --git a/database/mysql/mysql3/src/main/resources/applicationContext.xml b/database/mysql/mysql3/src/main/resources/applicationContext.xml deleted file mode 100644 index c5aaa79d..00000000 --- a/database/mysql/mysql3/src/main/resources/applicationContext.xml +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/database/mysql/mysql3/src/main/resources/db.properties b/database/mysql/mysql3/src/main/resources/db.properties deleted file mode 100644 index b5f8c2fc..00000000 --- a/database/mysql/mysql3/src/main/resources/db.properties +++ /dev/null @@ -1,4 +0,0 @@ -jdbc.driver=com.mysql.jdbc.Driver -jdbc.url=jdbc:mysql://192.168.108.100:3306/mytest -jdbc.username=root -jdbc.password=root \ No newline at end of file diff --git a/database/mysql/mysql3/src/main/resources/log4j.properties b/database/mysql/mysql3/src/main/resources/log4j.properties deleted file mode 100644 index ef7157ce..00000000 --- a/database/mysql/mysql3/src/main/resources/log4j.properties +++ /dev/null @@ -1,11 +0,0 @@ -# Global logging configuration\uff0c\u5efa\u8bae\u5f00\u53d1\u73af\u5883\u4e2d\u8981\u7528debug -log4j.rootLogger=DEBUG, stdout -# Console output... -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n -[java] view plain copy -log4j.rootLogger = ${log.level},Console,default,allfile -log4j.logger.com.ibatis=debug -log4j.logger.java.sql=debug -log4j.logger.com.sf.egmas.dcn.web.mapper=debug \ No newline at end of file diff --git a/database/mysql/mysql3/src/main/resources/sqlMapConfig.xml b/database/mysql/mysql3/src/main/resources/sqlMapConfig.xml deleted file mode 100644 index 8418d1a2..00000000 --- a/database/mysql/mysql3/src/main/resources/sqlMapConfig.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - diff --git a/database/mysql/pom.xml b/database/mysql/pom.xml deleted file mode 100644 index 9cb40bd9..00000000 --- a/database/mysql/pom.xml +++ /dev/null @@ -1,152 +0,0 @@ - - - 4.0.0 - - cn.lastwhisper - mysql - pom - 1.0-SNAPSHOT - - mysql2 - mysql1 - - - - 4.2.5.RELEASE - 1.0.23 - 4.12 - 3.2.8 - - - - - - org.springframework - spring-core - ${spring.version} - - - org.springframework - spring-aop - ${spring.version} - - - org.springframework - spring-web - ${spring.version} - - - org.springframework - spring-webmvc - ${spring.version} - - - org.springframework - spring-jdbc - ${spring.version} - - - org.springframework - spring-tx - ${spring.version} - - - - - org.aspectj - aspectjrt - 1.8.0 - - - org.aspectj - aspectjweaver - 1.8.0 - - - - - - org.mybatis - mybatis - ${mybatis.version} - - - - mysql - mysql-connector-java - 5.1.26 - - - - com.alibaba - druid - ${druid.version} - - - - - org.mybatis - mybatis-spring - 1.2.3 - - - - - junit - junit - ${junit.version} - - - - - - - src/main/java - - **/*.properties - **/*.xml - - false - - - src/main/resources - - **/*.properties - **/*.xml - - false - - - - - - org.apache.maven.plugins - maven-compiler-plugin - - 1.8 - 1.8 - UTF-8 - - - - org.apache.maven.plugins - maven-war-plugin - 2.6 - - false - - - - - org.apache.maven.plugins - maven-surefire-plugin - - true - - - - - - \ No newline at end of file diff --git a/database/redis/pom.xml b/database/redis/pom.xml deleted file mode 100644 index deb4a90f..00000000 --- a/database/redis/pom.xml +++ /dev/null @@ -1,59 +0,0 @@ - - - 4.0.0 - - cn.lastwhisper - redis - 1.0-SNAPSHOT - - - - - com.redislabs - jrebloom - 1.0.1 - - - - com.alibaba - fastjson - 1.2.56 - - - - com.google.guava - guava - 27.0.1-jre - - - - - redis.clients - jedis - 2.9.0 - - - - junit - junit - 4.12 - - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.7.0 - - 1.8 - 1.8 - - - - - \ No newline at end of file diff --git a/database/redis/reademe b/database/redis/reademe deleted file mode 100644 index 63308e8f..00000000 --- a/database/redis/reademe +++ /dev/null @@ -1,18 +0,0 @@ -redis学习时的代码笔记 -asynqueue 异步队列 -basic 基础数据结构操作 -cluster Java集群操作 -dlock redis分布式锁 -hyperloglog 统计 -bloomfilter 布隆过滤器 -partition hash节点迁移率 -pipeline 流水线指令 -publishersubscriber 发布订阅 -sentinel 哨兵 -transaction 事务 - - - - - - diff --git a/database/redis/src/main/java/cn/lastwhisper/redis/basic/BasicOperation.java b/database/redis/src/main/java/cn/lastwhisper/redis/basic/BasicOperation.java deleted file mode 100644 index 81dac8bc..00000000 --- a/database/redis/src/main/java/cn/lastwhisper/redis/basic/BasicOperation.java +++ /dev/null @@ -1,12 +0,0 @@ -package cn.lastwhisper.redis.basic; - -/** - * Redis基础数据结构的操作 - * @author lastwhisper - * @date 2019/11/23 - */ -public class BasicOperation { - - - -} diff --git a/database/redis/src/main/java/cn/lastwhisper/redis/dlock/LockTest.java b/database/redis/src/main/java/cn/lastwhisper/redis/dlock/LockTest.java deleted file mode 100644 index adcde4d8..00000000 --- a/database/redis/src/main/java/cn/lastwhisper/redis/dlock/LockTest.java +++ /dev/null @@ -1,76 +0,0 @@ -package cn.lastwhisper.redis.dlock; - -import redis.clients.jedis.Jedis; - -/** - * 分布式锁上锁正确实例与错误实例 - * https://wudashan.cn/2017/10/23/Redis-Distributed-Lock-Implement/ - * @author lastwhisper - */ -public class LockTest { - - private static final String LOCK_SUCCESS = "OK"; - private static final String SET_IF_NOT_EXIST = "NX"; - private static final String SET_WITH_EXPIRE_TIME = "PX"; - - /** - * 尝试获取分布式锁 - * @param jedis Redis客户端 - * @param lockKey 锁 - * @param requestId 请求标识 - * @param expireTime 超期时间 - * @return 是否获取成功 - */ - public static boolean tryGetDistributedLock(Jedis jedis, String lockKey, String requestId, int expireTime) { - String result = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime); - if (LOCK_SUCCESS.equals(result)) { - return true; - } - return false; - - } - - /** - * 尝试获取分布式锁 - * @param jedis Redis客户端 - * @param lockKey 锁 - * @param requestId 请求标识 - * @param expireTime 超期时间 - */ - public static void wrongGetLock1(Jedis jedis, String lockKey, String requestId, int expireTime) { - - Long result = jedis.setnx(lockKey, requestId); - if (result == 1) { - // 若在这里程序突然崩溃,则无法设置过期时间,将发生死锁 - jedis.expire(lockKey, expireTime); - } - - } - - - public static boolean wrongGetLock2(Jedis jedis, String lockKey, int expireTime) { - - long expires = System.currentTimeMillis() + expireTime; - String expiresStr = String.valueOf(expires); - - // 如果当前锁不存在,返回加锁成功 - if (jedis.setnx(lockKey, expiresStr) == 1) { - return true; - } - - // 如果锁存在,获取锁的过期时间 - String currentValueStr = jedis.get(lockKey); - if (currentValueStr != null && Long.parseLong(currentValueStr) < System.currentTimeMillis()) { - // 锁已过期,获取上一个锁的过期时间,并设置现在锁的过期时间 - String oldValueStr = jedis.getSet(lockKey, expiresStr); - if (oldValueStr != null && oldValueStr.equals(currentValueStr)) { - // 考虑多线程并发的情况,只有一个线程的设置值和当前值相同,它才有权利加锁 - return true; - } - } - - // 其他情况,一律返回加锁失败 - return false; - - } -} diff --git a/database/redis/src/main/java/cn/lastwhisper/redis/dlock/UnLockTest.java b/database/redis/src/main/java/cn/lastwhisper/redis/dlock/UnLockTest.java deleted file mode 100644 index 3bb5e1b3..00000000 --- a/database/redis/src/main/java/cn/lastwhisper/redis/dlock/UnLockTest.java +++ /dev/null @@ -1,54 +0,0 @@ -package cn.lastwhisper.redis.dlock; - -import redis.clients.jedis.Jedis; - -import java.util.Collections; - -/** - * 分布式锁解锁正确实例与错误实例 - * @author lastwhisper - */ -public class UnLockTest { - private static final Long RELEASE_SUCCESS = 1L; - - /** - * lua脚本释放分布式锁 - * @param jedis Redis客户端 - * @param lockKey 锁 - * @param requestId 请求标识 - * @return 是否释放成功 - */ - public static boolean releaseDistributedLock(Jedis jedis, String lockKey, String requestId) { - // 首先获取锁对应的value值,检查是否与requestId相等,如果相等则删除锁(解锁) - String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end"; - Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId)); - - if (RELEASE_SUCCESS.equals(result)) { - return true; - } - return false; - - } - - /** - * 直接使用jedis.del()方法删除锁,这种不先判断锁的拥有者而直接解锁的方式, - * 会导致任何客户端都可以随时进行解锁,即使这把锁不是它的。 - */ - public static void wrongReleaseLock1(Jedis jedis, String lockKey) { - jedis.del(lockKey); - } - - /** - * 无法保证原子性 - */ - public static void wrongReleaseLock2(Jedis jedis, String lockKey, String requestId) { - // 判断加锁与解锁是不是同一个客户端 - if (requestId.equals(jedis.get(lockKey))) { - // 若在此时,这把锁突然不是这个客户端的,则会误解锁 - jedis.del(lockKey); - } - - } - -} - diff --git a/database/redis/target/classes/cn/lastwhisper/redis/asynqueue/RedisDelayingQueue$1.class b/database/redis/target/classes/cn/lastwhisper/redis/asynqueue/RedisDelayingQueue$1.class deleted file mode 100644 index 4cbb27f7..00000000 Binary files a/database/redis/target/classes/cn/lastwhisper/redis/asynqueue/RedisDelayingQueue$1.class and /dev/null differ diff --git a/database/redis/target/classes/cn/lastwhisper/redis/asynqueue/RedisDelayingQueue$2.class b/database/redis/target/classes/cn/lastwhisper/redis/asynqueue/RedisDelayingQueue$2.class deleted file mode 100644 index 88571fd9..00000000 Binary files a/database/redis/target/classes/cn/lastwhisper/redis/asynqueue/RedisDelayingQueue$2.class and /dev/null differ diff --git a/database/redis/target/classes/cn/lastwhisper/redis/asynqueue/RedisDelayingQueue$3.class b/database/redis/target/classes/cn/lastwhisper/redis/asynqueue/RedisDelayingQueue$3.class deleted file mode 100644 index 330c6bef..00000000 Binary files a/database/redis/target/classes/cn/lastwhisper/redis/asynqueue/RedisDelayingQueue$3.class and /dev/null differ diff --git a/database/redis/target/classes/cn/lastwhisper/redis/asynqueue/RedisDelayingQueue$TaskItem.class b/database/redis/target/classes/cn/lastwhisper/redis/asynqueue/RedisDelayingQueue$TaskItem.class deleted file mode 100644 index cca969b2..00000000 Binary files a/database/redis/target/classes/cn/lastwhisper/redis/asynqueue/RedisDelayingQueue$TaskItem.class and /dev/null differ diff --git a/database/redis/target/classes/cn/lastwhisper/redis/asynqueue/RedisDelayingQueue.class b/database/redis/target/classes/cn/lastwhisper/redis/asynqueue/RedisDelayingQueue.class deleted file mode 100644 index b0ae7d0f..00000000 Binary files a/database/redis/target/classes/cn/lastwhisper/redis/asynqueue/RedisDelayingQueue.class and /dev/null differ diff --git a/database/redis/target/classes/cn/lastwhisper/redis/basic/BasicOperation.class b/database/redis/target/classes/cn/lastwhisper/redis/basic/BasicOperation.class deleted file mode 100644 index 1f02627c..00000000 Binary files a/database/redis/target/classes/cn/lastwhisper/redis/basic/BasicOperation.class and /dev/null differ diff --git a/database/redis/target/classes/cn/lastwhisper/redis/basic/StringOper.class b/database/redis/target/classes/cn/lastwhisper/redis/basic/StringOper.class deleted file mode 100644 index f44cab85..00000000 Binary files a/database/redis/target/classes/cn/lastwhisper/redis/basic/StringOper.class and /dev/null differ diff --git a/database/redis/target/classes/cn/lastwhisper/redis/bloomfilter/BloomTest.class b/database/redis/target/classes/cn/lastwhisper/redis/bloomfilter/BloomTest.class deleted file mode 100644 index e957c206..00000000 Binary files a/database/redis/target/classes/cn/lastwhisper/redis/bloomfilter/BloomTest.class and /dev/null differ diff --git a/database/redis/target/classes/cn/lastwhisper/redis/bloomfilter/BloomTest2.class b/database/redis/target/classes/cn/lastwhisper/redis/bloomfilter/BloomTest2.class deleted file mode 100644 index 6ea15685..00000000 Binary files a/database/redis/target/classes/cn/lastwhisper/redis/bloomfilter/BloomTest2.class and /dev/null differ diff --git a/database/redis/target/classes/cn/lastwhisper/redis/bloomfilter/BloomTest3.class b/database/redis/target/classes/cn/lastwhisper/redis/bloomfilter/BloomTest3.class deleted file mode 100644 index e4fb2f9c..00000000 Binary files a/database/redis/target/classes/cn/lastwhisper/redis/bloomfilter/BloomTest3.class and /dev/null differ diff --git a/database/redis/target/classes/cn/lastwhisper/redis/bloomfilter/GuavaBloom.class b/database/redis/target/classes/cn/lastwhisper/redis/bloomfilter/GuavaBloom.class deleted file mode 100644 index 1f95bbf2..00000000 Binary files a/database/redis/target/classes/cn/lastwhisper/redis/bloomfilter/GuavaBloom.class and /dev/null differ diff --git a/database/redis/target/classes/cn/lastwhisper/redis/cluster/ClusterTest.class b/database/redis/target/classes/cn/lastwhisper/redis/cluster/ClusterTest.class deleted file mode 100644 index e73a90e4..00000000 Binary files a/database/redis/target/classes/cn/lastwhisper/redis/cluster/ClusterTest.class and /dev/null differ diff --git a/database/redis/target/classes/cn/lastwhisper/redis/cluster/JedisClusterFactory.class b/database/redis/target/classes/cn/lastwhisper/redis/cluster/JedisClusterFactory.class deleted file mode 100644 index 25d49ff3..00000000 Binary files a/database/redis/target/classes/cn/lastwhisper/redis/cluster/JedisClusterFactory.class and /dev/null differ diff --git a/database/redis/target/classes/cn/lastwhisper/redis/dlock/LockTest.class b/database/redis/target/classes/cn/lastwhisper/redis/dlock/LockTest.class deleted file mode 100644 index 6d4a5b6b..00000000 Binary files a/database/redis/target/classes/cn/lastwhisper/redis/dlock/LockTest.class and /dev/null differ diff --git a/database/redis/target/classes/cn/lastwhisper/redis/dlock/UnLockTest.class b/database/redis/target/classes/cn/lastwhisper/redis/dlock/UnLockTest.class deleted file mode 100644 index 3e150249..00000000 Binary files a/database/redis/target/classes/cn/lastwhisper/redis/dlock/UnLockTest.class and /dev/null differ diff --git a/database/redis/target/classes/cn/lastwhisper/redis/hyperloglog/PfTest.class b/database/redis/target/classes/cn/lastwhisper/redis/hyperloglog/PfTest.class deleted file mode 100644 index ac8d29b2..00000000 Binary files a/database/redis/target/classes/cn/lastwhisper/redis/hyperloglog/PfTest.class and /dev/null differ diff --git a/database/redis/target/classes/cn/lastwhisper/redis/partition/PartitionTest.class b/database/redis/target/classes/cn/lastwhisper/redis/partition/PartitionTest.class deleted file mode 100644 index 17ffe3a7..00000000 Binary files a/database/redis/target/classes/cn/lastwhisper/redis/partition/PartitionTest.class and /dev/null differ diff --git a/database/redis/target/classes/cn/lastwhisper/redis/pipeline/PipelineTest.class b/database/redis/target/classes/cn/lastwhisper/redis/pipeline/PipelineTest.class deleted file mode 100644 index 1b442a1c..00000000 Binary files a/database/redis/target/classes/cn/lastwhisper/redis/pipeline/PipelineTest.class and /dev/null differ diff --git a/database/redis/target/classes/cn/lastwhisper/redis/publishersubscriber/PublisherTest.class b/database/redis/target/classes/cn/lastwhisper/redis/publishersubscriber/PublisherTest.class deleted file mode 100644 index e094da8e..00000000 Binary files a/database/redis/target/classes/cn/lastwhisper/redis/publishersubscriber/PublisherTest.class and /dev/null differ diff --git a/database/redis/target/classes/cn/lastwhisper/redis/publishersubscriber/SubscriberTest$1.class b/database/redis/target/classes/cn/lastwhisper/redis/publishersubscriber/SubscriberTest$1.class deleted file mode 100644 index 7c7e15ca..00000000 Binary files a/database/redis/target/classes/cn/lastwhisper/redis/publishersubscriber/SubscriberTest$1.class and /dev/null differ diff --git a/database/redis/target/classes/cn/lastwhisper/redis/publishersubscriber/SubscriberTest.class b/database/redis/target/classes/cn/lastwhisper/redis/publishersubscriber/SubscriberTest.class deleted file mode 100644 index 67997bd9..00000000 Binary files a/database/redis/target/classes/cn/lastwhisper/redis/publishersubscriber/SubscriberTest.class and /dev/null differ diff --git a/database/redis/target/classes/cn/lastwhisper/redis/sentinel/SentinelTest$1.class b/database/redis/target/classes/cn/lastwhisper/redis/sentinel/SentinelTest$1.class deleted file mode 100644 index bee70f88..00000000 Binary files a/database/redis/target/classes/cn/lastwhisper/redis/sentinel/SentinelTest$1.class and /dev/null differ diff --git a/database/redis/target/classes/cn/lastwhisper/redis/sentinel/SentinelTest.class b/database/redis/target/classes/cn/lastwhisper/redis/sentinel/SentinelTest.class deleted file mode 100644 index 6b17242e..00000000 Binary files a/database/redis/target/classes/cn/lastwhisper/redis/sentinel/SentinelTest.class and /dev/null differ diff --git a/database/redis/target/classes/cn/lastwhisper/redis/transaction/TransactionTest.class b/database/redis/target/classes/cn/lastwhisper/redis/transaction/TransactionTest.class deleted file mode 100644 index 6a97e71c..00000000 Binary files a/database/redis/target/classes/cn/lastwhisper/redis/transaction/TransactionTest.class and /dev/null differ diff --git a/design-pattern/.gitattributes b/design-pattern/.gitattributes deleted file mode 100644 index 47eefcf0..00000000 --- a/design-pattern/.gitattributes +++ /dev/null @@ -1,4 +0,0 @@ -*.js linguist-language=java -*.css linguist-language=java -*.html linguist-language=java -*.jsp linguist-language=java \ No newline at end of file diff --git a/design-pattern/.gitignore b/design-pattern/.gitignore deleted file mode 100644 index 162f523a..00000000 --- a/design-pattern/.gitignore +++ /dev/null @@ -1,29 +0,0 @@ -/target/ -!.mvn/wrapper/maven-wrapper.jar -logs - -### STS or Eclipse ### -.apt_generated -.classpath -.factorypath -.project -.settings -.springBeans -.sts4-cache - -### IntelliJ IDEA ### -.idea -*.iws -*.iml -*.ipr - -### NetBeans ### -/nbproject/private/ -/nbbuild/ -/dist/ -/nbdist/ -/.nb-gradle/ -/build/ - -### VS Code ### -.vscode/ \ No newline at end of file diff --git a/design-pattern/README.md b/design-pattern/README.md deleted file mode 100644 index fba38945..00000000 --- a/design-pattern/README.md +++ /dev/null @@ -1,82 +0,0 @@ -> 设计模式源码地址:https://github.com/ggb2312/JavaNotes/tree/master/design-pattern (设计模式相关代码与笔记) -> 设计模式类图地址:https://github.com/ggb2312/JavaNotes/tree/master/design-pattern/uml -> 设计模式markdown笔记地址:https://github.com/ggb2312/JavaNotes/tree/master/design-pattern/notes -> 简书地址:https://www.jianshu.com/nb/36824480 - - -# 1. 前导 - -学设计模式最好有以下两点知识基础。 - -[软件设计七大原则](https://www.cnblogs.com/gj-blog/p/10929440.html) - -[UML类图以及类与类之间的关系](https://www.cnblogs.com/gj-blog/p/10929447.html) - -原因: -- 设计模式是围绕着软件设计七大原则来说的,每一种设计模式通常会满足一到两三种软件设计原则,同时又可能违反某一种原则。学习这些原则可以理解该设计模式适用什么业务场景以及为什么要这样做。 -- 设计模式通常都伴随着面向对象的特性(封装、继承、多态),所以会涉及到大量的类与类之间的关系。通过画类图可以更好的理解设计模式。 - -# 2. 设计模式 - -## 2.1 创建型 - -[创建型模式——简单工厂(不在GOF23种设计模式中)](https://www.cnblogs.com/gj-blog/p/10929455.html) - -[创建型模式——工厂方法(一)](https://www.cnblogs.com/gj-blog/p/10929460.html) - -[创建型模式——抽象工厂(二)](https://www.cnblogs.com/gj-blog/p/10929466.html) - -[创建型模式——建造者模式(三)](https://www.cnblogs.com/gj-blog/p/10929475.html) - -[创建型模式——单例模式(四)](https://www.cnblogs.com/gj-blog/p/10929478.html) - -[创建型模式——原型模式(五)](https://www.cnblogs.com/gj-blog/p/10929480.html) - -## 2.2 结构型 - -[结构型模式——外观模式(一)](https://www.cnblogs.com/gj-blog/p/10929486.html) - -[结构型模式——装饰者模式(二)](https://www.cnblogs.com/gj-blog/p/10929489.html) - -[结构型模式——适配器模式(三)](https://www.cnblogs.com/gj-blog/p/10929498.html) - -[结构型模式——享元模式(四)](https://www.cnblogs.com/gj-blog/p/10929493.html) - -[结构型模式——组合模式(五)](https://www.cnblogs.com/gj-blog/p/10929506.html) - -[结构型模式——桥接模式(六)](https://www.cnblogs.com/gj-blog/p/10929510.html) - -[结构型模式——代理模式(七)](https://www.cnblogs.com/gj-blog/p/10929514.html) - -## 2.3 行为型 - -[行为型模式——模板方法(一)](https://www.cnblogs.com/gj-blog/p/10929517.html) - -[行为型模式——迭代器模式(二)](https://www.cnblogs.com/gj-blog/p/10929524.html) - -[行为型模式——策略模式(三)](https://www.cnblogs.com/gj-blog/p/10929544.html) - -[行为型模式——解释器模式(四)](https://www.cnblogs.com/gj-blog/p/10929551.html) - -[行为型模式——观察者模式(五)](https://www.cnblogs.com/gj-blog/p/10929556.html) - -[行为型模式——备忘录模式(六)](https://www.cnblogs.com/gj-blog/p/10929563.html) - -[行为型模式——命令模式(七)](https://www.cnblogs.com/gj-blog/p/10929571.html) - -[行为型模式——中介者模式(八)](https://www.cnblogs.com/gj-blog/p/10929579.html) - -[行为型模式——责任链模式(九)](https://www.cnblogs.com/gj-blog/p/10929600.html) - -[行为型模式——访问者模式(十)](https://www.cnblogs.com/gj-blog/p/10929607.html) - -[行为型模式——状态模式(十一)](https://www.cnblogs.com/gj-blog/p/10929616.html) - - - -# 3. 最后 - -设计模式的学习主要参考`Geely老师的` [Java设计模式精讲 Debug方式+内存分析](https://coding.imooc.com/class/270.html) - -中间也参考了无数的博客,这里只贴几个参考比较多的。 -[chenssy设计模式](https://www.cnblogs.com/chenssy/category/482229.html) diff --git "a/design-pattern/notes/\345\210\233\345\273\272\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\345\215\225\344\276\213\346\250\241\345\274\217\357\274\210\345\233\233\357\274\211.md" "b/design-pattern/notes/\345\210\233\345\273\272\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\345\215\225\344\276\213\346\250\241\345\274\217\357\274\210\345\233\233\357\274\211.md" deleted file mode 100644 index f90ccf5a..00000000 --- "a/design-pattern/notes/\345\210\233\345\273\272\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\345\215\225\344\276\213\346\250\241\345\274\217\357\274\210\345\233\233\357\274\211.md" +++ /dev/null @@ -1,1296 +0,0 @@ -> 该项目源码地址:[https://github.com/ggb2312/JavaNotes/tree/master/design-pattern](https://github.com/ggb2312/JavaNotes/tree/master/design-pattern)(设计模式相关代码与笔记) - -# 1. 定义 -保证一个类仅有一个实例,并提供一个全局访问点 - -# 2. 介绍 -**适用场景** -想确保任何情况下都绝对只有一个实例 - -**单例模式的重点** -- 私有构造器 -- 线程安全 -- 延迟加载 -- 序列化和反序列化安全 -- 反射攻击 - -# 3. 模式实例 -在Java中,我们通过使用对象(类实例化后)来操作这些类,类实例化是通过它的构造方法进行的,要是想实现一个类只有一个实例化对象,就要对类的构造方法下功夫。 - -![类图](https://upload-images.jianshu.io/upload_images/5336514-c7d9ca8ea0d564d5.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -**单例模式的一般实现:(含使用步骤)** - -```java -public class Singleton { -//1. 创建私有变量 ourInstance(用以记录 Singleton 的唯一实例) -//2. 内部进行实例化 - private static Singleton ourInstance = new Singleton(); - -//3. 把类的构造方法私有化,不让外部调用构造方法实例化 - private Singleton() { - } -//4. 定义公有方法提供该类的全局唯一访问点 -//5. 外部通过调用getInstance()方法来返回唯一的实例 - public static Singleton newInstance() { - return ourInstance; - } -} -``` - -## 3.1 懒汉式(延迟加载) -**懒汉式基础实现** - -特点:懒加载,需要时才创建,线程不安全 -```java -public class LazySingleton { - private static LazySingleton lazySingleton = null; - private LazySingleton(){ - - } - public static LazySingleton getInstance(){ - if(lazySingleton == null){ - lazySingleton = new LazySingleton(); - } - return lazySingleton; - } -} -``` -测试 -```java -public class Test { - public static void main(String[] args){ - LazySingleton lazySingleton1 = LazySingleton.getInstance(); - LazySingleton lazySingleton2 = LazySingleton.getInstance(); - System.out.println(lazySingleton1); - System.out.println(lazySingleton1); - System.out.println(lazySingleton1 == lazySingleton2); - } -} -``` - -![测试结果](https://upload-images.jianshu.io/upload_images/5336514-5bb624d42ad28329.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -懒汉式是线程不安全的,假如有两个线程使用懒汉式创建对象,thread1调用getInstance()方法时,lazySingleton == null为true,进入if,但未new对象。此时cpu调度,thread2调用getInstance()方法时,lazySingleton == null为true,进入if,并new了对象,返回给thread2。此时thread1开始在if里面new对象,返回给thread1.创建了两次对象。 - -**懒汉式多线程创建对象测试** - -```java -public class T implements Runnable { - @Override - public void run() { - LazySingleton lazySingleton = LazySingleton.getInstance(); - System.out.println(Thread.currentThread().getName()+" " + lazySingleton); - } -} -``` - -修改测试类 -```java -public class Test { - public static void main(String[] args){ - Thread t1 = new Thread(new T()); - Thread t2 = new Thread(new T()); - t1.start(); - t2.start(); - System.out.println("end"); - } -} -``` - -在多线程debug,人为干扰的情况下(或者多run几次也可以),创建了两个不同的对象。 - -![测试结果](https://upload-images.jianshu.io/upload_images/5336514-2609ad4c9b57ade5.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -### 3.1.1 同步锁 - -特点:使用同步锁,线程安全,但性能比较差 -修改LazySingleton单例类(静态方法synchronized会锁住这个文件) - -```java -public class LazySingleton { - private static LazySingleton lazySingleton = null; - private LazySingleton(){ - - } - public synchronized static LazySingleton getInstance(){ - if(lazySingleton == null){ - lazySingleton = new LazySingleton(); - } - return lazySingleton; - } -} -``` -在多线程debug,人为干扰的情况下,同步锁会保证只有一个线程进入同步方法,创建对象。 - -### 3.1.2 double-checked locking(双重检查加锁) - -特点:懒加载,jdk1.5及以上版本线程安全,性能好 -创建LazyDoubleCheckSingleton类 - -```java -public class LazyDoubleCheckSingleton { - private static LazyDoubleCheckSingleton lazyDoubleCheckSingleton = null; - private LazyDoubleCheckSingleton(){ - - } - public static LazyDoubleCheckSingleton getInstance(){ - if(lazyDoubleCheckSingleton == null){ - synchronized (LazyDoubleCheckSingleton.class){ - if(lazyDoubleCheckSingleton == null){ - lazyDoubleCheckSingleton = new LazyDoubleCheckSingleton(); - } - } - } - return lazyDoubleCheckSingleton; - } -} -``` -在代码的第12行首先判断lazyDoubleCheckSingleton是否为null(是否分配内存地址),如果lazyDoubleCheckSingleton为null使用synchronized同步锁保证线程安全,将同步锁放在if判断内比直接放在方法上,大大减少了性能开销。 - -我们来模拟一下多线程情况下。 - -thread1与thread2都进入了12行iflazyDoubleCheckSingleton == null判断为true,进入if。thread1握住了锁进入了同步代码块,thread2阻塞。thread1进入14行再次iflazyDoubleCheckSingleton == null判断为true,进入15行new对象,释放同步锁,return对象。thread2握住了锁进入了同步代码块,iflazyDoubleCheckSingleton == null判断为false,释放锁,直接return对象。 - -`看似没有任何问题,实际上会出现问题的,问题出在第12行和第15行,分析如下:` - -我们通常会将第15行lazyDoubleCheckSingleton = new LazyDoubleCheckSingleton();看成是一个步骤,实际上JVM内部已经转换为三条指令。 - -三条指令如下: - -步骤一: memory = allocate();——》分配对象的内存空间 -步骤二: ctorInstance(memory);——》初始化对象 -步骤三: instance = memory;——》设置lazyDoubleCheckSingleton 指向刚分配的内存地址 - -对象创建图示: - -![java对象创建过程](https://upload-images.jianshu.io/upload_images/5336514-c4b0f31bbee57eea.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -在这里会出现一个`指令重排`的问题。 - ->指令重排:大多数现代微处理器都会采用将指令乱序执行(out-of-order execution,简称OoOE或OOE)的方法,在条件允许的情况下,直接运行当前有能力立即执行的后续指令,避开获取下一条指令所需数据时造成的等待。通过乱序执行的技术,处理器可以大大提高执行效率。 ->除了处理器,常见的Java运行时环境的JIT编译器也会做指令重排序操作,即生成的机器指令与字节码指令顺序不一致。 - -经过重排序后的对象创建过程如下: - -步骤一: memory = allocate();——》分配对象的内存空间 -步骤三: instance = memory; ——》设置lazyDoubleCheckSingleton 指向刚分配的内存地址 -步骤二: ctorInstance(memory);——》初始化对象 - -经过重排序后的对象创建过程图示如下: - -![指令重排后的对象创建](https://upload-images.jianshu.io/upload_images/5336514-39457e539902bb4c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -在单线程指令重排的情况下,由于“intra-thread semantics”的存在,保证指令重排序不会改变单线程内的程序执行结果。 - -在多线程指令重排的情况下,thread1进入了12行**lazyDoubleCheckSingleton == null**判断为true,进入if。thread1握住了锁进入了同步代码块。thread1进入14行再次**lazyDoubleCheckSingleton == null**判断为true,进入15行new对象,在new对象的过程中:**1.分配对象的内存空间 3.设置lazyDoubleCheckSingleton 指向刚分配的内存地址。**此时thread2调用getInstance(),进入了12行lazyDoubleCheckSingleton == null判断为false(ps:java的“==”比的内存地址,此时lazyDoubleCheckSingleton已经分配内存地址了),直接返回现有的对象lazyDoubleCheckSingleton,thread2使用lazyDoubleCheckSingleton时就会出错,抛异常,因为lazyDoubleCheckSingleton并未被初始化。 - -![多线程指令重排](https://upload-images.jianshu.io/upload_images/5336514-53a1a5608b74e6ab.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -上面说的那么多,大家估计会晕,总结一下原因:thread1在第15行执行“1.分配对象的内存空间地址、3.设置instance指向内存空间地址”时,thread2在第12行判断instance是否为null,由于thread1设置了instance的内存空间地址,所以返回false,直接返回instance,thread2就会直接拿着instance去使用,instance没有被初始化就会报错。 - -归根究底,是因为thread1指令重排过程,thread2使用了未初始化的对象。 - -我们知道了问题所在,就可以从两方面入手。 -`方法1.不允许thread1第二步与第三步指令重排。` -`方法2.thread1指令重排时,不让thread2看到这个指令重排。` - -使用volatile关键字是使用方法1 不允许thread1第二步与第三步指令重排。 - ->关于volatile: ->在多线程情况下,cpu会有共享内存,在加入volatile关键字后,所有线程都可以看到共享内存的最新状态,保证内存的可见性。 ->用volatile关键字修饰的共享变量,在进行写操作时,会多出一些汇编代码,主要作用:会将当前处理器的缓存行的数据写到系统内存中,这个写回内存的操作,会使其他处理器缓存的数据失效,由于处理器缓存的数据失效了,它们就会从共享内存同步数据,这样就保证了内存的可见性(缓存一致性协议)。 - -使用volatile关键字重写LazyDoubleCheckSingleton类 - -```java -package com.desgin.pattern.creational.singleton; -/** - * Create by lastwhisper on 2019/1/25 - */ -public class LazyDoubleCheckSingleton { - private volatile static LazyDoubleCheckSingleton lazyDoubleCheckSingleton = null; - private LazyDoubleCheckSingleton(){ - - } - public static LazyDoubleCheckSingleton getInstance(){ - if(lazyDoubleCheckSingleton == null){ - synchronized (LazyDoubleCheckSingleton.class){ - if(lazyDoubleCheckSingleton == null){ - lazyDoubleCheckSingleton = new LazyDoubleCheckSingleton(); - } - } - } - return lazyDoubleCheckSingleton; - } -} -``` - -修改多线程T类 -```java -package com.desgin.pattern.creational.singleton; - -/** - * Create by lastwhisper on 2019/1/25 - */ -public class T implements Runnable { - @Override - public void run() { - LazyDoubleCheckSingleton lzyDoubleCheckSingleton = LazyDoubleCheckSingleton.getInstance(); - System.out.println(Thread.currentThread().getName()+" " + lzyDoubleCheckSingleton); - } -} -``` -测试类 - -``` -package com.desgin.pattern.creational.singleton; -/** - * Create by lastwhisper on 2019/1/25 - */ -public class Test { - public static void main(String[] args){ - Thread t1 = new Thread(new T()); - Thread t2 = new Thread(new T()); - t1.start(); - t2.start(); - System.out.println("end"); - } -} -``` -测试结果: - -![测试结果](https://upload-images.jianshu.io/upload_images/5336514-5e8861a58f7785c0.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -### 3.1.3 静态内部类 - -**特点:**不仅能确保线程安全,也能保证单例的唯一性,同时也延迟了单例的实例化。 -使用静态内部类是使用方法2:thread1指令重排时,不让thread2看到这个指令重排(ps:因为jvm会使用初始化锁保证多个线程下只会有一个线程加载类)。 - -```java -public class StaticInnerClassSingleton { - private StaticInnerClassSingleton() { - } - private static class InnerClass{ - private static StaticInnerClassSingleton staticInnerClassSingleton = new StaticInnerClassSingleton(); - } - public static StaticInnerClassSingleton getInstance(){ - return InnerClass.staticInnerClassSingleton; - } -} -``` - -那么,静态内部类又是如何实现线程安全的呢? -首先,我们先了解下类的加载时机。有5种情况,首次发生时,一个类将被立刻初始化,类是泛指,包括接口。 - - ->1.有一个类的实例被创建 ->2.类中声明的静态方法被调用 ->3.类中声明的静态成员被赋值 ->4.类中声明的静态成员被使用,且不是常量成员 ->5.类是顶级类,且类中有嵌套的断言语句 - -我们这里使用的是**4.类中声明的静态成员被使用,且不是常量成员。** - ->JVM在类的初始化阶段(也就是class被加载后,被线程使用前,都是类的初始化阶段),JVM会保证一个类的()方法在多线程环境中被正确地加锁、同步,如果多个线程同时去初始化一个类,那么只会有一个线程去执行这个类的()方法,其他线程都需要阻塞等待,直到活动线程执行()方法完毕。如果在一个类的()方法中有耗时很长的操作,就可能造成多个进程阻塞(需要注意的是,其他线程虽然会被阻塞,但如果执行()方法后,其他线程唤醒之后不会再次进入()方法。同一个加载器下,一个类型只会初始化一次。),在实际应用中,这种阻塞往往是很隐蔽的。 ->ps:()是用于初始化静态的类变量, ()是初始化实例变量 - -![jvm初始化锁图示](https://upload-images.jianshu.io/upload_images/5336514-a1679a131bd4ddd8.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -简单来说:在执行类的初始化期间,JVM会去获取一个锁。这个锁可以同步多个线程对同一个类的初始化 - -修改多线程T类 - -```java -public class T implements Runnable { - @Override - public void run() { - StaticInnerClassSingleton instance = StaticInnerClassSingleton.getInstance(); - System.out.println(Thread.currentThread().getName() + " " + instance); - } -} -``` -测试结果: - -![测试结果](https://upload-images.jianshu.io/upload_images/5336514-b6d703b4e3bb8b4d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - - -## 3.2 饿汉式(立即加载) - -**饿汉式** - -**特点:**实现简单,由于是立即加载,如果这个类一直不被使用就会浪费内存。 - -```java -public class HungrySingleton { - private static HungrySingleton hungrySingleton; - static { - hungrySingleton = new HungrySingleton(); - } - private HungrySingleton() { - - } - public static HungrySingleton getInstance() { - return hungrySingleton; - } -} -``` -简单来说,在类的初始化期间,JVM会去获取一个锁。这个锁可以同步多个线程对同一个类的初始化,保证线程安全(ps:详细解释在3.1.3 静态内部类) - -# 4. 序列化破坏解决方案及原理分析 - -使用上述的任意一个正确的单例模式进行序列化破坏测试都可以,这里我们选择饿汉式进行测试。 - -## 4.1 序列化破坏 - -为HungrySingleton类实现Serializable接口进行序列化 - -```java -public class HungrySingleton implements Serializable { - private static HungrySingleton hungrySingleton; - static { - hungrySingleton = new HungrySingleton(); - } - private HungrySingleton() { - - } - public static HungrySingleton getInstance() { - return hungrySingleton; - } -} -``` - -测试代码 - -```java -import java.io.*; - -/** - * Create by lastwhisper on 2019/1/25 - */ -public class Test { - public static void main(String[] args) throws Exception { - HungrySingleton instance = HungrySingleton.getInstance(); - ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("E:\\singleton_file")); - oos.writeObject(instance); - - File file = new File("E:\\singleton_file"); - ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file)); - HungrySingleton newInstance = (HungrySingleton)ois.readObject(); - - System.out.println(instance); - System.out.println(newInstance); - System.out.println(instance == newInstance); - } -} -``` - -测试结果,发现单例生成的对象与序列化后反序列化回来的对象不一样了。 - -![序列化攻击测试](https://upload-images.jianshu.io/upload_images/5336514-b55e40a3f60120fa.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -我们为HungrySingleton类添加一个`readResolve()`方法 - -```java -public class HungrySingleton implements Serializable { - private static HungrySingleton hungrySingleton; - static { - hungrySingleton = new HungrySingleton(); - } - private HungrySingleton() { - - } - public static HungrySingleton getInstance() { - return hungrySingleton; - } - - private Object readResolve(){ - return hungrySingleton; - } - -} -``` - -测试代码不变,再次测试,发现单例生成的对象与序列化后反序列化回来的对象一样了。 - -![序列化攻击测试](https://upload-images.jianshu.io/upload_images/5336514-c19367879e04e85a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -## 4.2 返回不同对象原理分析 - -在测试代码Test的反序列化方法readObject()里 - -![readObject()](https://upload-images.jianshu.io/upload_images/5336514-c4e28a89979073f0.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -readObject()调用readObject0(false); - -![readObject0(false)](https://upload-images.jianshu.io/upload_images/5336514-69c5c550783f55c9.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -在readObject0()里。会进入一个switch,调用checkResolve(readOrdinaryObject(unshared)) - -![checkResolve(readOrdinaryObject(unshared))](https://upload-images.jianshu.io/upload_images/5336514-f8e40f4cff2a78bf.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -在readOrdinaryObject()方法里面调用 -obj = desc.isInstantiable() ? desc.newInstance() : null; - -![obj = desc.isInstantiable() ? desc.newInstance() : null](https://upload-images.jianshu.io/upload_images/5336514-4e144df8fc371d3e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -desc.isInstantiable(),只要实现serializable/externalizable接口就返回true。 -返回true就会执行**desc.newInstance()**,obj就会被**newInstance()**初始化,所以序列化后返回的对象与单例获得对象地址不同 - -![desc.isInstantiable()](https://upload-images.jianshu.io/upload_images/5336514-8f75a11a04db1bea.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -## 4.3 返回相同对象原理分析 - -既然实现了serializable/externalizable接口,反序列化时就会重新创建对象,造成单例模式创建出不同的对象,为什么加上readResolve()方法就可以单例了呢? - -```java -private Object readResolve(){ - return hungrySingleton; -} -``` - -接着readOrdinaryObject()方法 - -![readOrdinaryObject()](https://upload-images.jianshu.io/upload_images/5336514-1f1e4b4d16e81189.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -**desc.hasReadResolveMethod()**方法,对于实现了serializable or externalizable接口,同时有readResolve方法的,返回true。进入if判断,执行**Object rep = desc.invokeReadResolve(obj);** - -![desc.hasReadResolveMethod()](https://upload-images.jianshu.io/upload_images/5336514-fcc890b962a4ca4e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -在**Object rep = desc.invokeReadResolve(obj);**中,由于我们有**readResolve()**方法,会直接执行**readResolveMethod.invoke(obj, (Object[]) null);**,然后invoke执行我们单例模式本身的**readResolve()**方法,直接返回hungrySingleton。 - -![readResolveMethod.invoke(obj, (Object[]) null)](https://upload-images.jianshu.io/upload_images/5336514-ebf3e0d1fff5065d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -![readResolveMethod](https://upload-images.jianshu.io/upload_images/5336514-37e9e9c8bd974ad7.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -![readResolve()](https://upload-images.jianshu.io/upload_images/5336514-1a204eecbd9b3453.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -所以添加readResolve方法,返回了相同对象。 - -## 4.4 总结 - -使用序列化时,进行反序列化会使用反射重新创建对象,解决方案就是添加readResolve方法,但是添加readResolve方法,也只是给反射创建的对象覆盖成单例创建的对象,在单例模式使用序列化时一定要注意。 - -# 5. 反射攻击解决方案及原理分析 - -反射攻击就是,通过反射创建与单例对象不同的对象,破坏单例模式。 -虽然在单例模式构造器是私有的,但是我们可以通过反射进行修改权限,进行访问。 - -## 5.1 反射攻击 - -**(1)饿汉式** - -使用反射破坏饿汉式单例模式HungrySingleton,编写测试代码 - -```java -public class Test { - public static void main(String[] args) throws Exception { - /*反射测试*/ - Class objectClass = HungrySingleton.class; - - Constructor constructor = objectClass.getDeclaredConstructor(); - constructor.setAccessible(true); - HungrySingleton instance = HungrySingleton.getInstance(); - HungrySingleton newInstance = (HungrySingleton) constructor.newInstance(); - - System.out.println(instance); - System.out.println(newInstance); - System.out.println(instance == newInstance); - } -} -``` - -测试结果,可以通过反射破坏单例模式饿汉式的对象创建 - -![反射破坏单例模式饿汉式测试结果](https://upload-images.jianshu.io/upload_images/5336514-5a86b00a954e824b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -**(2)懒汉式之静态内部类** - -**静态内部类** - - ```java -public class Test { - public static void main(String[] args) throws Exception { - /*反射测试*/ - Class objectClass = StaticInnerClassSingleton.class; - - Constructor constructor = objectClass.getDeclaredConstructor(); - constructor.setAccessible(true); - StaticInnerClassSingleton instance = StaticInnerClassSingleton.getInstance(); - StaticInnerClassSingleton newInstance = (StaticInnerClassSingleton) constructor.newInstance(); - - System.out.println(instance); - System.out.println(newInstance); - System.out.println(instance == newInstance); - } -} - ``` - -测试结果,单例模式懒汉式的静态内部类实现,也可以通过反射破坏。 - -![单例模式的静态内部类反射攻击](https://upload-images.jianshu.io/upload_images/5336514-db7f77d53c1a22a2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -**(3)双重检测加锁与懒汉式同步锁** - -代码与(1)(2)攻击方式类似,不在赘述。 - -## 5.2 解决方案 - - -反射是通过修改私有构造器的访问权限,破坏单例模式的。我们可以在私有构造器进行一些判断,防止反射修改访问权限,调用私有构造器初始化对象。 - -`ps:此方式只能防止 类加载时创建单例对象的方式` - -**(1) 饿汉式 ** - -在私有构造器中判断是否存在已经存在单例对象,如果存在就抛异常。 - -```java -public class HungrySingleton implements Serializable { - private static HungrySingleton hungrySingleton; - static { - hungrySingleton = new HungrySingleton(); - } - private HungrySingleton() { - if (hungrySingleton != null) { - throw new RuntimeException("单例构造器禁止反射调用"); - } - } - public static HungrySingleton getInstance() { - return hungrySingleton; - } - -} -``` - -测试 - -```java -import java.lang.reflect.Constructor; - -/** - * Create by lastwhisper on 2019/1/25 - */ -public class Test { - public static void main(String[] args) throws Exception { - /*反射测试*/ - Class objectClass = HungrySingleton.class; - - Constructor constructor = objectClass.getDeclaredConstructor(); - constructor.setAccessible(true); - - HungrySingleton instance = HungrySingleton.getInstance(); - HungrySingleton newInstance = (HungrySingleton) constructor.newInstance(); - System.out.println(instance); - System.out.println(newInstance); - System.out.println(instance == newInstance); - } -} -``` - -测试结果,成功抵挡反射攻击。 - -![饿汉式抵挡反射攻击](https://upload-images.jianshu.io/upload_images/5336514-c60b482349d2d408.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -**(2) 懒汉式之静态内部类** - -同样的思路,在私有构造器中判断是否存在已经存在单例对象,如果存在就抛异常。 - -```java -public class StaticInnerClassSingleton { - private StaticInnerClassSingleton() { - if (InnerClass.staticInnerClassSingleton != null) { - throw new RuntimeException("单例构造器禁止反射调用"); - } - } - - private static class InnerClass { - private static StaticInnerClassSingleton staticInnerClassSingleton = new StaticInnerClassSingleton(); - } - - public static StaticInnerClassSingleton getInstance() { - return InnerClass.staticInnerClassSingleton; - } -} -``` -测试代码 - -```java -import java.lang.reflect.Constructor; - -/** - * Create by lastwhisper on 2019/1/25 - */ -public class Test { - public static void main(String[] args) throws Exception { - /*反射测试*/ - Class objectClass = StaticInnerClassSingleton.class; - - Constructor constructor = objectClass.getDeclaredConstructor(); - constructor.setAccessible(true); - - StaticInnerClassSingleton instance = StaticInnerClassSingleton.getInstance(); - StaticInnerClassSingleton newInstance = (StaticInnerClassSingleton) constructor.newInstance(); - - System.out.println(instance); - System.out.println(newInstance); - System.out.println(instance == newInstance); - } -} -``` - -测试结果,成功抵挡反射攻击。 - -![懒汉式之静态内部类抵挡反射攻击](https://upload-images.jianshu.io/upload_images/5336514-85074958f985f999.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -**(3) 懒汉式之同步锁与双重检测加锁** - -很不幸,这两种方式无法抵挡反射攻击,因为这两种方式在类加载时并不创建对象。`在私有构造器进行判断的方法只能防止类加载时创建单例对象的方式。` - -这里我们以懒汉式之同步锁为例(ps:双重检测锁也相同)。 -在私有构造器中添加判断 - -```java -public class LazySingleton { - private static LazySingleton lazySingleton = null; - private LazySingleton() { - if (lazySingleton != null) { - throw new RuntimeException("单例构造器禁止反射调用"); - } - - } - - public synchronized static LazySingleton getInstance() { - if (lazySingleton == null) { - lazySingleton = new LazySingleton(); - } - return lazySingleton; - } -} -``` - -测试代码 - -```java -import java.lang.reflect.Constructor; - -/** - * Create by lastwhisper on 2019/1/25 - */ -public class Test { - public static void main(String[] args) throws Exception { - /*反射测试*/ - Class objectClass = LazySingleton.class; - - Constructor constructor = objectClass.getDeclaredConstructor(); - constructor.setAccessible(true); - - LazySingleton instance = LazySingleton.getInstance(); - LazySingleton newInstance = (LazySingleton) constructor.newInstance(); - - System.out.println(instance); - System.out.println(newInstance); - System.out.println(instance == newInstance); - } -} -``` - -测试结果 - -![懒汉式之同步锁抵挡反射攻击测试结果](https://upload-images.jianshu.io/upload_images/5336514-944a90061ef55dac.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -看似抵挡了反射攻击。 -我们来交换一下测试代码这两行代码执行顺序。 - -```java -LazySingleton newInstance = (LazySingleton) constructor.newInstance(); -LazySingleton instance = LazySingleton.getInstance(); -``` - -变换为: - -```java -LazySingleton instance = LazySingleton.getInstance(); -LazySingleton newInstance = (LazySingleton) constructor.newInstance(); -``` - -测试结果,无法阻止反射攻击。 - -![懒汉式之同步锁抵挡反射攻击测试结果](https://upload-images.jianshu.io/upload_images/5336514-4c18556c23701c85.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -双重检测加锁效果也类似,无法抵挡反射攻击。 - -## 5.3 原理分析与扩展 - -**(1)原理分析** - -我们接着“5.2.3 懒汉式之同步锁与双重检测加锁”,来分析下测试代码。 - -```java -Class objectClass = LazySingleton.class; -Constructor constructor = objectClass.getDeclaredConstructor(); -constructor.setAccessible(true); -LazySingleton newInstance = (LazySingleton) constructor.newInstance(); -``` - -这几行代码,会通过**反射**创建LazySingleton对象,但是静态私有变量lazySingleton还是为null。 - -```java -private static LazySingleton lazySingleton = null; -``` - - -我们使用反射创建对象与**getInstance()**创建对象,打印一下私有静态变量lazySingleton(暂时将权限设为public,测试一下私有静态变量lazySingleton) - -```java -public static LazySingleton lazySingleton = null; -``` - -![私有静态变量lazySingleton](https://upload-images.jianshu.io/upload_images/5336514-c2bc145d53afdc7e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -所以将反射创建对象代码**constructor.newInstance()**放在**LazySingleton.getInstance()**之前,**constructor.newInstance()**创建LazySingleton对象的静态私有变量lazySingleton为null,**LazySingleton.getInstance()**创建对象调用私有构造器时if判断失效。 - -`如果是多线程情况下,thread1执行constructor.newInstance()在thread2执行LazySingleton.getInstance()之前,私有构造器判断失效。所以如果不是类加载时初始化单例类(比如懒汉式之同步锁与双重检测加锁),是无法阻止反射攻击。` - -**(2)扩展1** - -不知道有没有人比较较真,增加私有静态成员变量,增强私有构造器的判断。我们增加一个flag标志(ps:使用更复杂逻辑道理也是相同)。 - -```java -public class LazySingleton { - public static LazySingleton lazySingleton = null; - private static boolean flag = true; - - private LazySingleton() { - if (flag) { - flag = false; - } else { - throw new RuntimeException("单例构造器禁止反射调用"); - } - } - - public synchronized static LazySingleton getInstance() { - if (lazySingleton == null) { - lazySingleton = new LazySingleton(); - } - return lazySingleton; - } - -} -``` - -这种方式同样会被反射攻击,因为反射可以修改权限设置值。 - -测试代码 -```java -public static void main(String[] args) throws Exception { - Class objectClass = LazySingleton.class; - Constructor constructor = objectClass.getDeclaredConstructor(); - constructor.setAccessible(true); - LazySingleton o1 = LazySingleton.getInstance(); - //修改flag=true - Field flag = o1.getClass().getDeclaredField("flag"); - flag.setAccessible(true); - flag.set(o1,true); - - LazySingleton o2 = (LazySingleton) constructor.newInstance(); - - System.out.println(o1); - System.out.println(o2); - System.out.println(o1 == o2); -} -``` - -测试结果,反射攻击成功,无法阻止反射攻击。 - -![测试结果](https://upload-images.jianshu.io/upload_images/5336514-a75fa300c83d0fd3.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -**(3)扩展2** - -那为什么不可以通过反射设置静态私有变量lazySingleton的值为自己创建的值呢?哪样所有的私有构造器方法判断都会失效,即使类加载时初始化单例类也无法阻止反射攻击?像这样。 - -```java -Field lazySingleton = o1.getClass().getDeclaredField("lazySingleton"); -lazySingleton.setAccessible(true); -lazySingleton.set(o1,new LazySingleton()); -``` -哈哈哈哈哈哈啊哈哈哈,报错了吧,忘了我们的构造器是私有了的么。 - -``` -'LazySingleton()' has private access in -'com.desgin.pattern.creational.singleton.LazySingleton' -``` - -# 6. 单例模式的最佳实践 - -**序列化与反序列化:**懒汉式之同步锁、双重检测加锁、静态内部类与饿汉式都必须增加一个readResolve()方法,不然反序列化回来的不是同一个对象。并且就算是增加了readResolve()方法反序列化时也会newInstance一个对象,只不过被readResolve()返回的单例对象覆盖。 - -**反射攻击:**懒汉式之同步锁、双重检测加锁由于不是在类加载时初始化单例对象,无法阻止反射攻击。懒汉式之静态内部类与饿汉式需要在私有构造器增加判断,可以防止反射攻击。 - -上面四种单例模式方式需要根据不同业务场景使用相对应的单例模式实现。 - -## 6.1 最佳实践 - -下面介绍一种单例模式的最佳实践(ps:也是《EffectiveJava》推荐的单例实现方式) - -**Enum实现单例模式** - -```java -public enum EnumInstance { - INSTANCE; - private Object data; - - public Object getData() { - return data; - } - - public void setData(Object data) { - this.data = data; - } - public static EnumInstance getInstance(){ - return INSTANCE; - } -} -``` - -## 6.2 序列化攻击 - -**(1)测试** - -使用序列化与反序列化测试一下会不会出问题。我们先测试这个枚举持有的INSTANCE - -```java -import java.io.*; - -/** - * Create by lastwhisper on 2019/1/26 - */ -public class Test1 { - public static void main(String[] args) throws Exception { - EnumInstance instance = EnumInstance.getInstance(); - ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("E:\\singleton_file")); - oos.writeObject(instance); - - File file = new File("E:\\singleton_file"); - ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file)); - EnumInstance newInstance = (EnumInstance)ois.readObject(); - System.out.println(instance); - System.out.println(newInstance); - System.out.println(instance == newInstance); - } -} -``` - -测试结果,序列化与反序列化并不会破坏单例模式 - -![序列化攻击Enum实现单例模式](https://upload-images.jianshu.io/upload_images/5336514-730914ab23feaa7e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -再测试枚举持有的对象data,看看这个data是不是同一个 - -```java -import java.io.*; - -/** - * Create by lastwhisper on 2019/1/26 - */ -public class Test1 { - public static void main(String[] args) throws Exception { - EnumInstance instance = EnumInstance.getInstance(); - instance.setData(new Object()); - ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("E:\\singleton_file")); - oos.writeObject(instance); - - File file = new File("E:\\singleton_file"); - ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file)); - EnumInstance newInstance = (EnumInstance)ois.readObject(); - System.out.println(instance.getData()); - System.out.println(newInstance.getData()); - System.out.println(instance.getData() == newInstance.getData()); - } -} -``` - -测试结果,是同一个data。 - -![序列化攻击Enum实现单例模式](https://upload-images.jianshu.io/upload_images/5336514-cc7c86fe835612f7.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -(2)原理分析 - -![readObject()](https://upload-images.jianshu.io/upload_images/5336514-f5e76be627b72913.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -在测试类的**readObject()**方法中,会调用**Object obj = readObject0(false);** - -![Object obj = readObject0(false)](https://upload-images.jianshu.io/upload_images/5336514-79f3caba4d422632.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -**readObject0()**方法,进入switch,case TC_ENUM - -![case TC_ENUM](https://upload-images.jianshu.io/upload_images/5336514-e1cb42794d6c1d52.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -在**readEnum()**方法里,进入一系列校验。在1715行**String name = readString(false);**,通过**readString()**方法获取枚举对象的名称name。在1716行Enum en = null;声明一个Enum类型。在1717行**Class cl = desc.forClass();**获取枚举对象的类型。在1720行**en = Enum.valueOf(cl, name);**根据类型和name,对枚举常量进行初始化。没有创建新的对象,维持了单例属性。 - -![readEnum()](https://upload-images.jianshu.io/upload_images/5336514-750246cec24e8cff.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -## 6.3 反射攻击 - -(1)测试以及原理分析 - -```java -import java.lang.reflect.Constructor; - -/** - * Create by lastwhisper on 2019/1/25 - */ -public class Test { - public static void main(String[] args) throws Exception { - /*反射测试*/ - Class objectClass = EnumInstance.class; - Constructor constructor = objectClass.getDeclaredConstructor(); - constructor.setAccessible(true); - EnumInstance newInstance = (EnumInstance) constructor.newInstance(); - } -} - -``` - -测试结果,抛出异常NoSuchMethodException,获取构造器时没有获得无参构造器。 - -![抛出异常NoSuchMethodException](https://upload-images.jianshu.io/upload_images/5336514-13492a49520fc18e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -为什么会这样的呢?我们进入java.lang.Enum的源码中看一下。 -**在Enum类中只有一个有参构造器** - -![Enum的有参构造器](https://upload-images.jianshu.io/upload_images/5336514-e91fcb4b68c53a5e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -![Enum的有参构造器](https://upload-images.jianshu.io/upload_images/5336514-69191ff5ddf268f1.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -修改测试代码,构造一个有参构造器 - -```java -Class objectClass = EnumInstance.class; - -Constructor constructor = objectClass.getDeclaredConstructor(String.class,int.class); -constructor.setAccessible(true); -EnumInstance newInstance = (EnumInstance) constructor.newInstance("gaojun",123456); -``` - -测试结果,异常信息:**Cannot reflectively create enum objects** - -![测试结果](https://upload-images.jianshu.io/upload_images/5336514-610e0a63066303a2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -我们点进520行错误代码里面,发现如果是Enum类型Coustructor的newInstance方法就会抛出异常,**Cannot reflectively create enum objects**。所以无法通过反射创建Enum类型。 - -![无法通过反射创建Enum类型](https://upload-images.jianshu.io/upload_images/5336514-ed4a828a98add0dd.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -## 6.4 Enum实现单例模式的优势 - -我们使用jad对EnumInstance进行反编译,查看Enum做单例的优势。 - -``` -jad EnumInstance.class -``` - -![jad EnumInstance.class](https://upload-images.jianshu.io/upload_images/5336514-4547c77b212f9b0c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -打开生成的jad文件。 - -```java -// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov. -// Jad home page: http://www.kpdus.com/jad.html -// Decompiler options: packimports(3) -// Source File Name: EnumInstance.java -package com.desgin.pattern.creational.singleton; - -public final class EnumInstance extends Enum -{ - - public static EnumInstance[] values() - { - return (EnumInstance[])$VALUES.clone(); - } - - public static EnumInstance valueOf(String name) - { - return (EnumInstance)Enum.valueOf(com/desgin/pattern/creational/singleton/EnumInstance, name); - } - - private EnumInstance(String s, int i) - { - super(s, i); - } - - public Object getData() - { - return data; - } - - public void setData(Object data) - { - this.data = data; - } - - public static EnumInstance getInstance() - { - return INSTANCE; - } - public static final EnumInstance INSTANCE; - private Object data; - private static final EnumInstance $VALUES[]; - - static - { - INSTANCE = new EnumInstance("INSTANCE", 0); - $VALUES = (new EnumInstance[] { - INSTANCE - }); - } -} - -``` - -首先EnumInstance类是final类型的无法被继承,有一个私有构造器。 - -```java -private EnumInstance(String s, int i) - { - super(s, i); - } -``` - -以及静态的final的单例对象,在类被加载时就会被静态代码块(ps:static{})初始化,并且不可被修改,保证了线程安全。加上I/O类、反射类对Enum类型的支持,Enum非吧常适合做单例模式。 - -```java -public static final EnumInstance INSTANCE; - private Object data; - private static final EnumInstance $VALUES[]; - - static - { - INSTANCE = new EnumInstance("INSTANCE", 0); - $VALUES = (new EnumInstance[] { - INSTANCE - }); - } - -``` - **Enum单例实现优势总结** - -1. 写法简单 -2. 线程安全 -3. 懒加载 -4. 避免序列化攻击 -5. 避免反射攻击 - - -# 7. 容器单例 - -将单例对象都保存在一个容器中 - -```java -package com.desgin.pattern.creational.singleton; -import org.apache.commons.lang3.StringUtils; -import java.util.HashMap; -import java.util.Map; - -/** - * Create by lastwhisper on 2019/1/27 - */ -public class ContainerSingleton { - private static Map singletonMap = new HashMap(); - - private ContainerSingleton() { - } - public static void putInstance(String key, String instance){ - if(StringUtils.isNoneBlank(key) && instance != null){ - if(!singletonMap.containsKey(key)){ - singletonMap.put(key,instance); - } - } - } - public static Object getInstance(String key){ - return singletonMap.get(key); - } -} - -``` - -由于HashMap线程不安全,导致这种容器单例模式也是线程不安全的,这种场景适用于,项目初始化时将需要的单例对象放入Map中。如果改有HashTable,虽然线程安全,但在频繁get的过程会有同步锁,效率低。如果改用CurrentHashMap,此时是静态的CurrentHashMap,并且是直接操作的CurrentHashMap,CurrentHashMap并不是绝对的线程安全。 - - -# 8. 线程单例 - -这种方式只能保证在一个线程内拿到单例对象 - -```java -public class ThreadLocalInstance { - private static final ThreadLocal treadLocalInstance = - new ThreadLocal() { - @Override - protected ThreadLocalInstance initialValue() { - return new ThreadLocalInstance(); - } - }; - - private ThreadLocalInstance() { - } - - public static ThreadLocalInstance getInstance() { - return treadLocalInstance.get(); - } -} -``` - -# 9. 优缺点 - -**优点:** - -- 在内存里只有一个实例,减少了内存开销 -- 可以避免对资源的多重占用 -- 设置全局访问点,严格控制访问 - -**缺点:** -- 没有接口,扩展困难 - - -# 10. 扩展-JDK1.7源码中的单例模式 - -## 10.1 Runtime——单例模式的饿汉式 - -通过查看**java.lang.Runtime**静态成员变量**currentRuntime、getRunTime()**方法、私有构造器,可知是一个单例模式的饿汉式。 - -![Runtime](https://upload-images.jianshu.io/upload_images/5336514-329d3ab84ddb01a4.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -## 10.2 Desktop——容器单例 - -10.2 Desktop——容器单例 -查看 **java.awt.Desktop**类的getDesktop()方法,是一个同步方法,会从一个AppContext中取值,如果context中没有就new一个,并put进context中。 - -![getDesktop()](https://upload-images.jianshu.io/upload_images/5336514-ad3e1f66b33800a7.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -查看put方法,会将值put到this.table中。 - -![put方法](https://upload-images.jianshu.io/upload_images/5336514-c34778d54601f2e8.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -查看this.table是一个HashMap。是一个容器单例,只不过put方法里面加了同步锁,保证put时是线程安全的。 - -![table](https://upload-images.jianshu.io/upload_images/5336514-ef745ad981bcbef5.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -## 10.3 ErrorContext——线程单例 - -在**org.apache.ibatis.executor.ErrorContext**类中使用ThreadLocal保证线程安全,调用**instance()**方法创建单例的ErrorContext对象,每个线程自己的错误,线程自己保存。 - -```java -public class ErrorContext { - - private static final String LINE_SEPARATOR = System.getProperty("line.separator","\n"); - private static final ThreadLocal LOCAL = new ThreadLocal(); - - private ErrorContext stored; - private String resource; - private String activity; - private String object; - private String message; - private String sql; - private Throwable cause; - - private ErrorContext() { - } - - public static ErrorContext instance() { - ErrorContext context = LOCAL.get(); - if (context == null) { - context = new ErrorContext(); - LOCAL.set(context); - } - return context; - } -} -``` - -## 10.4 AbstractFactoryBean——懒汉式 - -在**org.springframework.beans.factory.config.AbstractFactoryBean**的**getObject() **方法中,查看调用**getEarlySingletonInstance()** - -![getObject()](https://upload-images.jianshu.io/upload_images/5336514-4a04cf972389a958.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -使用了懒汉式,初始化单例对象 - -![getEarlySingletonInstance()](https://upload-images.jianshu.io/upload_images/5336514-7f00044a382a14de.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -# 11. 单例模式总结 - -## 11.1 单例模式实现方法 - -![单例模式实现方法](https://upload-images.jianshu.io/upload_images/5336514-3ccf2d2d7fd15ccf.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -## 11.2 安全性 - -** 序列化与反序列化:** - -- 懒汉式之同步锁、双重检测加锁、静态内部类与饿汉式都必须增加一个readResolve()方法,不然反序列化回来的不是同一个对象。并且就算是增加了readResolve()方法反序列化时也会newInstance一个对象,只不过被readResolve()返回的单例对象覆盖。 -- 枚举实现不会被序列化与反序列化影响 - -**反射攻击:** - -- 懒汉式之同步锁、双重检测加锁由于不是在类加载时初始化单例对象,无法阻止反射攻击。 -- 懒汉式之静态内部类与饿汉式需要在私有构造器增加判断,可以防止反射攻击。 -- 枚举类无法反射创建对象,所有不会被反射影响。 - -## 11.3 扩展-CAS实现单例 - -**上面的所有实现的单例方法本质上都使用的是锁,不使用锁的话,有办法实现线程安全的单例吗?** - -有,那就是使用CAS。 - -> CAS是项乐观锁技术,当多个线程尝试使用CAS同时更新同一个变量时,只有其中一个线程能更新变量的值,而其它线程都失败,失败的线程并不会被挂起,而是被告知这次竞争中失败,并可以再次尝试。实现单例的方式如下: - -```java -package com.desgin.pattern.creational.singleton; - -import java.util.concurrent.atomic.AtomicReference; - -/** - * @author lastwhisper - * - */ -public class CASSingleton { - private static final AtomicReference INSTANCE = new AtomicReference(); - - private CASSingleton() { - } - - - public static CASSingleton getInstance() { - for (;;) { - CASSingleton singleton = INSTANCE.get(); - if (null != singleton) { - return singleton; - } - - singleton = new CASSingleton(); - if (INSTANCE.compareAndSet(null, singleton)) { - return singleton; - } - } - } -} -``` - -**这种方式实现的单例有啥优缺点吗?** - - - -用CAS的好处在于不需要使用传统的锁机制来保证线程安全,CAS是一种基于忙等待的算法,依赖底层硬件的实现,相对于锁它没有线程切换和阻塞的额外消耗,可以支持较大的并行度。 - - -CAS的一个重要缺点在于如果忙等待一直执行不成功(一直在死循环中),会对CPU造成较大的执行开销。 - -另外,如果N个线程同时执行到singleton = new Singleton();的时候,会有大量对象创建,很可能导致内存溢出。**所以,不建议使用这种实现方式。** - - - -# 参考 - -[geely Java设计模式精讲 Debug方式+内存分析 的单例模式](https://coding.imooc.com/class/chapter/270.html#Anchor) - -[面试官:不使用synchronized和lock,如何实现一个线程安全的单例?](https://mp.weixin.qq.com/s?__biz=MzI3NzE0NjcwMg==&mid=2650123793&idx=1&sn=6ee37f4c6d071da6bf64fea3a11d394f&chksm=f36bb330c41c3a266c4cc6dfc7d4a9ee506a14bb98aad7822c053c56c04a5b20452fc3a07481&xtrack=1&scene=0&subscene=131&clicktime=1556240543&ascene=7&devicetype=android-27&version=27000439&nettype=WIFI&abtest_cookie=BAABAAoACwASABMABQAjlx4AVpkeAMGZHgDSmR4A3JkeAAAA&lang=zh_CN&pass_ticket=ZaAUN4e5PZMsHnUTJNTf7fRybPAFWaunIB7kH%2BEGtwNtqHSnlc4rdBUFm0Oc0IXc&wx_header=1) - diff --git "a/design-pattern/notes/\345\210\233\345\273\272\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\345\216\237\345\236\213\346\250\241\345\274\217\357\274\210\344\272\224\357\274\211.md" "b/design-pattern/notes/\345\210\233\345\273\272\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\345\216\237\345\236\213\346\250\241\345\274\217\357\274\210\344\272\224\357\274\211.md" deleted file mode 100644 index a51478d5..00000000 --- "a/design-pattern/notes/\345\210\233\345\273\272\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\345\216\237\345\236\213\346\250\241\345\274\217\357\274\210\344\272\224\357\274\211.md" +++ /dev/null @@ -1,216 +0,0 @@ -> 该项目源码地址:[https://github.com/ggb2312/JavaNotes/tree/master/design-pattern](https://github.com/ggb2312/JavaNotes/tree/master/design-pattern)(设计模式相关代码与笔记) - -# 1. 定义 - -指原型实例指定创建对象的种类,并通过克隆这些原型创建新的对象 - -# 2. 适用场景 - -- 类初始化消耗较多资源 -- new产生的一个对象需要非常繁琐的过程(数据准备、访问权限等) -- 构造函数比较复杂 -- 循环体中生产大量对象时 - -# 3. 深浅克隆 - -**浅克隆:**创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址。 -**深克隆:**创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址。 -总之深浅克隆都会在堆中新分配一块区域,区别在于对象属性引用的对象是否需要进行克隆(递归性的)。 - -# 4. 模式实例 - -原型模式就是让类实现**Cloneable**接口,达到克隆原型类的方式。 - -## 4.1 深浅克隆原型对比 - -复印简历各位都应该做过吧!这里我们利用原型模式来模拟复印简历。 - -**(1)简历类** - -```java -import java.util.Date; -public class Resume implements Cloneable { - private String name; - private Date birthday; - private String sex; - private String school; - private String timeArea; - private String company; - - public Resume(String name, Date birthday, String sex, String school, String timeArea, String company) { - this.name = name; - this.birthday = birthday; - this.sex = sex; - this.school = school; - this.timeArea = timeArea; - this.company = company; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public Date getBirthday() { - return birthday; - } - - public void setBirthday(Date birthday) { - this.birthday = birthday; - } - - public String getSex() { - return sex; - } - - public void setSex(String sex) { - this.sex = sex; - } - - public String getSchool() { - return school; - } - - public void setSchool(String school) { - this.school = school; - } - - public String getTimeArea() { - return timeArea; - } - - public void setTimeArea(String timeArea) { - this.timeArea = timeArea; - } - - public String getCompany() { - return company; - } - - public void setCompany(String company) { - this.company = company; - } - - /** - * 克隆该实例 - */ - @Override - public Object clone() { - Resume resume = null; - try { - resume = (Resume) super.clone(); - } catch (CloneNotSupportedException e) { - e.printStackTrace(); - } - return resume; - } - - public void display() { - System.out.println("姓名:" + name); - System.out.println("生日:" + birthday + ",性别:" + sex + ",毕业学校:" + school); - System.out.println("工作年限:" + timeArea + ",公司:" + company); - } - -} -``` - -**(2)测试类** - -```java -public class Test { - public static void main(String[] args) { - //原型A对象 - Resume a = new Resume("小李子",new Date(), "男", "XX大学","2012.09.05", "XX科技有限公司"); - a.display(); - System.out.println("*************克隆简历**************"); - //克隆B对象 - Resume b = (Resume) a.clone(); - b.display(); - System.out.println("***************比较***************"); - /* - * 测试A==B? - * 对任何的对象x,都有x.clone() !=x,即克隆对象与原对象不是同一个对象 - */ - System.out.print("比较:A==B?"); - System.out.println( a == b); - - b.getBirthday().setTime(666666666666L); - System.out.println("修改B简历的Birthday为:"+b.getBirthday()); - System.out.println("查看A简历的Birthday为:"+a.getBirthday()); - - /* - * 比较Date对象 - */ - System.out.print("比较:A.Date==B.Date?"); - System.out.println(a.getBirthday() == b.getBirthday()); - } -} -``` - -**(3)测试结果** - -可以发现B在克隆A的birthday时,是直接克隆的引用。这种是浅克隆。 - -![浅克隆](https://upload-images.jianshu.io/upload_images/5336514-3167bad92aff5599.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -**(4)修改为深克隆** - -```java -@Override -public Object clone() { - Resume resume = null; - try { - resume = (Resume) super.clone(); - resume.birthday = (Date) resume.birthday.clone(); - } catch (CloneNotSupportedException e) { - e.printStackTrace(); - } - return resume; -} -``` - -再次测试,可以发现B在克隆A的birthday时,是重新克隆的birthday,而不是直接克隆的引用。 - -![深克隆](https://upload-images.jianshu.io/upload_images/5336514-f9bb479f45c0b034.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -## 4.2 抽象原型类 - -```java -public abstract class A implements Cloneable{ - @Override - protected Object clone() throws CloneNotSupportedException { - return super.clone(); - } -} -``` - -```java -public class B extends A{ - public static void main(String[] args) throws CloneNotSupportedException { - B b = new B(); - b.clone(); - } -} -``` - -# 5. 优缺点 - -**优点:** - -1. 当创建对象的实例较为复杂的时候,使用原型模式可以简化对象的创建过程,通过复制一个已有的实例可以提高实例的创建效率。 -2. 扩展性好。由于原型模式提供了抽象原型类,在客户端针对抽象原型类进行编程,而将具体原型类写到配置文件中,增减或减少产品对原有系统都没有影响。 -3. 可以使用深克隆方式保存对象的状态。使用原型模式将对象复制一份并将其状态保存起来,以便在需要的时候使用(例如恢复到历史某一状态),可辅助实现撤销操作。 - -**缺点:** - -1. 需要为每一个类配置一个克隆方法,而且该克隆方法位于类的内部,当对已有类进行改造的时候,需要修改代码,违反了“开闭原则”。 -2. 在实现深克隆时需要编写较为复杂的代码,而且当对象之间存在多重引用时,为了实现深克隆,每一层对象对应的类都必须支持深克隆,实现起来会比较麻烦。 - -# 6. 扩展-JDK1.7源码中的原型模式 - -ArrayList的clone() -HashMap的clone() -CacheKey的clone() \ No newline at end of file diff --git "a/design-pattern/notes/\345\210\233\345\273\272\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\345\267\245\345\216\202\346\226\271\346\263\225\357\274\210\344\270\200\357\274\211.md" "b/design-pattern/notes/\345\210\233\345\273\272\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\345\267\245\345\216\202\346\226\271\346\263\225\357\274\210\344\270\200\357\274\211.md" deleted file mode 100644 index c92ff02c..00000000 --- "a/design-pattern/notes/\345\210\233\345\273\272\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\345\267\245\345\216\202\346\226\271\346\263\225\357\274\210\344\270\200\357\274\211.md" +++ /dev/null @@ -1,155 +0,0 @@ -> 该项目源码地址:[https://github.com/ggb2312/JavaNotes/tree/master/design-pattern](https://github.com/ggb2312/JavaNotes/tree/master/design-pattern)(设计模式相关代码与笔记) - -# 1. 定义 -定义一个创建对象的接口,但让实现这个接口的类来决定实例化那个类,工厂方法让类的实例化推迟到子类中进行。 - -# 2. 适用场景 -- 创建对象需要大量重复的代码 -- 应用层不依赖于产品类实例如何被创建、实现等细节 -- 一个类通过其子类来指定创建那个对象 - -# 3. 类图以及角色 - -![工厂方法类图](https://upload-images.jianshu.io/upload_images/5336514-08619d3e5e1098ba.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -- **Product**: 定义工厂方法所创建的对象的接口; -- **Creator**:声明工厂方法,并返回一个Product类型的对象; -- **ConcreteProduct**:是具体的产品,实现了Product接口; -- **ConcreteCreator**:是具体的工厂方法,返回一个ConcreteProduct实例。 - -# 4. 代码实例 - -**背景:现在慕课网需要录制Java、Python等视频课程** - -**(1)创建抽象视频类,定义具体录制视频课程的公共接口** - -类图对应的角色**Product** - -```java -public abstract class Video { - public abstract void produce(); -} -``` - -**(2)创建抽象工厂类,定义具体工厂的公共接口** - -类图对应的角色**Creator** - -```java -public abstract class VideoFactory { - public abstract Video getVideo(); -} -``` - -**(3)创建具体视频类(继承抽象视频类),定义录制的具体视频课程** - -类图对应的角色**ConcreteProduct** -```java -public class JavaVideo extends Video { - @Override - public void produce() { - System.out.println("录制java课程"); - } -} -``` - -```java -public class PythonVideo extends Video { - @Override - public void produce() { - System.out.println("录制python课程"); - } -} -``` - -**(4)创建具体工厂类(继承抽象工厂类),定义创建对应具体视频实例的方法** - -类图对应的角色**ConcreteCreteCreator** -```java -public class JavaVideoFactory extends VideoFactory { - public Video getVideo() { - return new JavaVideo(); - } -} -``` -```java -public class PythonVideoFactory extends VideoFactory { - public Video getVideo() { - return new PythonVideo(); - } -} -``` - -**(5)创建应用层进行测试** - -![项目结构](https://upload-images.jianshu.io/upload_images/5336514-e27732bc67b4a487.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -```java -public class Test { - public static void main(String[] args) { - VideoFactory videoFactory = new PythonVideoFactory(); - VideoFactory videoFactory1 = new JavaVideoFactory(); - Video video = videoFactory.getVideo(); - video.produce(); - } -} -``` - -测试结果: - -![测试结果](https://upload-images.jianshu.io/upload_images/5336514-e5a8a12095ebe7fd.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -**(6)扩展** - -如果现在需要录制前端课程只需要,添加一个录制前端视频类和一个创建前端视频类的工厂即可。 - -```java -public class FEVideo extends Video { - @Override - public void produce() { - System.out.println("录制前端课程视频"); - } -} -``` -```java -public class FEVideoFactory extends VideoFactory { - public Video getVideo() { - return new FEVideo(); - } -} -``` - -应用层调用测试 - -```java -public class Test { - public static void main(String[] args) { - VideoFactory videoFactory = new PythonVideoFactory(); - VideoFactory videoFactory1 = new JavaVideoFactory(); - VideoFactory videoFactory2 = new FEVideoFactory(); - Video video = videoFactory.getVideo(); - video.produce(); - } -} -``` - -查看类图 - -![类图](https://upload-images.jianshu.io/upload_images/5336514-bbb576cc6d7493a9.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -# 5. 优点 - -- 用户只需要关心所需产品对应的工厂,无须关系创建细节 -- 加入新产品,只需要增加相应的具体产品类和相应的工厂子类即可,符合开闭原则,提高可扩展性 -- 每个具体工厂类只负责创建对应的产品,符合单一职责原则 - -# 6. 缺点 - -- 添加新产品时,除了增加新产品类外,还要提供与之对应的具体工厂类,系统类的个数将成对增加,在一定程度上增加了系统的复杂度;同时,有更多的类需要编译和运行,会给系统带来一些额外的开销。 -- 由于考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度,且在实现时可能需要用到DOM、反射等技术,增加了系统的实现难度。 -- 一个具体工厂只能创建一种具体产品 - -# 7. 总结 -工厂模式可以说是简单工厂模式的进一步抽象和拓展,在保留了简单工厂的封装优点的同时,让扩展变得简单,让继承变得可行,增加了多态性的体现。 - -# 8. 扩展-JDK1.7源码中的工厂方法 \ No newline at end of file diff --git "a/design-pattern/notes/\345\210\233\345\273\272\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\345\273\272\351\200\240\350\200\205\346\250\241\345\274\217\357\274\210\344\270\211\357\274\211.md" "b/design-pattern/notes/\345\210\233\345\273\272\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\345\273\272\351\200\240\350\200\205\346\250\241\345\274\217\357\274\210\344\270\211\357\274\211.md" deleted file mode 100644 index 1ff3132c..00000000 --- "a/design-pattern/notes/\345\210\233\345\273\272\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\345\273\272\351\200\240\350\200\205\346\250\241\345\274\217\357\274\210\344\270\211\357\274\211.md" +++ /dev/null @@ -1,396 +0,0 @@ -> 该项目源码地址:[https://github.com/ggb2312/JavaNotes/tree/master/design-pattern](https://github.com/ggb2312/JavaNotes/tree/master/design-pattern)(设计模式相关代码与笔记) - -# 1. 定义 -将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示 - -# 2. 适用场景 - -- 如果一个对象有非常复杂的内部结构,在用户不知道对象的建造过程和细节的情况下就可以直接创建复杂的对象。 -- 想把复杂对象的创建和使用分离。 - -# 3. 类图以及角色 - -![建造者模式类图](https://upload-images.jianshu.io/upload_images/5336514-3004a08392bdaad7.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - - -- **Director**:指挥者/导演类,负责安排已有模块的顺序,然后告诉Builder开始建造。 -- **Builder**:抽象建造者,规范产品的组建,一般由子类实现。 -- **ConcreteBuilder**:具体建造者,实现抽象类定义的所有方法,并且返回一个组建好的对象。 -- **Product**:产品类,通常实现了模板方法模式。 - -# 4. 代码实例 - -**背景:建造慕课网的java、python课程。 -过程:课程指导员(Coach)将课程(Course)划分为几个部分(CourseBuilder)(课程名,课程PPT,课程视频,课程手记,课程问答),让真正建造的人(CourseActualBuilder)制作课程。** - -## 4.1 V1版本 -**(1)定义需要建造的课程(Course)** - -类图中对应的角色 **Product** - -```java -public class Course { - private String courseName; - private String coursePPT; - private String courseVideo; - private String courseArticle; - private String courseQA; - - @Override - public String toString() { - return "Course{" + - "courseName='" + courseName + '\'' + - ", coursePPT='" + coursePPT + '\'' + - ", courseVideo='" + courseVideo + '\'' + - ", courseArticle='" + courseArticle + '\'' + - ", courseQA='" + courseQA + '\'' + - '}'; - } - - public String getCourseName() { - return courseName; - } - - public void setCourseName(String courseName) { - this.courseName = courseName; - } - - public String getCoursePPT() { - return coursePPT; - } - - public void setCoursePPT(String coursePPT) { - this.coursePPT = coursePPT; - } - - public String getCourseVideo() { - return courseVideo; - } - - public void setCourseVideo(String courseVideo) { - this.courseVideo = courseVideo; - } - - public String getCourseArticle() { - return courseArticle; - } - - public void setCourseArticle(String courseArticle) { - this.courseArticle = courseArticle; - } - - public String getCourseQA() { - return courseQA; - } - - public void setCourseQA(String courseQA) { - this.courseQA = courseQA; - } -} -``` -**(2)定义制作的过程(Builder)** - -类图中对应的角色 **Builder** - -```java -public abstract class CourseBuilder { -// private String courseName; -// private String coursePPT; -// private String courseVideo; -// private String courseArticle; -// private String courseQA; - - public abstract void buildCourseName(String courseName); - - public abstract void buildCoursePPT(String coursePPT); - - public abstract void buildCourseVideo(String courseVideo); - - public abstract void buildCourseArticle(String courseArticle); - - public abstract void buildCourseQA(String courseQA); - - public abstract Course makeCourse(); -} -``` -**(3)定义真正建造的人(CourseActualBuilder)** - -类图中对应的角色 **ConcreteBuilder** - -```java -public class CourseActualBuilder extends CourseBuilder { - private Course course = new Course(); - - - @Override - public void buildCourseName(String courseName) { - course.setCourseName(courseName); - } - - @Override - public void buildCoursePPT(String coursePPT) { - course.setCoursePPT(coursePPT); - } - - @Override - public void buildCourseVideo(String courseVideo) { - course.setCourseVideo(courseVideo); - } - - @Override - public void buildCourseArticle(String courseArticle) { - course.setCourseArticle(courseArticle); - } - - @Override - public void buildCourseQA(String courseQA) { - course.setCourseQA(courseQA); - } - - @Override - public Course makeCourse() { - return course; - } -} -``` -**(4)定义指挥者(Coach)** - -类图中对应的角色 **Director** - -```java -public class Coach { - private CourseBuilder courseBuilder; - - public void setCourseBuilder(CourseBuilder courseBuilder) { - this.courseBuilder = courseBuilder; - } - - public Course makeCourse(String courseName,String coursePPT,String courseVideo,String courseArticle,String courseQA){ - this.courseBuilder.buildCourseName(courseName); - this.courseBuilder.buildCoursePPT(coursePPT); - this.courseBuilder.buildCourseVideo(courseVideo); - this.courseBuilder.buildCourseArticle(courseArticle); - this.courseBuilder.buildCourseQA(courseQA); - return this.courseBuilder.makeCourse(); - } -} -``` -查看此时的类图,标准的建造者模式 - -![类图](https://upload-images.jianshu.io/upload_images/5336514-731cf0ec4e748587.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -**(5)测试** -![项目结构](https://upload-images.jianshu.io/upload_images/5336514-5f36c73b9eecfa7c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -```java -public class Test { - public static void main(String[] args) { - CourseBuilder courseBuilder = new CourseActualBuilder(); - Coach coach = new Coach(); - coach.setCourseBuilder(courseBuilder); - - Course course = coach.makeCourse("Java设计模式", - "Java设计模式PPT", - "Java设计模式视频", - "Java设计模式手记", - "Java设计模式问答"); - System.out.println(course); - } -} -``` -测试结果 - -![测试结果](https://upload-images.jianshu.io/upload_images/5336514-aba0c63821f5c9ca.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -此时的类图,应用层选择不同builder交个Coach(指导者),Coach建造不同的课程。 - -![类图](https://upload-images.jianshu.io/upload_images/5336514-b03508b5775de8d2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -## 4.2 V2版本 -使用链式调用 - -```java -public class Course { - - private String courseName; - private String coursePPT; - private String courseVideo; - private String courseArticle; - private String courseQA; - - public Course(CourseBuilder courseBuilder) { - this.courseName = courseBuilder.courseName; - this.coursePPT = courseBuilder.coursePPT; - this.courseVideo = courseBuilder.courseVideo; - this.courseArticle = courseBuilder.courseArticle; - this.courseQA = courseBuilder.courseQA; - } - - public String toString() { - return "Course{" + - "courseName='" + courseName + '\'' + - ", coursePPT='" + coursePPT + '\'' + - ", courseVideo='" + courseVideo + '\'' + - ", courseArticle='" + courseArticle + '\'' + - ", courseQA='" + courseQA + '\'' + - '}'; - } - - public static class CourseBuilder{ - private String courseName; - private String coursePPT; - private String courseVideo; - private String courseArticle; - private String courseQA; - - - public CourseBuilder buildCourseName(String courseName) { - this.courseName=courseName; - return this; - } - - - public CourseBuilder buildCoursePPT(String coursePPT) { - this.coursePPT = coursePPT; - return this; - } - - - public CourseBuilder buildCourseVideo(String courseVideo) { - this.courseVideo = courseVideo; - return this; - } - - - public CourseBuilder buildCourseArticle(String courseArticle) { - this.courseArticle = courseArticle; - return this; - } - - - public CourseBuilder buildCourseQA(String courseQA) { - this.courseQA = courseQA; - return this; - } - - public Course build(){ - return new Course(this); - } - } -} -``` -测试代码 - -```java -public class Test { - public static void main(String[] args){ - Course course = new Course.CourseBuilder() - .buildCourseName("Java设计模式") - .buildCoursePPT("Java设计模式PPT") - //.buildCourseVideo("Java设计模式视频") - //.buildCourseArticle("Java设计模式手记") - .buildCourseQA("Java设计模式问答").build(); - System.out.println(course); - } -} -``` - -测试结果 - -![测试结果](https://upload-images.jianshu.io/upload_images/5336514-a02f5484a1aac9a7.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -此时类图 - -![类图](https://upload-images.jianshu.io/upload_images/5336514-550a3caca0c5e493.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - - -# 5. 优点 - -- 封装性好,创建和使用分离 -- 扩展性好、建造类之间独立、一定程度上解耦 - -# 6. 缺点 - -- 产生多余的builder对象 -- 产品内部发送变化,建造者都要修改,成本比较大 - -# 7. 建造者与工厂模式区别 - -**建造者模式** - -- 注重于方法的调用顺序 -- 可以创建复杂的对象 -- 不仅要知道创建了那些产品,还需要知道创建的产品由哪些部分组成的 - -**工厂模式** - -- 注重于创建产品 -- 创建的产品都是一个模样 -- 创建产品出来后就没事了(相对于建造者模式) - -# 8. 扩展-JDK1.7源码中的建造者模式 - -## 8.1 StringBuilder -StringBuilder中一部分源码,典型的建造者模式 - - -```java -public StringBuilder append(boolean b) { - super.append(b); - return this; -} - -public StringBuilder append(char c) { - super.append(c); - return this; -} - -public StringBuilder append(int i) { - super.append(i); - return this; -} - -public StringBuilder append(long lng) { - super.append(lng); - return this; -} - -public StringBuilder append(float f) { - super.append(f); - return this; -} - -public StringBuilder append(double d) { - super.append(d); - return this; -} -``` -## 8.2 StringBuffer - -StringBuffer中一部分源码,比StringBuilder多一个synchronized,典型的建造者模式 - -```java -public synchronized StringBuffer append(boolean b) { - super.append(b); - return this; -} - -public synchronized StringBuffer append(char c) { - super.append(c); - return this; -} - -public synchronized StringBuffer append(int i) { - super.append(i); - return this; -} -``` - -## 8.3 ImmutableSet - -类似于V2版本,可以看到builder方法返回this,在builder构造器里面创建对象 - -## 8.4 BeanDefinitionBuilder - -## 8.5 SqlSessionFactoryBuilder -在建造者模式里面再用了建造者模式 \ No newline at end of file diff --git "a/design-pattern/notes/\345\210\233\345\273\272\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\346\212\275\350\261\241\345\267\245\345\216\202\357\274\210\344\272\214\357\274\211.md" "b/design-pattern/notes/\345\210\233\345\273\272\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\346\212\275\350\261\241\345\267\245\345\216\202\357\274\210\344\272\214\357\274\211.md" deleted file mode 100644 index 3ddbcba6..00000000 --- "a/design-pattern/notes/\345\210\233\345\273\272\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\346\212\275\350\261\241\345\267\245\345\216\202\357\274\210\344\272\214\357\274\211.md" +++ /dev/null @@ -1,181 +0,0 @@ -> 该项目源码地址:[https://github.com/ggb2312/JavaNotes/tree/master/design-pattern](https://github.com/ggb2312/JavaNotes/tree/master/design-pattern)(设计模式相关代码与笔记) - -# 1. 定义 - -抽象工厂模式提供同一个创建一系列相关或相互依赖对象的接口,无须指定它们具体的类 - -# 2. 适用场景 - -- 客户端(应用层)不依赖于具体产品类实例如何被创建、实现等细节 -- 强调一系列相关的产品对象(属于同一产品族)一起使用创建对象需要大量重复的代码 -- 提供一个产品类的库,所有的产品以同样的接口出现从而使客户端不依赖于具体实现 - -# 3. 类图以及角色 - -![抽象工厂类图](https://upload-images.jianshu.io/upload_images/5336514-c6644b945ec1c41d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -- **AbstractFactory**:抽象工厂接口,里面包含所有的产品创建的抽象方法 -- **ConcreteFactory**:具体的工厂,创建具有特定实现的产品对象 -- **AbstractProduct**:抽象产品,有可能由两种不同的实现 -- **ConcreteProduct**:对于抽象产品的具体分类的实现 - -# 4. 产品等级结构与产品族 - -![产品等级结构与产品族](https://upload-images.jianshu.io/upload_images/5336514-4b29734e2c71f3a3.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -理解抽象工厂和工厂方法需要理解**产品等级结构与产品族**的区别和关系。 -关于产品等级结构与产品族,可以打一个比方 -美的生产空调、洗衣机、冰箱;海尔也生产空调、洗衣机、冰箱。 -美的空调、美的洗衣机、美的冰箱就是一个产品族 -美的空调、海尔空调就是一个产品等级结构 -**抽象工厂与工厂方法区别:** -工厂方法:针对的是产品等级结构 -抽象工厂:针对的是产品族 - -# 5. 代码实例 -**背景:现在慕课网需要制作Java、Python等课程,需要视频+手记组合才算一套课程** - -**(1)创建抽象工厂类,定义具体工厂的公共接口** - -类图对应的角色 **AbstractFactory** - -```java -public interface CourseFactory { - Video getVideo(); - Article getArticle(); -} -``` -**(2)创建抽象产品族类,定义具体产品的公共接口** - -类图对应的角色 **AbstractProduct** - -```java -public abstract class Video { - public abstract void produce(); -} -``` - -```java -public abstract class Article { - public abstract void produce(); -} -``` -**(3)创建具体产品类(继承抽象产品类), 定义生产的具体产品** - -类图对应的角色 **ConcreteProduct** - -录制java、python视频 - -```java -public class JavaVideo extends Video { - @Override - public void produce() { - System.out.println("录制Java课程视频"); - } -} -``` - -```java -public class PythonVideo extends Video { - @Override - public void produce() { - System.out.println("录制python课程视频 "); - } -} -``` -编写java、python手记 - -```java -public class JavaArticle extends Article { - @Override - public void produce() { - System.out.println("编写Java课程手记"); - } -} -``` -```java -public class PythonArticle extends Article { - @Override - public void produce() { - System.out.println("编写Python课程手记"); - } -} -``` - -**(4)创建具体工厂类(继承抽象工厂类),定义创建对应具体产品实例的方法** - -类图对应的角色 **ConcreteFactory** - -JavaCourseFactory工厂录制java视频、编写java手记 -```java -public class JavaCourseFactory implements CourseFactory { - @Override - public Video getVideo() { - return new JavaVideo(); - } - @Override - public Article getArticle() { - return new JavaArticle(); - } -} -``` -PythonCourseFactory工厂录制python视频、编写python手记 - -```java -public class PythonCourseFactory implements CourseFactory { - @Override - public Video getVideo() { - return new PythonVideo(); - } - - @Override - public Article getArticle() { - return new PythonArticle(); - } -} -``` - -**(5)测试** - -![项目结构](https://upload-images.jianshu.io/upload_images/5336514-6f79740e9ea98105.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -慕课网制作java、python课程 - -```java -public class Test { - public static void main(String[] args){ - CourseFactory courseFactory = new JavaCourseFactory(); - Video video = courseFactory.getVideo(); - Article article = courseFactory.getArticle(); - article.produce(); - video.produce(); - } -} -``` - -![测试结果](https://upload-images.jianshu.io/upload_images/5336514-5c594cc7d289e1c1.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -**(6)类图** -查看此时的类图帮助理解。 -应用层制作java课程时,根本无需关注java视频与java手记的创建等细节,只需要和JavaCourseFactory工厂类打交道即可。 - -![类图](https://upload-images.jianshu.io/upload_images/5336514-98366268b882c809.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -# 5. 优点 - -- 具体产品在应用层代码隔离,无须关系创建细节 -- 将一个系列的产品族统一到一起创建 -- 新的产品族扩展性好,符合了“开闭原则” - -# 6. 缺点 - -- 规定了所有可能被创建的产品等级集合,产品族中扩展新的产品等级困难,需要修改抽象工厂的接口,违背了“开闭原则”。 -- 增加了系统的抽象性和理解难度 - -# 7. 扩展-JDK1.7源码中的抽象工厂 - -java.sql.Connection - -java.sql.Statement - -sqlsessionfactory \ No newline at end of file diff --git "a/design-pattern/notes/\345\210\233\345\273\272\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\347\256\200\345\215\225\345\267\245\345\216\202\357\274\210\344\270\215\345\234\250GOF23\347\247\215\350\256\276\350\256\241\346\250\241\345\274\217\344\270\255\357\274\211.md" "b/design-pattern/notes/\345\210\233\345\273\272\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\347\256\200\345\215\225\345\267\245\345\216\202\357\274\210\344\270\215\345\234\250GOF23\347\247\215\350\256\276\350\256\241\346\250\241\345\274\217\344\270\255\357\274\211.md" deleted file mode 100644 index 58b938cc..00000000 --- "a/design-pattern/notes/\345\210\233\345\273\272\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\347\256\200\345\215\225\345\267\245\345\216\202\357\274\210\344\270\215\345\234\250GOF23\347\247\215\350\256\276\350\256\241\346\250\241\345\274\217\344\270\255\357\274\211.md" +++ /dev/null @@ -1,319 +0,0 @@ -> 该项目源码地址:[https://github.com/ggb2312/JavaNotes/tree/master/design-pattern](https://github.com/ggb2312/JavaNotes/tree/master/design-pattern)(设计模式相关代码与笔记) - -# 1. 定义 - -有一个工厂对象决定创建出哪一种产品类的实例 - -# 2.适用场景 - -- 工厂类负责创建的对象比较少 -- 客户端(应用层)只知道传入工厂类的参数对于如何创建对象(逻辑)不关心 - -# 3. 代码实例 - -**背景:现在慕课网需要录制Java、Python等视频课程** - -## 3.1 V1版本 -(1)创建一个抽象类Video类,定义具体录制视频课程的公共接口 - -```java -/** - * Create by eval on 2019/1/23 - */ -public abstract class Video { - public abstract void produce(); -} -``` -(2)创建具体的录制视频课程类 -录制Java课程 - -```java -/** - * Create by lastwhisper on 2019/1/23 - */ -public class JavaVideo extends Video{ - @Override - public void produce() { - System.out.println("录制java课程"); - } -} -``` -录制Python课程 - -```java -/** - * Create by lastwhisper on 2019/1/23 - */ -public class PythonVideo extends Video { - @Override - public void produce() { - System.out.println("录制python课程"); - } -} -``` -(3)测试 - -![代码结构](https://upload-images.jianshu.io/upload_images/5336514-beb0832f55727c5f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -创建应用层对视频进行录制 - -```java -/** - * Create by lastwhisper on 2019/1/23 - */ -public class Test { - public static void main(String[] args) { - Video video = new JavaVideo(); - video.produce(); - - } -} -``` -测试结果: - -![测试结果](https://upload-images.jianshu.io/upload_images/5336514-78a04f77c58cc488.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -(4)总结 -如果JavaVideo类(服务层)和Test(应用层)不在同一个包中,则需要引JavaVideo类的包,但是应用层不应该知道服务层的类,这里我们可以使用简单工厂改进。 - -## 3.2 V2版本 - -在V2版本使用简单工厂修改V1版本的问题,V1版本(1)(2)步骤不变。 - -(1)新建一个VideoFactory类 -这个类根据type创建对应的录制视频对象 - -```java -/** - * Create by lastwhisper on 2019/1/23 - */ -public class VideoFactory { - /** - * 根据type,创建对象 - * @param type - * @return - */ - public static Video getVideo(String type){ - if("java".equalsIgnoreCase(type)){ - return new JavaVideo(); - }else if("python".equalsIgnoreCase(type)){ - return new PythonVideo(); - } - return null; - } -} -``` -(2)修改Test(应用层) -使用工厂类创建对象 - -```java -/** - * Create by lastwhisper on 2019/1/23 - */ -public class Test { - public static void main(String[] args) { - Video video = VideoFactory.getVideo("java"); - video.produce(); - - } -} -``` - -(3)类图 -查看此时的类图 - -![V2版本类图](https://upload-images.jianshu.io/upload_images/5336514-2158b758a93383b4.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -(4)总结 -如果我们现在需要录制前端课程,就需要修改VideoFactory的getVideo方法,添加else if,违反了“开闭原则”。 - -## 3.3 V3版本 - -在V3版本使用java的反射修改V2版本违反“开闭原则”的问题 -**(1)修改VideoFactory类** - -```java -/** - * Create by lastwhisper on 2019/1/23 - */ -public class VideoFactory { - /** - * 根据Class字节码创建对象 - * @param c - * @return - */ - public static Video getVideo(Class c){ - Video video = null; - try { - video = (Video) Class.forName(c.getName()).newInstance(); - return video; - } catch (InstantiationException e) { - e.printStackTrace(); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } catch (ClassNotFoundException e) { - e.printStackTrace(); - } - return null; - } -} -``` -**(2)修改Test** - -```java -/** - * Create by lastwhisper on 2019/1/23 - */ -public class Test { - public static void main(String[] args) { - Video video = VideoFactory.getVideo(JavaVideo.class); - video.produce(); - - } -} -``` -测试运行 - -![运行结果](https://upload-images.jianshu.io/upload_images/5336514-d30f6ebda8aa5b95.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -**(3)类图** - -![类图](https://upload-images.jianshu.io/upload_images/5336514-30cb6d11e5c038be.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -**(4)总结** - -此时不管需要录制什么课程都不需要修改VideoFactory工厂类了。 -但是我们的VideoFactory的getVideo方法是static方法,无法扩展,如果需要扩展则去掉static修饰。 - -# 4. 优点 - -- 将创建实例的工作与使用实例的工作分开,使用者不必关心类对象如何创建,实现了解耦; -- 把初始化实例时的工作放到工厂里进行,使代码更容易维护。 更符合面向对象的原则 & 面向接口编程,而不是面向实现编程。 - -# 5. 缺点 - -- 工厂类集中了所有实例(产品)的创建逻辑,一旦这个工厂不能正常工作,整个系统都会受到影响; -- 违背“开闭原则”,一旦添加新产品就不得不修改工厂类的逻辑,这样就会造成工厂逻辑过于复杂。 -- 简单工厂模式由于使用了静态工厂方法,静态方法不能被继承和重写,会造成工厂角色无法形成基于继承的等级结构。 - -# 6. 扩展——JDK1.7源码中的简单工厂 - -## 6.1 Calendar类中的简单工厂 - -在IDEA使用Ctrl+Shift+N查找Calendar.java类,Ctrl+F12查看方法列表中的getInstance()方法 - -```java -public static Calendar getInstance() -{ - Calendar cal = createCalendar(TimeZone.getDefaultRef(), Locale.getDefault(Locale.Category.FORMAT)); - cal.sharedZone = true; - return cal; -} -``` - -进入createCalendar()方法,可以发现使用了简单工厂模式创建对象 - -```java -private static Calendar createCalendar(TimeZone zone, - Locale aLocale) -{ - Calendar cal = null; - - String caltype = aLocale.getUnicodeLocaleType("ca"); - if (caltype == null) { - // Calendar type is not specified. - // If the specified locale is a Thai locale, - // returns a BuddhistCalendar instance. - if ("th".equals(aLocale.getLanguage()) - && ("TH".equals(aLocale.getCountry()))) { - cal = new BuddhistCalendar(zone, aLocale); - } else { - cal = new GregorianCalendar(zone, aLocale); - } - } else if (caltype.equals("japanese")) { - cal = new JapaneseImperialCalendar(zone, aLocale); - } else if (caltype.equals("buddhist")) { - cal = new BuddhistCalendar(zone, aLocale); - } else { - // Unsupported calendar type. - // Use Gregorian calendar as a fallback. - cal = new GregorianCalendar(zone, aLocale); - } - - return cal; -} -``` - -在project的Extenrnal Libraries中有JDK1.7的依赖进入rt.jar->java->util->Calendar;选中Calendar,Ctrl+Alt+Shfit+U,选中Java class diagrams生成Calendar类相关的类图;Ctrl+Alt+B可以显示该类的实现类。通过UML类图方式我们可以更加轻松的学习他人的源码。 - -![Calendar类结构](https://upload-images.jianshu.io/upload_images/5336514-b0fd829a03d340aa.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -## 6.2 LoggerFactroy类中的简单工厂 - -Ctrl+N(enter class name)查找LoggerFactroy类,查看它的getLogger()方法。 -该方法有两个重载,不过最终都是调用一个方法getLogger(String name)。 - -```java -public static Logger getLogger(String name) { - ILoggerFactory iLoggerFactory = getILoggerFactory(); - return iLoggerFactory.getLogger(name); -} -public static Logger getLogger(Class clazz) { - return getLogger(clazz.getName()); -} -``` - -iLoggerFactory是一个接口,有多个实现类,查看LoggerContext实现 -iLoggerFactory.getLogger(name)方法使用简单工厂创建对象,根据name创建不同的对象。 - -```java -public final Logger getLogger(final String name) { - - if (name == null) { - throw new IllegalArgumentException("name argument cannot be null"); - } - - // if we are asking for the root logger, then let us return it without - // wasting time - if (Logger.ROOT_LOGGER_NAME.equalsIgnoreCase(name)) { - return root; - } - - int i = 0; - Logger logger = root; - - // check if the desired logger exists, if it does, return it - // without further ado. - Logger childLogger = (Logger) loggerCache.get(name); - // if we have the child, then let us return it without wasting time - if (childLogger != null) { - return childLogger; - } - - // if the desired logger does not exist, them create all the loggers - // in between as well (if they don't already exist) - String childName; - while (true) { - int h = LoggerNameUtil.getSeparatorIndexOf(name, i); - if (h == -1) { - childName = name; - } else { - childName = name.substring(0, h); - } - // move i left of the last point - i = h + 1; - synchronized (logger) { - childLogger = logger.getChildByName(childName); - if (childLogger == null) { - childLogger = logger.createChildByName(childName); - loggerCache.put(childName, childLogger); - incSize(); - } - } - logger = childLogger; - if (h == -1) { - return childLogger; - } - } -} -``` \ No newline at end of file diff --git "a/design-pattern/notes/\347\273\223\346\236\204\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\344\272\253\345\205\203\346\250\241\345\274\217.md" "b/design-pattern/notes/\347\273\223\346\236\204\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\344\272\253\345\205\203\346\250\241\345\274\217.md" deleted file mode 100644 index 009ed02c..00000000 --- "a/design-pattern/notes/\347\273\223\346\236\204\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\344\272\253\345\205\203\346\250\241\345\274\217.md" +++ /dev/null @@ -1,195 +0,0 @@ -> 该项目源码地址:[https://github.com/ggb2312/JavaNotes/tree/master/design-pattern](https://github.com/ggb2312/JavaNotes/tree/master/design-pattern)(设计模式相关代码与笔记) - -# 1. 定义 - -提供了减少对象数且从而改善应用所需的对象结构的方式。运用共享技术有效地支持大是细粒度的对象。 - -# 2. 适用场景 - -- 常常应用于系统底层的开发,以便解决系统的性能问题。 -- 系统有大量相似对象、需要缓冲池的场景。 - -比如:String常量池、Integer常量池、数据库连接池、线程池 - -# 3. 类图与角色 - -![享元模式类图](https://upload-images.jianshu.io/upload_images/5336514-9409835b81a6aa23.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -**享元模式存在如下几个角色:** - -**Flyweight:**抽象享元类。所有具体享元类的超类或者接口,通过这个接口,Flyweight可以接受并作用于外部专题 。 - -**ConcreteFlyweight:**具体享元类。指定内部状态,为内部状态增加存储空间。 - -**UnsharedConcreteFlyweight:**非共享具体享元类。指出那些不需要共享的Flyweight子类。 - -**FlyweightFactory:**享元工厂类。用来创建并管理Flyweight对象,它主要用来确保合理地共享Flyweight,当用户请求一个Flyweight时,FlyweightFactory就会提供一个已经创建的Flyweight对象或者新建一个(如果不存在)。 - -**享元模式的核心在于享元工厂类,享元工厂类的作用在于提供一个用于存储享元对象的享元池,用户需要对象时,首先从享元池中获取,如果享元池中不存在,则创建一个新的享元对象返回给用户,并在享元池中保存该新增对象。** - - -# 4. 内部状态与外部状态 - -**内部状态:**在享元对象内部不随外界环境改变而改变的共享部分 - -**外部状态:**随着环境的改变而改变,不能够共享的状态就是外部状态 - -# 5. 相关设计模式 - -**享元模式和代理模式** -- 代理模式生成的代理类,可以使用享元模式来生成代理类。 - -**享元模式和单例模式** - -- 享元模式可以再次创建对象,也可以取缓存对象。单例模式则是严格控制只有一个实例对象。 -- 享元模式可以通过自己实现对外部的单例,也可以在需要的使用创建更多的对象。单例模式是自身控制,需要增加不属于该对象本身的逻辑。 - -# 6. 模式实例 - -**背景:**公司要求各个部门的管理者做一下年底总结报告,如果这些报告都已经生成过了,那么我们就没有必要再去new一个了;我们通过这么一个场景来体现一下享元模式: - -## 6.1 模式基本结构 - -**抽象享元类** 有一个员工接口: -```java -public interface Employee { - void report(); -} -``` -**具体享元类** 还有一个经理类: - -```java -public class Manager implements Employee { - - private String department; - private String reportContent; - - public Manager(String department) { - this.department = department; - } - /** 我们可以在外部来重置年终报告 */ - public void setReportContent(String reportContent) { - this.reportContent = reportContent; - } - - @Override - public void report() { - System.out.println(reportContent); - } -} -``` - -**享元工厂类** 还有一个经理工厂类: - -```java -public class EmployeeFactory { - /** - * 定义一个池容器 - */ - private static final Map EMPLOYEE_MAP = new HashMap<>(); - - /** - * 享元工厂 - * - * @param department - * @return - */ - public static Employee getManager(String department) { - Manager manager = (Manager) EMPLOYEE_MAP.get(department); - if (manager == null) { - manager = new Manager(department); - System.out.print("创建部门经理" + department); - String reportContent = department + "部门汇报:此次报告的主要内容是......"; - manager.setReportContent(reportContent); - System.out.println(" 创建报告" + reportContent); - //享元工厂 - EMPLOYEE_MAP.put(department, manager); - } - return manager; - } -} -``` -测试: - -```java -public class Test { - private static final String departments[] = {"RD","QA","PM","BD"}; - - public static void main(String[]args){ - for (int i = 0; i < 10; i++) { - String department = departments[(int) (Math.random() * departments.length)]; - Manager manager = (Manager) EmployeeFactory.getManager(department); - manager.report(); - } - } -} -``` -测试结果: - -![测试结果](https://upload-images.jianshu.io/upload_images/5336514-3a0f0f58db0abc93.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -此时类图: - -![类图](https://upload-images.jianshu.io/upload_images/5336514-9db83e1ce1a18a24.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -## 6.2 内部状态与外部状态 - -**内部状态:**在享元对象内部不随外界环境改变而改变的共享部分 -**外部状态:**随着环境的改变而改变,不能够共享的状态就是外部状态 -对于Manager雷,成员变量department就是外部状态,随着Manager的变化而变化。title是内部状态,Manager怎么变,title也不会变化。 - -```java -public class Manager implements Employee { - /** - * 内部状态 - */ - private String title = "部门经理"; - /** - * 外部状态 - */ - private String department; - private String reportContent; - - public Manager(String department) { - this.department = department; - } - - /** - * 我们可以在外部来重置年终报告 - */ - public void setReportContent(String reportContent) { - this.reportContent = reportContent; - } - - @Override - public void report() { - System.out.println(reportContent); - } -} -``` - -# 7. 优缺点 - -**优点:** - -- 减少对象的创建,降低内存中对象的数量,降低系统的内存,提高效率 -- 减少内存之外的其他资源占用 - -**缺点:** - -- 关注内/外部状态、关注线程安全问题 -- 使系统、程序的逻辑复杂化 - - -# 8. 模式总结 - -1、享元模式可以极大地减少系统中对象的数量。但是它可能会引起系统的逻辑更加复杂化。 -2、享元模式的核心在于享元工厂,它主要用来确保合理地共享享元对象。 -3、内部状态为不变共享部分,存储于享元享元对象内部,而外部状态是可变部分,它应由客户端来负责。 - -# 9. 扩展-JDK1.7以及框架源码中的享元模式 - -9.1 Integer类里面的valueOf方法; -9.2 IntegerCache -9.3 tomcat的连接池:GenericObjectPoolConfig -org.apache.commons.pool2.impl.GenericKeyedObjectPool \ No newline at end of file diff --git "a/design-pattern/notes/\347\273\223\346\236\204\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\344\273\243\347\220\206\346\250\241\345\274\217\357\274\210\344\270\203\357\274\211.md" "b/design-pattern/notes/\347\273\223\346\236\204\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\344\273\243\347\220\206\346\250\241\345\274\217\357\274\210\344\270\203\357\274\211.md" deleted file mode 100644 index 518230b7..00000000 --- "a/design-pattern/notes/\347\273\223\346\236\204\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\344\273\243\347\220\206\346\250\241\345\274\217\357\274\210\344\270\203\357\274\211.md" +++ /dev/null @@ -1,389 +0,0 @@ -> 该项目源码地址:[https://github.com/ggb2312/JavaNotes/tree/master/design-pattern](https://github.com/ggb2312/JavaNotes/tree/master/design-pattern)(设计模式相关代码与笔记) - -# 1. 定义 - -为其他对象提供一种代理,以控制对这个对象的访问 - -# 2. 适用场景 - -- 保护目标对象 -- 增强目标对象 - -# 3. 代理类型 - -**静态代理** - -- 静态代理就是在代码中显示指定的代理 - -**动态代理** - -- 动态代理无法代理类,但是可以代理接口 - -**CGLib代理** - -- 在使用CGLib代理的时候,因为要用到继承,还有重写,所以对final的这个关键字的时候一定要格外的注意 - -**代理速度:** -JDK7、JDK8动态代理比CGLib快 - -# 4. Spring代理选择 - -当Bean有实现接口时,Spring就会用JDK的动态代理。当Bean没有实现接口时,Spring使用CGIib。可以强制使用CGIib,在spring配置中加入 - -# 5.相关设计模式 - -**代理模式和装饰器模式** - -- 装饰器模式是为对象加上行为,代理模式是控制访问 - -**代理模式和适配器模式** - -- 适配器模式主要考虑改变所对象的接口,代理模式是不能改变所代理类的接口。 - -# 6. 模式实例 - -**背景:订单分库** - -![项目结构](https://upload-images.jianshu.io/upload_images/5336514-244ef3a19ed35d1e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -## 6.1 静态代理 - -**(1)订单实体** - -```java -public class Order { - private Object orderInfo; - private Integer userId; - - public Object getOrderInfo() { - return orderInfo; - } - - public void setOrderInfo(Object orderInfo) { - this.orderInfo = orderInfo; - } - - public Integer getUserId() { - return userId; - } - - public void setUserId(Integer userId) { - this.userId = userId; - } -} -``` -**(2)Dao** - -Dao层的接口: - -```java -public interface IOrderDao { - int insert(Order order); -} -``` -Dao层的实现: -假装订单添加成功。 - -```java -public class OrderDaoImpl implements IOrderDao { - @Override - public int insert(Order order) { - System.out.println("Dao层添加order成功"); - return 1; - } -} -``` - -**(3)Service** - -Service层的接口: - -```java -public interface IOrderService { - /** 保存订单,参数为订单对象,返回值为生效行数 */ - int saveOrder(Order order); -} -``` -Service层的实现: - -```java -public class OrderServiceImpl implements IOrderService { - - private IOrderDao iOrderDao; - - @Override - public int saveOrder(Order order) { - /** Spring会自己注入,我们这里就直接new出来了 */ - iOrderDao = new OrderDaoImpl(); - System.out.println("Service调用Dao层添加Order层"); - return iOrderDao.insert(order); - } -} -``` -**(4)实现分库与静态代理** - -DataSourceContextHolder 维护着数据库的信息 - -```java -public class DataSourceContextHolder { - private static final ThreadLocal CONTEXT_HOLDER = new ThreadLocal<>(); - - public static void setDBType(String dbType) { - CONTEXT_HOLDER.set(dbType); - } - - public static String getDBType() { - return (String) CONTEXT_HOLDER.get(); - } - - public static void clearDBType() { - CONTEXT_HOLDER.remove(); - } -} -``` - -Spring里面的分库: - -```java -public class DynamicDataSource extends AbstractRoutingDataSource { - @Override - protected Object determineCurrentLookupKey() { - return DataSourceContextHolder.getDBType(); - } -} -``` -还有一个静态代理类: - -```java -public class OrderServiceStaticProxy { - /** 在代理类里面注入目标对象 */ - private IOrderService iOrderService; - - /** 我们要在这静态代理类里面增强这个方法 */ - public int saveOrder(Order order){ - beforeMethod(); - /** 如果这里有spring容器的话,就不用显示的new了 */ - iOrderService = new OrderServiceImpl(); - int userId = order.getUserId(); - /** 这里就是实现一个分库的功能,对userId取模2,这里就只会得到0或者是1 */ - int dbRouter = userId % 2; - System.out.println("静态代理分配到【db"+dbRouter+"】处理数据"); - - //todo 设置dataSource; - DataSourceContextHolder.setDBType("db"+dbRouter); - - afterMethod(); - return iOrderService.saveOrder(order); - } - - /** 我们要增强,我们就来写上一个before和after */ - private void beforeMethod(){ - System.out.println("静态代理 before code"); - } - - private void afterMethod(){ - System.out.println("静态代理 after code"); - } -} -``` - -在代理类中让orderId对2取模,余数为0放入db0,余数为1放入db1。在spring的dataSource配置中,指定class为**DynamicDataSource**,**DynamicDataSource**从**DataSourceContextHolder.getDBType()**中获取需要存入那个数据库。 - -分库时spring的配置 - -```xml -//数据库0 - - - - - - - - //数据库1 - - - - - - - - - - - - - - - - - - - -``` -**(5)测试** - -```java -public class Test { - public static void main(String[]args){ - Order order = new Order(); - order.setUserId(0); - /** 这里没有采用spring自动注入的方式,而是采用了直接new的方式 */ - OrderServiceStaticProxy orderServiceStaticProxy = new OrderServiceStaticProxy(); - orderServiceStaticProxy.saveOrder(order); - } -} -``` - -测试结果: - -![测试结果](https://upload-images.jianshu.io/upload_images/5336514-9703e1c2219d4436.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -**(6)类图** - -此时的类图 - -![类图](https://upload-images.jianshu.io/upload_images/5336514-438dbd04f79bccaa.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -**(7)代理的最佳实践** - -通常将需要增强的部分放到beforeMethod和afterMethod中。要划分方法的界限 - -```java -public class OrderServiceStaticProxy { - /** 在代理类里面注入目标对象 */ - private IOrderService iOrderService; - - /** 我们要在这静态代理类里面增强这个方法 */ - public int saveOrder(Order order){ - beforeMethod(order); - /** 如果这里有spring容器的话,就不用显示的new了 */ - iOrderService = new OrderServiceImpl(); - int result = iOrderService.saveOrder(order); - afterMethod(); - return result; - } - - /** 我们要增强,我们就来写上一个before和after */ - private void beforeMethod(Order order){ - int userId = order.getUserId(); - /** 这里就是实现一个分库的功能,对userId取模2,这里就只会得到0或者是1 */ - int dbRouter = userId % 2; - System.out.println("静态代理分配到【db"+dbRouter+"】处理数据"); - - //todo 设置dataSource; - DataSourceContextHolder.setDBType("db"+dbRouter); - System.out.println("静态代理 before code"); - } - - private void afterMethod(){ - System.out.println("静态代理 after code"); - } -} -``` - -## 6.2 动态代理 - -![项目结构](https://upload-images.jianshu.io/upload_images/5336514-fa9adbe0767b801b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -动态代理类 - -```java -public class OrderServiceDynamicProxy implements InvocationHandler { - - /** 这是目标类 */ - private Object target; - - /** 通过构造器把目标类注入进来 */ - public OrderServiceDynamicProxy(Object target) { - this.target = target; - } - - /** 进行绑定目标对象 */ - public Object bind() { - Class clazz = target.getClass(); - return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this); - } - - /** - * proxy:代理类代理的真实代理对象com.sun.proxy.$Proxy0 - * method:我们所要调用某个对象真实的方法的Method对象 - * args:指代代理对象方法传递的参数 - */ - @Override - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - Object argObject = args[0]; - beforeMethod(argObject); - Object object = method.invoke(target, args); - afterMethod(); - return object; - } - - public void beforeMethod(Object obj) { - int userId = 0; - System.out.println("动态代理before code"); - if (obj instanceof Order) { - Order order = (Order) obj; - userId = order.getUserId(); - } - /** 这里就是实现一个分库的功能,对userId取模2,这里就只会得到0或者是1 */ - int dbRouter = userId % 2; - System.out.println("动态代理分配到【db"+dbRouter+"】处理数据"); - //todo 设置dataSource; - DataSourceContextHolder.setDBType(String.valueOf(dbRouter)); - } - public void afterMethod() { - System.out.println("动态代理after code"); - } -} -``` - -测试: - -```java -public class Test { - public static void main(String[]args){ - Order order = new Order(); - order.setUserId(2); - /** 这里没有采用spring自动注入的方式,而是采用了直接new的方式 */ - IOrderService orderServiceDynamicProxy = (IOrderService) new OrderServiceDynamicProxy(new OrderServiceImpl()).bind(); - orderServiceDynamicProxy.saveOrder(order); - } -} -``` - -测试结果: - -![测试结果](https://upload-images.jianshu.io/upload_images/5336514-ae6f2c00b162de8e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -# 7. 优缺点 - -**优点:** - -- 代理模式能将代理对象与真实被调用的目标对象分离 -- 一定程度上降低了系统的耦合度,扩展性好 -- 保护目标对象 -- 增强目标对象 - -**缺点:** - -- 代理模式会造成系统设计中类的数目增加 -- 在客户端和目标对象增加一个代理对象,会造成请求处理速度变慢 -- 增加系统的复杂度 - -# 8. 扩展-JDK1.7以及框架源码中的外观模式 - -8.1 java.lang.reflect.proxy - -8.2 org.springframework.aop.framework.ProxyFactoryBean的getObject() - -8.3 org.springframework.aop.framework.JdkDynamicAopProxy对jdk的动态代理进行封装 -org.springframework.aop.framework.CglibAopProxy - -8.4 org.apache.ibatis.binding.MapperProxyFactory的newInstance(SqlSession sqlSession)的MapperProxy实现了 InvocationHandler - -![MapperProxy](https://upload-images.jianshu.io/upload_images/5336514-5fb7356d869b14ae.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -在cachedMapperMethod方法中使用了享元模式 - -![cachedMapperMethod](https://upload-images.jianshu.io/upload_images/5336514-77dc70a25a46bb24.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) \ No newline at end of file diff --git "a/design-pattern/notes/\347\273\223\346\236\204\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\345\244\226\350\247\202\346\250\241\345\274\217\357\274\210\344\270\200\357\274\211.md" "b/design-pattern/notes/\347\273\223\346\236\204\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\345\244\226\350\247\202\346\250\241\345\274\217\357\274\210\344\270\200\357\274\211.md" deleted file mode 100644 index 598cd78b..00000000 --- "a/design-pattern/notes/\347\273\223\346\236\204\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\345\244\226\350\247\202\346\250\241\345\274\217\357\274\210\344\270\200\357\274\211.md" +++ /dev/null @@ -1,221 +0,0 @@ -> 该项目源码地址:[https://github.com/ggb2312/JavaNotes/tree/master/design-pattern](https://github.com/ggb2312/JavaNotes/tree/master/design-pattern)(设计模式相关代码与笔记) - -# 1. 定义 - -外观模式又叫门面模式,提供了一个统一的接口,用来访问子系统中的一群接口 - -# 2. 适用场景 - -- 子系统越来越复杂,增加外观模式是供简单调用接口 -- 构建多层系统结构,利用外观对象作为每层的入口,简化层间调用 - -# 3. 相关设计模式 - -**外观模式和中介者模式:** -- 外观模式:关注外界和子系统之间的交互 -- 中介者模式:关注子系统内部之间的交互 - -**外观模式和单例模式:** - -- 通常把外观模式中的外观对象做成单例模式 - -**外观模式和抽象工厂模式** - -- 外观模式可以通过抽象工厂获得子系统的实例,这样子系统内部可以对外观类进行屏蔽。 - -# 4. 相关角色 - -![相关角色](https://upload-images.jianshu.io/upload_images/5336514-4f2d9bb8a3e4b50a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -简单来说,该模式就是把一些复杂的流程封装成一个接口供给外部用户更简单的使用。这个模式中,设计到3个角色。 - -- **门面角色**:外观模式的核心。它被客户角色调用,它熟悉子系统的功能。内部根据客户角色的需求预定了几种功能的组合。 -- **子系统角色**:实现了子系统的功能。它对客户角色和Facade时未知的。它内部可以有系统内的相互交互,也可以由供外界调用的接口。 -- **客户角色**:通过调用Facede来完成要实现的功能。 - -# 5. 模式实例 - -背景:慕课网积分礼物兑换系统 - -**(1)相关类** - -有一个积分礼物类: - -```java -/** 积分礼物 */ -public class PointsGift { - private String name; - - public PointsGift(String name) { - this.name = name; - } - - public String getName() { - return name; - } -} -``` - -**子系统角色** 校验类:是否有资格 - -```java -public class QualifyService { - public boolean isAvailable(PointsGift pointsGift) { - System.out.println("校验"+pointsGift.getName()+"积分资格通过,库存通过"); - return true; - } -} -``` - -**子系统角色** 积分支付类: - -```java -public class PointsPaymentService { - public boolean pay(PointsGift pointsGift) { - /** 扣减积分 */ - System.out.println("支付"+pointsGift.getName()+" 积分成功"); - return true; - } -} -``` - -**子系统角色** 还要一个物流子系统: - -```java -public class ShippingService { - public String shipGift(PointsGift pointsGift) { - /** 物流系统对接逻辑 */ - System.out.println(pointsGift.getName() + "进入物流系统"); - String shippingOrderNo = "666"; - return shippingOrderNo; - } -} -``` - -**门面角色** 积分交换交易: - -```java -public class GiftExchangeService { - private QualifyService qualifyService; - private PointsPaymentService pointsPaymentService; - private ShippingService shippingService; - - public void setQualifyService(QualifyService qualifyService) { - this.qualifyService = qualifyService; - } - - public void setPointsPaymentService(PointsPaymentService pointsPaymentService) { - this.pointsPaymentService = pointsPaymentService; - } - - public void setShippingService(ShippingService shippingService) { - this.shippingService = shippingService; - } - - public void giftExchange(PointsGift pointsGift) { - if (qualifyService.isAvailable(pointsGift)) { - /** 资格检验通过 */ - if (pointsPaymentService.pay(pointsGift)) { - //如果积分支付成功,那么就是可以返回订单号了 - String shippingOrderNo = shippingService.shipGift(pointsGift); - System.out.println("物流订单系统下单成功,订单号是:"+shippingOrderNo); - } - } - } -} -``` - -此时就是一个外观模式,类图: - -![外观模式的类图](https://upload-images.jianshu.io/upload_images/5336514-e8d82c22404f8755.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -**(2)测试** - -**客户角色** - -```java -public class Test { - public static void main(String[]args){ - PointsGift pointsGift = new PointsGift("T恤"); - GiftExchangeService giftExchangeService = new GiftExchangeService(); - - giftExchangeService.setQualifyService(new QualifyService()); - giftExchangeService.setPointsPaymentService(new PointsPaymentService()); - giftExchangeService.setShippingService(new ShippingService()); - - giftExchangeService.giftExchange(pointsGift); - } -} -``` -测试结果: - -![测试结果](https://upload-images.jianshu.io/upload_images/5336514-1b0be6af24ba6033.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -此时的类图: - -![类图](https://upload-images.jianshu.io/upload_images/5336514-57dba71fe25759d2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -会发现应用层在进行积分兑换商品时,还是依赖子系统,这是因为在应用层使用外观类的set方法注入了子系统接口的实例,在通常情况下这里应该使用spring依赖注入的,我们可以直接在外观类里new子系统的实例,模拟使用了Spring依赖注入。 - -**(3)标准的外观模式** - -修改GiftExchangeService类 - -```java -public class GiftExchangeService { - private QualifyService qualifyService = new QualifyService(); - private PointsPaymentService pointsPaymentService = new PointsPaymentService(); - private ShippingService shippingService = new ShippingService(); - - - public void giftExchange(PointsGift pointsGift) { - if (qualifyService.isAvailable(pointsGift)) { - /** 资格检验通过 */ - if (pointsPaymentService.pay(pointsGift)) { - //如果积分支付成功,那么就是可以返回订单号了 - String shippingOrderNo = shippingService.shipGift(pointsGift); - System.out.println("物流订单系统下单成功,订单号是:" + shippingOrderNo); - } - } - } -} -``` -修改测试类Test - -```java -public class Test { - public static void main(String[] args) { - PointsGift pointsGift = new PointsGift("T恤"); - GiftExchangeService giftExchangeService = new GiftExchangeService(); - giftExchangeService.giftExchange(pointsGift); - } -} -``` - -测试结果 - -![测试结果](https://upload-images.jianshu.io/upload_images/5336514-3a5ad9df57e5fd91.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -此时类图,应用层不依赖于子系统,只与外观类打交道。 - -![真正的外观模式类图](https://upload-images.jianshu.io/upload_images/5336514-5d8807a074b81996.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -# 6. 优缺点 - -**优点:** - -- 简化了调用过程,无需了解深入子系统,防止带来风险。 -- 减少系统依赖、松散耦合 -- 更好的划分访问层次 -- 符合迪米特法则,即最少知道原则 - -**缺点:** - -- 增加子系统、扩展子系统行为容易引入风险 -- 不符合开闭原则 - -# 7. 扩展-JDK1.7源码中的外观模式 - -org.springframework.jdbc.support.JdbcUtils -org.apache.ibatis.session.Configuration -org.apache.catalina.connector.RequestFacade与org.apache.catalina.connector.Request \ No newline at end of file diff --git "a/design-pattern/notes/\347\273\223\346\236\204\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\346\241\245\346\216\245\346\250\241\345\274\217\357\274\210\345\205\255\357\274\211.md" "b/design-pattern/notes/\347\273\223\346\236\204\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\346\241\245\346\216\245\346\250\241\345\274\217\357\274\210\345\205\255\357\274\211.md" deleted file mode 100644 index 43a1256d..00000000 --- "a/design-pattern/notes/\347\273\223\346\236\204\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\346\241\245\346\216\245\346\250\241\345\274\217\357\274\210\345\205\255\357\274\211.md" +++ /dev/null @@ -1,202 +0,0 @@ -> 该项目源码地址:[https://github.com/ggb2312/JavaNotes/tree/master/design-pattern](https://github.com/ggb2312/JavaNotes/tree/master/design-pattern)(设计模式相关代码与笔记) - -# 1. 定义 - -将抽象部分与它的具体实现部分分离。使它们都可以独立地变化。通过组合的方式建立两个类之间联系,而不是继承。 - -# 2. 适用情况 - -- 抽象和具体实现之间增加更多的灵活性 -- 一个类存在两个(或多个)独立变化的维度。且这两个(或多个)维度都需要独立进行扩展 -- 不希望使用继承,或因为多层继承导致系统类的个数剧增 - -# 3. 类图与角色 - -![桥接模式类图](https://upload-images.jianshu.io/upload_images/5336514-7baf90a70211c041.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -- **Abstraction**为抽象化角色,定义出该角色的行为,同时保存一个对实现化角色的引用; -- **Implementor**是实现化角色,它是接口或者抽象类,定义角色必需的行为和属性; -- **RefinedAbstraction**为修正抽象化角色,引用实现化角色对抽象化角色进行修正; -- **ConcreteImplementor**为具体实现化角色,实现接口或抽象类定义的方法或属性。 - -# 4. 相关设计模式 - -**桥接模式和组合模式** -- 组合模式强调的是部分和整体间的组合,桥接模式强调的是平行级别上,不同类的组合 - -**桥接模式和适配器模式** - -- 适配器模式改变已有的接口,桥接模式分离抽象和具体。 - -# 5. 模式实例 - -**背景:**中国有很多银行,有中国农业银行和中国工商银行关于我们的账号,有定期账号和活期账号。 - -**(1)桥接模式-实现** - -有一个账户接口: - -```java -public interface Account { - /** 打开我们的账号,打开账号,就要返回账号 */ - Account openAccount(); - - /** 打开我们的账号,查看为什么账户类型,是定期类型还是活期类型 */ - void showAccountType(); - -} -``` - -一个定期的账号: - -```java -/** 定期的账号 */ -public class DepositAccount implements Account { - @Override - public Account openAccount() { - System.out.println("定期账号"); - return new DepositAccount(); - } - - @Override - public void showAccountType() { - System.out.println("这是一个定期账号"); - } -} -``` -一个活期的账号: - -```java -/** 活期账号 */ -public class SavingAccount implements Account { - @Override - public Account openAccount() { - System.out.println("打开活期账号"); - return new SavingAccount(); - } - - @Override - public void showAccountType() { - System.out.println("这是一个活期账号"); - } -} -``` - -**(2)桥接模式-抽象** - -将Account账户接口组合到这个银行类: - -```java -public abstract class Bank { - /** 只有子类能拿到这个Account的这个接口 */ - protected Account account; - - /** 组合的时候,可以通过构造器的方式来进行注入也可以通过set方法的方式来进行注入 */ - public Bank(Account account) { - this.account = account; - } - - /** 这里声明成和接口里面的方法名一致,只是方便理解,Bank里面的方法要委托给Account接口里面的方法 */ - abstract Account openAccount(); - -} -``` - -我们现在看到就是Account就是具体的实现,我们要使用这个接口的具体实现。Bank是一个抽象类,然后这个抽象类里面的某个行为委托给Account的这个接口。 -在前面有说到桥接模式指的就是抽象和实现分离;而这里的实现正式这里的Account的实现类。 - -现在这个银行接口有两个子类去继承它。 - -中国农业银行类: - -```java -public class ABCBank extends Bank { - /** - * 组合的时候,可以通过构造器的方式来进行注入也可以通过set方法的方式来进行注入 - * - * @param account - */ - public ABCBank(Account account) { - super(account); - } - - @Override - Account openAccount() { - System.out.println("打开中国农业银行账号"); - //将行为委托给account - account.openAccount(); - return account; - } -} -``` -中国工商银行账号: - -```java -public class ICBCBank extends Bank { - /** - * 组合的时候,可以通过构造器的方式来进行注入也可以通过set方法的方式来进行注入 - * - * @param account - */ - public ICBCBank(Account account) { - super(account); - } - - @Override - Account openAccount() { - System.out.println("打开中国工商银行账号"); - //将行为委托给account - account.openAccount(); - return account; - } -} -``` -**(3)测试类** - -```java -public class Test { - public static void main(String[]args){ - Bank icbcBank = new ICBCBank(new DepositAccount()); - Account icbcAccount = icbcBank.openAccount(); - icbcAccount.showAccountType(); - - Bank icbcBank2 = new ICBCBank(new SavingAccount()); - Account icbcAccount2 = icbcBank2.openAccount(); - icbcAccount2.showAccountType(); - - Bank abcBank = new ABCBank(new SavingAccount()); - Account abcAccount = abcBank.openAccount(); - abcAccount.showAccountType(); - } -} -``` -测试结果: - -![测试结果](https://upload-images.jianshu.io/upload_images/5336514-4173a9cca0fc4a6e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -**(4)类图** - -将抽象与实现剥离,在Bank中使用组合引入Account,在Bank中抽象,在Acount中实现。将需要的功能委托给实现。 - -![类图](https://upload-images.jianshu.io/upload_images/5336514-9b567124ba9dddc2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -# 6. 优缺点 - -**优点:** - -- 分离抽象部分及其具体实现部分 -- 提高了系统的可扩展性 -- 符合开闭原则 -- 符合合成复用原则 - -**缺点:** - -- 增加了系统的理解与设计难度 -- 需要正确地识别出系统中两个独立变化的维度 - -# 7. 扩展-JDK1.7以及框架源码中的桥接模式 - -7.1 java.sql.Driver、java.sql.DriverManager与java.sql.DriverInfo -mysql的Driver、oracle的Driver就是桥接模式的实现部分。 - -7.2 DriverManager与DriverInfo(也就是Driver)实现了桥接模式 \ No newline at end of file diff --git "a/design-pattern/notes/\347\273\223\346\236\204\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\347\273\204\345\220\210\346\250\241\345\274\217\357\274\210\344\272\224\357\274\211.md" "b/design-pattern/notes/\347\273\223\346\236\204\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\347\273\204\345\220\210\346\250\241\345\274\217\357\274\210\344\272\224\357\274\211.md" deleted file mode 100644 index 93e71b84..00000000 --- "a/design-pattern/notes/\347\273\223\346\236\204\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\347\273\204\345\220\210\346\250\241\345\274\217\357\274\210\344\272\224\357\274\211.md" +++ /dev/null @@ -1,180 +0,0 @@ -> 该项目源码地址:[https://github.com/ggb2312/JavaNotes/tree/master/design-pattern](https://github.com/ggb2312/JavaNotes/tree/master/design-pattern)(设计模式相关代码与笔记) - -# 1. 定义 - -将对象组合成树形结构以表示“部分一整体”的层次结构 - -# 2. 适用情况 - -- 希望客户端可以忽略组合对象与单个对象的差异时 -- 处理一个树形结构时 - -# 3. 类图与角色 - -![组合模式类图](https://upload-images.jianshu.io/upload_images/5336514-269a211c00708f16.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -- **Component**是对象声明接口,在适当情况下,实现所有类共有接口的默认行为。 -- **Leaf**是叶子节点对象,其没有子节点。 -- **Composite**是树枝节点对象,用来存储部件,组合树枝节点和叶子节点形成一个树形结构。 - -# 4. 相关设计模式 - -**组合模式和访问者模式** - -- 可以使用访问者模式访问组合模式的递归结构。 - -# 5. 模式实例 - -**背景:**慕课网要对课程进行划分目录结构 -**Component** 有一个课程的抽象类: - -```java -public abstract class CatalogComponent { - public void add(CatalogComponent catalogComponent) { - throw new UnsupportedOperationException("不支持添加操作"); - } - public void remove(CatalogComponent catalogComponent) { - throw new UnsupportedOperationException("不支持删除操作"); - } - public String getName(CatalogComponent catalogComponent) { - throw new UnsupportedOperationException("不支持获取名称操作"); - } - public double getPrice(CatalogComponent catalogComponent) { - throw new UnsupportedOperationException("不支持获取价格操作"); - } - public void print() { - throw new UnsupportedOperationException("不支持打印操作"); - } -} -``` - -**Leaf** 课程类: - -```java -public class Course extends CatalogComponent{ - private String name; - private double price; - - public Course(String name, double price) { - this.name = name; - this.price = price; - } - - @Override - public String getName(CatalogComponent catalogComponent) { - return this.name; - } - - @Override - public double getPrice(CatalogComponent catalogComponent) { - return this.price; - } - - @Override - public void print() { - System.out.println("Course Name :"+name+" price"+price); - } -} -``` - -**Composite** 目录类: - -```java -public class CourseCatalog extends CatalogComponent { - private List items = new ArrayList<>(); - - private String name; - private Integer level; - - public CourseCatalog(String name, Integer level) { - this.name = name; - this.level = level; - } - - @Override - public void add(CatalogComponent catalogComponent) { - items.add(catalogComponent); - } - - @Override - public void remove(CatalogComponent catalogComponent) { - items.remove(catalogComponent); - } - - @Override - public void print() { - System.out.println(this.name); - for (CatalogComponent catalogComponent : items) { - if (level != null) { - for (int i=0;i 该项目源码地址:[https://github.com/ggb2312/JavaNotes/tree/master/design-pattern](https://github.com/ggb2312/JavaNotes/tree/master/design-pattern)(设计模式相关代码与笔记) - -# 1. 定义 - -在不改变原有对象的基础之上,动态地给一个对象添加一些额外的职责。 - -# 2. 适用场景 - -- 扩展一个类的功能或给一个类添加附加职责 -- 动态的给一个对象添加功能,这些功能可以再动态的撤销 -- 当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。 - -例如:在java的I/O类中有很深刻的体现。 - -# 3. 类图与角色 - -![装饰者模式类图](https://upload-images.jianshu.io/upload_images/5336514-5f9adc598467d598.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -- Component(被装饰对象的基类) - 定义一个对象接口,可以给这些对象动态地添加职责。 -- ConcreteComponent(具体被装饰对象) - 定义一个对象,可以给这个对象添加一些职责。 -- Decorator(装饰者抽象类) - 维持一个指向Component实例的引用,并定义一个与Component接口一致的接口。 -- ConcreteDecorator(具体装饰者) - 具体的装饰对象,给内部持有的具体被装饰对象,增加具体的职责。 - -# 4. 相关设计模式 - -**装饰者模式和代理模式** - -- **装饰者模式:**关注在一个对象上动态添加方法。 -- **代理模式:**关注在控制对对象的访问,代理模式的代理类可以对客户隐藏一个对象具体的信息。 -- 在使用**代理模式**的时候,常常在一个代理对象中创建对象的实例。而当我们在使用**装饰者模式**时,通常会把原始对象作为参数,传给装饰者的构造器 - -**装饰者模式和适配器模式** - -- 装饰者模式和适配器模式都叫做包装模式。在装饰者模式中,装饰者与被装饰者都可以实现相同的接口,或者装饰者是被装饰者的子类。在适配器模式中,适配类与被适配类具有不同的接口,当然也有可能有部分接口是重合的。 - -# 5. 模式实例 - -**背景:**公司门口有一个小摊卖煎饼的,点了煎饼之后往往还可以在这个基础之上增加一些配料,例如煎蛋,火腿等等,每个配料的价格都不一样,不管你怎么配配料,最终价格是煎饼基础价加上每一种所选配料价格的总和。 - -## 5.1 V1版本 - -**(1)相关类** - -有一个煎饼类: - -```java -public class Battercake { - protected String getDesc() { - return "煎饼"; - } - protected int cost() { - return 8; - } -} -``` -如果此时需要一个加鸡蛋的煎饼,只需要让煎饼加鸡蛋类继承煎饼类即可。 - -煎饼加鸡蛋类: - -```java -public class BattercakeWithEgg extends Battercake { - @Override - public String getDesc() { - return super.getDesc()+"加一个鸡蛋"; - } - - @Override - public int cost() { - return super.cost()+1; - } - -} -``` -如果此时需要一个加鸡蛋加香肠的煎饼,只需要让煎饼加鸡蛋加香肠类继承煎饼加鸡蛋类即可。 - -煎饼加鸡蛋加香肠类: - -```java -public class BattercakeWithEggSausage extends BattercakeWithEgg{ - @Override - public String getDesc() { - return super.getDesc()+"一个香肠"; - } - - @Override - public int cost() { - return super.cost()+2; - } -} -``` - -**(2)测试** - -```java -public class Test { - public static void main(String[]args){ - Battercake battercake = new Battercake(); - System.out.println(battercake.getDesc()+"销售价格:"+battercake.cost()); - - BattercakeWithEgg battercakeWithEgg = new BattercakeWithEgg(); - System.out.println(battercakeWithEgg.getDesc()+"销售价格:"+battercakeWithEgg.cost()); - - BattercakeWithEggSausage battercakeWithEggSausage = new BattercakeWithEggSausage(); - System.out.println(battercakeWithEggSausage.getDesc()+"销售价格:"+battercakeWithEggSausage.cost()); - - } -} -``` -测试结果: - -![测试结果](https://upload-images.jianshu.io/upload_images/5336514-089ee032be0d67e6.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -此时类图,单纯的继承结构: - -![类图](https://upload-images.jianshu.io/upload_images/5336514-b721a9b532046063.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -如果我们此时想要一个煎饼加两个鸡蛋,就需要重新继承煎饼类Battercake,生成一个“加两个鸡蛋的煎饼类”。加三个鸡蛋...以此类推,每加一种类型的煎饼就会多生成一个类。下面使用装饰者模式进行改造。 - -## 5.2 V2版本 - -现在,我们用装饰者模式来改写V1版本: - -**(1)相关类** - -**Component** 有一个抽象的煎饼类: - -```java -public abstract class ABattercake { - protected abstract String getDesc(); - protected abstract int cost(); -} -``` -**ConcreteComponent** 煎饼类继承于上面的抽象兼饼类: - -```java -public class Battercate extends ABattercake { - @Override - protected String getDesc() { - return "煎饼"; - } - - @Override - protected int cost() { - return 8; - } -} -``` - -**Decorator** 我们让抽象的装饰者类继承抽象的实体: - -```java -public class AbstractDecorator extends ABattercake{ - private ABattercake aBattercake; - - public AbstractDecorator(ABattercake aBattercake) { - this.aBattercake = aBattercake; - } - - @Override - protected String getDesc() { - return aBattercake.getDesc(); - } - - @Override - protected int cost() { - return aBattercake.cost(); - } -} -``` - -**ConcreteDectrator** 煎饼添加鸡蛋的装饰类继承于抽象的装饰类: - -```java -public class EggDecorator extends AbstractDecorator{ - - public EggDecorator(ABattercake aBattercake) { - super(aBattercake); - } - - @Override - protected String getDesc() { - return super.getDesc()+"加一个鸡蛋"; - } - - @Override - protected int cost() { - return super.cost()+1; - } -} -``` -**ConcreteDectrator** 煎饼添加香肠的装饰类,继承于抽象的装饰类: - -```java -public class SausageDecorator extends AbstractDecorator{ - - public SausageDecorator(ABattercake aBattercake) { - super(aBattercake); - } - - @Override - protected String getDesc() { - return super.getDesc()+"加一根香肠"; - } - - @Override - protected int cost() { - return super.cost()+2; - } -} -``` - -**(2)测试** -```java -public class Test { - public static void main(String[]args){ - ABattercake aBattercake; - aBattercake = new Battercate(); - aBattercake = new EggDecorator(aBattercake); - aBattercake = new EggDecorator(aBattercake); - aBattercake = new SausageDecorator(aBattercake); - System.out.println(aBattercake.getDesc()+"价格为:"+aBattercake.cost()); - } -} -``` - -测试结果: - -![测试结果](https://upload-images.jianshu.io/upload_images/5336514-d9dd76ab82d4d853.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -此时不管想加多少个鸡蛋还是香肠,都可以很灵活的添加上。 - -此时的类图: - -![V2版本类图](https://upload-images.jianshu.io/upload_images/5336514-53bfbad63ca77ecb.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -# 6. 优缺点 - -**优点:** - -- 继承的有力补充,比继承灵活,不改变原有对象的情况下给一个对象扩展功能 -- 通过使用不同装饰类以及这些装饰类的排列组合,可以实现不同效果 -- 符合开闭原则 - -**缺点:** - -- 会出现更多的代码,更多的类,增加程序复杂性 -- 动态装饰时,多层装饰时会使程序更复杂 - -# 7. 扩展-JDK1.7以及框架源码中的装饰者模式 - -## 7.1 Java I/O - -**Reader与java.io.BufferedReader** - -![Reader](https://upload-images.jianshu.io/upload_images/5336514-a19754f4eec626fe.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -![BufferedReader](https://upload-images.jianshu.io/upload_images/5336514-87687eb1ac3a7fed.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -`Reader`是被装饰者,`BufferedReader`是装饰者 - -**InputStream与FilterInputStream** - -![InputStream](https://upload-images.jianshu.io/upload_images/5336514-339e9817b3e41e2b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -![FilterInputStream](https://upload-images.jianshu.io/upload_images/5336514-dbccdc6ba8243a0d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -`InputStream`是被装饰者,`FilterInputStream`是装饰者 - -下面是**InputStream**相关类图的装饰者模式体现。 - -![InputStream类结构](https://upload-images.jianshu.io/upload_images/5336514-adbcca00aa6054fe.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -## 7.2 Spring - -**TransactionAwareCacheDecorator** - -![Cache](https://upload-images.jianshu.io/upload_images/5336514-13b6cac0c2957bc7.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -![TransactionAwareCacheDecorator](https://upload-images.jianshu.io/upload_images/5336514-85e67a2f37154c56.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -## 7.3 Spring-session - -**org.springframework.session.web.http.SessionRepositoryFilter.SessionRepositoryRequestWrapper** - - -## 7.4 Tomcat - -**javax.servlet.ServletRequestWrapper** - -![ServletRequestWrapper](https://upload-images.jianshu.io/upload_images/5336514-6d0a08be4fa188cb.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -## 7.5 Mybatis - -**org.apache.ibatis.cache.Cache** - -![org.apache.ibatis.cache.Cache](https://upload-images.jianshu.io/upload_images/5336514-7e2d2cd6e162b07d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) \ No newline at end of file diff --git "a/design-pattern/notes/\347\273\223\346\236\204\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\351\200\202\351\205\215\345\231\250\346\250\241\345\274\217\357\274\210\344\270\211\357\274\211.md" "b/design-pattern/notes/\347\273\223\346\236\204\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\351\200\202\351\205\215\345\231\250\346\250\241\345\274\217\357\274\210\344\270\211\357\274\211.md" deleted file mode 100644 index 5473b0ec..00000000 --- "a/design-pattern/notes/\347\273\223\346\236\204\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\351\200\202\351\205\215\345\231\250\346\250\241\345\274\217\357\274\210\344\270\211\357\274\211.md" +++ /dev/null @@ -1,258 +0,0 @@ -> 该项目源码地址:[https://github.com/ggb2312/JavaNotes/tree/master/design-pattern](https://github.com/ggb2312/JavaNotes/tree/master/design-pattern)(设计模式相关代码与笔记) - -# 1. 定义 - -将一个类的接口转换成客户期望的另一个接口。适配器模式让那些接口不兼容的类可以一起工作。 - -# 2. 适用场景 - -- 已经存在的类,它的方法和需求不匹配时(方法结果相同或相似) -- 不是软件设计阶段考虑的设计模式,是随着软件维护。由于不同产品、不同厂家造成功能类似而接口不相同情况下的解决方案 - -# 3. 适配器类图与角色 - -## 3.1 适配器类型 - -**适配器类型**有两种类型实现,一种是类适配器,一种是对象适配器。 - -**(1)类适配器** - -通过类继承实现的。 - -![类适配器](https://upload-images.jianshu.io/upload_images/5336514-8f810733b8168e44.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -让Adapter继承Adaptee类,Client在使用Target的request()接口(实际上是调用Adapter的request()方法)时,间接调用adapteeRequest()方法。 - -**(2)对象适配器** - -符合组合复用原则,使用委托机制。 - -![对象适配器](https://upload-images.jianshu.io/upload_images/5336514-5ffcc43260128f1d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -对比着类适配器理解。在Adapter内部创建Adaptee对象,Client在使用Target的request()接口(实际上是调用Adapter的request()方法)时,间接调用adapteeRequest()方法。 - -## 3.2 角色 -由图可知适配器模式包含一下三个角色: - -- **Target(目标抽象类)**:目标抽象类定义客户所需的接口,可以是一个抽象类或接口,也可以是具体类。在类适配器中,由于Java语言不支持多重继承,所以它很可能是接口。 - -- **Adapter(适配器类)**:它可以调用另一个接口,作为一个转换器,对Adaptee和Target进行适配。它是适配器模式的核心。 - -- **Adaptee(被适配类)**:被适配类即被适配的角色,它定义了一个已经存在的接口,这个接口需要适配,适配者类包好了客户希望的业务方法。 - -# 4. 相关设计模式 - -**适配器模式和外观模式** -- 适配器复用现有的接口,外观模式则是定义新的接口。 - -# 5. 模式实例 - -## 5.1 类适配器 - -**Adaptee** 有一个被适配器类: - -```java -public class Adaptee { - public void adapteeRequest() { - System.out.println("被适配者的方法"); - } -} -``` - -**Target** 这个是目标方法的接口: - -```java -public interface Target { - void request(); -} -``` -**ConcreteTarget** 这个是目标方法的实现: - -```java -/** 具体的实现类 */ -public class ConcreteTarget implements Target { - @Override - public void request() { - System.out.println("ConcreteTarget目标方法"); - } -} -``` -**Adapter** 而这个就是适配类:继承于被适配类,实现目标方法的接口: - -```java -public class Adapter extends Adaptee implements Target { - @Override - public void request() { - super.adapteeRequest(); - } -} -``` -**Client** 我们来进行测试一下: - -```java -public class Test { - public static void main(String[]args){ - Target target = new ConcreteTarget(); - target.request(); - - /** 现在,我们就来通过适配器类来进行实现 */ - Target adapterTarget = new Adapter(); - adapterTarget.request(); - } -} -``` -测试结果: - -![测试结果](https://upload-images.jianshu.io/upload_images/5336514-a4d14cceb474f060.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -此时的类图: - -![类适配器类图](https://upload-images.jianshu.io/upload_images/5336514-c15e8e5ef6a3dccf.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -## 5.2 对象适配器 - -有一个目标接口: - -```java -public interface Target { - void request(); -} -``` - -有一个具体的目标类: - -```java -/** 具体的实现类 */ -public class ConcreteTarget implements Target { - @Override - public void request() { - System.out.println("ConcreteTarget目标方法"); - } -} -``` - -以及被适配的类: - -```java -public class Adaptee { - public void adapteeRequest() { - System.out.println("被适配者的方法"); - } -} -``` - -适配类和上面的有一些不同,这里被适配类不是继承过来的,而是作为属性组合到里面来,然后通过对象来调用被适配类里面的方法: - -```java -public class Adapter implements Target { - - private Adaptee adaptee = new Adaptee(); - - @Override - public void request() { - adaptee.adapteeRequest(); - } -} -``` - -测试: - -```java -public class Test { - public static void main(String[]args){ - Target target = new ConcreteTarget(); - target.request(); - - /** 现在,我们就来通过适配器类来进行实现 */ - Target adapterTarget = new Adapter(); - adapterTarget.request(); - } -} -``` - -测试结果: - -![测试结果](https://upload-images.jianshu.io/upload_images/5336514-863999635528654f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -此时类图: - -![对象适配类图](https://upload-images.jianshu.io/upload_images/5336514-77776e7558f50d36.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -## 5.3 适配器demo - -简单的抽象一个场景:手机充电需要将220V的交流电转化为手机锂电池需要的5V直流电,我们的demo就是写一个电源适配器,将 AC220v ——> DC5V - -首先有一个被适配的类:220V的类 - -```java -public class AC220 { - public int outputAC220V() { - int output = 220; - System.out.println("输出220V的交流电"+output+"V"); - return output; - } -} -``` -我们有一个目标方法的接口:转为5V的直流电 - -```java -public interface DC5 { - int outputDC5V(); -} -``` - -这个就是适配类(使用对象适配): - -```java -public class PowerAdapter implements DC5 { - - private AC220 ac220 = new AC220(); - - @Override - public int outputDC5V() { - int adapterInput = ac220.outputAC220V(); - /** 变压器 */ - int adapterOutput = adapterInput / 44; - System.out.println("通过PowerAdapter电源适配器输入AC"+adapterInput+"V"+"输出DC:"+adapterOutput+"V"); - return adapterOutput; - } -} -``` - -测试: - -```java -public class Test { - public static void main(String[]args){ - DC5 dc5 = new PowerAdapter(); - dc5.outputDC5V(); - } -} -``` - -测试结果: - -![测试结果](https://upload-images.jianshu.io/upload_images/5336514-10537c6af481851a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -# 6. 优缺点 - -**优点:** - -- 能提高类的透明性和复用,现有的类复用但不需要改变 -- 目标类和适配器类解耦,提高程序扩展性 -- 符合开闭原则 - -**缺点:** - -- 适配器编写过程需要全面考虑,可能会增加系统的复杂性 -- 增加系统代码可读的难度 - -# 7. 扩展-JDK1.7以及框架源码中的适配器模式 - -javax.xml.bind.annotation.adapters.XmlAdapter - -org.springframework.aop.framework.adapter.AdvisorAdapter、MethodBeforeAdviceAdapter - -org.springframework.orm.jpa.JpaVendorAdapter - -org.springframework.web.servlet.HandlerAdapter、org.springframework.web.servlet.DispatcherServlet、org.springframework.web.servlet.mvc.Controller \ No newline at end of file diff --git "a/design-pattern/notes/\350\241\214\344\270\272\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\344\270\255\344\273\213\350\200\205\346\250\241\345\274\217\357\274\210\345\205\253\357\274\211.md" "b/design-pattern/notes/\350\241\214\344\270\272\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\344\270\255\344\273\213\350\200\205\346\250\241\345\274\217\357\274\210\345\205\253\357\274\211.md" deleted file mode 100644 index 95120a7c..00000000 --- "a/design-pattern/notes/\350\241\214\344\270\272\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\344\270\255\344\273\213\350\200\205\346\250\241\345\274\217\357\274\210\345\205\253\357\274\211.md" +++ /dev/null @@ -1,111 +0,0 @@ -> 该项目源码地址:[https://github.com/ggb2312/JavaNotes/tree/master/design-pattern](https://github.com/ggb2312/JavaNotes/tree/master/design-pattern)(设计模式相关代码与笔记) - -# 1. 定义 - -定义一个封装一组对象如何交互的对象(通过使对象明确地相互引用来促进松散耦合,并允许独立地改变它们的交互) - -# 2. 适用场景 - -- 系统中对象之间存在复杂的引用关系,产生的相互依赖关系结构混乱且难以理解 -- 交互的公共行为,如果需要改变行为则可以增加新的中介者类 - -应用例子:聊天室 - -# 3. 类图与角色 - -![中介者模式类图](https://upload-images.jianshu.io/upload_images/5336514-8e6caadce33da545.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -它主要包含如下几个角色: - -**Mediator**:抽象中介者。定义了同事对象到中介者对象之间的接口。 - -**ConcreteMediator**:具体中介者。实现抽象中介者的方法,它需要知道所有的具体同事类,同时需要从具体的同事类那里接收信息,并且向具体的同事类发送信息。 - -**Colleague**:抽象同事类。 - -**ConcreteColleague**:具体同事类。每个具体同事类都只需要知道自己的行为即可,但是他们都需要认识中介者。 - - -在中介者模式中中介者对象处于核心地位,因为它定义了整个系统中所有具体同事类之间的关系。在整个系统中它主要承担两个方面的责任: - -**1、 结构上起到中转作用**。通过中介者对象对关系的封装,使得具体的同事类不再需要显示的引用其他对象,它只需要通过中介者就可以完成与其他同事类之间的通信。 - -**2、 行为上起到协作作用**。中介者对同事类之间的关系进行封装,同事类在不需要知道其他对象的情况下通过中介者与其他对象完成通信。在这个过程中同事类是不需要指明中介者该如何做,中介者可以根据自身的逻辑来进行协调,对同事的请求进一步处理,将同事成员之间的关系行为进行分离和封装。 - - 同时由于中介者对对象的关系进行了封装,使得各个同事类之间的耦合减少了,使得他们可以独立改变和复用。 - -# 4. 相关设计模式 - -**中介者模式和观察者模式** -观察者模式来实现中介者模式中的角色之间的通讯 - -# 5. 模式实例 - -**背景**:聊天室聊天 - -**(1)ConcreteColleague 用户类** - -发送消息的时候,就是通过中介者来进行发送 - -```java -public class User { - private String name; - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public User(String name) { - this.name = name; - } - - public void sendMessage(String message) { - StudyGroup.showMessage(this,message); - } -} -``` - -**(2)ConcreteMediator 中介者** - -```java -public class StudyGroup { - public static void showMessage(User user, String message) { - System.out.println(new Date().toString()+"["+user.getName()+"]:"+message); - } -} -``` - -**(3)测试** - -```java -public class Test { - public static void main(String[] args) { - User tom = new User("ldc"); - User jack = new User("ghl"); - - tom.sendMessage("hey!jack"); - jack.sendMessage("hey!tom"); - } -} -``` - -测试结果: - -![测试结果](https://upload-images.jianshu.io/upload_images/5336514-40df23ec370f8eeb.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -# 6. 优缺点 - -**优点:** -- 将一对多转化成了一对一、降低程序复杂度 -- 类之间解耦 - -**缺点:** -- 中介者过多,导致系统复杂 - -# 7. 扩展-JDK1.7源码以及框架中的中介者模式 - -java.util.Timer就是一个中介者,TimerTask就是user(同事类),通过sched进行协调 \ No newline at end of file diff --git "a/design-pattern/notes/\350\241\214\344\270\272\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\345\221\275\344\273\244\346\250\241\345\274\217\357\274\210\344\270\203\357\274\211.md" "b/design-pattern/notes/\350\241\214\344\270\272\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\345\221\275\344\273\244\346\250\241\345\274\217\357\274\210\344\270\203\357\274\211.md" deleted file mode 100644 index 85466dd9..00000000 --- "a/design-pattern/notes/\350\241\214\344\270\272\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\345\221\275\344\273\244\346\250\241\345\274\217\357\274\210\344\270\203\357\274\211.md" +++ /dev/null @@ -1,179 +0,0 @@ -> 该项目源码地址:[https://github.com/ggb2312/JavaNotes/tree/master/design-pattern](https://github.com/ggb2312/JavaNotes/tree/master/design-pattern)(设计模式相关代码与笔记) - -# 1. 定义 - -将请求封装成对象,以便使用不同的请求、日志、队列等来参数化其他对象。命令模式也支持撤销操作。(命令模式解决了应用程序中对象的职责以及它们之间的通信方式) - -# 2. 适用场景 - -- 请求调用者和请求接收者需要解耦,使得调用者和接收者不直接交互 -- 需要抽象出等待执行的行为 - -# 3. 类图与角色 - -![命令模式类图](https://upload-images.jianshu.io/upload_images/5336514-c594e991605cffa5.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -**Command(抽象命令类)**:抽象出命令对象,可以根据不同的命令类型。写出不同的实现类 - -**ConcreteCommand(具体命令类)**:实现了抽象命令对象的具体实现 - -**Invoker(调用者/请求者)**:`请求的发送者,它通过命令对象来执行请求。`一个调用者并不需要在设计时确定其接收者,因此它只与抽象命令来之间存在关联。在程序运行时,将调用命令对象的execute() ,间接调用接收者的相关操作。 - -**Receiver(接收者)**:接收者执行与请求相关的操作,`真正执行命令的对象。`具体实现对请求的业务处理。未抽象前,实际执行操作内容的对象。 - -**Client(客户端)**:在客户类中需要创建调用者对象,具体命令类对象,在创建具体命令 对象时指定对应的接收者。发送者和接收者之间没有之间关系。 - -# 4. 相关设计模式 - -**命令模式和备忘录模式** -使用备忘录模式保存命令的历史记录 - -# 5. 模式实例 - -**(1)Command抽象命令类** - -Command - -```java -/** - * 抽象命令类:抽象的命令,可以根据不同类型的命令写出不同的实现 - */ -public interface Command { - void execute(); -} -``` -**(2)Receiver接收者** -CourseVideo -```java -/** - * 接收者:真正执行命令的对象 - */ -public class CourseVideo { - private String name; - - public CourseVideo(String name) { - this.name = name; - } - - public void open() { - System.out.println(this.name + "课程开放"); - } - - public void close() { - System.out.println(this.name + "课程关闭"); - } -} -``` -**(3)ConcreteCommand具体命令类** - -OpenCourseVideoCommand、CloseCourseVideoCommand - -```java -/** - * 具体命令类 - */ -public class OpenCourseVideoCommand implements Command { - private CourseVideo courseVideo; - - public OpenCourseVideoCommand(CourseVideo courseVideo) { - this.courseVideo = courseVideo; - } - - @Override - public void execute() { - courseVideo.open(); - } -} -``` - -```java -/** - * 具体命令类 - * @author lastwhisper - */ -public class CloseCourseVideoCommand implements Command { - - private CourseVideo courseVideo; - - public CloseCourseVideoCommand(CourseVideo courseVideo) { - this.courseVideo = courseVideo; - } - - @Override - public void execute() { - courseVideo.close(); - } -} -``` -**(4)Invoker调用者/请求者** -Staff - -```java -import java.util.ArrayList; -import java.util.List; - -/** - * 命令的发起者 - */ -public class Staff { - /** - * 持有真正执行命令对象的引用 - */ - private List commandList = new ArrayList<>(); - - public void addCommand(Command command) { - commandList.add(command); - } - - public void executeCommands() { - for (Command command : commandList) { - //请求者调用命令对象执行命令的那个execute方法 - command.execute(); - } - commandList.clear(); - } -} -``` -**(5)Client客户端** - test - -```java -public class Test { - public static void main(String[] args) { - //通过请求者(invoker)调用命令对象(command),命令对象中调用了命令具体执行者(CourseVideo) - CourseVideo courseVideo = new CourseVideo("Java设计模式"); - OpenCourseVideoCommand openCourseVideoCommand = new OpenCourseVideoCommand(courseVideo); - CloseCourseVideoCommand closeCourseVideoCommand = new CloseCourseVideoCommand(courseVideo); - - Staff staff = new Staff(); - staff.addCommand(openCourseVideoCommand); - staff.addCommand(closeCourseVideoCommand); - staff.executeCommands(); - } -} -``` - -测试结果: - -![测试结果](https://upload-images.jianshu.io/upload_images/5336514-434b1d246644899e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -**(6)类图** - -![类图](https://upload-images.jianshu.io/upload_images/5336514-e2da6a6a56f26308.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -# 6. 优缺点 - -**优点:** - -- 降低耦合 -- 容易扩展新命令或者一组命令 - -**缺点:** - -- 命令的无限扩展会增加类的数量,提高系统实现复杂度 - -# 7. 扩展-JDK1.7源码以及框架中的命令模式 - -7.1 java.lang.Runnable是一个抽象命令类,在编写多线程时,实现Runnable接口就是具体的命令。 - -7.2 junit.framework.Test的run方法就是execute方法 \ No newline at end of file diff --git "a/design-pattern/notes/\350\241\214\344\270\272\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\345\244\207\345\277\230\345\275\225\346\250\241\345\274\217\357\274\210\345\205\255\357\274\211.md" "b/design-pattern/notes/\350\241\214\344\270\272\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\345\244\207\345\277\230\345\275\225\346\250\241\345\274\217\357\274\210\345\205\255\357\274\211.md" deleted file mode 100644 index fbae2eea..00000000 --- "a/design-pattern/notes/\350\241\214\344\270\272\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\345\244\207\345\277\230\345\275\225\346\250\241\345\274\217\357\274\210\345\205\255\357\274\211.md" +++ /dev/null @@ -1,173 +0,0 @@ -> 该项目源码地址:[https://github.com/ggb2312/JavaNotes/tree/master/design-pattern](https://github.com/ggb2312/JavaNotes/tree/master/design-pattern)(设计模式相关代码与笔记) - -# 1. 定义 - -在不破坏封装性的前提下,保存一个对象的某个状态,以便在适当的时候恢复对象。 - -# 2. 适用场景 - -- 保存及恢复数据相关业务场景 -- 后悔的时候,即想恢复到之前的状态 - -比如:wps之类的文本编辑器 - -# 3. 类图与角色 - -![类图](https://upload-images.jianshu.io/upload_images/5336514-6d4670661e11b4cc.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -备忘录模式主要包含入下几个角色: - -**Originator:原发器。**负责创建一个备忘录,用以记录当前对象的内部状态,通过使用它来利用备忘录恢复内部状态。同时原发器还可以根据需要决定Memento存储Originator的那些内部状态。 - -**Memento:备忘录。**用于存储Originator的内部状态,并且可以防止Originator以外的对象访问Memento。在备忘录Memento中有两个接口,其中Caretaker只能看到备忘录中的窄接口,它只能将备忘录传递给其他对象。Originator可以看到宽接口,允许它访问返回到先前状态的所有数据 - -**Caretaker:负责人。**负责保存好备忘录,不能对备忘录的内容进行操作和访问,只能够将备忘录传递给其他对象。 - -在备忘录模式中,最重要的就是备忘录Memento了。我们都是备忘录中存储的就是原发器的部分或者所有的状态信息,而这些状态信息是不能够被其他对象所访问了,也就是说我们是不可能在备忘录之外的对象来存储这些状态信息,如果暴漏了内部状态信息就违反了封装的原则,故备忘录是除了原发器外其他对象都是不可以访问的。 - - 所以为了实现备忘录模式的封装,我们需要对备忘录的访问做些控制: - -**对原发器**:可以访问备忘录里的所有信息。 - -**对负责人**:不可以访问备忘录里面的数据,但是他可以保存备忘录并且可以将备忘录传递给其他对象。 - -**其他对象**:不可访问也不可以保存,它只负责接收从负责人那里传递过来的备忘录同时恢复原发器的状态。 - -所以就备忘录模式而言理想的情况就是只允许生成该备忘录的那个原发器访问备忘录的内部状态。 - -# 4. 相关设计模式 - -**备忘录模式和状态模式** -备忘录模式是对象表示状态,状态模式是用类来表示状态。 - -# 5. 模式实例 - -**背景**:我们就以游戏挑战BOSS为实现场景,在挑战BOSS之前,角色的血量、蓝量都是满值,然后存档,在大战BOSS时,由于操作失误导致血量和蓝量大量损耗,所以只好恢复到刚刚开始的存档点,继续进行大战BOSS了。这里使用备忘录模式来实现。 - -**(1)首先是游戏角色类:Role** - -```java -public class Role { - private int bloodFlow;//血量 - private int magicPoint;//蓝量 - - public Role(int bloodFlow,int magicPoint){ - this.bloodFlow = bloodFlow; - this.magicPoint = magicPoint; - } - - public int getBloodFlow() { - return bloodFlow; - } - - public void setBloodFlow(int bloodFlow) { - this.bloodFlow = bloodFlow; - } - - public int getMagicPoint() { - return magicPoint; - } - - public void setMagicPoint(int magicPoint) { - this.magicPoint = magicPoint; - } - - - public void display(){ - System.out.println("用户当前状态:"); - System.out.println("血量:" + getBloodFlow() + ";蓝量:" + getMagicPoint()); - } - - - public Memento saveMemento(){ - return new Memento(getBloodFlow(), getMagicPoint()); - } - - - public void restoreMemento(Memento memento){ - this.bloodFlow = memento.getBloodFlow(); - this.magicPoint = memento.getMagicPoint(); - } -} - -``` -**(2)备忘录:Memento** -```java -class Memento { - private int bloodFlow; - private int magicPoint; - - public int getBloodFlow() { - return bloodFlow; - } - - public int getMagicPoint() { - return magicPoint; - } - - public Memento(int bloodFlow,int magicPoint){ - this.bloodFlow = bloodFlow; - this.magicPoint = magicPoint; - } -} -``` -**(3)负责人:Caretaker** - -```java -public class Caretaker { - Memento memento; - - public Memento getMemento() { - return memento; - } - - public void setMemento(Memento memento) { - this.memento = memento; - } - -} -``` - -**(4)客户端:Client** - -```java -public class Client { - public static void main(String[] args) { - //打BOSS之前:血、蓝全部满值 - Role role = new Role(100, 100); - System.out.println("----------大战BOSS之前----------"); - role.display(); - - //保持进度 - Caretaker caretaker = new Caretaker(); - caretaker.memento = role.saveMemento(); - - //大战BOSS,快come Over了 - role.setBloodFlow(20); - role.setMagicPoint(20); - System.out.println("----------大战BOSS----------"); - role.display(); - - //恢复存档 - role.restoreMemento(caretaker.getMemento()); - System.out.println("----------恢复----------"); - role.display(); - - } -} -``` - -# 6. 优缺点 - -**优点:** -- 为用户提供一种可恢复机制 -- 存档信息的封装 - -**缺点:** -- 资源占用 - -# 7. 扩展-JDK1.7源码以及框架中的备忘录模式 - -org.springframework.binding.message.StateManageableMessageContext - -![StateManageableMessageContext](https://upload-images.jianshu.io/upload_images/5336514-569f6de7cbae8b01.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) \ No newline at end of file diff --git "a/design-pattern/notes/\350\241\214\344\270\272\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\346\250\241\346\235\277\346\226\271\346\263\225\357\274\210\344\270\200\357\274\211.md" "b/design-pattern/notes/\350\241\214\344\270\272\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\346\250\241\346\235\277\346\226\271\346\263\225\357\274\210\344\270\200\357\274\211.md" deleted file mode 100644 index 79147bdd..00000000 --- "a/design-pattern/notes/\350\241\214\344\270\272\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\346\250\241\346\235\277\346\226\271\346\263\225\357\274\210\344\270\200\357\274\211.md" +++ /dev/null @@ -1,225 +0,0 @@ -> 该项目源码地址:[https://github.com/ggb2312/JavaNotes/tree/master/design-pattern](https://github.com/ggb2312/JavaNotes/tree/master/design-pattern)(设计模式相关代码与笔记) - -# 1. 定义 - -定义了一个算法的骨架,并允许子类为一个或多个步骤提供实现。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法的某些步骤 - -# 2. 适用场景 - -- 一次性实现一个算法的不变的部分,并将可变的行为留给子类来实现 -- 各子类中公共的行为被提取出来并集中到一个公共父类中,从而避免代码重复 - -# 3. 相关设计模式 - -**模板方法模式和工厂方法模式** - -- 工厂方法模式是模板方法模式的一种特殊实现 - -**模板方法模式和策略模式** - -- 策略模式是使不同的算法可以相互替换,并且不影响客户端的使用。模板方法模式定义算法的执行流程,不同的算法交给子类去实现 - - -# 4. 模式实例 - -## 4.1 常规-模板方法 - -背景:学炒菜,手撕包菜 & 蒜蓉炒菜心** - -**(1)创建抽象模板结构(Abstract Class)** - -炒菜的步骤 - -```java -public abstract class Abstract { - //模板方法,用来控制炒菜的流程 (炒菜的流程是一样的-复用) -//申明为final,不希望子类覆盖这个方法,防止更改流程的执行顺序 - final void cookProcess() { - //第一步:倒油 - this.pourOil(); - //第二步:热油 - this.HeatOil(); - //第三步:倒蔬菜 - this.pourVegetable(); - //第四步:倒调味料 - this.pourSauce(); - //第五步:翻炒 - this.fry(); - } - -//定义结构里哪些方法是所有过程都是一样的可复用的,哪些是需要子类进行实现的 - - //第一步:倒油是一样的,所以直接实现 - void pourOil() { - System.out.println("倒油"); - } - - //第二步:热油是一样的,所以直接实现 - void HeatOil() { - System.out.println("热油"); - } - - //第三步:倒蔬菜是不一样的(一个下包菜,一个是下菜心) -//所以声明为抽象方法,具体由子类实现 - abstract void pourVegetable(); - - //第四步:倒调味料是不一样的(一个下辣椒,一个是下蒜蓉) -//所以声明为抽象方法,具体由子类实现 - abstract void pourSauce(); - - - //第五步:翻炒是一样的,所以直接实现 - void fry() { - System.out.println("炒啊炒啊炒到熟啊"); - } -} -``` - -**(2) 创建具体模板(Concrete Class)** - -炒”手撕包菜“和”蒜蓉炒菜心“的具体步骤 - -```java -//炒手撕包菜的类 -public class ConcreteClass_BaoCai extends Abstract { - @Override - public void pourVegetable() { - System.out.println("下锅的蔬菜是包菜"); - } - - @Override - public void pourSauce() { - System.out.println("下锅的酱料是辣椒"); - } -} -``` - -```java -//炒蒜蓉菜心的类 -public class ConcreteClass_CaiXin extends Abstract { - @Override - public void pourVegetable() { - System.out.println("下锅的蔬菜是菜心"); - } - - @Override - public void pourSauce() { - System.out.println("下锅的酱料是蒜蓉"); - } -} -``` - -**(3)测试** - -```java -public class Test { - public static void main(String[] args) { - //炒 - 手撕包菜 - ConcreteClass_BaoCai BaoCai = new ConcreteClass_BaoCai(); - BaoCai.cookProcess(); - //炒 - 蒜蓉菜心 - ConcreteClass_CaiXin CaiXin = new ConcreteClass_CaiXin(); - CaiXin.cookProcess(); - } -} -``` - -测试结果: - -![测试结果](https://upload-images.jianshu.io/upload_images/5336514-11ec1eef4ccf01ee.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -## 4.2 扩展-钩子方法 - -如果想炒两盘青菜,一盘是不放调味料,一盘放调味料怎么办呢。 -按照模板方法的正常步骤就是,写一个炒青菜子类ConcreteClass_Qingcai_NotPourSauce空实现倒调味料方法,写一个炒青菜子类ConcreteClass_Qingcai实现倒调味料方法。然后炒不放调味料的青菜使用ConcreteClass_Qingcai_NotPourSauce,炒放调味料的青菜 -使用ConcreteClass_Qingcai。 - -如果想要炒更多青菜怎么办呢? - -可以在抽象的模板里面添加钩子方法,在抽象的执行流程中,根据钩子函数决定是否调用某个步骤。 - -```java -public abstract class Abstract { - //模板方法,用来控制炒菜的流程 (炒菜的流程是一样的-复用) -//申明为final,不希望子类覆盖这个方法,防止更改流程的执行顺序 - final void cookProcess() { - //第一步:倒油 - this.pourOil(); - //d第二步:热油 - this.HeatOil(); - //第三步:倒蔬菜 - this.pourVegetable(); - //第四步:倒调味料 - - // 这里是否需要倒调味料交由钩子方法来决定 - if (needPourSauce()) { - this.pourSauce(); - } - //第五步:翻炒 - this.fry(); - } - - -//定义结构里哪些方法是所有过程都是一样的可复用的,哪些是需要子类进行实现的 - - //第一步:倒油是一样的,所以直接实现 - void pourOil() { - System.out.println("倒油"); - } - - //第二步:热油是一样的,所以直接实现 - void HeatOil() { - System.out.println("热油"); - } - - //第三步:倒蔬菜是不一样的(一个下包菜,一个是下菜心) -//所以声明为抽象方法,具体由子类实现 - abstract void pourVegetable(); - - //第四步:倒调味料是不一样的(一个下辣椒,一个是下蒜蓉) -//所以声明为抽象方法,具体由子类实现 - abstract void pourSauce(); - - - //第五步:翻炒是一样的,所以直接实现 - void fry() { - System.out.println("炒啊炒啊炒到熟啊"); - } - - /** - * 我们就要给这个倒调味料声明一个钩子方法 - */ - protected boolean needPourSauce() { - return true; - } -} -``` -这样我们只需要一个炒青菜子类。子类可以选择性的重写钩子方法,决定是否倒入调料。 - -# 5. 优缺点 - -**优点:** - -- 提高复用性 -- 提高扩展性 -- 符合开闭原则 - -**缺点:** - -- 类数目增加 -- 增加了系统实现的复杂度 -- 如果父类添加新的抽象方法,所有子类都要改一遍 - -# 6. 扩展-JDK1.7源码以及框架中的模板方法 - -## 6.1 jdk - -java.util.AbstractList定义一套算法模板,如get(),set()等等,由子类实现。 - -## 6.2 servlet - -javax.servlet.http.HttpServlet定义一套算法模板,如doGet()、doPost()等等,由子类实现。。 - -## 6.3 mybatis - -org.apache.ibatis.executor.BaseExecutor \ No newline at end of file diff --git "a/design-pattern/notes/\350\241\214\344\270\272\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\347\212\266\346\200\201\346\250\241\345\274\217\357\274\210\345\215\201\344\270\200\357\274\211.md" "b/design-pattern/notes/\350\241\214\344\270\272\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\347\212\266\346\200\201\346\250\241\345\274\217\357\274\210\345\215\201\344\270\200\357\274\211.md" deleted file mode 100644 index 4eb082f8..00000000 --- "a/design-pattern/notes/\350\241\214\344\270\272\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\347\212\266\346\200\201\346\250\241\345\274\217\357\274\210\345\215\201\344\270\200\357\274\211.md" +++ /dev/null @@ -1,266 +0,0 @@ -> 该项目源码地址:[https://github.com/ggb2312/JavaNotes/tree/master/design-pattern](https://github.com/ggb2312/JavaNotes/tree/master/design-pattern)(设计模式相关代码与笔记) - -# 1. 定义 - -允许一个对象在其内部状态改变时,改变它的行为 - -# 2. 适用场景 - -一个对象存在多个状态(不同状态下行为不同),且状态可相互转换 -比如:电商订单状态扭转等 - -# 3. 类图与角色 - -![状态模式类图](https://upload-images.jianshu.io/upload_images/5336514-8031e4d346d21d3f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - - -**Context**:它就是那个含有状态的对象,它可以处理一些请求,这些请求最终产生的响应会与状态相关。 - -**State**:状态接口,它定义了每一个状态的行为集合,这些行为会在Context中得以使用。 - -**ConcreteState**:具体状态,实现相关行为的具体状态类。 - -# 4. 相关设计模式 - -**状态模式和享元模式** -状态模式和享元模式可以组合使用 - -# 5. 模式实例 - -![项目结构](https://upload-images.jianshu.io/upload_images/5336514-8219734a946f2089.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -背景:视频的播放状态切换 - -**(1)视频状态抽象类** -```java -/** - * Create by lastwhisper on 2019/2/11 - */ -public abstract class CourseVideoState { - protected CourseVideoContext courseVideoContext; - - public void setCourseVideoContext(CourseVideoContext courseVideoContext) { - this.courseVideoContext = courseVideoContext; - } - - public abstract void play(); - - public abstract void speed(); - - public abstract void pause(); - - public abstract void stop(); -} -``` - -**(2)视频上下文** - -```java -/** - * Create by lastwhisper on 2019/2/11 - */ -public class CourseVideoContext { - private CourseVideoState courseVideoState; - public final static PlayState PLAY_STATE = new PlayState(); - public final static StopState STOP_STATE = new StopState(); - public final static PauseState PAUSE_STATE = new PauseState(); - public final static SpeedState SPEED_STATE = new SpeedState(); - - public CourseVideoState getCourseVideoState() { - return courseVideoState; - } - - public void setCourseVideoState(CourseVideoState courseVideoState) { - this.courseVideoState = courseVideoState; - this.courseVideoState.setCourseVideoContext(this); - } - - public void play() { - this.courseVideoState.play(); - } - - public void speed() { - this.courseVideoState.speed(); - } - - public void pause() { - this.courseVideoState.pause(); - } - - public void stop() { - this.courseVideoState.stop(); - } -} -``` - -**(3)视频的各种具体状态类** - -PlayState 正常播放课程视频状态 - -```java -/** - * Create by lastwhisper on 2019/2/11 - */ -public class PlayState extends CourseVideoState { - - @Override - public void play() { - System.out.println("正常播放课程视频状态"); - } - - @Override - public void speed() { - super.courseVideoContext.setCourseVideoState(CourseVideoContext.SPEED_STATE); - } - - @Override - public void pause() { - super.courseVideoContext.setCourseVideoState(CourseVideoContext.PAUSE_STATE); - } - - @Override - public void stop() { - super.courseVideoContext.setCourseVideoState(CourseVideoContext.STOP_STATE); - } -} -``` - -SpeedState 快进播放课程视频状态 - -```java -/** - * Create by lastwhisper on 2019/2/11 - */ -public class SpeedState extends CourseVideoState { - @Override - public void play() { - super.courseVideoContext.setCourseVideoState(CourseVideoContext.PLAY_STATE); - } - - @Override - public void speed() { - System.out.println("快进播放课程视频状态"); - } - - @Override - public void pause() { - super.courseVideoContext.setCourseVideoState(CourseVideoContext.PAUSE_STATE); - } - - @Override - public void stop() { - super.courseVideoContext.setCourseVideoState(CourseVideoContext.STOP_STATE); - } -} - -``` - -PauseState 暂停播放课程视频状态 - -```java -/** - * Create by lastwhisper on 2019/2/11 - */ -public class PauseState extends CourseVideoState { - @Override - public void play() { - super.courseVideoContext.setCourseVideoState(CourseVideoContext.PLAY_STATE); - } - - @Override - public void speed() { - super.courseVideoContext.setCourseVideoState(CourseVideoContext.SPEED_STATE); - } - - @Override - public void pause() { - System.out.println("暂停播放课程视频状态"); - } - - @Override - public void stop() { - super.courseVideoContext.setCourseVideoState(CourseVideoContext.STOP_STATE); - } -} -``` - -StopState 停止播放课程视频状态 - -```java -/** - * Create by lastwhisper on 2019/2/11 - */ -public class StopState extends CourseVideoState { - @Override - public void play() { - super.courseVideoContext.setCourseVideoState(CourseVideoContext.PLAY_STATE); - } - - @Override - public void speed() { - System.out.println("ERROR 停止状态不能快进!!"); - } - - @Override - public void pause() { - System.out.println("ERROR 停止状态不能暂停!!"); - } - - @Override - public void stop() { - System.out.println("停止播放课程视频状态"); - } -} -``` - -**(4)测试** - -```java -/** - * Create by lastwhisper on 2019/2/11 - */ -public class Test { - public static void main(String[] args){ - CourseVideoContext courseVideoContext = new CourseVideoContext(); - courseVideoContext.setCourseVideoState(new PlayState()); - System.out.println("当前状态"+ courseVideoContext.getCourseVideoState().getClass().getSimpleName()); - - courseVideoContext.pause(); - System.out.println("当前状态"+ courseVideoContext.getCourseVideoState().getClass().getSimpleName()); - - courseVideoContext.speed(); - System.out.println("当前状态"+ courseVideoContext.getCourseVideoState().getClass().getSimpleName()); - - courseVideoContext.stop(); - System.out.println("当前状态"+ courseVideoContext.getCourseVideoState().getClass().getSimpleName()); - - courseVideoContext.speed(); - } -} -``` - -测试结果: - -![测试结果](https://upload-images.jianshu.io/upload_images/5336514-dc174f10141d07bc.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -(5)类图 - -![类图](https://upload-images.jianshu.io/upload_images/5336514-58ddbd8a459c5b5a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -![类图](https://upload-images.jianshu.io/upload_images/5336514-406b1bd008a13d51.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -# 6. 优缺点 - -**优点:** - -- 将不同的状态隔离 -- 把各种状态的转换逻辑,分布到State的子类中,减少相互间依赖 -- 增加新的状态非常简单 - -**缺点:** - -- 状态多的业务场景导致类数目增加,系统变复杂 - -# 7. 扩展-JDK1.7源码以及框架中的状态模式 - -javax.faces.lifecycle.Lifecycle、javax.faces.webapp.FacesServlet \ No newline at end of file diff --git "a/design-pattern/notes/\350\241\214\344\270\272\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\347\255\226\347\225\245\346\250\241\345\274\217\357\274\210\344\270\211\357\274\211.md" "b/design-pattern/notes/\350\241\214\344\270\272\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\347\255\226\347\225\245\346\250\241\345\274\217\357\274\210\344\270\211\357\274\211.md" deleted file mode 100644 index 18481623..00000000 --- "a/design-pattern/notes/\350\241\214\344\270\272\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\347\255\226\347\225\245\346\250\241\345\274\217\357\274\210\344\270\211\357\274\211.md" +++ /dev/null @@ -1,237 +0,0 @@ -> 该项目源码地址:[https://github.com/ggb2312/JavaNotes/tree/master/design-pattern](https://github.com/ggb2312/JavaNotes/tree/master/design-pattern)(设计模式相关代码与笔记) - -# 1. 定义 - -定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。 - -# 2. 适用场景 - -- 系统有很多类,而他们的区别仅仅在于他们的行为不同 -- 一个系统需要动态地在几种算法中选择一种 - -# 3. 相关设计模式 - -## 3.1 策略模式和工厂模式 - -**(1)用途不一样** - -工厂是创建型模式,它的作用就是创建对象; -策略是行为型模式,它的作用是让一个对象在许多行为中选择一种行为; - -**(2)关注点不一样** - -一个关注对象创建 -一个关注行为的封装 - -**(3)解决不同的问题** - -工厂模式是创建型的设计模式,它接受指令,创建出符合要求的实例;它主要解决的是资源的统一分发,将对象的创建完全独立出来,让对象的创建和具体的使用客户无关。主要应用在多数据库选择,类库文件加载等。 - -策略模式是为了解决的是策略的切换与扩展,更简洁的说是定义策略族,分别封装起来,让他们之间可以相互替换,策略模式让策略的变化独立于使用策略的客户。 - -**(4)工厂相当于黑盒子,策略相当于白盒子** - -## 3.2 策略模式和状态模式 - -使用策略模式时,客户端知道所有的行为。使用状态模式时,客户端不需要关心具体的行为。 - -# 4. 模式实例 - -**背景:**慕课网网站里面在618和双十一的时候,会有各种促销,而促销就是课程的一个行为,是一个促销行为,但是这种促销行为有多种实现,网站里面的课程促销。 - -## 4.1 基础实现 - -促销策略接口: - -```java -public interface PromotionStrategy { - void doPromotion(); -} -``` -立减促销类实现促销策略接口: - -```java -public class LiJianPromotionStrategy implements PromotionStrategy{ - @Override - public void doPromotion() { - System.out.println("立减促销,课程的价格直接减去配置的价格"); - } -} -``` - -满减促销类实现促销策略接口: - -```java -public class ManJianPromotionStrategy implements PromotionStrategy{ - - @Override - public void doPromotion() { - System.out.println("满减促销,满200减20元"); - } -} -``` -反现促销类实现促销策略接口: - -```java -public class FanXianPromotionStrategy implements PromotionStrategy{ - - @Override - public void doPromotion() { - System.out.println("反现促销,返回的金额存放到网站用户的余额中"); - } -} -``` - -PromotionActivity实现促销类,去执行促销策略 - -```java -public class PromotionActivity { - private PromotionStrategy promotionStrategy; - - public PromotionActivity(PromotionStrategy promotionStrategy) { - this.promotionStrategy = promotionStrategy; - } - - public void executePromotionStrategy() { - promotionStrategy.doPromotion(); - } -} -``` - -此时类图: - -![类图](https://upload-images.jianshu.io/upload_images/5336514-824e1192a5bba192.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -测试类: - -```java -public class Test { - public static void main(String[]args){ - /** 在618的时候,我们使用立减的策略 */ - PromotionActivity promotionActivity618 = new PromotionActivity(new LiJianPromotionStrategy()); - /** 在双11的时候,我们使用反现的策略 */ - PromotionActivity promotionActivity1111 = new PromotionActivity(new FanXianPromotionStrategy()); - - promotionActivity618.executePromotionStrategy(); - promotionActivity1111.executePromotionStrategy(); - } -} -``` - -测试结果: - -![测试结果](https://upload-images.jianshu.io/upload_images/5336514-c69287aa5122491c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -当我们新增促销策略的时候,只需要实现PromotionStrategy即可。 -根据上面的策略模式实现,我们来模拟一下真实场景,假如现在要在所有策略中选择立减促销。 - -修改测试类: - -```java -public class Test { - public static void main(String[]args){ - PromotionActivity promotionActivity = null; - /** 我们来创建一个promotionKey */ - String promotionKey = "LIJIAN"; - - if (StringUtils.equals(promotionKey, "LIJIAN")) { - promotionActivity = new PromotionActivity(new LiJianPromotionStrategy()); - } else if (StringUtils.equals(promotionKey, "FANXIAN")) { - promotionActivity = new PromotionActivity(new FanXianPromotionStrategy()); - }else if (StringUtils.equals(promotionKey, "MAINJIAN")){ - promotionActivity = new PromotionActivity(new ManJianPromotionStrategy()); - } - promotionActivity.executePromotionStrategy(); - } -} -``` - -测试结果: - -![测试结果](https://upload-images.jianshu.io/upload_images/5336514-16d0c1ac7e1065fd.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -虽然使用策略模式来封装促销的具体行为,但是在使用时还是需要if else。可以把策略模式和工厂模式结合到一起,避免if else。 - -## 4.2 完善 - -为了避免空指针异常,我们没有促销活动的时候,我们可以还写一个空的促销策略: - -```java -public class EmptyPromotionStrategy implements PromotionStrategy { - @Override - public void doPromotion() { - System.out.println("无促销"); - } -} -``` -促销策略工厂: - -```java -public class PromotionStrategyFactory { - private static Map PROMOTION_STRATEGY_MAP = new HashMap<>(); - static { - PROMOTION_STRATEGY_MAP.put(PromotionKey.LIJIAN, new LiJianPromotionStrategy()); - PROMOTION_STRATEGY_MAP.put(PromotionKey.FANXIAN, new FanXianPromotionStrategy()); - PROMOTION_STRATEGY_MAP.put(PromotionKey.MANJIAN, new ManJianPromotionStrategy()); - } - - private static final PromotionStrategy NON_PROMOTION = new EmptyPromotionStrategy(); - - private PromotionStrategyFactory() { - - } - - public static PromotionStrategy getPromotionStrategy(String promotionKey) { - PromotionStrategy promotionStrategy = PROMOTION_STRATEGY_MAP.get(promotionKey); - return promotionStrategy == null ? NON_PROMOTION : promotionStrategy; - } - - private interface PromotionKey{ - String LIJIAN = "LIJIAN"; - String FANXIAN = "FANXIAN"; - String MANJIAN = "MANJIAN"; - } -} -``` -测试: - -```java -public class Test { - public static void main(String[]args){ - - /** 我们来创建一个promotionKey */ - String promotionKey = "LIJIAN"; - - PromotionActivity promotionActivity = new PromotionActivity(PromotionStrategyFactory.getPromotionStrategy(promotionKey)); - promotionActivity.executePromotionStrategy(); - } -} -``` -测试结果: - -![测试结果](https://upload-images.jianshu.io/upload_images/5336514-4103d0c68c7e27bb.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -使用策略模式+工厂模式完美的解决了ifelse的情况,并且在工厂模式中还可以结合享元模式。 - -# 5. 优缺点 - -**优点:** - -- 增加一个新的策略只需要添加一个具体的策略类即可,不需要改变- 原有的代码,符合“开闭原则” -- 避免适用多重条件转移语句 -- 提高算法的保密性和安全性 - -**缺点:** - -- 客户端必须知道所有的策略类,并自行决定使用哪一个策略类 -- 产生很多策略类 - -# 6. 扩展-JDK1.7源码以及框架中的策略模式 - -6.1 java.util.Comparator是一个抽象的策略。 - -6.2 java.util.TreeMap - -6.3 org.springframework.core.io.Resource - -6.4 org.springframework.beans.factory.support.InstantiationStrategy是一个抽象的策略,org.springframework.beans.factory.support.SimpleInstantiationStrategy是一个具体实现策略。CglibSubclassingInstantiationStrategy继承了SimpleInstantiationStrategy,说明策略与策略之间可以存在一个继承关系。 \ No newline at end of file diff --git "a/design-pattern/notes/\350\241\214\344\270\272\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\350\247\202\345\257\237\350\200\205\346\250\241\345\274\217\357\274\210\344\272\224\357\274\211.md" "b/design-pattern/notes/\350\241\214\344\270\272\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\350\247\202\345\257\237\350\200\205\346\250\241\345\274\217\357\274\210\344\272\224\357\274\211.md" deleted file mode 100644 index 3bc40178..00000000 --- "a/design-pattern/notes/\350\241\214\344\270\272\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\350\247\202\345\257\237\350\200\205\346\250\241\345\274\217\357\274\210\344\272\224\357\274\211.md" +++ /dev/null @@ -1,383 +0,0 @@ -> 该项目源码地址:[https://github.com/ggb2312/JavaNotes/tree/master/design-pattern](https://github.com/ggb2312/JavaNotes/tree/master/design-pattern)(设计模式相关代码与笔记) - -# 1. 定义 - -定义了对象之间的一对多依赖,让多个观察者对象同时监听某一个主题对象,当主题对象发生变化时,它的所有依赖者(观察者)都会收到通知并更新。 - -# 2. 适用场景 - -关联行为场景,建立一套触发机制 - -# 3. 类图与角色 - -![观察者模式类图](https://upload-images.jianshu.io/upload_images/5336514-d6dfcb4e47525c27.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -- **Subject**:主题或者叫被观察者。他把所有观察者保存在一个集合里,每一个主题都可以有多个观察者。 - -- **Observer**:观察者。为所有的具体观察者定义一个接口,在得到主题的通知时能够及时的更新自己。 - -- **ConcreteSubject**:具体主题或者叫具体被观察者。在具体主题发生改变时,给所有登记过的观察者发出通知。 - -- **ConcreteObserver**:具体观察者。实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题状态相协调。 - - -# 4. 模式实例 - -**背景**:有一个微信公众号服务,不定时发布一些消息,关注公众号就可以收到推送消息,取消关注就收不到推送消息。 - -在JDK中提供了观察者模式,这里先不用JDK提供的,使用自己实现的。 - -## 4.1 自己实现 -自己实现一个简单的观察者模式 - -**(1)定义一个抽象观察者接口** - -```java -/*** - * 抽象观察者 - * 定义了一个update()方法,当被观察者调用notifyObservers()方法时,观察者的update()方法会被回调。 - * @author lastwhisper - * - */ -public interface Observer { - /** - * 观察者接收通知 - * @param message - */ - void update(String message); -} -``` -**(2)定义一个抽象被观察者接口** - -```java -/*** - * 抽象被观察者 - * 声明了添加、删除、通知观察者方法 - * @author lastwhisper - */ -public interface Observerable { - /** - * 注册观察者 - * @param o - */ - void registerObserver(Observer o); - - /** - * 移除观察者 - * @param o - */ - void removeObserver(Observer o); - - /** - * 通知观察者 - */ - void notifyObserver(); -} -``` -```java -/*** - * 抽象被观察者 - * 声明了添加、删除、通知观察者方法 - * @author lastwhisper - */ -public interface Observerable { - /** - * 注册观察者 - * @param o - */ - void registerObserver(Observer o); - - /** - * 移除观察者 - * @param o - */ - void removeObserver(Observer o); - - /** - * 通知观察者 - */ - void notifyObserver(); -} -``` - -**(3)具体被观察者** - -定义被观察者,实现了Observerable接口,对Observerable接口的三个方法进行了具体实现,同时有一个List集合,用以保存注册的观察者,等需要通知观察者时,遍历该集合即可。 - -```java -/** - * 具体被观察者,也就是微信公众号服务 - * 实现了Observerable接口,对Observerable接口的三个方法进行了具体实现 - * - * @author lastwhisper - */ -public class WechatServer implements Observerable { - - /** - * 注意到这个List集合的泛型参数为Observer接口,设计原则:面向接口编程而不是面向实现编程 - */ - private List list; - private String message; - - public WechatServer() { - list = new ArrayList(); - } - - @Override - public void registerObserver(Observer o) { - list.add(o); - } - - @Override - public void removeObserver(Observer o) { - if (!list.isEmpty()) { - list.remove(o); - } - } - - /**遍历*/ - @Override - public void notifyObserver() { - for (int i = 0; i < list.size(); i++) { - Observer oserver = list.get(i); - oserver.update(message); - } - } - - public void setInfomation(String s) { - this.message = s; - System.out.println("微信服务更新消息: " + s); - //消息更新,通知所有观察者 - notifyObserver(); - } - -} -``` -**(4)定义具体观察者,微信公众号的具体观察者为用户User** - -```java -/** - * 具体观察者 - * 实现了update方法 - * - * @author lastwhisper - */ -public class User implements Observer { - - private String name; - private String message; - - public User(String name) { - this.name = name; - } - - public void read() { - System.out.println(name + " 收到推送消息: " + message); - } - - @Override - public void update(String message) { - this.message = message; - read(); - } -} -``` - -**(5)测试** - -首先注册了三个用户,ZhangSan、LiSi、WangWu。公众号发布了一条消息"PHP是世界上最好用的语言!",三个用户都收到了消息。 - -用户ZhangSan看到消息后颇为震惊,果断取消订阅,这时公众号又推送了一条消息,此时用户ZhangSan已经收不到消息,其他用户还是正常能收到推送消息。 - -```java -public class Test { - - public static void main(String[] args) { - WechatServer server = new WechatServer(); - - Observer userZhang = new User("ZhangSan"); - Observer userLi = new User("LiSi"); - Observer userWang = new User("WangWu"); - - server.registerObserver(userZhang); - server.registerObserver(userLi); - server.registerObserver(userWang); - server.setInfomation("PHP是世界上最好用的语言!"); - - System.out.println("----------------------------------------------"); - server.removeObserver(userZhang); - System.out.println("ZhangSan取消关注"); - System.out.println("----------------------------------------------"); - - server.setInfomation("JAVA是世界上最好用的语言!"); - - } -} -``` - -测试结果: - -![测试结果](https://upload-images.jianshu.io/upload_images/5336514-ef57826ed0ff273a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -**(6)类图** - -![类图](https://upload-images.jianshu.io/upload_images/5336514-78b07d99b33f09e9.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -## 4.2 JDK实现 - -这里使用jdk自带的观察者模式 - -**(1)被观察者对象** - -```java -/** - * 被观察者对象 - * @author lastwhisper - */ -public class Course extends Observable { - private String courseName; - - public Course(String courseName) { - this.courseName = courseName; - } - - public String getCourseName() { - return courseName; - } - - public void produceQuestion(Course course, Question question) { - System.out.println(question.getUserName() + "在" + course.getCourseName() + "提交了一个问题 "); - setChanged(); - notifyObservers(question); - } -} -``` - -**(2)问题类** - -```java -public class Question { - private String userName; - private String questionContent; - - public String getUserName() { - return userName; - } - - public void setUserName(String userName) { - this.userName = userName; - } - - public String getQuestionContent() { - return questionContent; - } - - public void setQuestionContent(String questionContent) { - this.questionContent = questionContent; - } -} -``` - -**(3)观察者类** -```java -/** - * 观察者类 - * @author lastwhisper - */ -public class Teacher implements Observer { - private String teacherName; - - public Teacher(String teacherName) { - this.teacherName = teacherName; - } - - @Override - public void update(Observable o, Object arg) { - Course course = (Course) o; - Question question = (Question) arg; - System.out.println(teacherName+"老师的"+course.getCourseName()+"课程接收到一个"+question.getUserName()+"同学提交的问答:"+question.getQuestionContent()); - } -} -``` -**(4)测试类** - -```java -public class Test { - public static void main(String[] args) { - Course course = new Course("Java设计模式精讲"); - Teacher teacher1 = new Teacher("Alpha"); - Teacher teacher2 = new Teacher("Beta"); - - course.addObserver(teacher1); - course.addObserver(teacher2); - //业务逻辑代码 - Question question = new Question(); - question.setUserName("ldc"); - question.setQuestionContent("Java的主函数如何编写"); - - course.produceQuestion(course, question); - } -} -``` - -测试结果: - -![测试结果](https://upload-images.jianshu.io/upload_images/5336514-4998d6a9510f8984.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -**(5)类图** - -![类图](https://upload-images.jianshu.io/upload_images/5336514-f7d2b688cfa30fd0.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -# 5. 优缺点 - -**优点:** - -- 观察者和被观察者之间建立一个抽象的耦合 -- 观察者模式支持广播通信 - -**缺点:** - -- 观察者之间有过多的细节依赖、提高时间消耗及程序复杂度 -- 使用要得当,要避免循环调用 - -# 6. 扩展-JDK1.7源码以及框架中的观察者模式 - -6.1 java.awt.Event - -6.2 org.springframework.web.context.request.RequestContextListener、ServletRequestListener、EventListener -监听器是观察者模式的实现一种 - -6.3 org.springframework.beans.factory.parsing.ReaderEventListener - -6.4 通过guava实现观察者 - -```java -import com.google.common.eventbus.Subscribe; - -/** - * Create by lastwhisper on 2019/2/11 - */ -public class GuavaEvent { - @Subscribe - public void subscribe(String str) { - System.out.println("执行subscribe方法,传入:" + str); - } -} -``` - -```java -import com.google.common.eventbus.EventBus; - -/** - * Create by lastwhisper on 2019/2/11 - */ -public class GuavaEventTest { - public static void main(String[] args) { - EventBus eventBus = new EventBus(); - GuavaEvent guavaEvent = new GuavaEvent(); - eventBus.register(guavaEvent); - eventBus.post("post的内容"); - } - -} -``` \ No newline at end of file diff --git "a/design-pattern/notes/\350\241\214\344\270\272\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\350\247\243\351\207\212\345\231\250\346\250\241\345\274\217\357\274\210\345\233\233\357\274\211.md" "b/design-pattern/notes/\350\241\214\344\270\272\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\350\247\243\351\207\212\345\231\250\346\250\241\345\274\217\357\274\210\345\233\233\357\274\211.md" deleted file mode 100644 index bea4f049..00000000 --- "a/design-pattern/notes/\350\241\214\344\270\272\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\350\247\243\351\207\212\345\231\250\346\250\241\345\274\217\357\274\210\345\233\233\357\274\211.md" +++ /dev/null @@ -1,218 +0,0 @@ -> 该项目源码地址:[https://github.com/ggb2312/JavaNotes/tree/master/design-pattern](https://github.com/ggb2312/JavaNotes/tree/master/design-pattern)(设计模式相关代码与笔记) - -# 1. 定义 - -给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。(为了解释一种语言,而为语言创建的解释器) - -# 2. 适用场景 - -某个特定类型问题发生频率足够高 - -# 3. 类图与角色 - -![解释器模式类图](https://upload-images.jianshu.io/upload_images/5336514-3083e577497bf294.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -**AbstractExpression:** 抽象表达式。声明一个抽象的解释操作,该接口为抽象语法树中所有的节点共享。 -**TerminalExpression:** 终结符表达式。实现与文法中的终结符相关的解释操作。实现抽象表达式中所要求的方法。文法中每一个终结符都有一个具体的终结表达式与之相对应。 -**NonterminalExpression:** 非终结符表达式。为文法中的非终结符相关的解释操作。 -**Context:** 环境类。包含解释器之外的一些全局信息。 -**Client:** 客户类。 -抽象语法树描述了如何构成一个复杂的句子,通过对抽象语法树的分析,可以识别出语言中的终结符和非终结符类。 在解释器模式中由于每一种终结符表达式、非终结符表达式都会有一个具体的实例与之相对应,所以系统的扩展性比较好。 - -# 4. 相关设计模式 - -**解释器模式与适配器模式** -适配器模式是不知道预先要适配的规则,解释器模式要先把规则写好,根据规则解释。 - -# 5. 模式实例 - -**背景:**现在我们用解释器模式来实现一个基本的加、减、乘、除和求模运算。例如用户输入表达式“3 * 4 / 2 % 4”,输出结果为2。下图为该实例的UML结构图: - -![模式实例类图](https://upload-images.jianshu.io/upload_images/5336514-b327360e3f7653f2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -抽象语法树 - -![抽象语法树](https://upload-images.jianshu.io/upload_images/5336514-7772a4e1d77c83be.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -抽象表达式:Node -```java -public interface Node { - public int interpret(); -} -``` - -非终结表达式:ValueNode 主要用解释该表达式的值。 - -```java -public class ValueNode implements Node -{ - private int value; - - public ValueNode(int value) - { - this.value=value; - } - - @Override - public int interpret() - { - return this.value; - } -} -``` -终结表达式抽象类,由于该终结表达式需要解释多个运算符号,同时用来构建抽象语法树: - -```java -public abstract class SymbolNode implements Node { - protected Node left; - protected Node right; - - public SymbolNode(Node left, Node right) { - this.left = left; - this.right = right; - } -} -``` - -MulNode - -```java -public class MulNode extends SymbolNode { - public MulNode(Node left, Node right) { - super(left, right); - } - - @Override - public int interpret() { - return left.interpret() * right.interpret(); - } -} -``` -ModNode - -```java -package com.desgin.pattern.behavioral.interpreter; - -public class ModNode extends SymbolNode { - public ModNode(Node left, Node right) { - super(left, right); - } - - @Override - public int interpret() { - return super.left.interpret() % super.right.interpret(); - } -} -``` -DivNode - -```java -public class DivNode extends SymbolNode { - public DivNode(Node left, Node right) { - super(left, right); - } - - @Override - public int interpret() { - return super.left.interpret() / super.right.interpret(); - } -} -``` - -Calculator - -```java -import java.util.Stack; - -public class Calculator { - private String statement; - private Node node; - - public void build(String statement) { - Node left = null, right = null; - Stack stack = new Stack(); - - String[] statementArr = statement.split(" "); - - for (int i = 0; i < statementArr.length; i++) { - if (statementArr[i].equalsIgnoreCase("*")) { - left = (Node) stack.pop(); - int val = Integer.parseInt(statementArr[++i]); - right = new ValueNode(val); - stack.push(new MulNode(left, right)); - } else if (statementArr[i].equalsIgnoreCase("/")) { - left = (Node) stack.pop(); - int val = Integer.parseInt(statementArr[++i]); - right = new ValueNode(val); - stack.push(new DivNode(left, right)); - } else if (statementArr[i].equalsIgnoreCase("%")) { - left = (Node) stack.pop(); - int val = Integer.parseInt(statementArr[++i]); - right = new ValueNode(val); - stack.push(new ModNode(left, right)); - } else { - stack.push(new ValueNode(Integer.parseInt(statementArr[i]))); - } - } - this.node = (Node) stack.pop(); - } - - public int compute() { - return node.interpret(); - } -} -``` -客户端:Client -```java -public class Client { - public static void main(String args[]) { - String statement = "3 * 2 * 4 / 6 % 5"; - Calculator calculator = new Calculator(); - calculator.build(statement); - int result = calculator.compute(); - System.out.println(statement + " = " + result); - } -} -``` -测试结果: - -![测试结果](https://upload-images.jianshu.io/upload_images/5336514-669f35ee73f05c6e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -# 6. 优缺点 - -**优点:** -- 语法由很多类表示,容易改变及扩展此”语言” - -**缺点:** -- 当语法规则数目太多时,增加了系统复杂度 -执行效率比较低,可利用场景比较少。 - -# 7. 扩展-JDK1.7源码以及框架中的解释器模式 - -java.util.regex.Pattern正则解释器,相当于是一个语法。 - -![java.util.regex.Pattern正则解释器](https://upload-images.jianshu.io/upload_images/5336514-bab9d49f3707eda8.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -Spring中的解释器 -```java -package com.desgin.pattern.behavioral.interpreter.springel; - -import org.springframework.expression.Expression; -import org.springframework.expression.ExpressionParser; -import org.springframework.expression.spel.standard.SpelExpressionParser; - -/** - * Create by lastwhisper on 2019/2/10 - */ -public class SpringTest { - public static void main(String[] args) { - ExpressionParser parser = new SpelExpressionParser(); - Expression expression = parser.parseExpression("100 * 2 + 400 * 1 + 66"); - int value = (int) expression.getValue(); - System.out.println(value); - } -} -``` - -# 参考 -https://www.cnblogs.com/chenssy/p/3346427.html \ No newline at end of file diff --git "a/design-pattern/notes/\350\241\214\344\270\272\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\350\256\277\351\227\256\350\200\205\346\250\241\345\274\217\357\274\210\345\215\201\357\274\211.md" "b/design-pattern/notes/\350\241\214\344\270\272\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\350\256\277\351\227\256\350\200\205\346\250\241\345\274\217\357\274\210\345\215\201\357\274\211.md" deleted file mode 100644 index 86c66e67..00000000 --- "a/design-pattern/notes/\350\241\214\344\270\272\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\350\256\277\351\227\256\350\200\205\346\250\241\345\274\217\357\274\210\345\215\201\357\274\211.md" +++ /dev/null @@ -1,178 +0,0 @@ -> 该项目源码地址:[https://github.com/ggb2312/JavaNotes/tree/master/design-pattern](https://github.com/ggb2312/JavaNotes/tree/master/design-pattern)(设计模式相关代码与笔记) - -# 1. 定义 - -封装作用于某数据结构(如List/Set/Map等)中的各元素的操作(可以在不改变各元素的类的前提下,定义作用于这些元素的操作) - -# 2. 适用场景 - -- 一个数据结构如(List/Set/Map等)包含很多类型对象 -- 数据结构与数据操作分离 - -# 3. 类图以及角色 - -![访问者模式类图](https://upload-images.jianshu.io/upload_images/5336514-dd2ff06a6228df60.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -**Visitor**:接口或者抽象类,它定义了对每一个元素(Element)访问的行为,它的参数就是可以访问的元素,它的方法数理论上来讲与元素个数是一样的,因此,访问者模式要求元素的类族要稳定,如果经常添加、移除元素类,必然会导致频繁地修改Visitor接口,如果这样则不适合使用访问者模式。 -**ConcreteVisitorA、ConcreteVisitorB **:具体的访问类,它需要给出对每一个元素类访问时所产生的具体行为。 -**Element**:元素接口或者抽象类,它定义了一个接受访问者的方法(Accept),其意义是指每一个元素都要可以被访问者访问。 -**ConcreteElementA、ConcreteElementB**:具体的元素类,它提供接受访问方法的具体实现,而这个具体的实现,通常情况下是使用访问者提供的访问该元素类的方法。 -**ObjectStructure**:定义当中所说的对象结构,对象结构是一个抽象表述,它内部管理了元素集合,并且可以迭代这些元素供访问者访问。 - -# 3. 相关设计模式 - -**访问者模式和迭代器模式** - -- 相同点:都是在某种数据结构上面处理 -- 不同点:访问者模式用于对保存在数据结构的元素进行某种特定的处理,迭代器模式重要用于逐个遍历在数据结构中的元素。 - -# 4. 模式实例 - -**背景**:不同的访问者(普通用户、老板)查看不同的课程(免费课程、收费课程),可以看到不同的结果。 - -**(1)Visitor 访问者接口** - -```java -/** - * Create by eval on 2019/2/11 - */ -public interface IVisitor { - void visit(FreeCourse freeCourse); - - void visit(CodingCourse codingCourse); -} -``` - -**(2)ConcreteVisitor 访问者实现类** -```java -/** - * Create by eval on 2019/2/11 - */ -public class Visitor implements IVisitor { - /** - * 访问免费课程,打印所有免费课程名称 - * - * @param freeCourse - */ - @Override - public void visit(FreeCourse freeCourse) { - System.out.println("免费课程:" + freeCourse.getName()); - } - - /** - * 访问实战课程,打印所有实战课程名称以及价格 - * - * @param codingCourse - */ - @Override - public void visit(CodingCourse codingCourse) { - System.out.println("实战课程:" + codingCourse.getName() + " 价格:" + codingCourse.getPrice()+ "元"); - } -} -``` - -**(3)Element 课程接口** -```java -/** - * Create by eval on 2019/2/11 - */ -public abstract class Course { - private String name; - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public abstract void accept(IVisitor visitor); -} -``` - -**(4)ConcreteElement 课程实现类** - -```java -/** - * Create by eval on 2019/2/11 - */ -public class CodingCourse extends Course { - private int price; - - public int getPrice() { - return price; - } - - public void setPrice(int price) { - this.price = price; - } - - @Override - public void accept(IVisitor visitor) { - visitor.visit(this); - } -} -``` -```java -/** - * Create by eval on 2019/2/11 - */ -public class FreeCourse extends Course { - @Override - public void accept(IVisitor visitor) { - visitor.visit(this); - } -} -``` - -**(5)测试** - -```java -import java.util.ArrayList; -import java.util.List; - -/** - * Create by eval on 2019/2/11 - */ -public class Test { - public static void main(String[] args) { - List courseList = new ArrayList<>(); - - FreeCourse freeCourse = new FreeCourse(); - freeCourse.setName("SpringMVC数据绑定"); - - CodingCourse codingCourse = new CodingCourse(); - codingCourse.setName("Java设计模式"); - codingCourse.setPrice(299); - - courseList.add(freeCourse); - courseList.add(codingCourse); - - for (Course course : courseList) { - course.accept(new Visitor()); - } - } -} -``` -测试结果: - -![测试结果](https://upload-images.jianshu.io/upload_images/5336514-60b5bae0762ca54e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -# 5. 优缺点 -**优点:** -- 增加新的操作很容易,即增加一个新的访问者 - -**缺点:** -- 增加新的数据结构困难 -- 具体元素变更比较麻烦 - -# 6. 扩展-JDK1.7源码以及框架中的访问者模式 - -java.nio.file.FileVisitor以及实现类SimpleFileVisitor - -org.springframework.beans.factory.config.BeanDefinitionVisitor可以遍历Bean的各种属性,委托valueResolver来实现 - -# 参考 - -https://www.cnblogs.com/chenssy/p/3339756.html \ No newline at end of file diff --git "a/design-pattern/notes/\350\241\214\344\270\272\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\350\264\243\344\273\273\351\223\276\346\250\241\345\274\217\357\274\210\344\271\235\357\274\211.md" "b/design-pattern/notes/\350\241\214\344\270\272\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\350\264\243\344\273\273\351\223\276\346\250\241\345\274\217\357\274\210\344\271\235\357\274\211.md" deleted file mode 100644 index 8e724baa..00000000 --- "a/design-pattern/notes/\350\241\214\344\270\272\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\350\264\243\344\273\273\351\223\276\346\250\241\345\274\217\357\274\210\344\271\235\357\274\211.md" +++ /dev/null @@ -1,160 +0,0 @@ -> 该项目源码地址:[https://github.com/ggb2312/JavaNotes/tree/master/design-pattern](https://github.com/ggb2312/JavaNotes/tree/master/design-pattern)(设计模式相关代码与笔记) - -# 1. 定义 - -为请求创建一个接收此次请求对象的链 - -# 2. 适用场景 - -- 一个请求的处理需要多个对象当中的一个或几个协作处理 - -应用例子:struts的拦截器、servlet的过滤器、Dubbo中的Filter、Mybatis中的Plugin - -# 3. 相关设计模式 - -**责任链模式和状态模式** -- 责任链模式中各个对象并不指定下一个处理对象是谁,由客户端设定责任链中的顺序以及元素,直到被某个责任链处理,或者整个责任链结束。 -- 状态模式是让各个对象知道下一个处理的对象是谁。 - -# 4. 模式实例 - -**背景**:慕课网的线上的课程在发布的时候,要经过两个人个批准,一个手记的检查人,另外一个是视频的检查人,我们在oa系统里面也会遇到这种情况,一级一级的进行审批。这个就是一个链条。 - -**(1)课程类** - -```java -public class Course { - private String name; - private String article; - private String video; - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getArticle() { - return article; - } - - public void setArticle(String article) { - this.article = article; - } - - public String getVideo() { - return video; - } - - public void setVideo(String video) { - this.video = video; - } - - @Override - public String toString() { - return "Course{" + - "name='" + name + '\'' + - ", article='" + article + '\'' + - ", video='" + video + '\'' + - '}'; - } -} -``` -**(2)批准者抽象类** - -```java -/** - * 批准者 - */ -public abstract class Approver { - /** 责任链的核心就是在类里面包含了一个自己同样类型的一个对象 */ - protected Approver approver; - - public void setNextApprover(Approver approver) { - this.approver = approver; - } - - public abstract void deploy(Course course) ; -} -``` - -**(3)手记的批准者** - -```java -public class ArticleApprover extends Approver{ - - @Override - public void deploy(Course course) { - if (StringUtils.isNoneEmpty(course.getArticle())) { - System.out.println(course.getName() + "含有手记,批准"); - if (approver != null) { - approver.deploy(course); - } - } else { - System.out.println(course.getName() + "不含有手记,不批准,流程结束"); - return; - } - } -} -``` - -**(4)视频的批准者** - -```java -public class VideoApprover extends Approver { - @Override - public void deploy(Course course) { - if (StringUtils.isNoneEmpty(course.getVideo())) { - System.out.println(course.getName() + "含有视频,批准"); - if (approver != null) { - approver.deploy(course); - } - } else { - System.out.println(course.getName() + "不含有视频,不批准,流程结束"); - return; - } - } -} -``` - -**(5)测试** - -```java -public class Test { - public static void main(String[] args) { - Approver articleApprover = new ArticleApprover(); - Approver videoApprover = new VideoApprover(); - - Course course = new Course(); - course.setName("Java设计模式精讲"); - course.setArticle("Java设计模式精讲的手记"); - course.setVideo("Java设计模式精讲的视频"); - /** 先通过手记的审核才交给视频的审核,视频的审核过了才能进行发布上线 */ - articleApprover.setNextApprover(videoApprover); - articleApprover.deploy(course); - } -} -``` -测试结果: - -![测试结果](https://upload-images.jianshu.io/upload_images/5336514-8dad140203216d3b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -# 5. 优缺点 - -**优点:** - -- 请求的发送者和接收者(请求的处理)解耦 -- 责任链可以动态组合 - -**缺点:** - -- 责任链太长或者处理时间过长,影响性能 -- 责任链有可能过多 - -# 6. 扩展-JDK1.7源码以及框架中的责任链模式 - -javax.servlet.Filter的doFilter、FilterChain - -SpringSecurity \ No newline at end of file diff --git "a/design-pattern/notes/\350\241\214\344\270\272\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\350\277\255\344\273\243\345\231\250\346\250\241\345\274\217\357\274\210\344\272\214\357\274\211.md" "b/design-pattern/notes/\350\241\214\344\270\272\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\350\277\255\344\273\243\345\231\250\346\250\241\345\274\217\357\274\210\344\272\214\357\274\211.md" deleted file mode 100644 index 996df8dc..00000000 --- "a/design-pattern/notes/\350\241\214\344\270\272\345\236\213\346\250\241\345\274\217\342\200\224\342\200\224\350\277\255\344\273\243\345\231\250\346\250\241\345\274\217\357\274\210\344\272\214\357\274\211.md" +++ /dev/null @@ -1,200 +0,0 @@ -> 该项目源码地址:[https://github.com/ggb2312/JavaNotes/tree/master/design-pattern](https://github.com/ggb2312/JavaNotes/tree/master/design-pattern)(设计模式相关代码与笔记) - -# 1. 定义 - -提供一种方法,顺序访问一个集合对象中的各个元素,而又不暴露该对象的内部表示 - -# 2. 适用场景 - -- 访问一个集合对象的内容而无需暴露它的内部表示 -- 为遍历不同的集合结构提供一个统一的接口 - -# 3. 类图与角色 - -![image.png](https://upload-images.jianshu.io/upload_images/5336514-bece139aa0f378a0.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -- **迭代器角色(Iterator):**定义遍历元素所需要的方法,一般来说会有这么三个方法:取得下一个元素的方法next(),判断是否遍历结束的方法hasNext()),移出当前对象的方法remove() - -- **具体迭代器角色(ConcreteIterator):**实现迭代器接口中定义的方法,完成集合的迭代 - -- **容器角色(Aggregate):**一般是一个接口,提供一个iterator()方法,例如java中的Collection接口,List接口,Set接口等 - -- **具体容器角色(ConcreteAggregate):**就是抽象容器的具体实现类,比如List接口的有序列表实现ArrayList,List接口的链表实现LinkList,Set接口的哈希列表的实现HashSet等 - -# 4.相关设计模式 - -**迭代器模式和访问者模式** - -- 相同:两者都是迭代的访问一个集合对象 -- 不同:访问者模式扩展开放的部分,在作用于对象的操作上。迭代器模式扩展开放的部分,是在集合的种类上。 - -# 5.模式实例 - -有一个课程类: - -```java -public class Course { - private String name; - - public Course(String name) { - this.name = name; - } - - public String getName() { - return name; - } - -} - -``` - -还有一个CourseAggregate接口,对课程进行处理: - -```java -public interface CourseAggregate { - - void addCourse(Course course); - void removeCourse(Course course); - /**获取迭代器 */ - CourseIterator getCourseIterator(); -} -``` - -这个就是处理接口的实现类: - -```java -public class CourseAggregateImpl implements CourseAggregate { - - private List courseList; - - public CourseAggregateImpl() { - this.courseList = new ArrayList(); - } - - @Override - public void addCourse(Course course) { - courseList.add(course); - } - - @Override - public void removeCourse(Course course) { - courseList.remove(course); - } - - @Override - public CourseIterator getCourseIterator() { - return new CourseIteratorImpl(courseList); - } -} -``` -这个就是迭代器接口: - -```java -public interface CourseIterator { - Course nextCourse(); - boolean isLastCourse(); - -} -``` - -而这个就是迭代器接口的实现类: - -```java -public class CourseIteratorImpl implements CourseIterator { - - private List courseList; - private int position; - private Course course; - public CourseIteratorImpl(List courseList){ - this.courseList=courseList; - } - - @Override - public Course nextCourse() { - System.out.println("返回课程,位置是: "+position); - course=(Course)courseList.get(position); - position++; - return course; - } - - @Override - public boolean isLastCourse(){ - if(position< courseList.size()){ - return false; - } - return true; - } -} -``` - -测试方法: - -```java -public class Test { - - public static void main(String[] args) { - Course course1 = new Course("Java电商一期"); - Course course2 = new Course("Java电商二期"); - Course course3 = new Course("Java设计模式精讲"); - Course course4 = new Course("Python课程"); - Course course5 = new Course("算法课程"); - Course course6 = new Course("前端课程"); - - CourseAggregate courseAggregate = new CourseAggregateImpl(); - - courseAggregate.addCourse(course1); - courseAggregate.addCourse(course2); - courseAggregate.addCourse(course3); - courseAggregate.addCourse(course4); - courseAggregate.addCourse(course5); - courseAggregate.addCourse(course6); - - System.out.println("-----课程列表-----"); - printCourses(courseAggregate); - - courseAggregate.removeCourse(course4); - courseAggregate.removeCourse(course5); - - System.out.println("-----删除操作之后的课程列表-----"); - printCourses(courseAggregate); - } - - public static void printCourses(CourseAggregate courseAggregate){ - CourseIterator courseIterator= courseAggregate.getCourseIterator(); - while(!courseIterator.isLastCourse()){ - Course course=courseIterator.nextCourse(); - System.out.println(course.getName()); - } - } -} -``` - -测试结果: - -![测试结果](https://upload-images.jianshu.io/upload_images/5336514-381f8d65a5d7db1f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -此时类图: - -![类图](https://upload-images.jianshu.io/upload_images/5336514-787316c2e880e7e1.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -# 6. 优缺点 - -**优点:** - -- 分离了集合对象的遍历行为 - -**缺点:** - -- 类的个数成对增加 - - -# 7. **扩展-JDK1.7源码以及框架中的迭代器模式** - -## 7.1 JDK - -java.util.Iterator -java.util.ArrayList中的Itr - -## 7.2 Mybatis - -org.apache.ibatis.cursor.defaults.DefaultCursor的cursorIterator \ No newline at end of file diff --git a/design-pattern/pom.xml b/design-pattern/pom.xml deleted file mode 100644 index f66a0a09..00000000 --- a/design-pattern/pom.xml +++ /dev/null @@ -1,304 +0,0 @@ - - - 4.0.0 - - com.design - design-pattern - 1.0-SNAPSHOT - - - UTF-8 - UTF-8 - UTF-8 - - 4.0.3.RELEASE - 3.4.1 - 1.3.0 - - - - - org.apache.tomcat - tomcat-servlet-api - 7.0.64 - - - - com.sun.faces - jsf-api - 1.2 - - - - org.springframework - spring-webmvc - ${org.springframework.version} - - - - org.springframework - spring-oxm - ${org.springframework.version} - - - - org.springframework - spring-jdbc - ${org.springframework.version} - - - - org.springframework - spring-tx - ${org.springframework.version} - - - - org.springframework - spring-test - ${org.springframework.version} - - - - org.springframework.webflow - spring-webflow - 2.4.5.RELEASE - - - - org.aspectj - aspectjweaver - 1.7.3 - - - - org.mybatis - mybatis-spring - ${org.mybatis.spring.version} - - - org.mybatis - mybatis - ${org.mybatis.version} - - - - org.aspectj - aspectjrt - 1.6.11 - - - - org.codehaus.jackson - jackson-mapper-asl - 1.9.12 - - - - commons-dbcp - commons-dbcp - 1.4 - - - - - - ch.qos.logback - logback-classic - 1.1.2 - compile - - - ch.qos.logback - logback-core - 1.1.2 - compile - - - - mysql - mysql-connector-java - 5.1.6 - - - - com.google.guava - guava - 20.0 - - - - - org.apache.commons - commons-lang3 - 3.5 - - - - - commons-collections - commons-collections - 3.2.1 - - - - - junit - junit - 4.12 - - - - - joda-time - joda-time - 2.3 - - - - - - org.hashids - hashids - 1.0.1 - - - - - - commons-net - commons-net - 3.1 - - - - - - - commons-fileupload - commons-fileupload - 1.3.3 - - - - commons-io - commons-io - 2.0.1 - - - - - - - com.github.pagehelper - pagehelper - 4.1.0 - - - - com.github.miemiedev - mybatis-paginator - 1.2.17 - - - - com.github.jsqlparser - jsqlparser - 0.9.4 - - - - - org.springframework.data - spring-data-jpa - 2.0.14.RELEASE - - - - - - commons-codec - commons-codec - 1.10 - - - commons-configuration - commons-configuration - 1.10 - - - commons-lang - commons-lang - 2.6 - - - commons-logging - commons-logging - 1.1.1 - - - com.google.zxing - core - 2.1 - - - com.google.code.gson - gson - 2.3.1 - - - org.hamcrest - hamcrest-core - 1.3 - - - - - - redis.clients - jedis - 2.6.0 - - - - org.projectlombok - lombok - 1.16.18 - - - - - org.springframework.session - spring-session-data-redis - 1.2.0.RELEASE - - - - org.redisson - redisson - 2.9.0 - - - com.fasterxml.jackson.dataformat - jackson-dataformat-avro - 2.9.0 - - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.6.1 - - 1.7 - 1.7 - - - - - \ No newline at end of file diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/Approver.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/Approver.java deleted file mode 100644 index 7a17b5bf..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/Approver.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.desgin.pattern.behavioral.chainofresponsibility; - -/** - * 批准者 - */ -public abstract class Approver { - /** 责任链的核心就是在类里面包含了一个自己同样类型的一个对象 */ - protected Approver approver; - - public void setNextApprover(Approver approver) { - this.approver = approver; - } - - public abstract void deploy(Course course) ; -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/ArticleApprover.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/ArticleApprover.java deleted file mode 100644 index 2a8d4359..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/ArticleApprover.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.desgin.pattern.behavioral.chainofresponsibility; - -import org.apache.commons.lang3.StringUtils; - -public class ArticleApprover extends Approver { - - @Override - public void deploy(Course course) { - if (StringUtils.isNoneEmpty(course.getArticle())) { - System.out.println(course.getName() + "含有手记,批准"); - //交给下一个责任链对象处理 - if (approver != null) { - approver.deploy(course); - } - } else { - System.out.println(course.getName() + "不含有手记,不批准,流程结束"); - return; - } - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/Course.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/Course.java deleted file mode 100644 index 702b314a..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/Course.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.desgin.pattern.behavioral.chainofresponsibility; - -public class Course { - private String name; - private String article; - private String video; - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getArticle() { - return article; - } - - public void setArticle(String article) { - this.article = article; - } - - public String getVideo() { - return video; - } - - public void setVideo(String video) { - this.video = video; - } - - @Override - public String toString() { - return "Course{" + - "name='" + name + '\'' + - ", article='" + article + '\'' + - ", video='" + video + '\'' + - '}'; - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/Test.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/Test.java deleted file mode 100644 index c232eec2..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/Test.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.desgin.pattern.behavioral.chainofresponsibility; - -public class Test { - public static void main(String[] args) { - Approver articleApprover = new ArticleApprover(); - Approver videoApprover = new VideoApprover(); - - Course course = new Course(); - course.setName("Java设计模式精讲"); - course.setArticle("Java设计模式精讲的手记"); - course.setVideo("Java设计模式精讲的视频"); - /** 先通过手记的审核才交给视频的审核,视频的审核过了才能进行发布上线 */ - articleApprover.setNextApprover(videoApprover); - articleApprover.deploy(course); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/VideoApprover.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/VideoApprover.java deleted file mode 100644 index 1cb9c4f6..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/VideoApprover.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.desgin.pattern.behavioral.chainofresponsibility; - -import org.apache.commons.lang3.StringUtils; - -public class VideoApprover extends Approver { - @Override - public void deploy(Course course) { - if (StringUtils.isNoneEmpty(course.getVideo())) { - System.out.println(course.getName() + "含有视频,批准"); - //交给下一个责任链对象处理 - if (approver != null) { - approver.deploy(course); - } - } else { - System.out.println(course.getName() + "不含有视频,不批准,流程结束"); - return; - } - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version1/Main.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version1/Main.java deleted file mode 100644 index caec89e0..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version1/Main.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.desgin.pattern.behavioral.chainofresponsibility.mashibing.version1; - -/** - * @author lastwhisper - */ -public class Main { - - public static void main(String[] args) { - String msg = "大家好,QAQ, ,敏感字眼,不学习!"; - MsgProcessor mp = new MsgProcessor(); - mp.setMsg(msg); - msg = mp.process(); - System.out.println(msg); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version1/MsgProcessor.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version1/MsgProcessor.java deleted file mode 100644 index e4d39d0b..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version1/MsgProcessor.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.desgin.pattern.behavioral.chainofresponsibility.mashibing.version1; - -/** - * @author lastwhisper - */ -public class MsgProcessor { - String msg; - - public String getMsg() { - return msg; - } - - public void setMsg(String msg) { - this.msg = msg; - } - - public String process() { - // process the html tag <> - String r = msg.replaceAll("<", "[") - .replaceAll(">", "]"); - // process the sensitive words - r= r.replaceAll("不学习", "好好学习") - .replaceAll("敏感字眼", ""); - - return r; - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version2/FaceFilter.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version2/FaceFilter.java deleted file mode 100644 index c8e2aa50..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version2/FaceFilter.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.desgin.pattern.behavioral.chainofresponsibility.mashibing.version2; - -/** - * @author lastwhisper - */ -public class FaceFilter implements Filter { - // process the face tag <> - @Override - public String doFilter(String str) { - String r = str.replaceAll("QAQ", "^V^"); - return r; - } - -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version2/Filter.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version2/Filter.java deleted file mode 100644 index 2cae1c0e..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version2/Filter.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.desgin.pattern.behavioral.chainofresponsibility.mashibing.version2; - -public interface Filter { - String doFilter(String str); -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version2/HTMLFilter.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version2/HTMLFilter.java deleted file mode 100644 index 86377771..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version2/HTMLFilter.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.desgin.pattern.behavioral.chainofresponsibility.mashibing.version2; - -/** - * @author lastwhisper - */ -public class HTMLFilter implements Filter { - // process the html tag <> - @Override - public String doFilter(String str) { - String r = str.replaceAll("<", "[") - .replaceAll(">", "]"); - return r; - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version2/Main.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version2/Main.java deleted file mode 100644 index 1898a170..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version2/Main.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.desgin.pattern.behavioral.chainofresponsibility.mashibing.version2; - -/** - * @author lastwhisper - */ -public class Main { - - public static void main(String[] args) { - String msg = "大家好,QAQ, ,敏感字眼,不学习!"; - MsgProcessor mp = new MsgProcessor(); - mp.setMsg(msg); - msg = mp.process(); - System.out.println(msg); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version2/MsgProcessor.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version2/MsgProcessor.java deleted file mode 100644 index ffce5536..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version2/MsgProcessor.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.desgin.pattern.behavioral.chainofresponsibility.mashibing.version2; - -/** - * @author lastwhisper - */ -public class MsgProcessor { - String msg; - - Filter[] filters = {new HTMLFilter(), new SesitiveFilter(), new FaceFilter()}; - - public String getMsg() { - return msg; - } - - public void setMsg(String msg) { - this.msg = msg; - } - - public String process() { - String r = msg; - for (Filter filter : filters) { - r = filter.doFilter(r); - } - return r; - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version2/SesitiveFilter.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version2/SesitiveFilter.java deleted file mode 100644 index ed062f8a..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version2/SesitiveFilter.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.desgin.pattern.behavioral.chainofresponsibility.mashibing.version2; - -/** - * @author lastwhisper - */ -public class SesitiveFilter implements Filter { - // process the sensitive words - @Override - public String doFilter(String str) { - String r = str.replaceAll("不学习", "好好学习") - .replaceAll("敏感字眼", ""); - return r; - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version3/FaceFilter.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version3/FaceFilter.java deleted file mode 100644 index e9bff6b8..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version3/FaceFilter.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.desgin.pattern.behavioral.chainofresponsibility.mashibing.version3; - -/** - * @author lastwhisper - */ -public class FaceFilter implements Filter { - // process the face tag <> - @Override - public String doFilter(String str) { - String r = str.replaceAll("QAQ", "^V^"); - return r; - } - -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version3/Filter.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version3/Filter.java deleted file mode 100644 index f0d49a82..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version3/Filter.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.desgin.pattern.behavioral.chainofresponsibility.mashibing.version3; - -public interface Filter { - String doFilter(String str); -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version3/FilterChain.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version3/FilterChain.java deleted file mode 100644 index 55cac184..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version3/FilterChain.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.desgin.pattern.behavioral.chainofresponsibility.mashibing.version3; - -import java.util.ArrayList; -import java.util.List; - -/** - * @author lastwhisper - */ -public class FilterChain implements Filter{ - - List filters = new ArrayList(); - - public FilterChain addFilter(Filter f) { - filters.add(f); - return this; - } - - public String doFilter(String str) { - String r = str; - for (Filter filter : filters) { - r = filter.doFilter(r); - } - return r; - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version3/HTMLFilter.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version3/HTMLFilter.java deleted file mode 100644 index 9cde94ff..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version3/HTMLFilter.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.desgin.pattern.behavioral.chainofresponsibility.mashibing.version3; - -/** - * @author lastwhisper - */ -public class HTMLFilter implements Filter { - // process the html tag <> - @Override - public String doFilter(String str) { - String r = str.replaceAll("<", "[") - .replaceAll(">", "]"); - return r; - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version3/Main.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version3/Main.java deleted file mode 100644 index 7384099b..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version3/Main.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.desgin.pattern.behavioral.chainofresponsibility.mashibing.version3; - - -/** - * @author lastwhisper - */ -public class Main { - - public static void main(String[] args) { - String msg = "大家好,QAQ, ,敏感字眼,不学习!"; - FilterChain filterChain = new FilterChain(); - filterChain.addFilter(new HTMLFilter()) - .addFilter(new SesitiveFilter()); - - FilterChain filterChain2 = new FilterChain(); - filterChain2.addFilter(new FaceFilter()); - - filterChain.addFilter(filterChain2); - - msg = filterChain.doFilter(msg); - System.out.println(msg); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version3/SesitiveFilter.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version3/SesitiveFilter.java deleted file mode 100644 index bbd9a142..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version3/SesitiveFilter.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.desgin.pattern.behavioral.chainofresponsibility.mashibing.version3; - -/** - * @author lastwhisper - */ -public class SesitiveFilter implements Filter { - // process the sensitive words - @Override - public String doFilter(String str) { - String r = str.replaceAll("不学习", "好好学习") - .replaceAll("敏感字眼", ""); - return r; - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version4/FaceFilter.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version4/FaceFilter.java deleted file mode 100644 index bc679660..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version4/FaceFilter.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.desgin.pattern.behavioral.chainofresponsibility.mashibing.version4; - -/** - * @author lastwhisper - */ -public class FaceFilter implements Filter { - - @Override - public void doFilter(Request request, Response response, FilterChain chain) { - // 处理request请求 - request.requestStr = request.requestStr.replaceAll("QAQ", "^V^") - + "---FaceFilter.request()"; - - // 处理response响应 - response.responseStr = response.responseStr.replaceAll("QAQ", "^V^") - + "---FaceFilter.response()"; - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version4/Filter.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version4/Filter.java deleted file mode 100644 index dcb57342..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version4/Filter.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.desgin.pattern.behavioral.chainofresponsibility.mashibing.version4; - -public interface Filter { - void doFilter(Request request,Response response,FilterChain chain); -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version4/FilterChain.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version4/FilterChain.java deleted file mode 100644 index ba0eb736..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version4/FilterChain.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.desgin.pattern.behavioral.chainofresponsibility.mashibing.version4; - -import java.util.ArrayList; -import java.util.List; - -/** - * @author lastwhisper - */ -public class FilterChain implements Filter { - - List filters = new ArrayList(); - - int index = 0; - - public FilterChain addFilter(Filter f) { - filters.add(f); - return this; - } - - @Override - public void doFilter(Request request, Response response, FilterChain chain) { - if (index == filters.size()) return; - Filter filter = filters.get(index); - index++; - filter.doFilter(request, response, chain); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version4/HTMLFilter.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version4/HTMLFilter.java deleted file mode 100644 index ea614cd7..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version4/HTMLFilter.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.desgin.pattern.behavioral.chainofresponsibility.mashibing.version4; - -/** - * @author lastwhisper - */ -public class HTMLFilter implements Filter { - - @Override - public void doFilter(Request request, Response response, FilterChain chain) { - // 处理request请求 - request.requestStr = request.requestStr.replaceAll("<", "[") - .replaceAll(">", "]") + "---HTMLFilter.request()"; - - chain.doFilter(request, response, chain); - - // 处理response响应 - response.responseStr = response.responseStr.replaceAll("<", "[") - .replaceAll(">", "]") + "---HTMLFilter.response()"; - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version4/Main.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version4/Main.java deleted file mode 100644 index b2b7a924..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version4/Main.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.desgin.pattern.behavioral.chainofresponsibility.mashibing.version4; - - -/** - * @author lastwhisper - */ -public class Main { - - public static void main(String[] args) { - // 初始化数据 - String msg = "大家好,QAQ, ,敏感字眼,不学习!"; - Request request = new Request(); - request.setRequestStr(msg); - Response response = new Response(); - response.setResponseStr(msg); - // 过滤链1 - FilterChain filterChain = new FilterChain(); - filterChain.addFilter(new HTMLFilter()) - .addFilter(new SesitiveFilter()); - // 过滤链2 - FilterChain filterChain2 = new FilterChain(); - filterChain2.addFilter(new FaceFilter()); - // 过滤链1+过滤链2 - filterChain.addFilter(filterChain2); - // 处理 - filterChain.doFilter(request, response, filterChain); - - System.out.println(request.getRequestStr()); - System.out.println(response.getResponseStr()); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version4/Request.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version4/Request.java deleted file mode 100644 index 9dc62243..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version4/Request.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.desgin.pattern.behavioral.chainofresponsibility.mashibing.version4; - -/** - * @author lastwhisper - */ -public class Request { - String requestStr; - - public String getRequestStr() { - return requestStr; - } - - public void setRequestStr(String requestStr) { - this.requestStr = requestStr; - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version4/Response.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version4/Response.java deleted file mode 100644 index b145d239..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version4/Response.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.desgin.pattern.behavioral.chainofresponsibility.mashibing.version4; - -/** - * @author lastwhisper - */ -public class Response { - String responseStr; - - public String getResponseStr() { - return responseStr; - } - - public void setResponseStr(String responseStr) { - this.responseStr = responseStr; - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version4/SesitiveFilter.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version4/SesitiveFilter.java deleted file mode 100644 index 1d2bcd0a..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version4/SesitiveFilter.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.desgin.pattern.behavioral.chainofresponsibility.mashibing.version4; - -/** - * @author lastwhisper - */ -public class SesitiveFilter implements Filter { - - @Override - public void doFilter(Request request, Response response, FilterChain chain) { - // 处理request请求 - request.requestStr = request.requestStr.replaceAll("不学习", "好好学习") - .replaceAll("敏感字眼", "") + "---SesitiveFilter.request()"; - // 处理response响应 - response.responseStr = response.responseStr.replaceAll("不学习", "好好学习") - .replaceAll("敏感字眼", "") + "---SesitiveFilter.response()"; - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/command/CloseCourseVideoCommand.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/command/CloseCourseVideoCommand.java deleted file mode 100644 index f214cedb..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/command/CloseCourseVideoCommand.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.desgin.pattern.behavioral.command; - -/** - * 具体命令类 - * @author lastwhisper - */ -public class CloseCourseVideoCommand implements Command { - - private CourseVideo courseVideo; - - public CloseCourseVideoCommand(CourseVideo courseVideo) { - this.courseVideo = courseVideo; - } - - @Override - public void execute() { - courseVideo.close(); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/command/Command.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/command/Command.java deleted file mode 100644 index 00306cfd..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/command/Command.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.desgin.pattern.behavioral.command; - -/** - * 抽象命令类:抽象的命令,可以根据不同类型的命令写出不同的实现 - */ -public interface Command { - void execute(); -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/command/CourseVideo.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/command/CourseVideo.java deleted file mode 100644 index a35cd2e2..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/command/CourseVideo.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.desgin.pattern.behavioral.command; - -/** - * 接收者:真正执行命令的对象 - */ -public class CourseVideo { - private String name; - - public CourseVideo(String name) { - this.name = name; - } - - public void open() { - System.out.println(this.name + "课程开放"); - } - - public void close() { - System.out.println(this.name + "课程关闭"); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/command/OpenCourseVideoCommand.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/command/OpenCourseVideoCommand.java deleted file mode 100644 index 0995a0db..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/command/OpenCourseVideoCommand.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.desgin.pattern.behavioral.command; - -/** - * 具体命令类 - */ -public class OpenCourseVideoCommand implements Command { - private CourseVideo courseVideo; - - public OpenCourseVideoCommand(CourseVideo courseVideo) { - this.courseVideo = courseVideo; - } - - @Override - public void execute() { - courseVideo.open(); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/command/Staff.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/command/Staff.java deleted file mode 100644 index 290edc02..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/command/Staff.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.desgin.pattern.behavioral.command; - -import java.util.ArrayList; -import java.util.List; - -/** - * 命令的发起者 - */ -public class Staff { - /** - * 持有真正执行命令对象的引用 - */ - private List commandList = new ArrayList<>(); - - public void addCommand(Command command) { - commandList.add(command); - } - - public void executeCommands() { - for (Command command : commandList) { - //请求者调用命令对象执行命令的那个execute方法 - command.execute(); - } - commandList.clear(); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/command/Test.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/command/Test.java deleted file mode 100644 index aacb69d4..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/command/Test.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.desgin.pattern.behavioral.command; - -public class Test { - public static void main(String[] args) { - //通过请求者(Staff)调用命令对象(command),命令对象中调用了命令具体执行者(CourseVideo) - CourseVideo courseVideo = new CourseVideo("Java设计模式"); - OpenCourseVideoCommand openCourseVideoCommand = new OpenCourseVideoCommand(courseVideo); - CloseCourseVideoCommand closeCourseVideoCommand = new CloseCourseVideoCommand(courseVideo); - - Staff staff = new Staff(); - staff.addCommand(openCourseVideoCommand); - staff.addCommand(closeCourseVideoCommand); - staff.executeCommands(); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/interpreter/Calculator.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/interpreter/Calculator.java deleted file mode 100644 index 24a418b4..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/interpreter/Calculator.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.desgin.pattern.behavioral.interpreter; - -import java.util.Stack; - -public class Calculator { - private String statement; - private Node node; - - public void build(String statement) { - Node left = null, right = null; - Stack stack = new Stack(); - - String[] statementArr = statement.split(" "); - - for (int i = 0; i < statementArr.length; i++) { - if (statementArr[i].equalsIgnoreCase("*")) { - left = (Node) stack.pop(); - int val = Integer.parseInt(statementArr[++i]); - right = new ValueNode(val); - stack.push(new MulNode(left, right)); - } else if (statementArr[i].equalsIgnoreCase("/")) { - left = (Node) stack.pop(); - int val = Integer.parseInt(statementArr[++i]); - right = new ValueNode(val); - stack.push(new DivNode(left, right)); - } else if (statementArr[i].equalsIgnoreCase("%")) { - left = (Node) stack.pop(); - int val = Integer.parseInt(statementArr[++i]); - right = new ValueNode(val); - stack.push(new ModNode(left, right)); - } else { - stack.push(new ValueNode(Integer.parseInt(statementArr[i]))); - } - } - this.node = (Node) stack.pop(); - } - - public int compute() { - return node.interpret(); - } -} \ No newline at end of file diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/interpreter/Client.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/interpreter/Client.java deleted file mode 100644 index b5d97177..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/interpreter/Client.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.desgin.pattern.behavioral.interpreter; - -public class Client { - public static void main(String args[]) { - String statement = "3 * 2 * 4 / 6 % 5"; - Calculator calculator = new Calculator(); - calculator.build(statement); - int result = calculator.compute(); - System.out.println(statement + " = " + result); - } -} \ No newline at end of file diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/interpreter/DivNode.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/interpreter/DivNode.java deleted file mode 100644 index 3b8e9ad8..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/interpreter/DivNode.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.desgin.pattern.behavioral.interpreter; - -public class DivNode extends SymbolNode { - public DivNode(Node left, Node right) { - super(left, right); - } - - @Override - public int interpret() { - return super.left.interpret() / super.right.interpret(); - } -} \ No newline at end of file diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/interpreter/ModNode.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/interpreter/ModNode.java deleted file mode 100644 index 57f13e8f..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/interpreter/ModNode.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.desgin.pattern.behavioral.interpreter; - -public class ModNode extends SymbolNode { - public ModNode(Node left, Node right) { - super(left, right); - } - - @Override - public int interpret() { - return super.left.interpret() % super.right.interpret(); - } -} \ No newline at end of file diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/interpreter/MulNode.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/interpreter/MulNode.java deleted file mode 100644 index 03b5bd76..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/interpreter/MulNode.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.desgin.pattern.behavioral.interpreter; - -public class MulNode extends SymbolNode { - public MulNode(Node left, Node right) { - super(left, right); - } - - @Override - public int interpret() { - return left.interpret() * right.interpret(); - } -} \ No newline at end of file diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/interpreter/Node.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/interpreter/Node.java deleted file mode 100644 index 8ff039fb..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/interpreter/Node.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.desgin.pattern.behavioral.interpreter; - -public interface Node { - public int interpret(); -} \ No newline at end of file diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/interpreter/SymbolNode.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/interpreter/SymbolNode.java deleted file mode 100644 index e3585d05..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/interpreter/SymbolNode.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.desgin.pattern.behavioral.interpreter; - -public abstract class SymbolNode implements Node { - protected Node left; - protected Node right; - - public SymbolNode(Node left, Node right) { - this.left = left; - this.right = right; - } -} \ No newline at end of file diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/interpreter/ValueNode.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/interpreter/ValueNode.java deleted file mode 100644 index 93af91ee..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/interpreter/ValueNode.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.desgin.pattern.behavioral.interpreter; - -public class ValueNode implements Node -{ - private int value; - - public ValueNode(int value) - { - this.value=value; - } - - @Override - public int interpret() - { - return this.value; - } -} \ No newline at end of file diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/interpreter/springel/SpringTest.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/interpreter/springel/SpringTest.java deleted file mode 100644 index 3d58d34f..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/interpreter/springel/SpringTest.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.desgin.pattern.behavioral.interpreter.springel; - -import org.springframework.expression.Expression; -import org.springframework.expression.ExpressionParser; -import org.springframework.expression.spel.standard.SpelExpressionParser; - -/** - * Create by lastwhisper on 2019/2/10 - */ -public class SpringTest { - public static void main(String[] args) { - ExpressionParser parser = new SpelExpressionParser(); - Expression expression = parser.parseExpression("100 * 2 + 400 * 1 + 66"); - int value = (int) expression.getValue(); - System.out.println(value); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/iterator/Course.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/iterator/Course.java deleted file mode 100644 index 5ff324f8..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/iterator/Course.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.desgin.pattern.behavioral.iterator; - -public class Course { - private String name; - - public Course(String name) { - this.name = name; - } - - public String getName() { - return name; - } - -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/iterator/CourseAggregate.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/iterator/CourseAggregate.java deleted file mode 100644 index ff0bfe09..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/iterator/CourseAggregate.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.desgin.pattern.behavioral.iterator; - -public interface CourseAggregate { - - void addCourse(Course course); - void removeCourse(Course course); - /**获取迭代器 */ - CourseIterator getCourseIterator(); -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/iterator/CourseAggregateImpl.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/iterator/CourseAggregateImpl.java deleted file mode 100644 index 2b7c0e34..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/iterator/CourseAggregateImpl.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.desgin.pattern.behavioral.iterator; - -import java.util.ArrayList; -import java.util.List; - -public class CourseAggregateImpl implements CourseAggregate { - - private List courseList; - - public CourseAggregateImpl() { - this.courseList = new ArrayList(); - } - - @Override - public void addCourse(Course course) { - courseList.add(course); - } - - @Override - public void removeCourse(Course course) { - courseList.remove(course); - } - - @Override - public CourseIterator getCourseIterator() { - return new CourseIteratorImpl(courseList); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/iterator/CourseIterator.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/iterator/CourseIterator.java deleted file mode 100644 index 5995fd8e..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/iterator/CourseIterator.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.desgin.pattern.behavioral.iterator; - -public interface CourseIterator { - Course nextCourse(); - - boolean isLastCourse(); -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/iterator/CourseIteratorImpl.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/iterator/CourseIteratorImpl.java deleted file mode 100644 index 0c6223ca..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/iterator/CourseIteratorImpl.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.desgin.pattern.behavioral.iterator; - -import java.util.List; - -public class CourseIteratorImpl implements CourseIterator { - - private List courseList; - private int position; - private Course course; - - public CourseIteratorImpl(List courseList) { - this.courseList = courseList; - } - - @Override - public Course nextCourse() { - System.out.println("返回课程,位置是: " + position); - course = (Course) courseList.get(position); - position++; - return course; - } - - @Override - public boolean isLastCourse() { - if (position < courseList.size()) { - return false; - } - return true; - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/iterator/Test.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/iterator/Test.java deleted file mode 100644 index a008b7da..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/iterator/Test.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.desgin.pattern.behavioral.iterator; - -public class Test { - - - public static void main(String[] args) { - Course course1 = new Course("Java电商一期"); - Course course2 = new Course("Java电商二期"); - Course course3 = new Course("Java设计模式精讲"); - Course course4 = new Course("Python课程"); - Course course5 = new Course("算法课程"); - Course course6 = new Course("前端课程"); - - - CourseAggregate courseAggregate = new CourseAggregateImpl(); - - courseAggregate.addCourse(course1); - courseAggregate.addCourse(course2); - courseAggregate.addCourse(course3); - courseAggregate.addCourse(course4); - courseAggregate.addCourse(course5); - courseAggregate.addCourse(course6); - - System.out.println("-----课程列表-----"); - printCourses(courseAggregate); - - courseAggregate.removeCourse(course4); - courseAggregate.removeCourse(course5); - - System.out.println("-----删除操作之后的课程列表-----"); - printCourses(courseAggregate); - } - - - public static void printCourses(CourseAggregate courseAggregate){ - CourseIterator courseIterator= courseAggregate.getCourseIterator(); - while(!courseIterator.isLastCourse()){ - Course course=courseIterator.nextCourse(); - System.out.println(course.getName()); - } - } - - -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/mediator/StudyGroup.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/mediator/StudyGroup.java deleted file mode 100644 index 6d7174aa..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/mediator/StudyGroup.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.desgin.pattern.behavioral.mediator; - -import java.util.Date; - -public class StudyGroup { - public static void showMessage(User user, String message) { - System.out.println(new Date().toString()+"["+user.getName()+"]:"+message); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/mediator/Test.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/mediator/Test.java deleted file mode 100644 index a376d81f..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/mediator/Test.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.desgin.pattern.behavioral.mediator; - -public class Test { - public static void main(String[] args) { - User tom = new User("ldc"); - User jack = new User("ghl"); - - tom.sendMessage("hey!jack"); - jack.sendMessage("hey!tom"); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/mediator/User.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/mediator/User.java deleted file mode 100644 index f4a544db..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/mediator/User.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.desgin.pattern.behavioral.mediator; - -public class User { - private String name; - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public User(String name) { - this.name = name; - } - - public void sendMessage(String message) { - StudyGroup.showMessage(this,message); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/mediator/my/Client.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/mediator/my/Client.java deleted file mode 100644 index ae9bf84d..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/mediator/my/Client.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.desgin.pattern.behavioral.mediator.my; - -public class Client { - public static void main(String[] args) { - //一个房主、一个租房者、一个中介机构 - MediatorStructure mediator = new MediatorStructure(); - - //房主和租房者只需要知道中介机构即可 - HouseOwner houseOwner = new HouseOwner("张三", mediator); - Tenant tenant = new Tenant("李四", mediator); - - //中介结构要知道房主和租房者 - mediator.setHouseOwner(houseOwner); - mediator.setTenant(tenant); - - tenant.constact("听说你那里有三室的房主出租....."); - houseOwner.constact("是的!请问你需要租吗?"); - } -} \ No newline at end of file diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/mediator/my/HouseOwner.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/mediator/my/HouseOwner.java deleted file mode 100644 index 5d1cf963..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/mediator/my/HouseOwner.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.desgin.pattern.behavioral.mediator.my; - -public class HouseOwner extends Person { - - HouseOwner(String name, Mediator mediator) { - super(name, mediator); - } - - /** - * @param message - * @return void - * @desc 与中介者联系 - */ - public void constact(String message) { - mediator.constact(message, this); - } - - /** - * @param message - * @return void - * @desc 获取信息 - */ - public void getMessage(String message) { - System.out.println("房主:" + name + ",获得信息:" + message); - } -} \ No newline at end of file diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/mediator/my/Mediator.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/mediator/my/Mediator.java deleted file mode 100644 index c6e69cbe..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/mediator/my/Mediator.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.desgin.pattern.behavioral.mediator.my; - -public abstract class Mediator { - //申明一个联络方法 - public abstract void constact(String message, Person person); -} \ No newline at end of file diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/mediator/my/MediatorStructure.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/mediator/my/MediatorStructure.java deleted file mode 100644 index 8c0ddb87..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/mediator/my/MediatorStructure.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.desgin.pattern.behavioral.mediator.my; - -public class MediatorStructure extends Mediator { - /** - * 首先中介结构必须知道所有房主和租房者的信息 - */ - private HouseOwner houseOwner; - private Tenant tenant; - - public HouseOwner getHouseOwner() { - return houseOwner; - } - - public void setHouseOwner(HouseOwner houseOwner) { - this.houseOwner = houseOwner; - } - - public Tenant getTenant() { - return tenant; - } - - public void setTenant(Tenant tenant) { - this.tenant = tenant; - } - - @Override - public void constact(String message, Person person) { - //如果是房主,则租房者获得信息 - if (person == houseOwner) { - tenant.getMessage(message); - } else { //反正则是房主获得信息 - houseOwner.getMessage(message); - } - } -} \ No newline at end of file diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/mediator/my/Person.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/mediator/my/Person.java deleted file mode 100644 index 07239129..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/mediator/my/Person.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.desgin.pattern.behavioral.mediator.my; - -public abstract class Person { - protected String name; - protected Mediator mediator; - - Person(String name,Mediator mediator){ - this.name = name; - this.mediator = mediator; - } - -} \ No newline at end of file diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/mediator/my/Tenant.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/mediator/my/Tenant.java deleted file mode 100644 index e1ae710c..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/mediator/my/Tenant.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.desgin.pattern.behavioral.mediator.my; - -public class Tenant extends Person { - - Tenant(String name, Mediator mediator) { - super(name, mediator); - } - - /** - * @param message - * @return void - * @desc 与中介者联系 - */ - public void constact(String message) { - mediator.constact(message, this); - } - - /** - * @param message - * @return void - * @desc 获取信息 - */ - public void getMessage(String message) { - System.out.println("租房者:" + name + ",获得信息:" + message); - } -} \ No newline at end of file diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/memento/Article.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/memento/Article.java deleted file mode 100644 index d278cf4b..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/memento/Article.java +++ /dev/null @@ -1,68 +0,0 @@ -package com.desgin.pattern.behavioral.memento; - -/** - * Create by lastwhisper on 2019/2/11 - */ -public class Article { - private String title; - private String content; - private String imgs; - - public Article(String title, String content, String imgs) { - this.title = title; - this.content = content; - this.imgs = imgs; - } - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - public String getContent() { - return content; - } - - public void setContent(String content) { - this.content = content; - } - - public String getImgs() { - return imgs; - } - - public void setImgs(String imgs) { - this.imgs = imgs; - } - - /** - * 保存笔记 - * @return - */ - public ArticleMemento saveToMemento() { - ArticleMemento articleMemento = new ArticleMemento(this.title, this.content, this.imgs); - return articleMemento; - } - - /** - * 撤回 - * @param articleMemento - */ - public void undoFromMemento(ArticleMemento articleMemento) { - this.title = articleMemento.getTitle(); - this.content = articleMemento.getContent(); - this.imgs = articleMemento.getImgs(); - } - - @Override - public String toString() { - return "Article{" + - "title='" + title + '\'' + - ", content='" + content + '\'' + - ", imgs='" + imgs + '\'' + - '}'; - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/memento/ArticleMemento.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/memento/ArticleMemento.java deleted file mode 100644 index 69d3d5e1..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/memento/ArticleMemento.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.desgin.pattern.behavioral.memento; - -/** - * Create by lastwhisper on 2019/2/11 - */ -public class ArticleMemento { - private String title; - private String content; - private String imgs; - - public ArticleMemento(String title, String content, String imgs) { - this.title = title; - this.content = content; - this.imgs = imgs; - } - - public String getTitle() { - return title; - } - - public String getContent() { - return content; - } - - public String getImgs() { - return imgs; - } - - @Override - public String toString() { - return "ArticleMemento{" + - "title='" + title + '\'' + - ", content='" + content + '\'' + - ", imgs='" + imgs + '\'' + - '}'; - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/memento/ArticleMementoManager.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/memento/ArticleMementoManager.java deleted file mode 100644 index 7f636693..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/memento/ArticleMementoManager.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.desgin.pattern.behavioral.memento; - -import java.util.Stack; - -/** - * Create by lastwhisper on 2019/2/11 - */ -public class ArticleMementoManager { - private final Stack ARTICLE_MEMENTO_STACK = new Stack<>(); - - public ArticleMemento getMemento() { - ArticleMemento articleMemento = ARTICLE_MEMENTO_STACK.pop(); - return articleMemento; - } - - public void addMemento(ArticleMemento articleMemento) { - ARTICLE_MEMENTO_STACK.push(articleMemento); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/memento/Test.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/memento/Test.java deleted file mode 100644 index 6e8a6c83..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/memento/Test.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.desgin.pattern.behavioral.memento; - -/** - * Create by lastwhisper on 2019/2/11 - */ -public class Test { - public static void main(String[] args) { - ArticleMementoManager articleMementoManager = new ArticleMementoManager(); - Article article = new Article("设计模式笔记A", "笔记内容A", "图片A"); - System.out.println("----------创建笔记A成功------------"); - ArticleMemento articleMemento = article.saveToMemento(); - articleMementoManager.addMemento(articleMemento); - System.out.println("----------笔记A保存成功-------------"); - System.out.print("笔记A内容"); - System.out.println(articleMemento); - //修改笔记 - System.out.println("----------修改笔记A ing-------------"); - article.setTitle("设计模式笔记B"); - article.setContent("笔记内容B"); - article.setImgs("图片B"); - System.out.println("----------修改笔记B end-------------"); - articleMemento = article.saveToMemento(); - articleMementoManager.addMemento(articleMemento); - System.out.println("----------A->B保存成功--------------"); - System.out.print("笔记B内容"); - System.out.println(articleMemento); - - System.out.println("----------修改笔记B ing-------------"); - article.setTitle("设计模式笔记C"); - article.setContent("笔记内容C"); - article.setImgs("图片C"); - System.out.println("----------修改笔记C end-------------"); - System.out.println("----------B->C未保存--------------"); - System.out.println("----------撤回一次--------------"); - articleMemento = articleMementoManager.getMemento(); - article.undoFromMemento(articleMemento); - System.out.println("----------撤回两次--------------"); - articleMemento = articleMementoManager.getMemento(); - article.undoFromMemento(articleMemento); - System.out.println("----------此时笔记-------------"); - System.out.println(articleMemento); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/memento/my/Caretaker.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/memento/my/Caretaker.java deleted file mode 100644 index 5b30a01f..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/memento/my/Caretaker.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.desgin.pattern.behavioral.memento.my; - -public class Caretaker { - Memento memento; - - public Memento getMemento() { - return memento; - } - - public void setMemento(Memento memento) { - this.memento = memento; - } - -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/memento/my/Client.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/memento/my/Client.java deleted file mode 100644 index 67e375ff..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/memento/my/Client.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.desgin.pattern.behavioral.memento.my; - -public class Client { - public static void main(String[] args) { - //打BOSS之前:血、蓝全部满值 - Role role = new Role(100, 100); - System.out.println("----------大战BOSS之前----------"); - role.display(); - - //保持进度 - Caretaker caretaker = new Caretaker(); - caretaker.memento = role.saveMemento(); - - //大战BOSS,快come Over了 - role.setBloodFlow(20); - role.setMagicPoint(20); - System.out.println("----------大战BOSS----------"); - role.display(); - - //恢复存档 - role.restoreMemento(caretaker.getMemento()); - System.out.println("----------恢复----------"); - role.display(); - - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/memento/my/Memento.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/memento/my/Memento.java deleted file mode 100644 index e568713b..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/memento/my/Memento.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.desgin.pattern.behavioral.memento.my; - -class Memento { - private int bloodFlow; - private int magicPoint; - - public int getBloodFlow() { - return bloodFlow; - } - - public int getMagicPoint() { - return magicPoint; - } - - public Memento(int bloodFlow,int magicPoint){ - this.bloodFlow = bloodFlow; - this.magicPoint = magicPoint; - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/memento/my/Role.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/memento/my/Role.java deleted file mode 100644 index e8ac0fce..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/memento/my/Role.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.desgin.pattern.behavioral.memento.my; - -public class Role { - private int bloodFlow;//血量 - private int magicPoint;//蓝量 - - public Role(int bloodFlow,int magicPoint){ - this.bloodFlow = bloodFlow; - this.magicPoint = magicPoint; - } - - public int getBloodFlow() { - return bloodFlow; - } - - public void setBloodFlow(int bloodFlow) { - this.bloodFlow = bloodFlow; - } - - public int getMagicPoint() { - return magicPoint; - } - - public void setMagicPoint(int magicPoint) { - this.magicPoint = magicPoint; - } - - - public void display(){ - System.out.println("用户当前状态:"); - System.out.println("血量:" + getBloodFlow() + ";蓝量:" + getMagicPoint()); - } - - - public Memento saveMemento(){ - return new Memento(getBloodFlow(), getMagicPoint()); - } - - - public void restoreMemento(Memento memento){ - this.bloodFlow = memento.getBloodFlow(); - this.magicPoint = memento.getMagicPoint(); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/Course.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/Course.java deleted file mode 100644 index 0c027ed5..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/Course.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.desgin.pattern.behavioral.observer; - -import java.util.Observable; - -/** - * 被观察者对象 - * @author lastwhisper - */ -public class Course extends Observable { - private String courseName; - - public Course(String courseName) { - this.courseName = courseName; - } - - public String getCourseName() { - return courseName; - } - - public void produceQuestion(Course course, Question question) { - System.out.println(question.getUserName() + "在" + course.getCourseName() + "提交了一个问题 "); - setChanged(); - notifyObservers(question); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/Question.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/Question.java deleted file mode 100644 index 2d092f92..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/Question.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.desgin.pattern.behavioral.observer; - -public class Question { - private String userName; - private String questionContent; - - public String getUserName() { - return userName; - } - - public void setUserName(String userName) { - this.userName = userName; - } - - public String getQuestionContent() { - return questionContent; - } - - public void setQuestionContent(String questionContent) { - this.questionContent = questionContent; - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/Teacher.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/Teacher.java deleted file mode 100644 index cc1ce07d..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/Teacher.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.desgin.pattern.behavioral.observer; - -import java.util.Observable; -import java.util.Observer; - -/** - * 观察者类 - * @author lastwhisper - */ -public class Teacher implements Observer { - private String teacherName; - - public Teacher(String teacherName) { - this.teacherName = teacherName; - } - - @Override - public void update(Observable o, Object arg) { - Course course = (Course) o; - Question question = (Question) arg; - System.out.println(teacherName+"老师的"+course.getCourseName()+"课程接收到一个"+question.getUserName()+"同学提交的问答:"+question.getQuestionContent()); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/Test.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/Test.java deleted file mode 100644 index 610fecdf..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/Test.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.desgin.pattern.behavioral.observer; - -public class Test { - public static void main(String[] args) { - Course course = new Course("Java设计模式精讲"); - Teacher teacher1 = new Teacher("Alpha"); - Teacher teacher2 = new Teacher("Beta"); - - course.addObserver(teacher1); - course.addObserver(teacher2); - //业务逻辑代码 - Question question = new Question(); - question.setUserName("ldc"); - question.setQuestionContent("Java的主函数如何编写"); - - course.produceQuestion(course, question); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/guavatest/GuavaEvent.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/guavatest/GuavaEvent.java deleted file mode 100644 index 10ab47ef..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/guavatest/GuavaEvent.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.desgin.pattern.behavioral.observer.guavatest; - -import com.google.common.eventbus.Subscribe; - -/** - * Create by lastwhisper on 2019/2/11 - */ -public class GuavaEvent { - @Subscribe - public void subscribe(String str) { - System.out.println("执行subscribe方法,传入:" + str); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/guavatest/GuavaEventTest.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/guavatest/GuavaEventTest.java deleted file mode 100644 index 349d20b6..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/guavatest/GuavaEventTest.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.desgin.pattern.behavioral.observer.guavatest; - -import com.google.common.eventbus.EventBus; - -/** - * Create by lastwhisper on 2019/2/11 - */ -public class GuavaEventTest { - public static void main(String[] args) { - EventBus eventBus = new EventBus(); - GuavaEvent guavaEvent = new GuavaEvent(); - eventBus.register(guavaEvent); - eventBus.post("post的内容"); - } - -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/my/Observer.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/my/Observer.java deleted file mode 100644 index 5ef23463..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/my/Observer.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.desgin.pattern.behavioral.observer.my; - -/*** - * 抽象观察者 - * 定义了一个update()方法,当被观察者调用notifyObservers()方法时,观察者的update()方法会被回调。 - * @author lastwhisper - * - */ -public interface Observer { - /** - * 观察者接收通知 - * @param message - */ - void update(String message); -} \ No newline at end of file diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/my/Observerable.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/my/Observerable.java deleted file mode 100644 index b559dade..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/my/Observerable.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.desgin.pattern.behavioral.observer.my; - -/*** - * 抽象被观察者 - * 声明了添加、删除、通知观察者方法 - * @author lastwhisper - */ -public interface Observerable { - /** - * 注册观察者 - * @param o - */ - void registerObserver(Observer o); - - /** - * 移除观察者 - * @param o - */ - void removeObserver(Observer o); - - /** - * 通知观察者 - */ - void notifyObserver(); - -} \ No newline at end of file diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/my/Test.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/my/Test.java deleted file mode 100644 index 2dee1940..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/my/Test.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.desgin.pattern.behavioral.observer.my; - -public class Test { - - public static void main(String[] args) { - WechatServer server = new WechatServer(); - - Observer userZhang = new User("ZhangSan"); - Observer userLi = new User("LiSi"); - Observer userWang = new User("WangWu"); - - server.registerObserver(userZhang); - server.registerObserver(userLi); - server.registerObserver(userWang); - server.setInfomation("PHP是世界上最好用的语言!"); - - System.out.println("----------------------------------------------"); - server.removeObserver(userZhang); - System.out.println("ZhangSan取消关注"); - System.out.println("----------------------------------------------"); - - server.setInfomation("JAVA是世界上最好用的语言!"); - - } -} \ No newline at end of file diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/my/User.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/my/User.java deleted file mode 100644 index 357bfd87..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/my/User.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.desgin.pattern.behavioral.observer.my; - -/** - * 具体观察者 - * 实现了update方法 - * - * @author lastwhisper - */ -public class User implements Observer { - - private String name; - private String message; - - public User(String name) { - this.name = name; - } - - public void read() { - System.out.println(name + " 收到推送消息: " + message); - } - - @Override - public void update(String message) { - this.message = message; - read(); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/my/WechatServer.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/my/WechatServer.java deleted file mode 100644 index bf36b711..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/my/WechatServer.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.desgin.pattern.behavioral.observer.my; - -import java.util.ArrayList; -import java.util.List; - -/** - * 具体被观察者,也就是微信公众号服务 - * 实现了Observerable接口,对Observerable接口的三个方法进行了具体实现 - * - * @author lastwhisper - */ -public class WechatServer implements Observerable { - - /** - * 注意到这个List集合的泛型参数为Observer接口,设计原则:面向接口编程而不是面向实现编程 - */ - private List list; - private String message; - - public WechatServer() { - list = new ArrayList(); - } - - @Override - public void registerObserver(Observer o) { - list.add(o); - } - - @Override - public void removeObserver(Observer o) { - if (!list.isEmpty()) { - list.remove(o); - } - } - - /**遍历*/ - @Override - public void notifyObserver() { - for (int i = 0; i < list.size(); i++) { - Observer oserver = list.get(i); - oserver.update(message); - } - } - - public void setInfomation(String s) { - this.message = s; - System.out.println("微信服务更新消息: " + s); - //消息更新,通知所有观察者 - notifyObserver(); - } - -} \ No newline at end of file diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/state/CourseVideoContext.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/state/CourseVideoContext.java deleted file mode 100644 index df330952..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/state/CourseVideoContext.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.desgin.pattern.behavioral.state; - -/** - * Create by lastwhisper on 2019/2/11 - */ -public class CourseVideoContext { - private CourseVideoState courseVideoState; - public final static PlayState PLAY_STATE = new PlayState(); - public final static StopState STOP_STATE = new StopState(); - public final static PauseState PAUSE_STATE = new PauseState(); - public final static SpeedState SPEED_STATE = new SpeedState(); - - public CourseVideoState getCourseVideoState() { - return courseVideoState; - } - - public void setCourseVideoState(CourseVideoState courseVideoState) { - this.courseVideoState = courseVideoState; - this.courseVideoState.setCourseVideoContext(this); - } - - public void play() { - this.courseVideoState.play(); - } - - public void speed() { - this.courseVideoState.speed(); - } - - public void pause() { - this.courseVideoState.pause(); - } - - public void stop() { - this.courseVideoState.stop(); - } - -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/state/CourseVideoState.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/state/CourseVideoState.java deleted file mode 100644 index d0acebcf..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/state/CourseVideoState.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.desgin.pattern.behavioral.state; - -/** - * Create by lastwhisper on 2019/2/11 - */ -public abstract class CourseVideoState { - protected CourseVideoContext courseVideoContext; - - public void setCourseVideoContext(CourseVideoContext courseVideoContext) { - this.courseVideoContext = courseVideoContext; - } - - public abstract void play(); - - public abstract void speed(); - - public abstract void pause(); - - public abstract void stop(); -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/state/PauseState.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/state/PauseState.java deleted file mode 100644 index 1a30ce9f..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/state/PauseState.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.desgin.pattern.behavioral.state; - -/** - * Create by lastwhisper on 2019/2/11 - */ -public class PauseState extends CourseVideoState { - @Override - public void play() { - super.courseVideoContext.setCourseVideoState(CourseVideoContext.PLAY_STATE); - } - - @Override - public void speed() { - super.courseVideoContext.setCourseVideoState(CourseVideoContext.SPEED_STATE); - } - - @Override - public void pause() { - System.out.println("暂停播放课程视频状态"); - } - - @Override - public void stop() { - super.courseVideoContext.setCourseVideoState(CourseVideoContext.STOP_STATE); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/state/PlayState.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/state/PlayState.java deleted file mode 100644 index d72ff0bd..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/state/PlayState.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.desgin.pattern.behavioral.state; - -/** - * Create by lastwhisper on 2019/2/11 - */ -public class PlayState extends CourseVideoState { - - @Override - public void play() { - System.out.println("正常播放课程视频状态"); - } - - @Override - public void speed() { - super.courseVideoContext.setCourseVideoState(CourseVideoContext.SPEED_STATE); - } - - @Override - public void pause() { - super.courseVideoContext.setCourseVideoState(CourseVideoContext.PAUSE_STATE); - } - - @Override - public void stop() { - super.courseVideoContext.setCourseVideoState(CourseVideoContext.STOP_STATE); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/state/SpeedState.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/state/SpeedState.java deleted file mode 100644 index b4986fe2..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/state/SpeedState.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.desgin.pattern.behavioral.state; - -/** - * Create by lastwhisper on 2019/2/11 - */ -public class SpeedState extends CourseVideoState { - @Override - public void play() { - super.courseVideoContext.setCourseVideoState(CourseVideoContext.PLAY_STATE); - } - - @Override - public void speed() { - System.out.println("快进播放课程视频状态"); - } - - @Override - public void pause() { - super.courseVideoContext.setCourseVideoState(CourseVideoContext.PAUSE_STATE); - } - - @Override - public void stop() { - super.courseVideoContext.setCourseVideoState(CourseVideoContext.STOP_STATE); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/state/StopState.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/state/StopState.java deleted file mode 100644 index 9700edf1..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/state/StopState.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.desgin.pattern.behavioral.state; - -/** - * Create by lastwhisper on 2019/2/11 - */ -public class StopState extends CourseVideoState { - @Override - public void play() { - super.courseVideoContext.setCourseVideoState(CourseVideoContext.PLAY_STATE); - } - - @Override - public void speed() { - System.out.println("ERROR 停止状态不能快进!!"); - } - - @Override - public void pause() { - System.out.println("ERROR 停止状态不能暂停!!"); - } - - @Override - public void stop() { - System.out.println("停止播放课程视频状态"); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/state/Test.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/state/Test.java deleted file mode 100644 index 80c37684..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/state/Test.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.desgin.pattern.behavioral.state; - -/** - * Create by lastwhisper on 2019/2/11 - */ -public class Test { - public static void main(String[] args){ - CourseVideoContext courseVideoContext = new CourseVideoContext(); - courseVideoContext.setCourseVideoState(new PlayState()); - System.out.println("当前状态"+ courseVideoContext.getCourseVideoState().getClass().getSimpleName()); - - courseVideoContext.pause(); - System.out.println("当前状态"+ courseVideoContext.getCourseVideoState().getClass().getSimpleName()); - - courseVideoContext.speed(); - System.out.println("当前状态"+ courseVideoContext.getCourseVideoState().getClass().getSimpleName()); - - courseVideoContext.stop(); - System.out.println("当前状态"+ courseVideoContext.getCourseVideoState().getClass().getSimpleName()); - - courseVideoContext.speed(); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/strategy/EmptyPromotionStrategy.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/strategy/EmptyPromotionStrategy.java deleted file mode 100644 index 2d51176c..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/strategy/EmptyPromotionStrategy.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.desgin.pattern.behavioral.strategy; - -public class EmptyPromotionStrategy implements PromotionStrategy { - @Override - public void doPromotion() { - System.out.println("无促销"); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/strategy/FanXianPromotionStrategy.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/strategy/FanXianPromotionStrategy.java deleted file mode 100644 index 469267c2..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/strategy/FanXianPromotionStrategy.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.desgin.pattern.behavioral.strategy; - -public class FanXianPromotionStrategy implements PromotionStrategy { - - @Override - public void doPromotion() { - System.out.println("反现促销,返回的金额存放到网站用户的余额中"); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/strategy/LiJianPromotionStrategy.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/strategy/LiJianPromotionStrategy.java deleted file mode 100644 index 3f241106..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/strategy/LiJianPromotionStrategy.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.desgin.pattern.behavioral.strategy; - -public class LiJianPromotionStrategy implements PromotionStrategy{ - @Override - public void doPromotion() { - System.out.println("立减促销,课程的价格直接减去配置的价格"); - } -} - diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/strategy/ManJianPromotionStrategy.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/strategy/ManJianPromotionStrategy.java deleted file mode 100644 index b9c01260..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/strategy/ManJianPromotionStrategy.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.desgin.pattern.behavioral.strategy; - -public class ManJianPromotionStrategy extends Test implements PromotionStrategy{ - - @Override - public void doPromotion() { - System.out.println("满减促销,满200减20元"); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/strategy/PromotionActivity.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/strategy/PromotionActivity.java deleted file mode 100644 index b21e32c1..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/strategy/PromotionActivity.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.desgin.pattern.behavioral.strategy; - -public class PromotionActivity { - private PromotionStrategy promotionStrategy; - - public PromotionActivity(PromotionStrategy promotionStrategy) { - this.promotionStrategy = promotionStrategy; - } - - public void executePromotionStrategy() { - promotionStrategy.doPromotion(); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/strategy/PromotionStrategy.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/strategy/PromotionStrategy.java deleted file mode 100644 index 29a6da91..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/strategy/PromotionStrategy.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.desgin.pattern.behavioral.strategy; - -public interface PromotionStrategy { - void doPromotion(); -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/strategy/PromotionStrategyFactory.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/strategy/PromotionStrategyFactory.java deleted file mode 100644 index b7ad3143..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/strategy/PromotionStrategyFactory.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.desgin.pattern.behavioral.strategy; - -import java.util.HashMap; -import java.util.Map; - -public class PromotionStrategyFactory { - private static Map PROMOTION_STRATEGY_MAP = new HashMap<>(); - static { - PROMOTION_STRATEGY_MAP.put(PromotionKey.LIJIAN, new LiJianPromotionStrategy()); - PROMOTION_STRATEGY_MAP.put(PromotionKey.FANXIAN, new FanXianPromotionStrategy()); - PROMOTION_STRATEGY_MAP.put(PromotionKey.MANJIAN, new ManJianPromotionStrategy()); - } - - private static final PromotionStrategy NON_PROMOTION = new EmptyPromotionStrategy(); - - private PromotionStrategyFactory() { - - } - - public static PromotionStrategy getPromotionStrategy(String promotionKey) { - PromotionStrategy promotionStrategy = PROMOTION_STRATEGY_MAP.get(promotionKey); - return promotionStrategy == null ? NON_PROMOTION : promotionStrategy; - } - - private interface PromotionKey{ - String LIJIAN = "LIJIAN"; - String FANXIAN = "FANXIAN"; - String MANJIAN = "MANJIAN"; - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/strategy/Test.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/strategy/Test.java deleted file mode 100644 index a240683b..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/strategy/Test.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.desgin.pattern.behavioral.strategy; - -public class Test { - public static void main(String[] args) { -// /** 在618的时候,我们使用立减的策略 */ -// PromotionActivity promotionActivity618 = new PromotionActivity(new LiJianPromotionStrategy()); -// /** 在双11的时候,我们使用反现的策略 */ -// PromotionActivity promotionActivity1111 = new PromotionActivity(new FanXianPromotionStrategy()); -// -// promotionActivity618.executePromotionStrategy(); -// promotionActivity1111.executePromotionStrategy(); - - -// PromotionActivity promotionActivity = null; -// -// /** 我们来创建一个promotionKey */ -// String promotionKey = "LIJIAN"; -// -// if (StringUtils.equals(promotionKey, "LIJIAN")) { -// promotionActivity = new PromotionActivity(new LiJianPromotionStrategy()); -// } else if (StringUtils.equals(promotionKey, "FANXIAN")) { -// promotionActivity = new PromotionActivity(new FanXianPromotionStrategy()); -// }else if (StringUtils.equals(promotionKey, "MAINJIAN")){ -// promotionActivity = new PromotionActivity(new ManJianPromotionStrategy()); -// } -// promotionActivity.executePromotionStrategy(); - - /** 我们来创建一个promotionKey */ - String promotionKey = "LIJIAN"; - - PromotionActivity promotionActivity = new PromotionActivity(PromotionStrategyFactory.getPromotionStrategy(promotionKey)); - promotionActivity.executePromotionStrategy(); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/templatemethod/ACourse.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/templatemethod/ACourse.java deleted file mode 100644 index 5b340a7a..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/templatemethod/ACourse.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.desgin.pattern.behavioral.templatemethod; - -public abstract class ACourse { - /** 声明成final就是不希望子类去覆盖这个方法 */ - protected final void makeCourse() { - this.makePPT(); - this.makeVideo(); - /** 这里是否需要写手记交由勾子方法来决定 */ - if (needWriteArticle()) { - this.writeArticle(); - } - this.packageCourse(); - } - - final void makePPT() { - System.out.println("制作PPT"); - } - - final void makeVideo() { - System.out.println("制作视频"); - } - - /** 这个编写手记是一个可选项 */ - final void writeArticle() { - System.out.println("编写手记"); - } - - /** 我们就要给这个编写手记声明一个勾子方法 */ - /** 这个并不是一个final方法,子类是可以进行覆盖的 */ - protected boolean needWriteArticle() { - return false; - } - - abstract void packageCourse(); - -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/templatemethod/DesignPatternCourse.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/templatemethod/DesignPatternCourse.java deleted file mode 100644 index 2b4e823a..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/templatemethod/DesignPatternCourse.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.desgin.pattern.behavioral.templatemethod; - -public class DesignPatternCourse extends ACourse { - @Override - void packageCourse() { - System.out.println("提供课程Java源代码"); - } - - @Override - protected boolean needWriteArticle() { - return true; - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/templatemethod/FECourse.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/templatemethod/FECourse.java deleted file mode 100644 index c8935742..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/templatemethod/FECourse.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.desgin.pattern.behavioral.templatemethod; - -public class FECourse extends ACourse { - - private boolean needWriteArticleFlag = false; - - public FECourse(boolean needWriteArticleFlag) { - this.needWriteArticleFlag = needWriteArticleFlag; - } - - @Override - void packageCourse() { - System.out.println("提供课程的前端代码"); - System.out.println("提供课程的图片等多媒体素材"); - } - - @Override - protected boolean needWriteArticle() { - return this.needWriteArticleFlag; - } - - -} - diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/templatemethod/Test.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/templatemethod/Test.java deleted file mode 100644 index 1059a518..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/templatemethod/Test.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.desgin.pattern.behavioral.templatemethod; - -public class Test { - public static void main(String[] args) { - System.out.println("后端设计模式课程start--"); - ACourse designPatternCourse = new DesignPatternCourse(); - designPatternCourse.makeCourse(); - System.out.println("后端设计模式课程end--"); - - System.out.println("前端式课程start--"); - ACourse feCourse = new FECourse(true); - feCourse.makeCourse(); - System.out.println("前端课程end--"); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/templatemethod/my/Abstract.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/templatemethod/my/Abstract.java deleted file mode 100644 index 598e3985..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/templatemethod/my/Abstract.java +++ /dev/null @@ -1,55 +0,0 @@ -package com.desgin.pattern.behavioral.templatemethod.my; - -public abstract class Abstract { - //模板方法,用来控制炒菜的流程 (炒菜的流程是一样的-复用) -//申明为final,不希望子类覆盖这个方法,防止更改流程的执行顺序 - final void cookProcess() { - //第一步:倒油 - this.pourOil(); - this.HeatOil(); - //第三步:倒蔬菜 - this.pourVegetable(); - //第四步:倒调味料 - - // 这里是否需要倒调味料交由钩子方法来决定 - if (needPourSauce()) { - this.pourSauce(); - } - //第五步:翻炒 - this.fry(); - } - - -//定义结构里哪些方法是所有过程都是一样的可复用的,哪些是需要子类进行实现的 - - //第一步:倒油是一样的,所以直接实现 - void pourOil() { - System.out.println("倒油"); - } - - //第二步:热油是一样的,所以直接实现 - void HeatOil() { - System.out.println("热油"); - } - - //第三步:倒蔬菜是不一样的(一个下包菜,一个是下菜心) -//所以声明为抽象方法,具体由子类实现 - abstract void pourVegetable(); - - //第四步:倒调味料是不一样的(一个下辣椒,一个是下蒜蓉) -//所以声明为抽象方法,具体由子类实现 - abstract void pourSauce(); - - - //第五步:翻炒是一样的,所以直接实现 - void fry() { - System.out.println("炒啊炒啊炒到熟啊"); - } - - /** - * 我们就要给这个倒调味料声明一个钩子方法 - */ - protected boolean needPourSauce() { - return true; - } -} \ No newline at end of file diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/templatemethod/my/ConcreteClass_BaoCai.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/templatemethod/my/ConcreteClass_BaoCai.java deleted file mode 100644 index 3d5b2b1a..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/templatemethod/my/ConcreteClass_BaoCai.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.desgin.pattern.behavioral.templatemethod.my; - -//炒手撕包菜的类 -public class ConcreteClass_BaoCai extends Abstract { - @Override - public void pourVegetable() { - System.out.println("下锅的蔬菜是包菜"); - } - - @Override - public void pourSauce() { - System.out.println("下锅的酱料是辣椒"); - } -} \ No newline at end of file diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/templatemethod/my/ConcreteClass_CaiXin.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/templatemethod/my/ConcreteClass_CaiXin.java deleted file mode 100644 index 2bd3a8f6..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/templatemethod/my/ConcreteClass_CaiXin.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.desgin.pattern.behavioral.templatemethod.my; - -//炒蒜蓉菜心的类 -public class ConcreteClass_CaiXin extends Abstract { - @Override - public void pourVegetable() { - System.out.println("下锅的蔬菜是菜心"); - } - - @Override - public void pourSauce() { - System.out.println("下锅的酱料是蒜蓉"); - } -} \ No newline at end of file diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/templatemethod/my/Test.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/templatemethod/my/Test.java deleted file mode 100644 index 0b90c604..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/templatemethod/my/Test.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.desgin.pattern.behavioral.templatemethod.my; - -public class Test { - public static void main(String[] args) { - //炒 - 手撕包菜 - ConcreteClass_BaoCai BaoCai = new ConcreteClass_BaoCai(); - BaoCai.cookProcess(); - //炒 - 蒜蓉菜心 - ConcreteClass_CaiXin CaiXin = new ConcreteClass_CaiXin(); - CaiXin.cookProcess(); - } - -} \ No newline at end of file diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/visitor/CodingCourse.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/visitor/CodingCourse.java deleted file mode 100644 index 507ef084..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/visitor/CodingCourse.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.desgin.pattern.behavioral.visitor; - -/** - * Create by lastwhisper on 2019/2/11 - */ -public class CodingCourse extends Course { - private int price; - - public int getPrice() { - return price; - } - - public void setPrice(int price) { - this.price = price; - } - - @Override - public void accept(IVisitor visitor) { - visitor.visit(this); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/visitor/Course.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/visitor/Course.java deleted file mode 100644 index 459ee6f4..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/visitor/Course.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.desgin.pattern.behavioral.visitor; - -/** - * Create by lastwhisper on 2019/2/11 - */ -public abstract class Course { - private String name; - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public abstract void accept(IVisitor visitor); -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/visitor/FreeCourse.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/visitor/FreeCourse.java deleted file mode 100644 index c3ed7d6f..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/visitor/FreeCourse.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.desgin.pattern.behavioral.visitor; - -/** - * Create by lastwhisper on 2019/2/11 - */ -public class FreeCourse extends Course { - @Override - public void accept(IVisitor visitor) { - visitor.visit(this); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/visitor/IVisitor.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/visitor/IVisitor.java deleted file mode 100644 index 8d1c22d6..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/visitor/IVisitor.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.desgin.pattern.behavioral.visitor; - -/** - * Create by lastwhisper on 2019/2/11 - */ -public interface IVisitor { - void visit(FreeCourse freeCourse); - - void visit(CodingCourse codingCourse); -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/visitor/Test.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/visitor/Test.java deleted file mode 100644 index 6a052c08..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/visitor/Test.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.desgin.pattern.behavioral.visitor; - -import java.util.ArrayList; -import java.util.List; - -/** - * Create by lastwhisper on 2019/2/11 - */ -public class Test { - public static void main(String[] args) { - List courseList = new ArrayList<>(); - - FreeCourse freeCourse = new FreeCourse(); - freeCourse.setName("SpringMVC数据绑定"); - - CodingCourse codingCourse = new CodingCourse(); - codingCourse.setName("Java设计模式"); - codingCourse.setPrice(299); - - courseList.add(freeCourse); - courseList.add(codingCourse); - - for (Course course : courseList) { - course.accept(new Visitor()); - } - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/behavioral/visitor/Visitor.java b/design-pattern/src/main/java/com/desgin/pattern/behavioral/visitor/Visitor.java deleted file mode 100644 index f3dea3de..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/behavioral/visitor/Visitor.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.desgin.pattern.behavioral.visitor; - -/** - * Create by lastwhisper on 2019/2/11 - */ -public class Visitor implements IVisitor { - /** - * 访问免费课程,打印所有免费课程名称 - * - * @param freeCourse - */ - @Override - public void visit(FreeCourse freeCourse) { - System.out.println("免费课程:" + freeCourse.getName()); - } - - /** - * 访问实战课程,打印所有实战课程名称以及价格 - * - * @param codingCourse - */ - @Override - public void visit(CodingCourse codingCourse) { - System.out.println("实战课程:" + codingCourse.getName() + " 价格:" + codingCourse.getPrice()+ "元"); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/Article.java b/design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/Article.java deleted file mode 100644 index b9372574..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/Article.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.desgin.pattern.creational.abstractfactory; - -/** - * Create by lastwhisper on 2019/1/24 - */ -public abstract class Article { - public abstract void produce(); -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/CourseFactory.java b/design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/CourseFactory.java deleted file mode 100644 index 58f42431..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/CourseFactory.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.desgin.pattern.creational.abstractfactory; - - - -/** - * Create by lastwhisper on 2019/1/24 - */ -public interface CourseFactory { - Video getVideo(); - Article getArticle(); -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/JavaArticle.java b/design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/JavaArticle.java deleted file mode 100644 index 432bb79c..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/JavaArticle.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.desgin.pattern.creational.abstractfactory; - -/** - * Create by lastwhisper on 2019/1/24 - */ -public class JavaArticle extends Article { - @Override - public void produce() { - System.out.println("编写Java课程手记"); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/JavaCourseFactory.java b/design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/JavaCourseFactory.java deleted file mode 100644 index f82d80e3..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/JavaCourseFactory.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.desgin.pattern.creational.abstractfactory; - -/** - * Create by lastwhisper on 2019/1/24 - */ -public class JavaCourseFactory implements CourseFactory { - @Override - public Video getVideo() { - return new JavaVideo(); - } - @Override - public Article getArticle() { - return new JavaArticle(); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/JavaVideo.java b/design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/JavaVideo.java deleted file mode 100644 index ab2502fb..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/JavaVideo.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.desgin.pattern.creational.abstractfactory; - -/** - * Create by lastwhisper on 2019/1/24 - */ -public class JavaVideo extends Video { - @Override - public void produce() { - System.out.println("录制Java课程视频"); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/PythonArticle.java b/design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/PythonArticle.java deleted file mode 100644 index f95f85c9..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/PythonArticle.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.desgin.pattern.creational.abstractfactory; - -/** - * Create by lastwhisper on 2019/1/24 - */ -public class PythonArticle extends Article { - @Override - public void produce() { - System.out.println("编写Python课程手记"); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/PythonCourseFactory.java b/design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/PythonCourseFactory.java deleted file mode 100644 index b1f30653..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/PythonCourseFactory.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.desgin.pattern.creational.abstractfactory; - -/** - * Create by lastwhisper on 2019/1/24 - */ -public class PythonCourseFactory implements CourseFactory { - @Override - public Video getVideo() { - return new PythonVideo(); - } - - @Override - public Article getArticle() { - return new PythonArticle(); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/PythonVideo.java b/design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/PythonVideo.java deleted file mode 100644 index 81c0fec4..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/PythonVideo.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.desgin.pattern.creational.abstractfactory; - -/** - * Create by lastwhisper on 2019/1/24 - */ -public class PythonVideo extends Video { - @Override - public void produce() { - System.out.println("录制python课程视频 "); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/Test.java b/design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/Test.java deleted file mode 100644 index e72b0a99..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/Test.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.desgin.pattern.creational.abstractfactory; - - -/** - * Create by lastwhisper on 2019/1/24 - */ -public class Test { - public static void main(String[] args){ - CourseFactory courseFactory = new JavaCourseFactory(); - Video video = courseFactory.getVideo(); - Article article = courseFactory.getArticle(); - article.produce(); - video.produce(); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/Video.java b/design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/Video.java deleted file mode 100644 index e1cdc61f..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/creational/abstractfactory/Video.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.desgin.pattern.creational.abstractfactory; - -/** - * Create by lastwhisper on 2019/1/24 - */ -public abstract class Video { - public abstract void produce(); -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/builder/Coach.java b/design-pattern/src/main/java/com/desgin/pattern/creational/builder/Coach.java deleted file mode 100644 index d54fa2c4..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/creational/builder/Coach.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.desgin.pattern.creational.builder; - -/** - * Create by lastwhisper on 2019/1/24 - */ -public class Coach { - private CourseBuilder courseBuilder; - - public void setCourseBuilder(CourseBuilder courseBuilder) { - this.courseBuilder = courseBuilder; - } - - public Course makeCourse(String courseName,String coursePPT,String courseVideo,String courseArticle,String courseQA){ - this.courseBuilder.buildCourseName(courseName); - this.courseBuilder.buildCoursePPT(coursePPT); - this.courseBuilder.buildCourseVideo(courseVideo); - this.courseBuilder.buildCourseArticle(courseArticle); - this.courseBuilder.buildCourseQA(courseQA); - return this.courseBuilder.makeCourse(); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/builder/Course.java b/design-pattern/src/main/java/com/desgin/pattern/creational/builder/Course.java deleted file mode 100644 index b95068fc..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/creational/builder/Course.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.desgin.pattern.creational.builder; - -/** - * Create by lastwhisper on 2019/1/24 - */ -public class Course { - private String courseName; - private String coursePPT; - private String courseVideo; - private String courseArticle; - private String courseQA; - - @Override - public String toString() { - return "Course{" + - "courseName='" + courseName + '\'' + - ", coursePPT='" + coursePPT + '\'' + - ", courseVideo='" + courseVideo + '\'' + - ", courseArticle='" + courseArticle + '\'' + - ", courseQA='" + courseQA + '\'' + - '}'; - } - - public String getCourseName() { - return courseName; - } - - public void setCourseName(String courseName) { - this.courseName = courseName; - } - - public String getCoursePPT() { - return coursePPT; - } - - public void setCoursePPT(String coursePPT) { - this.coursePPT = coursePPT; - } - - public String getCourseVideo() { - return courseVideo; - } - - public void setCourseVideo(String courseVideo) { - this.courseVideo = courseVideo; - } - - public String getCourseArticle() { - return courseArticle; - } - - public void setCourseArticle(String courseArticle) { - this.courseArticle = courseArticle; - } - - public String getCourseQA() { - return courseQA; - } - - public void setCourseQA(String courseQA) { - this.courseQA = courseQA; - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/builder/CourseActualBuilder.java b/design-pattern/src/main/java/com/desgin/pattern/creational/builder/CourseActualBuilder.java deleted file mode 100644 index 8a8e0a0e..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/creational/builder/CourseActualBuilder.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.desgin.pattern.creational.builder; - -/** - * Create by lastwhisper on 2019/1/24 - */ -public class CourseActualBuilder extends CourseBuilder { - private Course course = new Course(); - - - @Override - public void buildCourseName(String courseName) { - course.setCourseName(courseName); - } - - @Override - public void buildCoursePPT(String coursePPT) { - course.setCoursePPT(coursePPT); - } - - @Override - public void buildCourseVideo(String courseVideo) { - course.setCourseVideo(courseVideo); - } - - @Override - public void buildCourseArticle(String courseArticle) { - course.setCourseArticle(courseArticle); - } - - @Override - public void buildCourseQA(String courseQA) { - course.setCourseQA(courseQA); - } - - @Override - public Course makeCourse() { - return course; - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/builder/CourseBuilder.java b/design-pattern/src/main/java/com/desgin/pattern/creational/builder/CourseBuilder.java deleted file mode 100644 index 6c70d6d7..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/creational/builder/CourseBuilder.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.desgin.pattern.creational.builder; - -/** - * Create by lastwhisper on 2019/1/24 - */ -public abstract class CourseBuilder { -// private String courseName; -// private String coursePPT; -// private String courseVideo; -// private String courseArticle; -// private String courseQA; - - public abstract void buildCourseName(String courseName); - - public abstract void buildCoursePPT(String coursePPT); - - public abstract void buildCourseVideo(String courseVideo); - - public abstract void buildCourseArticle(String courseArticle); - - public abstract void buildCourseQA(String courseQA); - - public abstract Course makeCourse(); -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/builder/Test.java b/design-pattern/src/main/java/com/desgin/pattern/creational/builder/Test.java deleted file mode 100644 index 9e159ba7..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/creational/builder/Test.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.desgin.pattern.creational.builder; - -/** - * Create by lastwhisper on 2019/1/24 - */ -public class Test { - public static void main(String[] args) { - CourseBuilder courseBuilder = new CourseActualBuilder(); - Coach coach = new Coach(); - coach.setCourseBuilder(courseBuilder); - - Course course = coach.makeCourse("Java设计模式", - "Java设计模式PPT", - "Java设计模式视频", - "Java设计模式手记", - "Java设计模式问答"); - System.out.println(course); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/builder/V2/Course.java b/design-pattern/src/main/java/com/desgin/pattern/creational/builder/V2/Course.java deleted file mode 100644 index e2b3315e..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/creational/builder/V2/Course.java +++ /dev/null @@ -1,75 +0,0 @@ -package com.desgin.pattern.creational.builder.V2; - -/** - * Create by lastwhisper on 2019/1/24 - */ -public class Course { - - private String courseName; - private String coursePPT; - private String courseVideo; - private String courseArticle; - private String courseQA; - - public Course(CourseBuilder courseBuilder) { - this.courseName = courseBuilder.courseName; - this.coursePPT = courseBuilder.coursePPT; - this.courseVideo = courseBuilder.courseVideo; - this.courseArticle = courseBuilder.courseArticle; - this.courseQA = courseBuilder.courseQA; - } - - public String toString() { - return "Course{" + - "courseName='" + courseName + '\'' + - ", coursePPT='" + coursePPT + '\'' + - ", courseVideo='" + courseVideo + '\'' + - ", courseArticle='" + courseArticle + '\'' + - ", courseQA='" + courseQA + '\'' + - '}'; - } - - public static class CourseBuilder{ - private String courseName; - private String coursePPT; - private String courseVideo; - private String courseArticle; - private String courseQA; - - - public CourseBuilder buildCourseName(String courseName) { - this.courseName=courseName; - return this; - } - - - public CourseBuilder buildCoursePPT(String coursePPT) { - this.coursePPT = coursePPT; - return this; - } - - - public CourseBuilder buildCourseVideo(String courseVideo) { - this.courseVideo = courseVideo; - return this; - } - - - public CourseBuilder buildCourseArticle(String courseArticle) { - this.courseArticle = courseArticle; - return this; - } - - - public CourseBuilder buildCourseQA(String courseQA) { - this.courseQA = courseQA; - return this; - } - - public Course build(){ - return new Course(this); - } - - - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/builder/V2/Test.java b/design-pattern/src/main/java/com/desgin/pattern/creational/builder/V2/Test.java deleted file mode 100644 index 055a03a9..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/creational/builder/V2/Test.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.desgin.pattern.creational.builder.V2; - -/** - * Create by lastwhisper on 2019/1/25 - */ -public class Test { - public static void main(String[] args){ - Course course = new Course.CourseBuilder() - .buildCourseName("Java设计模式") - .buildCoursePPT("Java设计模式PPT") - //.buildCourseVideo("Java设计模式视频") - //.buildCourseArticle("Java设计模式手记") - .buildCourseQA("Java设计模式问答").build(); - System.out.println(course); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/factorymethod/FEVideo.java b/design-pattern/src/main/java/com/desgin/pattern/creational/factorymethod/FEVideo.java deleted file mode 100644 index 711e3d4c..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/creational/factorymethod/FEVideo.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.desgin.pattern.creational.factorymethod; - -/** - * Create by lastwhisper on 2019/1/24 - */ -public class FEVideo extends Video { - @Override - public void produce() { - System.out.println("录制前端课程视频"); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/factorymethod/FEVideoFactory.java b/design-pattern/src/main/java/com/desgin/pattern/creational/factorymethod/FEVideoFactory.java deleted file mode 100644 index 090cbf85..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/creational/factorymethod/FEVideoFactory.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.desgin.pattern.creational.factorymethod; - -/** - * Create by lastwhisper on 2019/1/24 - */ -public class FEVideoFactory extends VideoFactory { - public Video getVideo() { - return new FEVideo(); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/factorymethod/JavaVideo.java b/design-pattern/src/main/java/com/desgin/pattern/creational/factorymethod/JavaVideo.java deleted file mode 100644 index 3079e5b7..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/creational/factorymethod/JavaVideo.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.desgin.pattern.creational.factorymethod; - -/** - * Create by lastwhisper on 2019/1/23 - */ -public class JavaVideo extends Video { - @Override - public void produce() { - System.out.println("录制java课程"); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/factorymethod/JavaVideoFactory.java b/design-pattern/src/main/java/com/desgin/pattern/creational/factorymethod/JavaVideoFactory.java deleted file mode 100644 index d074ebea..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/creational/factorymethod/JavaVideoFactory.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.desgin.pattern.creational.factorymethod; - -/** - * Create by lastwhisper on 2019/1/24 - */ -public class JavaVideoFactory extends VideoFactory { - public Video getVideo() { - return new JavaVideo(); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/factorymethod/PythonVideo.java b/design-pattern/src/main/java/com/desgin/pattern/creational/factorymethod/PythonVideo.java deleted file mode 100644 index cead6638..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/creational/factorymethod/PythonVideo.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.desgin.pattern.creational.factorymethod; - -/** - * Create by lastwhisper on 2019/1/23 - */ -public class PythonVideo extends Video { - @Override - public void produce() { - System.out.println("录制python课程"); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/factorymethod/PythonVideoFactory.java b/design-pattern/src/main/java/com/desgin/pattern/creational/factorymethod/PythonVideoFactory.java deleted file mode 100644 index 7bc7b6b1..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/creational/factorymethod/PythonVideoFactory.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.desgin.pattern.creational.factorymethod; - -/** - * Create by lastwhisper on 2019/1/24 - */ -public class PythonVideoFactory extends VideoFactory { - public Video getVideo() { - return new PythonVideo(); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/factorymethod/Test.java b/design-pattern/src/main/java/com/desgin/pattern/creational/factorymethod/Test.java deleted file mode 100644 index a29ca806..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/creational/factorymethod/Test.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.desgin.pattern.creational.factorymethod; - -/** - * Create by lastwhisper on 2019/1/23 - */ -public class Test { - public static void main(String[] args) { - VideoFactory videoFactory = new PythonVideoFactory(); - VideoFactory videoFactory1 = new JavaVideoFactory(); - VideoFactory videoFactory2 = new FEVideoFactory(); - Video video = videoFactory.getVideo(); - video.produce(); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/factorymethod/Video.java b/design-pattern/src/main/java/com/desgin/pattern/creational/factorymethod/Video.java deleted file mode 100644 index 6c0b9ae0..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/creational/factorymethod/Video.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.desgin.pattern.creational.factorymethod; - -/** - * Create by lastwhisper on 2019/1/23 - */ -public abstract class Video { - public abstract void produce(); -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/factorymethod/VideoFactory.java b/design-pattern/src/main/java/com/desgin/pattern/creational/factorymethod/VideoFactory.java deleted file mode 100644 index b9a1bd2b..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/creational/factorymethod/VideoFactory.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.desgin.pattern.creational.factorymethod; - -/** - * Create by lastwhisper on 2019/1/23 - */ -public abstract class VideoFactory { - - public abstract Video getVideo(); - -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/prototype/Mail.java b/design-pattern/src/main/java/com/desgin/pattern/creational/prototype/Mail.java deleted file mode 100644 index 1fa56565..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/creational/prototype/Mail.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.desgin.pattern.creational.prototype; - -/** - * Create by lastwhisper on 2019/1/27 - */ -public class Mail implements Cloneable{ - private String name; - private String emailAddress; - private String content; - - public Mail() { - System.out.println("Mail Class Constructor"); - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getEmailAddress() { - return emailAddress; - } - - public void setEmailAddress(String emailAddress) { - this.emailAddress = emailAddress; - } - - public String getContent() { - return content; - } - - public void setContent(String content) { - this.content = content; - } - - @Override - public String toString() { - return "Mail{" + - "name='" + name + '\'' + - ", emailAddress='" + emailAddress + '\'' + - ", content='" + content + '\'' + - '}'+super.toString(); - } - - @Override - protected Object clone() throws CloneNotSupportedException { - System.out.println("clone mail object"); - return super.clone(); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/prototype/MailUtils.java b/design-pattern/src/main/java/com/desgin/pattern/creational/prototype/MailUtils.java deleted file mode 100644 index 753e47e3..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/creational/prototype/MailUtils.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.desgin.pattern.creational.prototype; - -import java.text.MessageFormat; - -/** - * Create by lastwhisper on 2019/1/27 - */ -public class MailUtils { - public static void sendMail(Mail mail){ - String outputContent = "向{0}同学,邮件地址:{1},邮件内容:{2}发送邮件成功"; - System.out.println(MessageFormat.format(outputContent, - mail.getName(),mail.getEmailAddress(),mail.getContent())); - } - public static void saveOriginMailRecord(Mail mail){ - System.out.println("存储originMail记录,originMail:"+mail.getContent()); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/prototype/Test.java b/design-pattern/src/main/java/com/desgin/pattern/creational/prototype/Test.java deleted file mode 100644 index 586573a2..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/creational/prototype/Test.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.desgin.pattern.creational.prototype; - -/** - * Create by lastwhisper on 2019/1/27 - */ -public class Test { - public static void main(String[] args) throws CloneNotSupportedException { - Mail mail = new Mail(); - mail.setContent("初始化模板"); - System.out.println("初始化mail:"+mail); - for (int i = 0; i < 10; i++) { - Mail mailTemp = (Mail) mail.clone(); -// mail.setName("姓名" + i); -// mail.setEmailAddress("姓名" + i + "@qq.com"); -// mail.setContent("恭喜您,QQ号中大奖了"); - mailTemp.setName("姓名" + i); - mailTemp.setEmailAddress("姓名" + i + "@qq.com"); - mailTemp.setContent("恭喜您,QQ号中大奖了"); - MailUtils.sendMail(mailTemp); - System.out.println("克隆的mailTemp:"+mailTemp); - } - MailUtils.saveOriginMailRecord(mail); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/prototype/abstractprototype/A.java b/design-pattern/src/main/java/com/desgin/pattern/creational/prototype/abstractprototype/A.java deleted file mode 100644 index 6190c5f3..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/creational/prototype/abstractprototype/A.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.desgin.pattern.creational.prototype.abstractprototype; - -/** - * Create by lastwhisper on 2019/1/27 - */ -public abstract class A implements Cloneable{ - @Override - protected Object clone() throws CloneNotSupportedException { - return super.clone(); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/prototype/abstractprototype/B.java b/design-pattern/src/main/java/com/desgin/pattern/creational/prototype/abstractprototype/B.java deleted file mode 100644 index e49d0798..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/creational/prototype/abstractprototype/B.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.desgin.pattern.creational.prototype.abstractprototype; - -/** - * Create by lastwhisper on 2019/1/27 - */ -public class B extends A{ - public static void main(String[] args) throws CloneNotSupportedException { - B b = new B(); - b.clone(); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/prototype/clone/Pig.java b/design-pattern/src/main/java/com/desgin/pattern/creational/prototype/clone/Pig.java deleted file mode 100644 index d45402fb..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/creational/prototype/clone/Pig.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.desgin.pattern.creational.prototype.clone; - -import java.util.Date; - -/** - * Create by lastwhisper on 2019/1/27 - */ -public class Pig implements Cloneable { - private String name; - private Date birthday; - - public Pig() { - } - - public Pig(String name, Date birthday) { - this.name = name; - this.birthday = birthday; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public Date getBirthday() { - return birthday; - } - - public void setBirthday(Date birthday) { - this.birthday = birthday; - } - - @Override - public String toString() { - return "Pig{" + - "name='" + name + '\'' + - ", birthday=" + birthday + - '}' + super.toString(); - } - - @Override - protected Object clone() throws CloneNotSupportedException { - Pig pig = (Pig) super.clone(); - //深克隆 - pig.birthday = (Date) pig.birthday.clone(); - return pig; - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/prototype/clone/Test.java b/design-pattern/src/main/java/com/desgin/pattern/creational/prototype/clone/Test.java deleted file mode 100644 index 515e4df5..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/creational/prototype/clone/Test.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.desgin.pattern.creational.prototype.clone; - -import com.desgin.pattern.creational.singleton.HungrySingleton; - -/** - * Create by lastwhisper on 2019/1/27 - */ -public class Test { - public static void main(String[] args) throws CloneNotSupportedException { -// Date birthday = new Date(0L); -// Pig pig1 = new Pig("佩奇", birthday); -// Pig pig2 = (Pig) pig1.clone(); -// System.out.println(pig1); -// System.out.println(pig2); -// pig1.getBirthday().setTime(666666666666L); -// System.out.println(pig1); -// System.out.println(pig2); - HungrySingleton instance = HungrySingleton.getInstance(); - - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/prototype/my/Resume.java b/design-pattern/src/main/java/com/desgin/pattern/creational/prototype/my/Resume.java deleted file mode 100644 index 2250832c..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/creational/prototype/my/Resume.java +++ /dev/null @@ -1,91 +0,0 @@ -package com.desgin.pattern.creational.prototype.my; - -import java.util.Date; - -public class Resume implements Cloneable { - private String name; - private Date birthday; - private String sex; - private String school; - private String timeArea; - private String company; - - public Resume(String name, Date birthday, String sex, String school, String timeArea, String company) { - this.name = name; - this.birthday = birthday; - this.sex = sex; - this.school = school; - this.timeArea = timeArea; - this.company = company; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public Date getBirthday() { - return birthday; - } - - public void setBirthday(Date birthday) { - this.birthday = birthday; - } - - public String getSex() { - return sex; - } - - public void setSex(String sex) { - this.sex = sex; - } - - public String getSchool() { - return school; - } - - public void setSchool(String school) { - this.school = school; - } - - public String getTimeArea() { - return timeArea; - } - - public void setTimeArea(String timeArea) { - this.timeArea = timeArea; - } - - public String getCompany() { - return company; - } - - public void setCompany(String company) { - this.company = company; - } - - /** - * 克隆该实例 - */ - @Override - public Object clone() { - Resume resume = null; - try { - resume = (Resume) super.clone(); - resume.birthday = (Date) resume.birthday.clone(); - } catch (CloneNotSupportedException e) { - e.printStackTrace(); - } - return resume; - } - - public void display() { - System.out.println("姓名:" + name); - System.out.println("生日:" + birthday + ",性别:" + sex + ",毕业学校:" + school); - System.out.println("工作年限:" + timeArea + ",公司:" + company); - } - -} \ No newline at end of file diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/prototype/my/Test.java b/design-pattern/src/main/java/com/desgin/pattern/creational/prototype/my/Test.java deleted file mode 100644 index 70682d82..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/creational/prototype/my/Test.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.desgin.pattern.creational.prototype.my; - -import java.util.Date; - -/** - * Create by lastwhisper on 2019/2/7 - */ -public class Test { - public static void main(String[] args) { - //原型A对象 - Resume a = new Resume("小李子",new Date(), "男", "XX大学","2012.09.05", "XX科技有限公司"); - a.display(); - System.out.println("*************克隆简历**************"); - //克隆B对象 - Resume b = (Resume) a.clone(); - b.display(); - System.out.println("***************比较***************"); - /* - * 测试A==B? - * 对任何的对象x,都有x.clone() !=x,即克隆对象与原对象不是同一个对象 - */ - System.out.print("比较:A==B?"); - System.out.println( a == b); - - b.getBirthday().setTime(666666666666L); - System.out.println("修改B简历的Birthday为:"+b.getBirthday()); - System.out.println("查看A简历的Birthday为:"+a.getBirthday()); - - /* - * 比较Date对象 - */ - System.out.print("比较:A.Date==B.Date?"); - System.out.println(a.getBirthday() == b.getBirthday()); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/simplefactory/JavaVideo.java b/design-pattern/src/main/java/com/desgin/pattern/creational/simplefactory/JavaVideo.java deleted file mode 100644 index b34c9874..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/creational/simplefactory/JavaVideo.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.desgin.pattern.creational.simplefactory; - -/** - * Create by lastwhisper on 2019/1/23 - */ -public class JavaVideo extends Video{ - @Override - public void produce() { - System.out.println("录制java课程"); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/simplefactory/PythonVideo.java b/design-pattern/src/main/java/com/desgin/pattern/creational/simplefactory/PythonVideo.java deleted file mode 100644 index 8a2441a2..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/creational/simplefactory/PythonVideo.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.desgin.pattern.creational.simplefactory; - -/** - * Create by lastwhisper on 2019/1/23 - */ -public class PythonVideo extends Video { - @Override - public void produce() { - System.out.println("录制python课程"); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/simplefactory/Test.java b/design-pattern/src/main/java/com/desgin/pattern/creational/simplefactory/Test.java deleted file mode 100644 index f6d376b8..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/creational/simplefactory/Test.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.desgin.pattern.creational.simplefactory; - -/** - * Create by lastwhisper on 2019/1/23 - */ -public class Test { - public static void main(String[] args) { - Video video = VideoFactory.getVideo(JavaVideo.class); - video.produce(); - - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/simplefactory/Video.java b/design-pattern/src/main/java/com/desgin/pattern/creational/simplefactory/Video.java deleted file mode 100644 index fd14983a..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/creational/simplefactory/Video.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.desgin.pattern.creational.simplefactory; - -/** - * Create by lastwhisper on 2019/1/23 - */ -public abstract class Video { - public abstract void produce(); -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/simplefactory/VideoFactory.java b/design-pattern/src/main/java/com/desgin/pattern/creational/simplefactory/VideoFactory.java deleted file mode 100644 index 2be3c04e..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/creational/simplefactory/VideoFactory.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.desgin.pattern.creational.simplefactory; - -/** - * Create by lastwhisper on 2019/1/23 - */ -public class VideoFactory { - /** - * 根据Class字节码创建对象 - * @param c - * @return - */ - public static Video getVideo(Class c){ - Video video = null; - try { - video = (Video) Class.forName(c.getName()).newInstance(); - return video; - } catch (InstantiationException e) { - e.printStackTrace(); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } catch (ClassNotFoundException e) { - e.printStackTrace(); - } - return null; - } - -// public static Video getVideo(String type){ -// if("java".equalsIgnoreCase(type)){ -// return new JavaVideo(); -// }else if("python".equalsIgnoreCase(type)){ -// return new PythonVideo(); -// } -// return null; -// } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/CASSingleton.java b/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/CASSingleton.java deleted file mode 100644 index b658923f..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/CASSingleton.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.desgin.pattern.creational.singleton; - -import java.util.concurrent.atomic.AtomicReference; - -/** - * @desc - * https://mp.weixin.qq.com/s?__biz=MzI3NzE0NjcwMg==&mid=2650123793&idx=1&sn=6ee37f4c6d071da6bf64fea3a11d394f&chksm=f36bb330c41c3a266c4cc6dfc7d4a9ee506a14bb98aad7822c053c56c04a5b20452fc3a07481&mpshare=1&scene=23&srcid=#rd - * @author lastwhisper - * - */ -public class CASSingleton { - private static final AtomicReference INSTANCE = new AtomicReference(); - - private CASSingleton() { - } - - - public static CASSingleton getInstance() { - for (;;) { - CASSingleton singleton = INSTANCE.get(); - if (null != singleton) { - return singleton; - } - - singleton = new CASSingleton(); - if (INSTANCE.compareAndSet(null, singleton)) { - return singleton; - } - } - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/CASSingletonTest.java b/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/CASSingletonTest.java deleted file mode 100644 index dcd9dfa0..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/CASSingletonTest.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.desgin.pattern.creational.singleton; - -/** - * @author lastwhisper - */ -public class CASSingletonTest { - public static void main(String[] args){ - //Thread t1 = new Thread(new T()); - //Thread t2 = new Thread(new T()); - //t1.start(); - //t2.start(); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/ContainerSingleton.java b/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/ContainerSingleton.java deleted file mode 100644 index 9fbc90ab..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/ContainerSingleton.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.desgin.pattern.creational.singleton; - -import org.apache.commons.lang3.StringUtils; - -import java.util.HashMap; -import java.util.Map; - -/** - * Create by lastwhisper on 2019/1/27 - */ -public class ContainerSingleton { - - private static Map singletonMap = new HashMap(); - - private ContainerSingleton() { - } - - public static void putInstance(String key, String instance){ - if(StringUtils.isNoneBlank(key) && instance != null){ - if(!singletonMap.containsKey(key)){ - singletonMap.put(key,instance); - } - } - } - public static Object getInstance(String key){ - return singletonMap.get(key); - } - -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/EnumInstance.java b/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/EnumInstance.java deleted file mode 100644 index 8ec518ae..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/EnumInstance.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.desgin.pattern.creational.singleton; - -/** - * Create by lastwhisper on 2019/1/26 - */ -public enum EnumInstance { - //单例对象 - INSTANCE; -// INSTANCE -// { -// protected void printTest(){ -// System.out.println("Gaojun Print Test"); -// } -// }; -// protected abstract void printTest(); - /** - * data测试 - */ - private Object data; - - public Object getData() { - return data; - } - - public void setData(Object data) { - this.data = data; - } - public static EnumInstance getInstance(){ - return INSTANCE; - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/HungrySingleton.java b/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/HungrySingleton.java deleted file mode 100644 index 2c13b382..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/HungrySingleton.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.desgin.pattern.creational.singleton; - -import java.io.Serializable; - -/** - * Create by lastwhisper on 2019/1/26 - */ -public class HungrySingleton implements Serializable,Cloneable { - private static HungrySingleton hungrySingleton; - - static { - hungrySingleton = new HungrySingleton(); - } - - private HungrySingleton() { - if (hungrySingleton != null) { - throw new RuntimeException("单例构造器禁止反射调用"); - } - } - - public static HungrySingleton getInstance() { - return hungrySingleton; - } - - private Object readResolve() { - return hungrySingleton; - } - -// @Override -// protected Object clone() throws CloneNotSupportedException { -// return super.clone(); -// } - - @Override - protected Object clone(){ - return getInstance(); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/LazyDoubleCheckSingleton.java b/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/LazyDoubleCheckSingleton.java deleted file mode 100644 index 753adee3..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/LazyDoubleCheckSingleton.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.desgin.pattern.creational.singleton; - -/** - * Create by lastwhisper on 2019/1/25 - */ -public class LazyDoubleCheckSingleton { - private static volatile LazyDoubleCheckSingleton lazyDoubleCheckSingleton = null; - private LazyDoubleCheckSingleton(){ - - } - public static LazyDoubleCheckSingleton getInstance(){ - if(lazyDoubleCheckSingleton == null){ - synchronized (LazyDoubleCheckSingleton.class){ - if(lazyDoubleCheckSingleton == null){ - lazyDoubleCheckSingleton = new LazyDoubleCheckSingleton(); - //第一步 分配内存给这个对象 - //第二步 初始化这个对象 - //第三步 设置lazyDoubleCheckSingleton 指向刚分配的内存地址 - } - } - } - return lazyDoubleCheckSingleton; - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/LazySingleton.java b/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/LazySingleton.java deleted file mode 100644 index 939d941b..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/LazySingleton.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.desgin.pattern.creational.singleton; - -/** - * Create by lastwhisper on 2019/1/25 - */ -public class LazySingleton { - private static LazySingleton lazySingleton = null; - private static boolean flag = true; - - private LazySingleton() { -// if (lazySingleton != null) { -// throw new RuntimeException("单例构造器禁止反射调用"); -// } -// if (flag) { -// flag = false; -// } else { -// throw new RuntimeException("单例构造器禁止反射调用"); -// } - } - - public synchronized static LazySingleton getInstance() { - if (lazySingleton == null) { - lazySingleton = new LazySingleton(); - } - return lazySingleton; - } - -// public static void main(String[] args) throws Exception { -// Class objectClass = LazySingleton.class; -// Constructor constructor = objectClass.getDeclaredConstructor(); -// constructor.setAccessible(true); -// LazySingleton o1 = LazySingleton.getInstance(); -// //修改flag=true -// Field flag = o1.getClass().getDeclaredField("flag"); -// flag.setAccessible(true); -// flag.set(o1,true); -// -// LazySingleton o2 = (LazySingleton) constructor.newInstance(); -// -// System.out.println(o1); -// System.out.println(o2); -// System.out.println(o1 == o2); -// } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/StaticInnerClassSingleton.java b/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/StaticInnerClassSingleton.java deleted file mode 100644 index 2432190d..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/StaticInnerClassSingleton.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.desgin.pattern.creational.singleton; - -/** - * Create by lastwhisper on 2019/1/26 - */ -public class StaticInnerClassSingleton { - private StaticInnerClassSingleton() { - if (InnerClass.staticInnerClassSingleton != null) { - throw new RuntimeException("单例构造器禁止反射调用"); - } - } - - private static class InnerClass { - private static StaticInnerClassSingleton staticInnerClassSingleton = new StaticInnerClassSingleton(); - } - - public static StaticInnerClassSingleton getInstance() { - return InnerClass.staticInnerClassSingleton; - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/T.java b/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/T.java deleted file mode 100644 index 97538ff7..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/T.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.desgin.pattern.creational.singleton; - -/** - * Create by lastwhisper on 2019/1/25 - */ -public class T implements Runnable { - @Override - public void run() { - //测试同步锁单例 -// LazySingleton instance = LazySingleton.getInstance(); - //测试双重检测锁单例 -// LazyDoubleCheckSingleton instance = LazyDoubleCheckSingleton.getInstance(); - //测试静态内部类单例 -// StaticInnerClassSingleton instance = StaticInnerClassSingleton.getInstance(); - //测试线程单例 -// ThreadLocalInstance instance = ThreadLocalInstance.getInstance(); -// System.out.println(Thread.currentThread().getName() + " " + instance); - //测试CAS单例 - CASSingleton instance = CASSingleton.getInstance(); - System.out.println(instance); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/Test.java b/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/Test.java deleted file mode 100644 index 585d1410..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/Test.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.desgin.pattern.creational.singleton; - -/** - * Create by lastwhisper on 2019/1/25 - */ -public class Test { - public static void main(String[] args) throws Exception { - /*反射测试*/ -// Class objectClass = HungrySingleton.class; -// Class objectClass = StaticInnerClassSingleton.class; -// Class objectClass = LazySingleton.class; - - /*枚举反射测试*/ - //Class objectClass = EnumInstance.class; - // - //Constructor constructor = objectClass.getDeclaredConstructor(String.class,int.class); - //constructor.setAccessible(true); - //EnumInstance newInstance = (EnumInstance) constructor.newInstance("gaojun",123456); - -// LazySingleton instance = LazySingleton.getInstance(); -// System.out.println("getInstance()的lazySingleton:"+instance.lazySingleton); - -// StaticInnerClassSingleton instance = StaticInnerClassSingleton.getInstance(); -// StaticInnerClassSingleton newInstance = (StaticInnerClassSingleton) constructor.newInstance(); -// HungrySingleton instance = HungrySingleton.getInstance(); -// HungrySingleton newInstance = (HungrySingleton) constructor.newInstance(); -// System.out.println(instance); -// System.out.println(newInstance); -// System.out.println(instance == newInstance); - //枚举类型 -// EnumInstance instance = EnumInstance.getInstance(); -// instance.printTest(); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/Test1.java b/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/Test1.java deleted file mode 100644 index fff1e9c3..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/Test1.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.desgin.pattern.creational.singleton; - -import java.io.*; - -/** - * 序列化攻击测试 - * Create by lastwhisper on 2019/1/26 - */ -public class Test1 { - public static void main(String[] args) throws Exception { - EnumInstance instance = EnumInstance.getInstance(); - instance.setData(new Object()); - ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("E:\\singleton_file")); - oos.writeObject(instance); - - File file = new File("E:\\singleton_file"); - ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file)); - EnumInstance newInstance = (EnumInstance)ois.readObject(); - - System.out.println(instance.getData()); - System.out.println(newInstance.getData()); - System.out.println(instance.getData() == newInstance.getData()); - } -} -// System.out.println(instance); -// System.out.println(newInstance); -// System.out.println(instance == newInstance); diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/ThreadLocalInstance.java b/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/ThreadLocalInstance.java deleted file mode 100644 index e6c202a5..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/ThreadLocalInstance.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.desgin.pattern.creational.singleton; - -/** - * Create by lastwhisper on 2019/1/27 - */ -public class ThreadLocalInstance { - private static final ThreadLocal treadLocalInstance = - new ThreadLocal() { - @Override - protected ThreadLocalInstance initialValue() { - return new ThreadLocalInstance(); - } - }; - - private ThreadLocalInstance() { - } - - public static ThreadLocalInstance getInstance() { - return treadLocalInstance.get(); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/ThreadTest.java b/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/ThreadTest.java deleted file mode 100644 index ee5bea3f..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/ThreadTest.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.desgin.pattern.creational.singleton; - -/** - * Create by lastwhisper on 2019/1/27 - */ -public class ThreadTest { - public static void main(String[] args) { - System.out.println(ThreadLocalInstance.getInstance()); - System.out.println(ThreadLocalInstance.getInstance()); - System.out.println(ThreadLocalInstance.getInstance()); - System.out.println(ThreadLocalInstance.getInstance()); - System.out.println(ThreadLocalInstance.getInstance()); - System.out.println(ThreadLocalInstance.getInstance()); - System.out.println(ThreadLocalInstance.getInstance()); - System.out.println("`````````````````````"); - Thread t1 = new Thread(new T()); - Thread t2 = new Thread(new T()); - t1.start(); - t2.start(); - System.out.println("end"); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/my/Singleton1.java b/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/my/Singleton1.java deleted file mode 100644 index bbe825f5..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/my/Singleton1.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.desgin.pattern.creational.singleton.my; - -/** - * 饿汉式 - * 使用静态变量 - * @author lastwhisper - */ -public class Singleton1 { - public static Singleton1 instance = new Singleton1(); - - private Singleton1() { - } - - public static Singleton1 getInstance() { - return instance; - } - -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/my/Singleton2.java b/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/my/Singleton2.java deleted file mode 100644 index eed8cf9c..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/my/Singleton2.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.desgin.pattern.creational.singleton.my; - -/** - * 懒汉式:同步锁 - * @author lastwhisper - */ -public class Singleton2 { - private static Singleton2 instance = null; - - private Singleton2() { - - } - - public static synchronized Singleton2 getInstance() { - if (instance == null) { - instance = new Singleton2(); - } - return instance; - } - -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/my/Singleton3.java b/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/my/Singleton3.java deleted file mode 100644 index e4c76cc6..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/my/Singleton3.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.desgin.pattern.creational.singleton.my; - -/** - * 懒汉式:DCL - * @author lastwhisper - */ -public class Singleton3 { - - private static volatile Singleton3 instance=null; - - - private Singleton3() { - } - - public static Singleton3 getInstance() { - if (instance == null) { - synchronized (Singleton3.class) { - if (instance == null) { - instance = new Singleton3(); - } - return instance; - } - } - return instance; - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/my/Singleton4.java b/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/my/Singleton4.java deleted file mode 100644 index 58f5014e..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/my/Singleton4.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.desgin.pattern.creational.singleton.my; - -/** - * 懒汉式:静态内部类 - * @author lastwhisper - */ -public class Singleton4 { - private Singleton4() { - } - - private static class StaticInnerClass { - private static Singleton4 instance = new Singleton4(); - } - - public Singleton4 getInstance() { - return StaticInnerClass.instance; - } - - -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/my/Singleton5.java b/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/my/Singleton5.java deleted file mode 100644 index 94b336f8..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/my/Singleton5.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.desgin.pattern.creational.singleton.my; - -/** - * 懒汉式:枚举 - */ -public enum Singleton5 { - -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/AC220.java b/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/AC220.java deleted file mode 100644 index 2eeae6d2..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/AC220.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.desgin.pattern.structural.adapter; - -public class AC220 { - public int outputAC220V() { - int output = 220; - System.out.println("输出220V的交流电"+output+"V"); - return output; - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/DC5.java b/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/DC5.java deleted file mode 100644 index 7d9124e6..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/DC5.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.desgin.pattern.structural.adapter; - -public interface DC5 { - int outputDC5V(); -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/PowerAdapter.java b/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/PowerAdapter.java deleted file mode 100644 index a6ec40c5..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/PowerAdapter.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.desgin.pattern.structural.adapter; - -public class PowerAdapter implements DC5 { - - private AC220 ac220 = new AC220(); - - @Override - public int outputDC5V() { - int adapterInput = ac220.outputAC220V(); - /** 变压器 */ - int adapterOutput = adapterInput / 44; - System.out.println("通过PowerAdapter电源适配器输入AC" + adapterInput + "V" + "输出DC:" + adapterOutput + "V"); - return adapterOutput; - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/Test.java b/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/Test.java deleted file mode 100644 index a0cd3786..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/Test.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.desgin.pattern.structural.adapter; - -public class Test { - public static void main(String[]args){ - DC5 dc5 = new PowerAdapter(); - dc5.outputDC5V(); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/classadapter/Adaptee.java b/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/classadapter/Adaptee.java deleted file mode 100644 index 5735bbb0..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/classadapter/Adaptee.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.desgin.pattern.structural.adapter.classadapter; - -public class Adaptee { - public void adapteeRequest() { - System.out.println("被适配者的方法"); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/classadapter/Adapter.java b/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/classadapter/Adapter.java deleted file mode 100644 index 7bda59d3..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/classadapter/Adapter.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.desgin.pattern.structural.adapter.classadapter; - -public class Adapter extends Adaptee implements Target { - @Override - public void request() { - super.adapteeRequest(); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/classadapter/ConcreteTarget.java b/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/classadapter/ConcreteTarget.java deleted file mode 100644 index f98c2ea8..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/classadapter/ConcreteTarget.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.desgin.pattern.structural.adapter.classadapter; - -/** - * 具体的实现类 - */ -public class ConcreteTarget implements Target { - @Override - public void request() { - System.out.println("ConcreteTarget目标方法"); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/classadapter/Target.java b/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/classadapter/Target.java deleted file mode 100644 index 149d7080..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/classadapter/Target.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.desgin.pattern.structural.adapter.classadapter; - -public interface Target { - void request(); -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/classadapter/Test.java b/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/classadapter/Test.java deleted file mode 100644 index 88b128a5..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/classadapter/Test.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.desgin.pattern.structural.adapter.classadapter; - -public abstract class Test { - public static void main(String[] args) { - Target target = new ConcreteTarget(); - target.request(); - - /** 现在,我们就来通过适配器类来进行实现 */ - Target adapterTarget = new Adapter(); - adapterTarget.request(); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/objectadapter/Adaptee.java b/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/objectadapter/Adaptee.java deleted file mode 100644 index 88f2a05a..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/objectadapter/Adaptee.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.desgin.pattern.structural.adapter.objectadapter; - -public class Adaptee { - public void adapteeRequest() { - System.out.println("被适配者的方法"); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/objectadapter/Adapter.java b/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/objectadapter/Adapter.java deleted file mode 100644 index faf77f52..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/objectadapter/Adapter.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.desgin.pattern.structural.adapter.objectadapter; - -public class Adapter implements Target { - - private Adaptee adaptee = new Adaptee(); - - @Override - public void request() { - adaptee.adapteeRequest(); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/objectadapter/ConcreteTarget.java b/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/objectadapter/ConcreteTarget.java deleted file mode 100644 index 90d1299b..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/objectadapter/ConcreteTarget.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.desgin.pattern.structural.adapter.objectadapter; - -/** - * 具体的实现类 - */ -public class ConcreteTarget implements Target { - @Override - public void request() { - System.out.println("ConcreteTarget目标方法"); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/objectadapter/Target.java b/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/objectadapter/Target.java deleted file mode 100644 index 3db60e96..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/objectadapter/Target.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.desgin.pattern.structural.adapter.objectadapter; - -public interface Target { - void request(); -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/objectadapter/Test.java b/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/objectadapter/Test.java deleted file mode 100644 index e33344d3..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/objectadapter/Test.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.desgin.pattern.structural.adapter.objectadapter; - -public class Test { - public static void main(String[] args) { - Target target = new ConcreteTarget(); - target.request(); - - /** 现在,我们就来通过适配器类来进行实现 */ - Target adapterTarget = new Adapter(); - adapterTarget.request(); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/bridge/ABCBank.java b/design-pattern/src/main/java/com/desgin/pattern/structural/bridge/ABCBank.java deleted file mode 100644 index 27f27774..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/structural/bridge/ABCBank.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.desgin.pattern.structural.bridge; - -public class ABCBank extends Bank { - /** - * 组合的时候,可以通过构造器的方式来进行注入也可以通过set方法的方式来进行注入 - * - * @param account - */ - public ABCBank(Account account) { - super(account); - } - - @Override - Account openAccount() { - System.out.println("打开中国农业银行账号"); - account.openAccount(); - return account; - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/bridge/Account.java b/design-pattern/src/main/java/com/desgin/pattern/structural/bridge/Account.java deleted file mode 100644 index 98d6a41a..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/structural/bridge/Account.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.desgin.pattern.structural.bridge; - -public interface Account { - /** - * 打开我们的账号,打开账号,就要返回账号 - */ - Account openAccount(); - - /** - * 打开我们的账号,查看为什么账户类型,是定期类型还是活期类型 - */ - void showAccountType(); - -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/bridge/Bank.java b/design-pattern/src/main/java/com/desgin/pattern/structural/bridge/Bank.java deleted file mode 100644 index 8aebd5ac..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/structural/bridge/Bank.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.desgin.pattern.structural.bridge; - -public abstract class Bank { - /** - * 只有子类能拿到这个Account的这个接口 - */ - protected Account account; - - /** - * 组合的时候,可以通过构造器的方式来进行注入也可以通过set方法的方式来进行注入 - */ - public Bank(Account account) { - this.account = account; - } - - /** - * 这里声明成和接口里面的方法名一致,只是方便理解,Bank里面的方法要委托给Account接口里面的方法 - */ - abstract Account openAccount(); - -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/bridge/DepositAccount.java b/design-pattern/src/main/java/com/desgin/pattern/structural/bridge/DepositAccount.java deleted file mode 100644 index 25f1f82e..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/structural/bridge/DepositAccount.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.desgin.pattern.structural.bridge; - -/** - * 定期的账号 - */ -public class DepositAccount implements Account { - @Override - public Account openAccount() { - System.out.println("打开定期账号"); - return new DepositAccount(); - } - - @Override - public void showAccountType() { - System.out.println("这是一个定期账号"); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/bridge/ICBCBank.java b/design-pattern/src/main/java/com/desgin/pattern/structural/bridge/ICBCBank.java deleted file mode 100644 index 30626ea2..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/structural/bridge/ICBCBank.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.desgin.pattern.structural.bridge; - -public class ICBCBank extends Bank { - /** - * 组合的时候,可以通过构造器的方式来进行注入也可以通过set方法的方式来进行注入 - * - * @param account - */ - public ICBCBank(Account account) { - super(account); - } - - @Override - Account openAccount() { - System.out.println("打开中国工商银行账号"); - account.openAccount(); - return account; - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/bridge/SavingAccount.java b/design-pattern/src/main/java/com/desgin/pattern/structural/bridge/SavingAccount.java deleted file mode 100644 index 8a0d9a11..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/structural/bridge/SavingAccount.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.desgin.pattern.structural.bridge; - -/** - * 活期账号 - */ -public class SavingAccount implements Account { - @Override - public Account openAccount() { - System.out.println("打开活期账号"); - return new SavingAccount(); - } - - @Override - public void showAccountType() { - System.out.println("这是一个活期账号"); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/bridge/Test.java b/design-pattern/src/main/java/com/desgin/pattern/structural/bridge/Test.java deleted file mode 100644 index 33d66189..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/structural/bridge/Test.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.desgin.pattern.structural.bridge; - -public class Test { - public static void main(String[] args) { - Bank icbcBank = new ICBCBank(new DepositAccount()); - Account icbcAccount = icbcBank.openAccount(); - icbcAccount.showAccountType(); - - Bank icbcBank2 = new ICBCBank(new SavingAccount()); - Account icbcAccount2 = icbcBank2.openAccount(); - icbcAccount2.showAccountType(); - - Bank abcBank = new ABCBank(new SavingAccount()); - Account abcAccount = abcBank.openAccount(); - abcAccount.showAccountType(); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/composite/CatalogComponent.java b/design-pattern/src/main/java/com/desgin/pattern/structural/composite/CatalogComponent.java deleted file mode 100644 index 88bf97b1..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/structural/composite/CatalogComponent.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.desgin.pattern.structural.composite; - -public abstract class CatalogComponent { - public void add(CatalogComponent catalogComponent) { - throw new UnsupportedOperationException("不支持添加操作"); - } - - public void remove(CatalogComponent catalogComponent) { - throw new UnsupportedOperationException("不支持删除操作"); - } - - public String getName(CatalogComponent catalogComponent) { - throw new UnsupportedOperationException("不支持获取名称操作"); - } - - public double getPrice(CatalogComponent catalogComponent) { - throw new UnsupportedOperationException("不支持获取价格操作"); - } - - public void print() { - throw new UnsupportedOperationException("不支持打印操作"); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/composite/Course.java b/design-pattern/src/main/java/com/desgin/pattern/structural/composite/Course.java deleted file mode 100644 index da23e21f..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/structural/composite/Course.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.desgin.pattern.structural.composite; - -public class Course extends CatalogComponent { - private String name; - private double price; - - public Course(String name, double price) { - this.name = name; - this.price = price; - } - - @Override - public String getName(CatalogComponent catalogComponent) { - return this.name; - } - - @Override - public double getPrice(CatalogComponent catalogComponent) { - return this.price; - } - - @Override - public void print() { - System.out.println("Course Name :" + name + " price" + price); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/composite/CourseCatalog.java b/design-pattern/src/main/java/com/desgin/pattern/structural/composite/CourseCatalog.java deleted file mode 100644 index 530a011b..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/structural/composite/CourseCatalog.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.desgin.pattern.structural.composite; - -import java.util.ArrayList; -import java.util.List; - -public class CourseCatalog extends CatalogComponent { - private List items = new ArrayList<>(); - - private String name; - private Integer level; - - public CourseCatalog(String name, Integer level) { - this.name = name; - this.level = level; - } - - @Override - public void add(CatalogComponent catalogComponent) { - items.add(catalogComponent); - } - - @Override - public void remove(CatalogComponent catalogComponent) { - items.remove(catalogComponent); - } - - @Override - public void print() { - System.out.println(this.name); - for (CatalogComponent catalogComponent : items) { - if (level != null) { - for (int i=0;i EMPLOYEE_MAP = new HashMap<>(); - - /** - * 享元工厂 - * - * @param department - * @return - */ - public static Employee getManager(String department) { - Manager manager = (Manager) EMPLOYEE_MAP.get(department); - if (manager == null) { - manager = new Manager(department); - System.out.print("创建部门经理" + department); - String reportContent = department + "部门汇报:此次报告的主要内容是......"; - manager.setReportContent(reportContent); - System.out.println(" 创建报告" + reportContent); - //享元工厂 - EMPLOYEE_MAP.put(department, manager); - } - return manager; - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/flyweight/Manager.java b/design-pattern/src/main/java/com/desgin/pattern/structural/flyweight/Manager.java deleted file mode 100644 index 1a9f6281..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/structural/flyweight/Manager.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.desgin.pattern.structural.flyweight; - -public class Manager implements Employee { - /** - * 内部状态 - */ - private String title = "部门经理"; - /** - * 外部状态 - */ - private String department; - private String reportContent; - - public Manager(String department) { - this.department = department; - } - - /** - * 我们可以在外部来重置年终报告 - */ - public void setReportContent(String reportContent) { - this.reportContent = reportContent; - } - - @Override - public void report() { - System.out.println(reportContent); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/flyweight/Test.java b/design-pattern/src/main/java/com/desgin/pattern/structural/flyweight/Test.java deleted file mode 100644 index c2ade7d0..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/structural/flyweight/Test.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.desgin.pattern.structural.flyweight; - -public class Test { - private static final String departments[] = {"RD","QA","PM","BD"}; - - public static void main(String[]args){ - for (int i = 0; i < 10; i++) { - String department = departments[(int) (Math.random() * departments.length)]; - Manager manager = (Manager) EmployeeFactory.getManager(department); - manager.report(); - } - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/IOrderDao.java b/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/IOrderDao.java deleted file mode 100644 index 84fec5c3..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/IOrderDao.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.desgin.pattern.structural.proxy; - -public interface IOrderDao { - int insert(Order order); -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/IOrderService.java b/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/IOrderService.java deleted file mode 100644 index 6ad40c8c..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/IOrderService.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.desgin.pattern.structural.proxy; - -public interface IOrderService { - /** 保存订单,参数为订单对象,返回值为生效行数 */ - int saveOrder(Order order); -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/Order.java b/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/Order.java deleted file mode 100644 index 9f5e3cb7..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/Order.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.desgin.pattern.structural.proxy; - -public class Order { - private Object orderInfo; - private Integer userId; - - public Object getOrderInfo() { - return orderInfo; - } - - public void setOrderInfo(Object orderInfo) { - this.orderInfo = orderInfo; - } - - public Integer getUserId() { - return userId; - } - - public void setUserId(Integer userId) { - this.userId = userId; - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/OrderDaoImpl.java b/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/OrderDaoImpl.java deleted file mode 100644 index bdad76e3..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/OrderDaoImpl.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.desgin.pattern.structural.proxy; - -public class OrderDaoImpl implements IOrderDao { - @Override - public int insert(Order order) { - System.out.println("Dao层添加order成功"); - return 1; - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/OrderServiceImpl.java b/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/OrderServiceImpl.java deleted file mode 100644 index 4cca5932..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/OrderServiceImpl.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.desgin.pattern.structural.proxy; - -public class OrderServiceImpl implements IOrderService { - - private IOrderDao iOrderDao; - - @Override - public int saveOrder(Order order) { - /** Spring会自己注入,我们这里就直接new出来了 */ - iOrderDao = new OrderDaoImpl(); - System.out.println("Service调用Dao层添加Order层"); - return iOrderDao.insert(order); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/db/DataSourceContextHolder.java b/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/db/DataSourceContextHolder.java deleted file mode 100644 index e31c35df..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/db/DataSourceContextHolder.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.desgin.pattern.structural.proxy.db; - -public class DataSourceContextHolder { - private static final ThreadLocal CONTEXT_HOLDER = new ThreadLocal<>(); - - public static void setDBType(String dbType) { - CONTEXT_HOLDER.set(dbType); - } - - public static String getDBType() { - return (String) CONTEXT_HOLDER.get(); - } - - public static void clearDBType() { - CONTEXT_HOLDER.remove(); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/db/DynamicDataSource.java b/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/db/DynamicDataSource.java deleted file mode 100644 index 05b6c1cd..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/db/DynamicDataSource.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.desgin.pattern.structural.proxy.db; - -import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; - -public class DynamicDataSource extends AbstractRoutingDataSource { - @Override - protected Object determineCurrentLookupKey() { - return DataSourceContextHolder.getDBType(); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/dynamicproxy/OrderServiceDynamicProxy.java b/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/dynamicproxy/OrderServiceDynamicProxy.java deleted file mode 100644 index 67e7b4af..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/dynamicproxy/OrderServiceDynamicProxy.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.desgin.pattern.structural.proxy.dynamicproxy; - -import com.desgin.pattern.structural.proxy.Order; -import com.desgin.pattern.structural.proxy.db.DataSourceContextHolder; - -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; - -/** - * Create by lastwhisper on 2019/2/10 - */ -public class OrderServiceDynamicProxy implements InvocationHandler { - - /** 这是目标类 */ - private Object target; - - /** 通过构造器把目标类注入进来 */ - public OrderServiceDynamicProxy(Object target) { - this.target = target; - } - - /** 进行绑定目标对象 */ - public Object bind() { - Class clazz = target.getClass(); - return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this); - } - - /** - * proxy:代理类代理的真实代理对象com.sun.proxy.$Proxy0 - * method:我们所要调用某个对象真实的方法的Method对象 - * args:指代代理对象方法传递的参数 - */ - @Override - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - Object argObject = args[0]; - beforeMethod(argObject); - Object object = method.invoke(target, args); - afterMethod(); - return object; - } - - public void beforeMethod(Object obj) { - int userId = 0; - System.out.println("动态代理before code"); - if (obj instanceof Order) { - Order order = (Order) obj; - userId = order.getUserId(); - } - /** 这里就是实现一个分库的功能,对userId取模2,这里就只会得到0或者是1 */ - int dbRouter = userId % 2; - System.out.println("动态代理分配到【db"+dbRouter+"】处理数据"); - //todo 设置dataSource; - DataSourceContextHolder.setDBType(String.valueOf(dbRouter)); - } - public void afterMethod() { - System.out.println("动态代理after code"); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/dynamicproxy/Test.java b/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/dynamicproxy/Test.java deleted file mode 100644 index c514b458..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/dynamicproxy/Test.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.desgin.pattern.structural.proxy.dynamicproxy; - -import com.desgin.pattern.structural.proxy.IOrderService; -import com.desgin.pattern.structural.proxy.Order; -import com.desgin.pattern.structural.proxy.OrderServiceImpl; - -public class Test { - public static void main(String[]args){ - Order order = new Order(); - order.setUserId(2); - /** 这里没有采用spring自动注入的方式,而是采用了直接new的方式 */ - IOrderService orderServiceDynamicProxy = (IOrderService) new OrderServiceDynamicProxy(new OrderServiceImpl()).bind(); - orderServiceDynamicProxy.saveOrder(order); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/my/dynamicproxy/Calculator.java b/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/my/dynamicproxy/Calculator.java deleted file mode 100644 index 54b26b10..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/my/dynamicproxy/Calculator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.desgin.pattern.structural.proxy.my.dynamicproxy; - -/** - * @author lastwhisper - */ -public interface Calculator { - int add(int a, int b); - int subtract(int a, int b); -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/my/dynamicproxy/CalculatorDynamicProxy.java b/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/my/dynamicproxy/CalculatorDynamicProxy.java deleted file mode 100644 index f4b61081..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/my/dynamicproxy/CalculatorDynamicProxy.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.desgin.pattern.structural.proxy.my.dynamicproxy; - -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; - -/** - * 动态代理 - * @author lastwhisper - */ -public class CalculatorDynamicProxy implements InvocationHandler { - // 目标类 - private Object target; - - // 代理类通过构造器接收目标对象(被代理类) - public CalculatorDynamicProxy(Object target) { - this.target = target; - } - - /** 获取目标对象 */ - public Object getProxy() { - Class clazz = target.getClass(); - return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this); - } - - /** - * proxy:代理类代理的真实代理对象com.sun.proxy.$Proxy0 - * method:我们所要调用某个对象真实的方法的Method对象 - * args:指代代理对象方法传递的参数 - */ - @Override - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - Object argObject = args[0]; - beforeMethod(); - Object object = method.invoke(target, args); - afterMethod(); - return object; - } - - public void beforeMethod() { - System.out.println("proxy代理,日志开始记录"); - } - - public void afterMethod() { - System.out.println("proxy代理,日志结束,已记录到数据库中"); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/my/dynamicproxy/CalculatorImpl.java b/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/my/dynamicproxy/CalculatorImpl.java deleted file mode 100644 index 64a66ab8..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/my/dynamicproxy/CalculatorImpl.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.desgin.pattern.structural.proxy.my.dynamicproxy; - -/** - * @author lastwhisper - */ -public class CalculatorImpl implements Calculator { - - @Override - public int add(int a, int b) { - int result = a + b; - return result; - } - - @Override - public int subtract(int a, int b) { - int result = a - b; - return result; - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/my/dynamicproxy/Client.java b/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/my/dynamicproxy/Client.java deleted file mode 100644 index 7a445068..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/my/dynamicproxy/Client.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.desgin.pattern.structural.proxy.my.dynamicproxy; - -/** - * @author lastwhisper - */ -public class Client { - public static void main(String[] args) { - Calculator calculator = (Calculator) new CalculatorDynamicProxy(new CalculatorImpl()).getProxy(); - System.out.println(calculator.add(1, 2)); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/my/hardcode/Calculator.java b/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/my/hardcode/Calculator.java deleted file mode 100644 index 8278ef64..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/my/hardcode/Calculator.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.desgin.pattern.structural.proxy.my.hardcode; -// 硬编码 -public class Calculator { - - //加 - public int add(int a, int b) { - System.out.println("add日志开始记录"); - int result = a + b; - System.out.println("add日志结束,已记录到数据库中"); - return result; - } - - //减 - public int subtract(int a, int b) { - System.out.println("subtract日志开始记录"); - int result = a - b; - System.out.println("subtract日志结束,已记录到数据库中"); - return result; - } - - //乘法、除法... -} \ No newline at end of file diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/my/staticproxy/Calculator.java b/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/my/staticproxy/Calculator.java deleted file mode 100644 index 562d1ba7..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/my/staticproxy/Calculator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.desgin.pattern.structural.proxy.my.staticproxy; - -/** - * @author lastwhisper - */ -public interface Calculator { - int add(int a, int b); - int subtract(int a, int b); -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/my/staticproxy/CalculatorImpl.java b/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/my/staticproxy/CalculatorImpl.java deleted file mode 100644 index e1cb4ac0..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/my/staticproxy/CalculatorImpl.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.desgin.pattern.structural.proxy.my.staticproxy; - -/** - * @author lastwhisper - */ -public class CalculatorImpl implements Calculator { - - @Override - public int add(int a, int b) { - int result = a + b; - return result; - } - - @Override - public int subtract(int a, int b) { - int result = a - b; - return result; - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/my/staticproxy/CalculatorStaticProxy.java b/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/my/staticproxy/CalculatorStaticProxy.java deleted file mode 100644 index b31c4dea..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/my/staticproxy/CalculatorStaticProxy.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.desgin.pattern.structural.proxy.my.staticproxy; - -/** - * 静态代理 - * @author lastwhisper - */ -public class CalculatorStaticProxy { - // 被代理类 - private Calculator calculator; - // 代理类通过构造器接收被代理类 - public CalculatorStaticProxy(Calculator calculator) { - this.calculator = calculator; - } - - public int proxyAdd(int a, int b) { - System.out.println("proxy代理,add日志开始记录"); - int result = calculator.add(a, b); - System.out.println("proxy代理,add日志结束,已记录到数据库中"); - return result; - } - - public int proxySubtract(int a, int b) { - System.out.println("proxy代理,subtract日志开始记录"); - int result = calculator.subtract(a, b); - System.out.println("proxy代理,subtract日志结束,已记录到数据库中"); - return result; - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/my/staticproxy/Client.java b/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/my/staticproxy/Client.java deleted file mode 100644 index 91faae34..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/my/staticproxy/Client.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.desgin.pattern.structural.proxy.my.staticproxy; - -/** - * @author lastwhisper - */ -public class Client { - public static void main(String[] args) { - CalculatorStaticProxy calculatorProxy = new CalculatorStaticProxy(new CalculatorImpl()); - int result = calculatorProxy.proxyAdd(5, 3); - - result = calculatorProxy.proxySubtract(5, 3); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/staticproxy/OrderServiceStaticProxy.java b/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/staticproxy/OrderServiceStaticProxy.java deleted file mode 100644 index 14233795..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/staticproxy/OrderServiceStaticProxy.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.desgin.pattern.structural.proxy.staticproxy; - -import com.desgin.pattern.structural.proxy.IOrderService; -import com.desgin.pattern.structural.proxy.Order; -import com.desgin.pattern.structural.proxy.OrderServiceImpl; -import com.desgin.pattern.structural.proxy.db.DataSourceContextHolder; - -public class OrderServiceStaticProxy { - /** 在代理类里面注入目标对象 */ - private IOrderService iOrderService; - - /** 我们要在这静态代理类里面增强这个方法 */ - public int saveOrder(Order order){ - beforeMethod(order); - /** 如果这里有spring容器的话,就不用显示的new了 */ - iOrderService = new OrderServiceImpl(); - int result = iOrderService.saveOrder(order); - afterMethod(); - return result; - } - - /** 我们要增强,我们就来写上一个before和after */ - private void beforeMethod(Order order){ - int userId = order.getUserId(); - /** 这里就是实现一个分库的功能,对userId取模2,这里就只会得到0或者是1 */ - int dbRouter = userId % 2; - System.out.println("静态代理分配到【db"+dbRouter+"】处理数据"); - - //todo 设置dataSource; - DataSourceContextHolder.setDBType("db"+dbRouter); - System.out.println("静态代理 before code"); - } - - private void afterMethod(){ - System.out.println("静态代理 after code"); - } -} diff --git a/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/staticproxy/Test.java b/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/staticproxy/Test.java deleted file mode 100644 index 6abc0f70..00000000 --- a/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/staticproxy/Test.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.desgin.pattern.structural.proxy.staticproxy; - -import com.desgin.pattern.structural.proxy.Order; - -public class Test { - public static void main(String[]args){ - Order order = new Order(); - order.setUserId(0); - /** 这里没有采用spring自动注入的方式,而是采用了直接new的方式 */ - OrderServiceStaticProxy orderServiceStaticProxy = new OrderServiceStaticProxy(); - orderServiceStaticProxy.saveOrder(order); - } -} diff --git a/design-pattern/src/main/java/com/desgin/principle/demeter/Boss.java b/design-pattern/src/main/java/com/desgin/principle/demeter/Boss.java deleted file mode 100644 index 9f4b88be..00000000 --- a/design-pattern/src/main/java/com/desgin/principle/demeter/Boss.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.desgin.principle.demeter; - -import java.util.ArrayList; -import java.util.List; - -/** - * Create by lastwhisper on 2019/1/22 - */ -public class Boss { - public void commandCheckNumber(TeamLeader teamLeader) { - teamLeader.checkNumberOfCourse(); - } -} diff --git a/design-pattern/src/main/java/com/desgin/principle/demeter/Course.java b/design-pattern/src/main/java/com/desgin/principle/demeter/Course.java deleted file mode 100644 index ff253858..00000000 --- a/design-pattern/src/main/java/com/desgin/principle/demeter/Course.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.desgin.principle.demeter; - -/** - * Create by lastwhisper on 2019/1/22 - */ -public class Course { -} diff --git a/design-pattern/src/main/java/com/desgin/principle/demeter/TeamLeader.java b/design-pattern/src/main/java/com/desgin/principle/demeter/TeamLeader.java deleted file mode 100644 index 5f2fafd0..00000000 --- a/design-pattern/src/main/java/com/desgin/principle/demeter/TeamLeader.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.desgin.principle.demeter; - -import java.util.ArrayList; -import java.util.List; - -/** - * Create by lastwhisper on 2019/1/22 - */ -public class TeamLeader { - public void checkNumberOfCourse(){ - List courseList = new ArrayList(); - for(int i =0;i<20 ;i++){ - courseList.add(new Course()); - } - System.out.println("在线课程数量:"+courseList.size()); - } -} diff --git a/design-pattern/src/main/java/com/desgin/principle/demeter/Test.java b/design-pattern/src/main/java/com/desgin/principle/demeter/Test.java deleted file mode 100644 index ce9edd1f..00000000 --- a/design-pattern/src/main/java/com/desgin/principle/demeter/Test.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.desgin.principle.demeter; - -/** - * Create by lastwhisper on 2019/1/22 - */ -public class Test { - public static void main(String[] args){ - Boss boss = new Boss(); - TeamLeader teamLeader = new TeamLeader(); - boss.commandCheckNumber(teamLeader); - } -} diff --git a/design-pattern/src/main/java/com/desgin/principle/dependenceinverson/FECourse.java b/design-pattern/src/main/java/com/desgin/principle/dependenceinverson/FECourse.java deleted file mode 100644 index 4a43c826..00000000 --- a/design-pattern/src/main/java/com/desgin/principle/dependenceinverson/FECourse.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.desgin.principle.dependenceinverson; - -/** - * Create by lastwhisper on 2019/1/22 - */ -public class FECourse implements ICourse { - public void studyCourse() { - System.out.println("person在学习前端课程"); - } -} diff --git a/design-pattern/src/main/java/com/desgin/principle/dependenceinverson/ICourse.java b/design-pattern/src/main/java/com/desgin/principle/dependenceinverson/ICourse.java deleted file mode 100644 index 8c298e56..00000000 --- a/design-pattern/src/main/java/com/desgin/principle/dependenceinverson/ICourse.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.desgin.principle.dependenceinverson; - -/** - * Create by lastwhisper on 2019/1/22 - */ -public interface ICourse { - void studyCourse(); -} diff --git a/design-pattern/src/main/java/com/desgin/principle/dependenceinverson/JavaCourse.java b/design-pattern/src/main/java/com/desgin/principle/dependenceinverson/JavaCourse.java deleted file mode 100644 index 3b2d7feb..00000000 --- a/design-pattern/src/main/java/com/desgin/principle/dependenceinverson/JavaCourse.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.desgin.principle.dependenceinverson; - -/** - * Create by lastwhisper on 2019/1/22 - */ -public class JavaCourse implements ICourse { - public void studyCourse() { - System.out.println("person在学习java课程"); - } -} diff --git a/design-pattern/src/main/java/com/desgin/principle/dependenceinverson/Person.java b/design-pattern/src/main/java/com/desgin/principle/dependenceinverson/Person.java deleted file mode 100644 index ae925e37..00000000 --- a/design-pattern/src/main/java/com/desgin/principle/dependenceinverson/Person.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.desgin.principle.dependenceinverson; - -/** - * Create by lastwhisper on 2019/1/22 - */ -public class Person { -// public void studyJavaCourse(){ -// System.out.println("person在学习java课程"); -// } -// -// public void studyFECourse(){ -// System.out.println("person在学习前端课程"); -// } -// -// public void studyPythonCourse(){ -// System.out.println("person在学习Python课程"); -// } - - private ICourse iCourse; - - - public void setiCourse(ICourse iCourse) { - this.iCourse = iCourse; - } - - // v2 -// public void studyImoocCourse(ICourse iCourse){ -// iCourse.studyCourse(); -// } - - public void studyImoocCourse(){ - iCourse.studyCourse(); - } - - -} diff --git a/design-pattern/src/main/java/com/desgin/principle/dependenceinverson/PythonCourse.java b/design-pattern/src/main/java/com/desgin/principle/dependenceinverson/PythonCourse.java deleted file mode 100644 index 3998487e..00000000 --- a/design-pattern/src/main/java/com/desgin/principle/dependenceinverson/PythonCourse.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.desgin.principle.dependenceinverson; - -/** - * Create by lastwhisper on 2019/1/22 - */ -public class PythonCourse implements ICourse { - public void studyCourse() { - System.out.println("person在学习Python课程"); - } -} diff --git a/design-pattern/src/main/java/com/desgin/principle/dependenceinverson/Test.java b/design-pattern/src/main/java/com/desgin/principle/dependenceinverson/Test.java deleted file mode 100644 index ba911330..00000000 --- a/design-pattern/src/main/java/com/desgin/principle/dependenceinverson/Test.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.desgin.principle.dependenceinverson; - -/** - * Create by lastwhisper on 2019/1/22 - */ -public class Test { - //v 1 -// public static void main(String[] args){ -// //高层次模块(Test)依赖于低层次模块(Person) -// Person person = new Person(); -// person.studyJavaCourse(); -// person.studyFECourse(); -// } - //v2 -// public static void main(String[] args){ -// Person person = new Person(); -// person.studyImoocCourse(new JavaCourse()); -// person.studyImoocCourse(new FECourse()); -// person.studyImoocCourse(new PythonCourse()); -// } - //v3 -// public static void main(String[] args){ -// Person person = new Person(new JavaCourse()); -// person.studyImoocCourse(); -// } - public static void main(String[] args) { - Person person = new Person(); - person.setiCourse(new JavaCourse()); - person.studyImoocCourse(); - person.setiCourse(new FECourse()); - person.studyImoocCourse(); - person.setiCourse(new PythonCourse()); - person.studyImoocCourse(); - } -} diff --git a/design-pattern/src/main/java/com/desgin/principle/interfacesegregation/Bird.java b/design-pattern/src/main/java/com/desgin/principle/interfacesegregation/Bird.java deleted file mode 100644 index 8d501e2e..00000000 --- a/design-pattern/src/main/java/com/desgin/principle/interfacesegregation/Bird.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.desgin.principle.interfacesegregation; - -/** - * Create by lastwhisper on 2019/1/22 - */ -public class Bird implements IAnimalAction { - @Override - public void eat() { - - } - - @Override - public void fly() { - - } - - @Override - public void swim() { - - } -} diff --git a/design-pattern/src/main/java/com/desgin/principle/interfacesegregation/Dog.java b/design-pattern/src/main/java/com/desgin/principle/interfacesegregation/Dog.java deleted file mode 100644 index 9843085f..00000000 --- a/design-pattern/src/main/java/com/desgin/principle/interfacesegregation/Dog.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.desgin.principle.interfacesegregation; - -/** - * Create by lastwhisper on 2019/1/22 - */ -public class Dog implements IEatAnimalAction,ISwimAnimalAction { - - - @Override - public void eat() { - - } - - @Override - public void swim() { - - } -} diff --git a/design-pattern/src/main/java/com/desgin/principle/interfacesegregation/IAnimalAction.java b/design-pattern/src/main/java/com/desgin/principle/interfacesegregation/IAnimalAction.java deleted file mode 100644 index 37ea4e6d..00000000 --- a/design-pattern/src/main/java/com/desgin/principle/interfacesegregation/IAnimalAction.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.desgin.principle.interfacesegregation; - -/** - * Create by lastwhisper on 2019/1/22 - */ -public interface IAnimalAction { - void eat(); - void fly(); - void swim(); -} diff --git a/design-pattern/src/main/java/com/desgin/principle/interfacesegregation/IEatAnimalAction.java b/design-pattern/src/main/java/com/desgin/principle/interfacesegregation/IEatAnimalAction.java deleted file mode 100644 index de2dee10..00000000 --- a/design-pattern/src/main/java/com/desgin/principle/interfacesegregation/IEatAnimalAction.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.desgin.principle.interfacesegregation; - -/** - * Create by lastwhisper on 2019/1/22 - */ -public interface IEatAnimalAction { - void eat(); -} diff --git a/design-pattern/src/main/java/com/desgin/principle/interfacesegregation/IFlyAnimalAction.java b/design-pattern/src/main/java/com/desgin/principle/interfacesegregation/IFlyAnimalAction.java deleted file mode 100644 index 6696710f..00000000 --- a/design-pattern/src/main/java/com/desgin/principle/interfacesegregation/IFlyAnimalAction.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.desgin.principle.interfacesegregation; - -/** - * Create by lastwhisper on 2019/1/22 - */ -public interface IFlyAnimalAction { - void fly(); -} diff --git a/design-pattern/src/main/java/com/desgin/principle/interfacesegregation/ISwimAnimalAction.java b/design-pattern/src/main/java/com/desgin/principle/interfacesegregation/ISwimAnimalAction.java deleted file mode 100644 index e30b3dfb..00000000 --- a/design-pattern/src/main/java/com/desgin/principle/interfacesegregation/ISwimAnimalAction.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.desgin.principle.interfacesegregation; - -/** - * Create by lastwhisper on 2019/1/22 - */ -public interface ISwimAnimalAction { - void swim(); -} diff --git a/design-pattern/src/main/java/com/desgin/principle/openclose/ICourse.java b/design-pattern/src/main/java/com/desgin/principle/openclose/ICourse.java deleted file mode 100644 index 4c9564c7..00000000 --- a/design-pattern/src/main/java/com/desgin/principle/openclose/ICourse.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.desgin.principle.openclose; - -/** - * Create by lastwhisper on 2019/1/22 - */ -public interface ICourse { - Integer getId(); - String getName(); - Double getPrice(); - //Double getDiscountPrice(); -} diff --git a/design-pattern/src/main/java/com/desgin/principle/openclose/JavaCourse.java b/design-pattern/src/main/java/com/desgin/principle/openclose/JavaCourse.java deleted file mode 100644 index 2e578e98..00000000 --- a/design-pattern/src/main/java/com/desgin/principle/openclose/JavaCourse.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.desgin.principle.openclose; - -/** - * Create by lastwhisper on 2019/1/22 - */ -public class JavaCourse implements ICourse { - - private Integer Id; - private String name; - private Double price; - - public JavaCourse(Integer id, String name, Double price) { - Id = id; - this.name = name; - this.price = price; - } - - public Integer getId() { - return Id; - } - - public String getName() { - return name; - } - - public Double getPrice() { - return price; - } - -// public Double getDiscountPrice() { -// return this.price*0.8; -// } -} diff --git a/design-pattern/src/main/java/com/desgin/principle/openclose/JavaDiscountCourse.java b/design-pattern/src/main/java/com/desgin/principle/openclose/JavaDiscountCourse.java deleted file mode 100644 index 5243f8f5..00000000 --- a/design-pattern/src/main/java/com/desgin/principle/openclose/JavaDiscountCourse.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.desgin.principle.openclose; - -/** - * Create by lastwhisper on 2019/1/22 - */ -public class JavaDiscountCourse extends JavaCourse { - public JavaDiscountCourse(Integer id, String name, Double price) { - super(id, name, price); - } - - public Double getOriginPrice(){ - return super.getPrice(); - } - - @Override - public Double getPrice() { - //如果当前价格大于300打8折;大于400打7折 - return super.getPrice()*0.8; - } -} diff --git a/design-pattern/src/main/java/com/desgin/principle/openclose/Test.java b/design-pattern/src/main/java/com/desgin/principle/openclose/Test.java deleted file mode 100644 index 4ae6b585..00000000 --- a/design-pattern/src/main/java/com/desgin/principle/openclose/Test.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.desgin.principle.openclose; - -/** - * Create by lastwhisper on 2019/1/22 - */ -public class Test { - public static void main(String[] args) { -// ICourse javaCourse = new JavaCourse(96,"javaee",348d); -// System.out.println("课程ID:"+javaCourse.getId()+" 课程名称:"+javaCourse.getName()+" 课程价格:"+javaCourse.getPrice()); - - ICourse iCourse = new JavaDiscountCourse(96,"javaee",348d); - JavaDiscountCourse javaCourse = (JavaDiscountCourse) iCourse; - System.out.println("课程ID:"+javaCourse.getId()+" 课程名称:"+javaCourse.getName()+" 课程原价价格:"+javaCourse.getOriginPrice()+" 课程打折价格:"+javaCourse.getPrice()); - - } -} - diff --git a/design-pattern/src/main/java/com/desgin/principle/singleresponsibility/Bird.java b/design-pattern/src/main/java/com/desgin/principle/singleresponsibility/Bird.java deleted file mode 100644 index c0cdb0b0..00000000 --- a/design-pattern/src/main/java/com/desgin/principle/singleresponsibility/Bird.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.desgin.principle.singleresponsibility; - -/** - * Create by lastwhisper on 2019/1/22 - */ -public class Bird { - public void mainMoveMode(String birdName){ - if("鸵鸟".equals(birdName)){ - System.out.println(birdName + "用脚走"); - }else { - System.out.println(birdName + "用翅膀飞"); - } - } -} diff --git a/design-pattern/src/main/java/com/desgin/principle/singleresponsibility/CourseImpl.java b/design-pattern/src/main/java/com/desgin/principle/singleresponsibility/CourseImpl.java deleted file mode 100644 index fb18245f..00000000 --- a/design-pattern/src/main/java/com/desgin/principle/singleresponsibility/CourseImpl.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.desgin.principle.singleresponsibility; - -/** - * Create by lastwhisper on 2019/1/22 - */ -public class CourseImpl implements ICourseManager,ICourseContent { - public String getCourseName() { - return null; - } - - public byte[] getCourseVideo() { - return new byte[0]; - } - - public void studyCourse() { - - } - - public void refundCourse() { - - } -} diff --git a/design-pattern/src/main/java/com/desgin/principle/singleresponsibility/FlyBird.java b/design-pattern/src/main/java/com/desgin/principle/singleresponsibility/FlyBird.java deleted file mode 100644 index 3bc20a21..00000000 --- a/design-pattern/src/main/java/com/desgin/principle/singleresponsibility/FlyBird.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.desgin.principle.singleresponsibility; - -/** - * Create by lastwhisper on 2019/1/22 - */ -public class FlyBird { - public void mainMoveMode(String birdName) { - System.out.println(birdName + "用翅膀飞"); - } -} diff --git a/design-pattern/src/main/java/com/desgin/principle/singleresponsibility/ICourse.java b/design-pattern/src/main/java/com/desgin/principle/singleresponsibility/ICourse.java deleted file mode 100644 index f0c0c46a..00000000 --- a/design-pattern/src/main/java/com/desgin/principle/singleresponsibility/ICourse.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.desgin.principle.singleresponsibility; - -/** - * Create by lastwhisper on 2019/1/22 - */ -public interface ICourse { - String getCourseName(); - - byte[] getCourseVideo(); - - void studyCourse(); - - void refundCourse(); -} diff --git a/design-pattern/src/main/java/com/desgin/principle/singleresponsibility/ICourseContent.java b/design-pattern/src/main/java/com/desgin/principle/singleresponsibility/ICourseContent.java deleted file mode 100644 index e56d9caf..00000000 --- a/design-pattern/src/main/java/com/desgin/principle/singleresponsibility/ICourseContent.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.desgin.principle.singleresponsibility; - -/** - * Create by lastwhisper on 2019/1/22 - */ -public interface ICourseContent { - String getCourseName(); - - byte[] getCourseVideo(); -} diff --git a/design-pattern/src/main/java/com/desgin/principle/singleresponsibility/ICourseManager.java b/design-pattern/src/main/java/com/desgin/principle/singleresponsibility/ICourseManager.java deleted file mode 100644 index a8a6190f..00000000 --- a/design-pattern/src/main/java/com/desgin/principle/singleresponsibility/ICourseManager.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.desgin.principle.singleresponsibility; - -/** - * Create by lastwhisper on 2019/1/22 - */ -public interface ICourseManager { - void studyCourse(); - - void refundCourse(); -} diff --git a/design-pattern/src/main/java/com/desgin/principle/singleresponsibility/Test.java b/design-pattern/src/main/java/com/desgin/principle/singleresponsibility/Test.java deleted file mode 100644 index ee57600b..00000000 --- a/design-pattern/src/main/java/com/desgin/principle/singleresponsibility/Test.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.desgin.principle.singleresponsibility; - -/** - * Create by lastwhisper on 2019/1/22 - */ -public class Test { - public static void main(String[] args){ -// Bird bird = new Bird(); -// bird.mainMoveMode("大雁"); -// bird.mainMoveMode("鸵鸟"); - FlyBird flyBird = new FlyBird(); - flyBird.mainMoveMode("大雁"); - WalkBird walkBird = new WalkBird(); - walkBird.mainMoveMode("鸵鸟"); - } -} diff --git a/design-pattern/src/main/java/com/desgin/principle/singleresponsibility/WalkBird.java b/design-pattern/src/main/java/com/desgin/principle/singleresponsibility/WalkBird.java deleted file mode 100644 index 62802a0e..00000000 --- a/design-pattern/src/main/java/com/desgin/principle/singleresponsibility/WalkBird.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.desgin.principle.singleresponsibility; - -/** - * Create by lastwhisper on 2019/1/22 - */ -public class WalkBird { - public void mainMoveMode(String birdName) { - System.out.println(birdName + "用脚走"); - } -} diff --git "a/design-pattern/uml/\350\256\276\350\256\241\346\250\241\345\274\217.mdj" "b/design-pattern/uml/\350\256\276\350\256\241\346\250\241\345\274\217.mdj" deleted file mode 100644 index dbb2a04b..00000000 --- "a/design-pattern/uml/\350\256\276\350\256\241\346\250\241\345\274\217.mdj" +++ /dev/null @@ -1,31890 +0,0 @@ -{ - "_type": "Project", - "_id": "AAAAAAFF+h6SjaM2Hec=", - "name": "设计模式", - "ownedElements": [ - { - "_type": "UMLModel", - "_id": "AAAAAAFq+IemIiECQeI=", - "_parent": { - "$ref": "AAAAAAFF+h6SjaM2Hec=" - }, - "name": "创建型模式——抽象工厂", - "ownedElements": [ - { - "_type": "UMLClassDiagram", - "_id": "AAAAAAFq+IemIiEDhm8=", - "_parent": { - "$ref": "AAAAAAFq+IemIiECQeI=" - }, - "name": "抽象工厂", - "ownedViews": [ - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+MxTxiFMCGw=", - "_parent": { - "$ref": "AAAAAAFq+IemIiEDhm8=" - }, - "model": { - "$ref": "AAAAAAFq+MxTxiFKDlo=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+MxTxiFNwuw=", - "_parent": { - "$ref": "AAAAAAFq+MxTxiFMCGw=" - }, - "model": { - "$ref": "AAAAAAFq+MxTxiFKDlo=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+MxTxiFOpHc=", - "_parent": { - "$ref": "AAAAAAFq+MxTxiFNwuw=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -240, - "top": 48, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+MxTxiFPsVA=", - "_parent": { - "$ref": "AAAAAAFq+MxTxiFNwuw=" - }, - "font": "Arial;13;1", - "left": 277, - "top": 183, - "width": 87, - "height": 13, - "text": "Client" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+MxTxiFQMuc=", - "_parent": { - "$ref": "AAAAAAFq+MxTxiFNwuw=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -240, - "top": 48, - "width": 220.27001953125, - "height": 13, - "text": "(from 创建型模式——抽象工厂)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+MxTxiFR8vc=", - "_parent": { - "$ref": "AAAAAAFq+MxTxiFNwuw=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -240, - "top": 48, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 272, - "top": 176, - "width": 97, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+MxTxiFOpHc=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+MxTxiFPsVA=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+MxTxiFQMuc=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+MxTxiFR8vc=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+MxTxiFSlxM=", - "_parent": { - "$ref": "AAAAAAFq+MxTxiFMCGw=" - }, - "model": { - "$ref": "AAAAAAFq+MxTxiFKDlo=" - }, - "font": "Arial;13;0", - "left": 272, - "top": 201, - "width": 97, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+MxTxiFT9Iw=", - "_parent": { - "$ref": "AAAAAAFq+MxTxiFMCGw=" - }, - "model": { - "$ref": "AAAAAAFq+MxTxiFKDlo=" - }, - "font": "Arial;13;0", - "left": 272, - "top": 211, - "width": 97, - "height": 10 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+MxTxiFUiS0=", - "_parent": { - "$ref": "AAAAAAFq+MxTxiFMCGw=" - }, - "model": { - "$ref": "AAAAAAFq+MxTxiFKDlo=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -120, - "top": 24, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+MxTxiFVxmY=", - "_parent": { - "$ref": "AAAAAAFq+MxTxiFMCGw=" - }, - "model": { - "$ref": "AAAAAAFq+MxTxiFKDlo=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -120, - "top": 24, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 272, - "top": 176, - "width": 97, - "height": 65, - "nameCompartment": { - "$ref": "AAAAAAFq+MxTxiFNwuw=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+MxTxiFSlxM=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+MxTxiFT9Iw=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+MxTxiFUiS0=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+MxTxiFVxmY=" - } - }, - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+MyJUyF4220=", - "_parent": { - "$ref": "AAAAAAFq+IemIiEDhm8=" - }, - "model": { - "$ref": "AAAAAAFq+MyJUiF2WzY=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+MyJUyF5A74=", - "_parent": { - "$ref": "AAAAAAFq+MyJUyF4220=" - }, - "model": { - "$ref": "AAAAAAFq+MyJUiF2WzY=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+MyJUyF6CbM=", - "_parent": { - "$ref": "AAAAAAFq+MyJUyF5A74=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -16, - "top": -80, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+MyJVCF7aGw=", - "_parent": { - "$ref": "AAAAAAFq+MyJUyF5A74=" - }, - "font": "Arial;13;1", - "left": 117, - "top": 279, - "width": 119, - "height": 13, - "text": "AbstractFactory" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+MyJVCF8clg=", - "_parent": { - "$ref": "AAAAAAFq+MyJUyF5A74=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -16, - "top": -80, - "width": 220.27001953125, - "height": 13, - "text": "(from 创建型模式——抽象工厂)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+MyJVCF94UY=", - "_parent": { - "$ref": "AAAAAAFq+MyJUyF5A74=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -16, - "top": -80, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 112, - "top": 272, - "width": 129, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+MyJUyF6CbM=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+MyJVCF7aGw=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+MyJVCF8clg=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+MyJVCF94UY=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+MyJVCF+yMI=", - "_parent": { - "$ref": "AAAAAAFq+MyJUyF4220=" - }, - "model": { - "$ref": "AAAAAAFq+MyJUiF2WzY=" - }, - "font": "Arial;13;0", - "left": 112, - "top": 297, - "width": 129, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+MyJVCF/LIs=", - "_parent": { - "$ref": "AAAAAAFq+MyJUyF4220=" - }, - "model": { - "$ref": "AAAAAAFq+MyJUiF2WzY=" - }, - "font": "Arial;13;0", - "left": 112, - "top": 307, - "width": 129, - "height": 10 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+MyJVCGA9Xw=", - "_parent": { - "$ref": "AAAAAAFq+MyJUyF4220=" - }, - "model": { - "$ref": "AAAAAAFq+MyJUiF2WzY=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -8, - "top": -40, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+MyJVCGBDV8=", - "_parent": { - "$ref": "AAAAAAFq+MyJUyF4220=" - }, - "model": { - "$ref": "AAAAAAFq+MyJUiF2WzY=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -8, - "top": -40, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 112, - "top": 272, - "width": 129, - "height": 65, - "nameCompartment": { - "$ref": "AAAAAAFq+MyJUyF5A74=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+MyJVCF+yMI=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+MyJVCF/LIs=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+MyJVCGA9Xw=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+MyJVCGBDV8=" - } - }, - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+MyPFCGhBCg=", - "_parent": { - "$ref": "AAAAAAFq+IemIiEDhm8=" - }, - "model": { - "$ref": "AAAAAAFq+MyPEyGffG0=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+MyPFCGiJ5k=", - "_parent": { - "$ref": "AAAAAAFq+MyPFCGhBCg=" - }, - "model": { - "$ref": "AAAAAAFq+MyPEyGffG0=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+MyPFCGjKfA=", - "_parent": { - "$ref": "AAAAAAFq+MyPFCGiJ5k=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -368, - "top": -112, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+MyPFCGkWAE=", - "_parent": { - "$ref": "AAAAAAFq+MyPFCGiJ5k=" - }, - "font": "Arial;13;1", - "left": 397, - "top": 279, - "width": 127, - "height": 13, - "text": "AbstractProduct" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+MyPFCGl/K4=", - "_parent": { - "$ref": "AAAAAAFq+MyPFCGiJ5k=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -368, - "top": -112, - "width": 220.27001953125, - "height": 13, - "text": "(from 创建型模式——抽象工厂)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+MyPFCGmgg8=", - "_parent": { - "$ref": "AAAAAAFq+MyPFCGiJ5k=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -368, - "top": -112, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 392, - "top": 272, - "width": 137, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+MyPFCGjKfA=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+MyPFCGkWAE=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+MyPFCGl/K4=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+MyPFCGmgg8=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+MyPFCGn4mQ=", - "_parent": { - "$ref": "AAAAAAFq+MyPFCGhBCg=" - }, - "model": { - "$ref": "AAAAAAFq+MyPEyGffG0=" - }, - "font": "Arial;13;0", - "left": 392, - "top": 297, - "width": 137, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+MyPFCGoWVg=", - "_parent": { - "$ref": "AAAAAAFq+MyPFCGhBCg=" - }, - "model": { - "$ref": "AAAAAAFq+MyPEyGffG0=" - }, - "font": "Arial;13;0", - "left": 392, - "top": 307, - "width": 137, - "height": 10 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+MyPFCGpy5o=", - "_parent": { - "$ref": "AAAAAAFq+MyPFCGhBCg=" - }, - "model": { - "$ref": "AAAAAAFq+MyPEyGffG0=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -184, - "top": -56, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+MyPFCGqrlc=", - "_parent": { - "$ref": "AAAAAAFq+MyPFCGhBCg=" - }, - "model": { - "$ref": "AAAAAAFq+MyPEyGffG0=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -184, - "top": -56, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 392, - "top": 272, - "width": 137, - "height": 65, - "nameCompartment": { - "$ref": "AAAAAAFq+MyPFCGiJ5k=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+MyPFCGn4mQ=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+MyPFCGoWVg=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+MyPFCGpy5o=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+MyPFCGqrlc=" - } - }, - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+MyWGiHKbBs=", - "_parent": { - "$ref": "AAAAAAFq+IemIiEDhm8=" - }, - "model": { - "$ref": "AAAAAAFq+MyWGiHISsM=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+MyWGyHLW1w=", - "_parent": { - "$ref": "AAAAAAFq+MyWGiHKbBs=" - }, - "model": { - "$ref": "AAAAAAFq+MyWGiHISsM=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+MyWGyHMYJw=", - "_parent": { - "$ref": "AAAAAAFq+MyWGyHLW1w=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 544, - "top": -128, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+MyWGyHNONg=", - "_parent": { - "$ref": "AAAAAAFq+MyWGyHLW1w=" - }, - "font": "Arial;13;1", - "left": 405, - "top": 407, - "width": 119, - "height": 13, - "text": "ConcreteFactory" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+MyWGyHOe4A=", - "_parent": { - "$ref": "AAAAAAFq+MyWGyHLW1w=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 544, - "top": -128, - "width": 220.27001953125, - "height": 13, - "text": "(from 创建型模式——抽象工厂)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+MyWGyHPo1E=", - "_parent": { - "$ref": "AAAAAAFq+MyWGyHLW1w=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 544, - "top": -128, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 400, - "top": 400, - "width": 129, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+MyWGyHMYJw=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+MyWGyHNONg=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+MyWGyHOe4A=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+MyWGyHPo1E=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+MyWGyHQuJo=", - "_parent": { - "$ref": "AAAAAAFq+MyWGiHKbBs=" - }, - "model": { - "$ref": "AAAAAAFq+MyWGiHISsM=" - }, - "font": "Arial;13;0", - "left": 400, - "top": 425, - "width": 129, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+MyWGyHRpag=", - "_parent": { - "$ref": "AAAAAAFq+MyWGiHKbBs=" - }, - "model": { - "$ref": "AAAAAAFq+MyWGiHISsM=" - }, - "font": "Arial;13;0", - "left": 400, - "top": 435, - "width": 129, - "height": 10 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+MyWGyHSQTU=", - "_parent": { - "$ref": "AAAAAAFq+MyWGiHKbBs=" - }, - "model": { - "$ref": "AAAAAAFq+MyWGiHISsM=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 272, - "top": -64, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+MyWGyHTgUg=", - "_parent": { - "$ref": "AAAAAAFq+MyWGiHKbBs=" - }, - "model": { - "$ref": "AAAAAAFq+MyWGiHISsM=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 272, - "top": -64, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 400, - "top": 400, - "width": 129, - "height": 65, - "nameCompartment": { - "$ref": "AAAAAAFq+MyWGyHLW1w=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+MyWGyHQuJo=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+MyWGyHRpag=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+MyWGyHSQTU=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+MyWGyHTgUg=" - } - }, - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+MybgSHzCss=", - "_parent": { - "$ref": "AAAAAAFq+IemIiEDhm8=" - }, - "model": { - "$ref": "AAAAAAFq+MybgSHxJf0=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+MybgSH0yJ0=", - "_parent": { - "$ref": "AAAAAAFq+MybgSHzCss=" - }, - "model": { - "$ref": "AAAAAAFq+MybgSHxJf0=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+MybgSH1W+8=", - "_parent": { - "$ref": "AAAAAAFq+MybgSH0yJ0=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -992, - "top": -208, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+MybgSH2evg=", - "_parent": { - "$ref": "AAAAAAFq+MybgSH0yJ0=" - }, - "font": "Arial;13;1", - "left": 117, - "top": 407, - "width": 119, - "height": 13, - "text": "ConcreteProduct" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+MybgSH3/NM=", - "_parent": { - "$ref": "AAAAAAFq+MybgSH0yJ0=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -992, - "top": -208, - "width": 220.27001953125, - "height": 13, - "text": "(from 创建型模式——抽象工厂)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+MybgSH4QHE=", - "_parent": { - "$ref": "AAAAAAFq+MybgSH0yJ0=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -992, - "top": -208, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 112, - "top": 400, - "width": 129, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+MybgSH1W+8=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+MybgSH2evg=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+MybgSH3/NM=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+MybgSH4QHE=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+MybgSH5Q0M=", - "_parent": { - "$ref": "AAAAAAFq+MybgSHzCss=" - }, - "model": { - "$ref": "AAAAAAFq+MybgSHxJf0=" - }, - "font": "Arial;13;0", - "left": 112, - "top": 425, - "width": 129, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+MybgSH63uc=", - "_parent": { - "$ref": "AAAAAAFq+MybgSHzCss=" - }, - "model": { - "$ref": "AAAAAAFq+MybgSHxJf0=" - }, - "font": "Arial;13;0", - "left": 112, - "top": 435, - "width": 129, - "height": 10 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+MybgSH7uX0=", - "_parent": { - "$ref": "AAAAAAFq+MybgSHzCss=" - }, - "model": { - "$ref": "AAAAAAFq+MybgSHxJf0=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -496, - "top": -104, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+MybgSH8XqQ=", - "_parent": { - "$ref": "AAAAAAFq+MybgSHzCss=" - }, - "model": { - "$ref": "AAAAAAFq+MybgSHxJf0=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -496, - "top": -104, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 112, - "top": 400, - "width": 129, - "height": 65, - "nameCompartment": { - "$ref": "AAAAAAFq+MybgSH0yJ0=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+MybgSH5Q0M=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+MybgSH63uc=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+MybgSH7uX0=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+MybgSH8XqQ=" - } - }, - { - "_type": "UMLAssociationView", - "_id": "AAAAAAFq+NCnvyJvysY=", - "_parent": { - "$ref": "AAAAAAFq+IemIiEDhm8=" - }, - "model": { - "$ref": "AAAAAAFq+NCnviJrdJA=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+NCnvyJwVQY=", - "_parent": { - "$ref": "AAAAAAFq+NCnvyJvysY=" - }, - "model": { - "$ref": "AAAAAAFq+NCnviJrdJA=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 174, - "top": 201, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+NCnvyJvysY=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+NCnvyJxRUQ=", - "_parent": { - "$ref": "AAAAAAFq+NCnvyJvysY=" - }, - "model": { - "$ref": "AAAAAAFq+NCnviJrdJA=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 189, - "top": 201, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+NCnvyJvysY=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+NCnvyJy35U=", - "_parent": { - "$ref": "AAAAAAFq+NCnvyJvysY=" - }, - "model": { - "$ref": "AAAAAAFq+NCnviJrdJA=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 145, - "top": 202, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+NCnvyJvysY=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+NCnvyJziEc=", - "_parent": { - "$ref": "AAAAAAFq+NCnvyJvysY=" - }, - "model": { - "$ref": "AAAAAAFq+NCnviJsTaI=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 246, - "top": 216, - "height": 13, - "alpha": 0.5235987755982988, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+NCnvyJvysY=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+NCnwCJ0X6Y=", - "_parent": { - "$ref": "AAAAAAFq+NCnvyJvysY=" - }, - "model": { - "$ref": "AAAAAAFq+NCnviJsTaI=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 243, - "top": 230, - "height": 13, - "alpha": 0.7853981633974483, - "distance": 40, - "hostEdge": { - "$ref": "AAAAAAFq+NCnvyJvysY=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+NCnwCJ1rXY=", - "_parent": { - "$ref": "AAAAAAFq+NCnvyJvysY=" - }, - "model": { - "$ref": "AAAAAAFq+NCnviJsTaI=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 250, - "top": 189, - "height": 13, - "alpha": -0.5235987755982988, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFq+NCnvyJvysY=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+NCnwCJ2dD0=", - "_parent": { - "$ref": "AAAAAAFq+NCnvyJvysY=" - }, - "model": { - "$ref": "AAAAAAFq+NCnvyJt/s4=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 175, - "top": 240, - "height": 13, - "alpha": -0.5235987755982988, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+NCnvyJvysY=" - } - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+NCnwCJ3sYE=", - "_parent": { - "$ref": "AAAAAAFq+NCnvyJvysY=" - }, - "model": { - "$ref": "AAAAAAFq+NCnvyJt/s4=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 188, - "top": 237, - "height": 13, - "alpha": -0.7853981633974483, - "distance": 40, - "hostEdge": { - "$ref": "AAAAAAFq+NCnvyJvysY=" - } - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+NCnwCJ4NiM=", - "_parent": { - "$ref": "AAAAAAFq+NCnvyJvysY=" - }, - "model": { - "$ref": "AAAAAAFq+NCnvyJt/s4=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 147, - "top": 244, - "height": 13, - "alpha": 0.5235987755982988, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFq+NCnvyJvysY=" - } - }, - { - "_type": "UMLQualifierCompartmentView", - "_id": "AAAAAAFq+NCnwCJ52SQ=", - "_parent": { - "$ref": "AAAAAAFq+NCnvyJvysY=" - }, - "model": { - "$ref": "AAAAAAFq+NCnviJsTaI=" - }, - "visible": false, - "font": "Arial;13;0", - "width": 10, - "height": 10 - }, - { - "_type": "UMLQualifierCompartmentView", - "_id": "AAAAAAFq+NCnwCJ6CV4=", - "_parent": { - "$ref": "AAAAAAFq+NCnvyJvysY=" - }, - "model": { - "$ref": "AAAAAAFq+NCnvyJt/s4=" - }, - "visible": false, - "font": "Arial;13;0", - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+MyJUyF4220=" - }, - "tail": { - "$ref": "AAAAAAFq+MxTxiFMCGw=" - }, - "points": "272:208;160:208;160:272", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+NCnvyJwVQY=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+NCnvyJxRUQ=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+NCnvyJy35U=" - }, - "tailRoleNameLabel": { - "$ref": "AAAAAAFq+NCnvyJziEc=" - }, - "tailPropertyLabel": { - "$ref": "AAAAAAFq+NCnwCJ0X6Y=" - }, - "tailMultiplicityLabel": { - "$ref": "AAAAAAFq+NCnwCJ1rXY=" - }, - "headRoleNameLabel": { - "$ref": "AAAAAAFq+NCnwCJ2dD0=" - }, - "headPropertyLabel": { - "$ref": "AAAAAAFq+NCnwCJ3sYE=" - }, - "headMultiplicityLabel": { - "$ref": "AAAAAAFq+NCnwCJ4NiM=" - }, - "tailQualifiersCompartment": { - "$ref": "AAAAAAFq+NCnwCJ52SQ=" - }, - "headQualifiersCompartment": { - "$ref": "AAAAAAFq+NCnwCJ6CV4=" - } - }, - { - "_type": "UMLAssociationView", - "_id": "AAAAAAFq+NEAjCLq8+I=", - "_parent": { - "$ref": "AAAAAAFq+IemIiEDhm8=" - }, - "model": { - "$ref": "AAAAAAFq+NEAiyLmOuA=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+NEAjCLrzXo=", - "_parent": { - "$ref": "AAAAAAFq+NEAjCLq8+I=" - }, - "model": { - "$ref": "AAAAAAFq+NEAiyLmOuA=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 478, - "top": 201, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+NEAjCLq8+I=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+NEAjCLsRFY=", - "_parent": { - "$ref": "AAAAAAFq+NEAjCLq8+I=" - }, - "model": { - "$ref": "AAAAAAFq+NEAiyLmOuA=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 493, - "top": 201, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+NEAjCLq8+I=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+NEAjCLtzyA=", - "_parent": { - "$ref": "AAAAAAFq+NEAjCLq8+I=" - }, - "model": { - "$ref": "AAAAAAFq+NEAiyLmOuA=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 449, - "top": 202, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+NEAjCLq8+I=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+NEAjCLuUks=", - "_parent": { - "$ref": "AAAAAAFq+NEAjCLq8+I=" - }, - "model": { - "$ref": "AAAAAAFq+NEAiyLn1vE=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 393, - "top": 187, - "height": 13, - "alpha": 0.5235987755982988, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+NEAjCLq8+I=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+NEAjCLv6Jc=", - "_parent": { - "$ref": "AAAAAAFq+NEAjCLq8+I=" - }, - "model": { - "$ref": "AAAAAAFq+NEAiyLn1vE=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 396, - "top": 173, - "height": 13, - "alpha": 0.7853981633974483, - "distance": 40, - "hostEdge": { - "$ref": "AAAAAAFq+NEAjCLq8+I=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+NEAjCLwkB0=", - "_parent": { - "$ref": "AAAAAAFq+NEAjCLq8+I=" - }, - "model": { - "$ref": "AAAAAAFq+NEAiyLn1vE=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 389, - "top": 214, - "height": 13, - "alpha": -0.5235987755982988, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFq+NEAjCLq8+I=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+NEAjCLxtP0=", - "_parent": { - "$ref": "AAAAAAFq+NEAjCLq8+I=" - }, - "model": { - "$ref": "AAAAAAFq+NEAiyLoBT4=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 479, - "top": 240, - "height": 13, - "alpha": -0.5235987755982988, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+NEAjCLq8+I=" - } - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+NEAjCLyoHc=", - "_parent": { - "$ref": "AAAAAAFq+NEAjCLq8+I=" - }, - "model": { - "$ref": "AAAAAAFq+NEAiyLoBT4=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 492, - "top": 237, - "height": 13, - "alpha": -0.7853981633974483, - "distance": 40, - "hostEdge": { - "$ref": "AAAAAAFq+NEAjCLq8+I=" - } - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+NEAjCLz/V8=", - "_parent": { - "$ref": "AAAAAAFq+NEAjCLq8+I=" - }, - "model": { - "$ref": "AAAAAAFq+NEAiyLoBT4=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 451, - "top": 244, - "height": 13, - "alpha": 0.5235987755982988, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFq+NEAjCLq8+I=" - } - }, - { - "_type": "UMLQualifierCompartmentView", - "_id": "AAAAAAFq+NEAjCL0alk=", - "_parent": { - "$ref": "AAAAAAFq+NEAjCLq8+I=" - }, - "model": { - "$ref": "AAAAAAFq+NEAiyLn1vE=" - }, - "visible": false, - "font": "Arial;13;0", - "width": 10, - "height": 10 - }, - { - "_type": "UMLQualifierCompartmentView", - "_id": "AAAAAAFq+NEAjCL1zyw=", - "_parent": { - "$ref": "AAAAAAFq+NEAjCLq8+I=" - }, - "model": { - "$ref": "AAAAAAFq+NEAiyLoBT4=" - }, - "visible": false, - "font": "Arial;13;0", - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+MyPFCGhBCg=" - }, - "tail": { - "$ref": "AAAAAAFq+MxTxiFMCGw=" - }, - "points": "368:208;464:208;464:272", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+NEAjCLrzXo=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+NEAjCLsRFY=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+NEAjCLtzyA=" - }, - "tailRoleNameLabel": { - "$ref": "AAAAAAFq+NEAjCLuUks=" - }, - "tailPropertyLabel": { - "$ref": "AAAAAAFq+NEAjCLv6Jc=" - }, - "tailMultiplicityLabel": { - "$ref": "AAAAAAFq+NEAjCLwkB0=" - }, - "headRoleNameLabel": { - "$ref": "AAAAAAFq+NEAjCLxtP0=" - }, - "headPropertyLabel": { - "$ref": "AAAAAAFq+NEAjCLyoHc=" - }, - "headMultiplicityLabel": { - "$ref": "AAAAAAFq+NEAjCLz/V8=" - }, - "tailQualifiersCompartment": { - "$ref": "AAAAAAFq+NEAjCL0alk=" - }, - "headQualifiersCompartment": { - "$ref": "AAAAAAFq+NEAjCL1zyw=" - } - }, - { - "_type": "UMLGeneralizationView", - "_id": "AAAAAAFq+NHWFyRgYG8=", - "_parent": { - "$ref": "AAAAAAFq+IemIiEDhm8=" - }, - "model": { - "$ref": "AAAAAAFq+NHWFyReXH8=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+NHWFyRhU/A=", - "_parent": { - "$ref": "AAAAAAFq+NHWFyRgYG8=" - }, - "model": { - "$ref": "AAAAAAFq+NHWFyReXH8=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 161, - "top": 361, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+NHWFyRgYG8=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+NHWFyRifzU=", - "_parent": { - "$ref": "AAAAAAFq+NHWFyRgYG8=" - }, - "model": { - "$ref": "AAAAAAFq+NHWFyReXH8=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 146, - "top": 361, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+NHWFyRgYG8=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+NHWFyRjwOo=", - "_parent": { - "$ref": "AAAAAAFq+NHWFyRgYG8=" - }, - "model": { - "$ref": "AAAAAAFq+NHWFyReXH8=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 190, - "top": 362, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+NHWFyRgYG8=" - }, - "edgePosition": 1 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+MyJUyF4220=" - }, - "tail": { - "$ref": "AAAAAAFq+MybgSHzCss=" - }, - "lineStyle": 1, - "points": "176:399;176:337", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+NHWFyRhU/A=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+NHWFyRifzU=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+NHWFyRjwOo=" - } - }, - { - "_type": "UMLGeneralizationView", - "_id": "AAAAAAFq+NHpVSSPRdA=", - "_parent": { - "$ref": "AAAAAAFq+IemIiEDhm8=" - }, - "model": { - "$ref": "AAAAAAFq+NHpVCSNKNk=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+NHpVSSQeoI=", - "_parent": { - "$ref": "AAAAAAFq+NHpVSSPRdA=" - }, - "model": { - "$ref": "AAAAAAFq+NHpVCSNKNk=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 447, - "top": 362, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+NHpVSSPRdA=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+NHpVSSRvrc=", - "_parent": { - "$ref": "AAAAAAFq+NHpVSSPRdA=" - }, - "model": { - "$ref": "AAAAAAFq+NHpVCSNKNk=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 432, - "top": 362, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+NHpVSSPRdA=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+NHpVSSSnas=", - "_parent": { - "$ref": "AAAAAAFq+NHpVSSPRdA=" - }, - "model": { - "$ref": "AAAAAAFq+NHpVCSNKNk=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 476, - "top": 361, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+NHpVSSPRdA=" - }, - "edgePosition": 1 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+MyPFCGhBCg=" - }, - "tail": { - "$ref": "AAAAAAFq+MyWGiHKbBs=" - }, - "lineStyle": 1, - "points": "463:399;461:337", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+NHpVSSQeoI=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+NHpVSSRvrc=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+NHpVSSSnas=" - } - }, - { - "_type": "UMLDependencyView", - "_id": "AAAAAAFq+NIEnSS+W9I=", - "_parent": { - "$ref": "AAAAAAFq+IemIiEDhm8=" - }, - "model": { - "$ref": "AAAAAAFq+NIEnCS8DVI=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+NIEnSS/qmA=", - "_parent": { - "$ref": "AAAAAAFq+NIEnSS+W9I=" - }, - "model": { - "$ref": "AAAAAAFq+NIEnCS8DVI=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 320, - "top": 411, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+NIEnSS+W9I=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+NIEnSTAG8I=", - "_parent": { - "$ref": "AAAAAAFq+NIEnSS+W9I=" - }, - "model": { - "$ref": "AAAAAAFq+NIEnCS8DVI=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 320, - "top": 396, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+NIEnSS+W9I=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+NIEnSTBKiw=", - "_parent": { - "$ref": "AAAAAAFq+NIEnSS+W9I=" - }, - "model": { - "$ref": "AAAAAAFq+NIEnCS8DVI=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 320, - "top": 441, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+NIEnSS+W9I=" - }, - "edgePosition": 1 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+MyWGiHKbBs=" - }, - "tail": { - "$ref": "AAAAAAFq+MybgSHzCss=" - }, - "lineStyle": 1, - "points": "241:432;399:432", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+NIEnSS/qmA=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+NIEnSTAG8I=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+NIEnSTBKiw=" - } - } - ] - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+MxTxiFKDlo=", - "_parent": { - "$ref": "AAAAAAFq+IemIiECQeI=" - }, - "name": "Client", - "ownedElements": [ - { - "_type": "UMLAssociation", - "_id": "AAAAAAFq+NCnviJrdJA=", - "_parent": { - "$ref": "AAAAAAFq+MxTxiFKDlo=" - }, - "end1": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFq+NCnviJsTaI=", - "_parent": { - "$ref": "AAAAAAFq+NCnviJrdJA=" - }, - "reference": { - "$ref": "AAAAAAFq+MxTxiFKDlo=" - }, - "navigable": false - }, - "end2": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFq+NCnvyJt/s4=", - "_parent": { - "$ref": "AAAAAAFq+NCnviJrdJA=" - }, - "reference": { - "$ref": "AAAAAAFq+MyJUiF2WzY=" - } - } - }, - { - "_type": "UMLAssociation", - "_id": "AAAAAAFq+NEAiyLmOuA=", - "_parent": { - "$ref": "AAAAAAFq+MxTxiFKDlo=" - }, - "end1": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFq+NEAiyLn1vE=", - "_parent": { - "$ref": "AAAAAAFq+NEAiyLmOuA=" - }, - "reference": { - "$ref": "AAAAAAFq+MxTxiFKDlo=" - }, - "navigable": false - }, - "end2": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFq+NEAiyLoBT4=", - "_parent": { - "$ref": "AAAAAAFq+NEAiyLmOuA=" - }, - "reference": { - "$ref": "AAAAAAFq+MyPEyGffG0=" - } - } - } - ] - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+MyJUiF2WzY=", - "_parent": { - "$ref": "AAAAAAFq+IemIiECQeI=" - }, - "name": "AbstractFactory" - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+MyPEyGffG0=", - "_parent": { - "$ref": "AAAAAAFq+IemIiECQeI=" - }, - "name": "AbstractProduct" - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+MyWGiHISsM=", - "_parent": { - "$ref": "AAAAAAFq+IemIiECQeI=" - }, - "name": "ConcreteFactory", - "ownedElements": [ - { - "_type": "UMLGeneralization", - "_id": "AAAAAAFq+NHpVCSNKNk=", - "_parent": { - "$ref": "AAAAAAFq+MyWGiHISsM=" - }, - "source": { - "$ref": "AAAAAAFq+MyWGiHISsM=" - }, - "target": { - "$ref": "AAAAAAFq+MyPEyGffG0=" - } - } - ] - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+MybgSHxJf0=", - "_parent": { - "$ref": "AAAAAAFq+IemIiECQeI=" - }, - "name": "ConcreteProduct", - "ownedElements": [ - { - "_type": "UMLGeneralization", - "_id": "AAAAAAFq+NHWFyReXH8=", - "_parent": { - "$ref": "AAAAAAFq+MybgSHxJf0=" - }, - "source": { - "$ref": "AAAAAAFq+MybgSHxJf0=" - }, - "target": { - "$ref": "AAAAAAFq+MyJUiF2WzY=" - } - }, - { - "_type": "UMLDependency", - "_id": "AAAAAAFq+NIEnCS8DVI=", - "_parent": { - "$ref": "AAAAAAFq+MybgSHxJf0=" - }, - "source": { - "$ref": "AAAAAAFq+MybgSHxJf0=" - }, - "target": { - "$ref": "AAAAAAFq+MyWGiHISsM=" - } - } - ] - } - ] - }, - { - "_type": "UMLModel", - "_id": "AAAAAAFq+OtXOVeYcVg=", - "_parent": { - "$ref": "AAAAAAFF+h6SjaM2Hec=" - }, - "name": "创建型模式——工厂方法", - "ownedElements": [ - { - "_type": "UMLClassDiagram", - "_id": "AAAAAAFq+OtXOVeZELc=", - "_parent": { - "$ref": "AAAAAAFq+OtXOVeYcVg=" - }, - "name": "工厂方法", - "ownedViews": [ - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+O2hcFj5oVg=", - "_parent": { - "$ref": "AAAAAAFq+OtXOVeZELc=" - }, - "model": { - "$ref": "AAAAAAFq+O2hcFj39GU=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+O2hcFj69As=", - "_parent": { - "$ref": "AAAAAAFq+O2hcFj5oVg=" - }, - "model": { - "$ref": "AAAAAAFq+O2hcFj39GU=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+O2hcFj7lKs=", - "_parent": { - "$ref": "AAAAAAFq+O2hcFj69As=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 48, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+O2hcFj8H/o=", - "_parent": { - "$ref": "AAAAAAFq+O2hcFj69As=" - }, - "font": "Arial;13;3", - "left": 149, - "top": 247, - "width": 119, - "height": 13, - "text": "Product" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+O2hcVj9LBQ=", - "_parent": { - "$ref": "AAAAAAFq+O2hcFj69As=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 48, - "width": 220.27001953125, - "height": 13, - "text": "(from 创建型模式——工厂方法)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+O2hcVj+CYU=", - "_parent": { - "$ref": "AAAAAAFq+O2hcFj69As=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 48, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 144, - "top": 240, - "width": 129, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+O2hcFj7lKs=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+O2hcFj8H/o=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+O2hcVj9LBQ=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+O2hcVj+CYU=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+O2hcVj/zn4=", - "_parent": { - "$ref": "AAAAAAFq+O2hcFj5oVg=" - }, - "model": { - "$ref": "AAAAAAFq+O2hcFj39GU=" - }, - "font": "Arial;13;0", - "left": 144, - "top": 265, - "width": 129, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+O2hcVkAE8A=", - "_parent": { - "$ref": "AAAAAAFq+O2hcFj5oVg=" - }, - "model": { - "$ref": "AAAAAAFq+O2hcFj39GU=" - }, - "font": "Arial;13;0", - "left": 144, - "top": 275, - "width": 129, - "height": 10 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+O2hcVkBgE0=", - "_parent": { - "$ref": "AAAAAAFq+O2hcFj5oVg=" - }, - "model": { - "$ref": "AAAAAAFq+O2hcFj39GU=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 24, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+O2hcVkCpuQ=", - "_parent": { - "$ref": "AAAAAAFq+O2hcFj5oVg=" - }, - "model": { - "$ref": "AAAAAAFq+O2hcFj39GU=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 24, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 144, - "top": 240, - "width": 129, - "height": 65, - "nameCompartment": { - "$ref": "AAAAAAFq+O2hcFj69As=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+O2hcVj/zn4=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+O2hcVkAE8A=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+O2hcVkBgE0=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+O2hcVkCpuQ=" - } - }, - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+O2l5VkiYR0=", - "_parent": { - "$ref": "AAAAAAFq+OtXOVeZELc=" - }, - "model": { - "$ref": "AAAAAAFq+O2l5VkgWKg=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+O2l5Vkjais=", - "_parent": { - "$ref": "AAAAAAFq+O2l5VkiYR0=" - }, - "model": { - "$ref": "AAAAAAFq+O2l5VkgWKg=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+O2l5Vkk7mE=", - "_parent": { - "$ref": "AAAAAAFq+O2l5Vkjais=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -64, - "top": -32, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+O2l5Vklc34=", - "_parent": { - "$ref": "AAAAAAFq+O2l5Vkjais=" - }, - "font": "Arial;13;3", - "left": 421, - "top": 247, - "width": 119, - "height": 13, - "text": "Creator" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+O2l5Vkmryc=", - "_parent": { - "$ref": "AAAAAAFq+O2l5Vkjais=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -64, - "top": -32, - "width": 220.27001953125, - "height": 13, - "text": "(from 创建型模式——工厂方法)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+O2l5VknaFA=", - "_parent": { - "$ref": "AAAAAAFq+O2l5Vkjais=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -64, - "top": -32, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 416, - "top": 240, - "width": 129, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+O2l5Vkk7mE=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+O2l5Vklc34=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+O2l5Vkmryc=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+O2l5VknaFA=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+O2l5VkohBg=", - "_parent": { - "$ref": "AAAAAAFq+O2l5VkiYR0=" - }, - "model": { - "$ref": "AAAAAAFq+O2l5VkgWKg=" - }, - "font": "Arial;13;0", - "left": 416, - "top": 265, - "width": 129, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+O2l5VkpYSw=", - "_parent": { - "$ref": "AAAAAAFq+O2l5VkiYR0=" - }, - "model": { - "$ref": "AAAAAAFq+O2l5VkgWKg=" - }, - "font": "Arial;13;0", - "left": 416, - "top": 275, - "width": 129, - "height": 10 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+O2l5Vkq6Ng=", - "_parent": { - "$ref": "AAAAAAFq+O2l5VkiYR0=" - }, - "model": { - "$ref": "AAAAAAFq+O2l5VkgWKg=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -32, - "top": -16, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+O2l5VkrUY4=", - "_parent": { - "$ref": "AAAAAAFq+O2l5VkiYR0=" - }, - "model": { - "$ref": "AAAAAAFq+O2l5VkgWKg=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -32, - "top": -16, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 416, - "top": 240, - "width": 129, - "height": 65, - "nameCompartment": { - "$ref": "AAAAAAFq+O2l5Vkjais=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+O2l5VkohBg=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+O2l5VkpYSw=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+O2l5Vkq6Ng=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+O2l5VkrUY4=" - } - }, - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+O2qzllL4qs=", - "_parent": { - "$ref": "AAAAAAFq+OtXOVeZELc=" - }, - "model": { - "$ref": "AAAAAAFq+O2qzllJQiM=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+O2qzllM+Ao=", - "_parent": { - "$ref": "AAAAAAFq+O2qzllL4qs=" - }, - "model": { - "$ref": "AAAAAAFq+O2qzllJQiM=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+O2qzllNlMQ=", - "_parent": { - "$ref": "AAAAAAFq+O2qzllM+Ao=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -80, - "top": 32, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+O2qzllOfZ0=", - "_parent": { - "$ref": "AAAAAAFq+O2qzllM+Ao=" - }, - "font": "Arial;13;1", - "left": 149, - "top": 407, - "width": 112.68994140625, - "height": 13, - "text": "ConcreateProduct" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+O2qzllPJQ8=", - "_parent": { - "$ref": "AAAAAAFq+O2qzllM+Ao=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -80, - "top": 32, - "width": 220.27001953125, - "height": 13, - "text": "(from 创建型模式——工厂方法)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+O2qzllQkxk=", - "_parent": { - "$ref": "AAAAAAFq+O2qzllM+Ao=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -80, - "top": 32, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 144, - "top": 400, - "width": 122.68994140625, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+O2qzllNlMQ=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+O2qzllOfZ0=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+O2qzllPJQ8=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+O2qzllQkxk=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+O2qzllRhC8=", - "_parent": { - "$ref": "AAAAAAFq+O2qzllL4qs=" - }, - "model": { - "$ref": "AAAAAAFq+O2qzllJQiM=" - }, - "font": "Arial;13;0", - "left": 144, - "top": 425, - "width": 122.68994140625, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+O2qzllSgKw=", - "_parent": { - "$ref": "AAAAAAFq+O2qzllL4qs=" - }, - "model": { - "$ref": "AAAAAAFq+O2qzllJQiM=" - }, - "font": "Arial;13;0", - "left": 144, - "top": 435, - "width": 122.68994140625, - "height": 10 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+O2qzllTTAg=", - "_parent": { - "$ref": "AAAAAAFq+O2qzllL4qs=" - }, - "model": { - "$ref": "AAAAAAFq+O2qzllJQiM=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -40, - "top": 16, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+O2qzllUORQ=", - "_parent": { - "$ref": "AAAAAAFq+O2qzllL4qs=" - }, - "model": { - "$ref": "AAAAAAFq+O2qzllJQiM=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -40, - "top": 16, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 144, - "top": 400, - "width": 122.68994140625, - "height": 65, - "nameCompartment": { - "$ref": "AAAAAAFq+O2qzllM+Ao=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+O2qzllRhC8=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+O2qzllSgKw=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+O2qzllTTAg=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+O2qzllUORQ=" - } - }, - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+O2wIVl0P5A=", - "_parent": { - "$ref": "AAAAAAFq+OtXOVeZELc=" - }, - "model": { - "$ref": "AAAAAAFq+O2wIVlyFwk=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+O2wIVl1amQ=", - "_parent": { - "$ref": "AAAAAAFq+O2wIVl0P5A=" - }, - "model": { - "$ref": "AAAAAAFq+O2wIVlyFwk=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+O2wIVl2cA8=", - "_parent": { - "$ref": "AAAAAAFq+O2wIVl1amQ=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -96, - "top": -16, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+O2wIVl3CCc=", - "_parent": { - "$ref": "AAAAAAFq+O2wIVl1amQ=" - }, - "font": "Arial;13;1", - "left": 421, - "top": 407, - "width": 119, - "height": 13, - "text": "ConcreateCreator" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+O2wIVl4uSw=", - "_parent": { - "$ref": "AAAAAAFq+O2wIVl1amQ=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -96, - "top": -16, - "width": 220.27001953125, - "height": 13, - "text": "(from 创建型模式——工厂方法)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+O2wIVl5xYE=", - "_parent": { - "$ref": "AAAAAAFq+O2wIVl1amQ=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -96, - "top": -16, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 416, - "top": 400, - "width": 129, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+O2wIVl2cA8=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+O2wIVl3CCc=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+O2wIVl4uSw=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+O2wIVl5xYE=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+O2wIVl6Nak=", - "_parent": { - "$ref": "AAAAAAFq+O2wIVl0P5A=" - }, - "model": { - "$ref": "AAAAAAFq+O2wIVlyFwk=" - }, - "font": "Arial;13;0", - "left": 416, - "top": 425, - "width": 129, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+O2wIVl7RRw=", - "_parent": { - "$ref": "AAAAAAFq+O2wIVl0P5A=" - }, - "model": { - "$ref": "AAAAAAFq+O2wIVlyFwk=" - }, - "font": "Arial;13;0", - "left": 416, - "top": 435, - "width": 129, - "height": 10 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+O2wIVl8iKc=", - "_parent": { - "$ref": "AAAAAAFq+O2wIVl0P5A=" - }, - "model": { - "$ref": "AAAAAAFq+O2wIVlyFwk=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -48, - "top": -8, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+O2wIVl95eI=", - "_parent": { - "$ref": "AAAAAAFq+O2wIVl0P5A=" - }, - "model": { - "$ref": "AAAAAAFq+O2wIVlyFwk=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -48, - "top": -8, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 416, - "top": 400, - "width": 129, - "height": 65, - "nameCompartment": { - "$ref": "AAAAAAFq+O2wIVl1amQ=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+O2wIVl6Nak=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+O2wIVl7RRw=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+O2wIVl8iKc=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+O2wIVl95eI=" - } - }, - { - "_type": "UMLGeneralizationView", - "_id": "AAAAAAFq+PJXglnADnY=", - "_parent": { - "$ref": "AAAAAAFq+OtXOVeZELc=" - }, - "model": { - "$ref": "AAAAAAFq+PJXglm+an0=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+PJXglnBbnA=", - "_parent": { - "$ref": "AAAAAAFq+PJXglnADnY=" - }, - "model": { - "$ref": "AAAAAAFq+PJXglm+an0=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 191, - "top": 345, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+PJXglnADnY=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+PJXglnC4zc=", - "_parent": { - "$ref": "AAAAAAFq+PJXglnADnY=" - }, - "model": { - "$ref": "AAAAAAFq+PJXglm+an0=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 176, - "top": 345, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+PJXglnADnY=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+PJXglnDWcI=", - "_parent": { - "$ref": "AAAAAAFq+PJXglnADnY=" - }, - "model": { - "$ref": "AAAAAAFq+PJXglm+an0=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 220, - "top": 346, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+PJXglnADnY=" - }, - "edgePosition": 1 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+O2hcFj5oVg=" - }, - "tail": { - "$ref": "AAAAAAFq+O2qzllL4qs=" - }, - "lineStyle": 1, - "points": "205:399;207:305", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+PJXglnBbnA=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+PJXglnC4zc=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+PJXglnDWcI=" - } - }, - { - "_type": "UMLGeneralizationView", - "_id": "AAAAAAFq+PJxpFnTB4I=", - "_parent": { - "$ref": "AAAAAAFq+OtXOVeZELc=" - }, - "model": { - "$ref": "AAAAAAFq+PJxpFnR8Z8=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+PJxpFnUZ6w=", - "_parent": { - "$ref": "AAAAAAFq+PJxpFnTB4I=" - }, - "model": { - "$ref": "AAAAAAFq+PJxpFnR8Z8=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 465, - "top": 345, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+PJxpFnTB4I=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+PJxpFnVn8I=", - "_parent": { - "$ref": "AAAAAAFq+PJxpFnTB4I=" - }, - "model": { - "$ref": "AAAAAAFq+PJxpFnR8Z8=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 450, - "top": 345, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+PJxpFnTB4I=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+PJxpFnWzfI=", - "_parent": { - "$ref": "AAAAAAFq+PJxpFnTB4I=" - }, - "model": { - "$ref": "AAAAAAFq+PJxpFnR8Z8=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 494, - "top": 346, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+PJxpFnTB4I=" - }, - "edgePosition": 1 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+O2l5VkiYR0=" - }, - "tail": { - "$ref": "AAAAAAFq+O2wIVl0P5A=" - }, - "lineStyle": 1, - "points": "480:399;480:305", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+PJxpFnUZ6w=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+PJxpFnVn8I=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+PJxpFnWzfI=" - } - }, - { - "_type": "UMLDependencyView", - "_id": "AAAAAAFq+PcMV1oHNmc=", - "_parent": { - "$ref": "AAAAAAFq+OtXOVeZELc=" - }, - "model": { - "$ref": "AAAAAAFq+PcMV1oFZ3E=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+PcMV1oIlO8=", - "_parent": { - "$ref": "AAAAAAFq+PcMV1oHNmc=" - }, - "model": { - "$ref": "AAAAAAFq+PcMV1oFZ3E=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 340, - "top": 441, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+PcMV1oHNmc=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+PcMV1oJsmI=", - "_parent": { - "$ref": "AAAAAAFq+PcMV1oHNmc=" - }, - "model": { - "$ref": "AAAAAAFq+PcMV1oFZ3E=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 340, - "top": 456, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+PcMV1oHNmc=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+PcMV1oKb2g=", - "_parent": { - "$ref": "AAAAAAFq+PcMV1oHNmc=" - }, - "model": { - "$ref": "AAAAAAFq+PcMV1oFZ3E=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 341, - "top": 411, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+PcMV1oHNmc=" - }, - "edgePosition": 1 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+O2qzllL4qs=" - }, - "tail": { - "$ref": "AAAAAAFq+O2wIVl0P5A=" - }, - "lineStyle": 1, - "points": "415:432;267:432", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+PcMV1oIlO8=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+PcMV1oJsmI=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+PcMV1oKb2g=" - } - } - ] - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+O2hcFj39GU=", - "_parent": { - "$ref": "AAAAAAFq+OtXOVeYcVg=" - }, - "name": "Product", - "ownedElements": [ - { - "_type": "UMLGeneralization", - "_id": "AAAAAAFq+PIuclmjkak=", - "_parent": { - "$ref": "AAAAAAFq+O2hcFj39GU=" - }, - "source": { - "$ref": "AAAAAAFq+O2hcFj39GU=" - }, - "target": { - "$ref": "AAAAAAFq+O2hcFj39GU=" - } - } - ], - "isAbstract": true - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+O2l5VkgWKg=", - "_parent": { - "$ref": "AAAAAAFq+OtXOVeYcVg=" - }, - "name": "Creator", - "isAbstract": true - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+O2qzllJQiM=", - "_parent": { - "$ref": "AAAAAAFq+OtXOVeYcVg=" - }, - "name": "ConcreateProduct", - "ownedElements": [ - { - "_type": "UMLGeneralization", - "_id": "AAAAAAFq+PJXglm+an0=", - "_parent": { - "$ref": "AAAAAAFq+O2qzllJQiM=" - }, - "source": { - "$ref": "AAAAAAFq+O2qzllJQiM=" - }, - "target": { - "$ref": "AAAAAAFq+O2hcFj39GU=" - } - } - ] - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+O2wIVlyFwk=", - "_parent": { - "$ref": "AAAAAAFq+OtXOVeYcVg=" - }, - "name": "ConcreateCreator", - "ownedElements": [ - { - "_type": "UMLGeneralization", - "_id": "AAAAAAFq+PJxpFnR8Z8=", - "_parent": { - "$ref": "AAAAAAFq+O2wIVlyFwk=" - }, - "source": { - "$ref": "AAAAAAFq+O2wIVlyFwk=" - }, - "target": { - "$ref": "AAAAAAFq+O2l5VkgWKg=" - } - }, - { - "_type": "UMLDependency", - "_id": "AAAAAAFq+PcMV1oFZ3E=", - "_parent": { - "$ref": "AAAAAAFq+O2wIVlyFwk=" - }, - "source": { - "$ref": "AAAAAAFq+O2wIVlyFwk=" - }, - "target": { - "$ref": "AAAAAAFq+O2qzllJQiM=" - } - } - ] - } - ] - }, - { - "_type": "UMLModel", - "_id": "AAAAAAFq+PxeHsute7g=", - "_parent": { - "$ref": "AAAAAAFF+h6SjaM2Hec=" - }, - "name": "创建型模式——建造模式", - "ownedElements": [ - { - "_type": "UMLClassDiagram", - "_id": "AAAAAAFq+PxeHsuubSY=", - "_parent": { - "$ref": "AAAAAAFq+PxeHsute7g=" - }, - "name": "建造模式", - "ownedViews": [ - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+PzhIcvCkG4=", - "_parent": { - "$ref": "AAAAAAFq+PxeHsuubSY=" - }, - "model": { - "$ref": "AAAAAAFq+PzhIcvAPHM=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+PzhIcvDX2Y=", - "_parent": { - "$ref": "AAAAAAFq+PzhIcvCkG4=" - }, - "model": { - "$ref": "AAAAAAFq+PzhIcvAPHM=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+PzhIcvErdo=", - "_parent": { - "$ref": "AAAAAAFq+PzhIcvDX2Y=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -192, - "top": 112, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+PzhIsvFv9o=", - "_parent": { - "$ref": "AAAAAAFq+PzhIcvDX2Y=" - }, - "font": "Arial;13;3", - "left": 37, - "top": 295, - "width": 103, - "height": 13, - "text": "Director" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+PzhIsvGQVs=", - "_parent": { - "$ref": "AAAAAAFq+PzhIcvDX2Y=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -192, - "top": 112, - "width": 181.27001953125, - "height": 13, - "text": "(from 创建型模式——建造模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+PzhIsvHEEE=", - "_parent": { - "$ref": "AAAAAAFq+PzhIcvDX2Y=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -192, - "top": 112, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 32, - "top": 288, - "width": 113, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+PzhIcvErdo=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+PzhIsvFv9o=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+PzhIsvGQVs=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+PzhIsvHEEE=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+PzhIsvI96w=", - "_parent": { - "$ref": "AAAAAAFq+PzhIcvCkG4=" - }, - "model": { - "$ref": "AAAAAAFq+PzhIcvAPHM=" - }, - "font": "Arial;13;0", - "left": 32, - "top": 313, - "width": 113, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+PzhIsvJNFA=", - "_parent": { - "$ref": "AAAAAAFq+PzhIcvCkG4=" - }, - "model": { - "$ref": "AAAAAAFq+PzhIcvAPHM=" - }, - "font": "Arial;13;0", - "left": 32, - "top": 323, - "width": 113, - "height": 10 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+PzhIsvKFSY=", - "_parent": { - "$ref": "AAAAAAFq+PzhIcvCkG4=" - }, - "model": { - "$ref": "AAAAAAFq+PzhIcvAPHM=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -96, - "top": 56, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+PzhIsvLcl8=", - "_parent": { - "$ref": "AAAAAAFq+PzhIcvCkG4=" - }, - "model": { - "$ref": "AAAAAAFq+PzhIcvAPHM=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -96, - "top": 56, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 32, - "top": 288, - "width": 113, - "height": 65, - "nameCompartment": { - "$ref": "AAAAAAFq+PzhIcvDX2Y=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+PzhIsvI96w=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+PzhIsvJNFA=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+PzhIsvKFSY=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+PzhIsvLcl8=" - } - }, - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+PzplcvrVRM=", - "_parent": { - "$ref": "AAAAAAFq+PxeHsuubSY=" - }, - "model": { - "$ref": "AAAAAAFq+PzplcvpJyU=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+Pzplcvs/Ts=", - "_parent": { - "$ref": "AAAAAAFq+PzplcvrVRM=" - }, - "model": { - "$ref": "AAAAAAFq+PzplcvpJyU=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+PzplcvtAlw=", - "_parent": { - "$ref": "AAAAAAFq+Pzplcvs/Ts=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -272, - "top": 64, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+Pzplcvu9jE=", - "_parent": { - "$ref": "AAAAAAFq+Pzplcvs/Ts=" - }, - "font": "Arial;13;3", - "left": 293, - "top": 295, - "width": 103, - "height": 13, - "text": "Builder" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+PzplcvvSds=", - "_parent": { - "$ref": "AAAAAAFq+Pzplcvs/Ts=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -272, - "top": 64, - "width": 181.27001953125, - "height": 13, - "text": "(from 创建型模式——建造模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+Pzplcvw6XU=", - "_parent": { - "$ref": "AAAAAAFq+Pzplcvs/Ts=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -272, - "top": 64, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 288, - "top": 288, - "width": 113, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+PzplcvtAlw=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+Pzplcvu9jE=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+PzplcvvSds=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+Pzplcvw6XU=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+PzplcvxArA=", - "_parent": { - "$ref": "AAAAAAFq+PzplcvrVRM=" - }, - "model": { - "$ref": "AAAAAAFq+PzplcvpJyU=" - }, - "font": "Arial;13;0", - "left": 288, - "top": 313, - "width": 113, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+PzplcvyrRM=", - "_parent": { - "$ref": "AAAAAAFq+PzplcvrVRM=" - }, - "model": { - "$ref": "AAAAAAFq+PzplcvpJyU=" - }, - "font": "Arial;13;0", - "left": 288, - "top": 323, - "width": 113, - "height": 10 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+Pzplcvz3ks=", - "_parent": { - "$ref": "AAAAAAFq+PzplcvrVRM=" - }, - "model": { - "$ref": "AAAAAAFq+PzplcvpJyU=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -136, - "top": 32, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+Pzplcv0ZfY=", - "_parent": { - "$ref": "AAAAAAFq+PzplcvrVRM=" - }, - "model": { - "$ref": "AAAAAAFq+PzplcvpJyU=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -136, - "top": 32, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 288, - "top": 288, - "width": 113, - "height": 65, - "nameCompartment": { - "$ref": "AAAAAAFq+Pzplcvs/Ts=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+PzplcvxArA=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+PzplcvyrRM=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+Pzplcvz3ks=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+Pzplcv0ZfY=" - } - }, - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+Pz1vcwU+F4=", - "_parent": { - "$ref": "AAAAAAFq+PxeHsuubSY=" - }, - "model": { - "$ref": "AAAAAAFq+Pz1vcwSBNM=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+Pz1vcwV5Dg=", - "_parent": { - "$ref": "AAAAAAFq+Pz1vcwU+F4=" - }, - "model": { - "$ref": "AAAAAAFq+Pz1vcwSBNM=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+Pz1vcwWPuw=", - "_parent": { - "$ref": "AAAAAAFq+Pz1vcwV5Dg=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 16, - "top": -64, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+Pz1vcwXbW8=", - "_parent": { - "$ref": "AAAAAAFq+Pz1vcwV5Dg=" - }, - "font": "Arial;13;1", - "left": 293, - "top": 455, - "width": 101.130859375, - "height": 13, - "text": "ConcreteBuilder" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+Pz1vcwYXF4=", - "_parent": { - "$ref": "AAAAAAFq+Pz1vcwV5Dg=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 16, - "top": -64, - "width": 181.27001953125, - "height": 13, - "text": "(from 创建型模式——建造模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+Pz1vcwZBug=", - "_parent": { - "$ref": "AAAAAAFq+Pz1vcwV5Dg=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 16, - "top": -64, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 288, - "top": 448, - "width": 111.130859375, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+Pz1vcwWPuw=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+Pz1vcwXbW8=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+Pz1vcwYXF4=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+Pz1vcwZBug=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+Pz1vcwa1Zw=", - "_parent": { - "$ref": "AAAAAAFq+Pz1vcwU+F4=" - }, - "model": { - "$ref": "AAAAAAFq+Pz1vcwSBNM=" - }, - "font": "Arial;13;0", - "left": 288, - "top": 473, - "width": 111.130859375, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+Pz1vswbwdY=", - "_parent": { - "$ref": "AAAAAAFq+Pz1vcwU+F4=" - }, - "model": { - "$ref": "AAAAAAFq+Pz1vcwSBNM=" - }, - "font": "Arial;13;0", - "left": 288, - "top": 483, - "width": 111.130859375, - "height": 10 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+Pz1vswcKzM=", - "_parent": { - "$ref": "AAAAAAFq+Pz1vcwU+F4=" - }, - "model": { - "$ref": "AAAAAAFq+Pz1vcwSBNM=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 8, - "top": -32, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+Pz1vswdo98=", - "_parent": { - "$ref": "AAAAAAFq+Pz1vcwU+F4=" - }, - "model": { - "$ref": "AAAAAAFq+Pz1vcwSBNM=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 8, - "top": -32, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 288, - "top": 448, - "width": 111.130859375, - "height": 65, - "nameCompartment": { - "$ref": "AAAAAAFq+Pz1vcwV5Dg=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+Pz1vcwa1Zw=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+Pz1vswbwdY=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+Pz1vswcKzM=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+Pz1vswdo98=" - } - }, - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+Pz6OMw9ioU=", - "_parent": { - "$ref": "AAAAAAFq+PxeHsuubSY=" - }, - "model": { - "$ref": "AAAAAAFq+Pz6OMw7pCM=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+Pz6OMw+fbk=", - "_parent": { - "$ref": "AAAAAAFq+Pz6OMw9ioU=" - }, - "model": { - "$ref": "AAAAAAFq+Pz6OMw7pCM=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+Pz6OMw/gbk=", - "_parent": { - "$ref": "AAAAAAFq+Pz6OMw+fbk=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 64, - "top": -80, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+Pz6OMxA4ww=", - "_parent": { - "$ref": "AAAAAAFq+Pz6OMw+fbk=" - }, - "font": "Arial;13;1", - "left": 517, - "top": 455, - "width": 103, - "height": 13, - "text": "Product" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+Pz6OMxBQJk=", - "_parent": { - "$ref": "AAAAAAFq+Pz6OMw+fbk=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 64, - "top": -80, - "width": 181.27001953125, - "height": 13, - "text": "(from 创建型模式——建造模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+Pz6OMxCkzc=", - "_parent": { - "$ref": "AAAAAAFq+Pz6OMw+fbk=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 64, - "top": -80, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 512, - "top": 448, - "width": 113, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+Pz6OMw/gbk=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+Pz6OMxA4ww=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+Pz6OMxBQJk=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+Pz6OMxCkzc=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+Pz6OMxDWGU=", - "_parent": { - "$ref": "AAAAAAFq+Pz6OMw9ioU=" - }, - "model": { - "$ref": "AAAAAAFq+Pz6OMw7pCM=" - }, - "font": "Arial;13;0", - "left": 512, - "top": 473, - "width": 113, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+Pz6OMxEuPw=", - "_parent": { - "$ref": "AAAAAAFq+Pz6OMw9ioU=" - }, - "model": { - "$ref": "AAAAAAFq+Pz6OMw7pCM=" - }, - "font": "Arial;13;0", - "left": 512, - "top": 483, - "width": 113, - "height": 10 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+Pz6OcxFS9g=", - "_parent": { - "$ref": "AAAAAAFq+Pz6OMw9ioU=" - }, - "model": { - "$ref": "AAAAAAFq+Pz6OMw7pCM=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 32, - "top": -40, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+Pz6OcxGCL0=", - "_parent": { - "$ref": "AAAAAAFq+Pz6OMw9ioU=" - }, - "model": { - "$ref": "AAAAAAFq+Pz6OMw7pCM=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 32, - "top": -40, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 512, - "top": 448, - "width": 113, - "height": 65, - "nameCompartment": { - "$ref": "AAAAAAFq+Pz6OMw+fbk=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+Pz6OMxDWGU=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+Pz6OMxEuPw=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+Pz6OcxFS9g=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+Pz6OcxGCL0=" - } - }, - { - "_type": "UMLAssociationView", - "_id": "AAAAAAFq+QK+pc6p+e8=", - "_parent": { - "$ref": "AAAAAAFq+PxeHsuubSY=" - }, - "model": { - "$ref": "AAAAAAFq+QK+pc6lEtw=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+QK+pc6qQrc=", - "_parent": { - "$ref": "AAAAAAFq+QK+pc6p+e8=" - }, - "model": { - "$ref": "AAAAAAFq+QK+pc6lEtw=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 215, - "top": 329, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+QK+pc6p+e8=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+QK+pc6rnbY=", - "_parent": { - "$ref": "AAAAAAFq+QK+pc6p+e8=" - }, - "model": { - "$ref": "AAAAAAFq+QK+pc6lEtw=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 215, - "top": 344, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+QK+pc6p+e8=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+QK+pc6sfz8=", - "_parent": { - "$ref": "AAAAAAFq+QK+pc6p+e8=" - }, - "model": { - "$ref": "AAAAAAFq+QK+pc6lEtw=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 216, - "top": 299, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+QK+pc6p+e8=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+QK+pc6tfec=", - "_parent": { - "$ref": "AAAAAAFq+QK+pc6p+e8=" - }, - "model": { - "$ref": "AAAAAAFq+QK+pc6mUbE=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 261, - "top": 328, - "height": 13, - "alpha": 0.5235987755982988, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+QK+pc6p+e8=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+QK+pc6unMw=", - "_parent": { - "$ref": "AAAAAAFq+QK+pc6p+e8=" - }, - "model": { - "$ref": "AAAAAAFq+QK+pc6mUbE=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 258, - "top": 342, - "height": 13, - "alpha": 0.7853981633974483, - "distance": 40, - "hostEdge": { - "$ref": "AAAAAAFq+QK+pc6p+e8=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+QK+pc6vRag=", - "_parent": { - "$ref": "AAAAAAFq+QK+pc6p+e8=" - }, - "model": { - "$ref": "AAAAAAFq+QK+pc6mUbE=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 265, - "top": 301, - "height": 13, - "alpha": -0.5235987755982988, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFq+QK+pc6p+e8=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+QK+pc6w6Rk=", - "_parent": { - "$ref": "AAAAAAFq+QK+pc6p+e8=" - }, - "model": { - "$ref": "AAAAAAFq+QK+pc6nkU8=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 170, - "top": 328, - "height": 13, - "alpha": -0.5235987755982988, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+QK+pc6p+e8=" - } - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+QK+pc6x2io=", - "_parent": { - "$ref": "AAAAAAFq+QK+pc6p+e8=" - }, - "model": { - "$ref": "AAAAAAFq+QK+pc6nkU8=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 173, - "top": 342, - "height": 13, - "alpha": -0.7853981633974483, - "distance": 40, - "hostEdge": { - "$ref": "AAAAAAFq+QK+pc6p+e8=" - } - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+QK+pc6yv+s=", - "_parent": { - "$ref": "AAAAAAFq+QK+pc6p+e8=" - }, - "model": { - "$ref": "AAAAAAFq+QK+pc6nkU8=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 166, - "top": 301, - "height": 13, - "alpha": 0.5235987755982988, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFq+QK+pc6p+e8=" - } - }, - { - "_type": "UMLQualifierCompartmentView", - "_id": "AAAAAAFq+QK+pc6zdKY=", - "_parent": { - "$ref": "AAAAAAFq+QK+pc6p+e8=" - }, - "model": { - "$ref": "AAAAAAFq+QK+pc6mUbE=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -96, - "top": 48, - "width": 10, - "height": 10 - }, - { - "_type": "UMLQualifierCompartmentView", - "_id": "AAAAAAFq+QK+pc60nvU=", - "_parent": { - "$ref": "AAAAAAFq+QK+pc6p+e8=" - }, - "model": { - "$ref": "AAAAAAFq+QK+pc6nkU8=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -96, - "top": 48, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+PzhIcvCkG4=" - }, - "tail": { - "$ref": "AAAAAAFq+PzplcvrVRM=" - }, - "lineStyle": 1, - "points": "287:320;145:320", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+QK+pc6qQrc=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+QK+pc6rnbY=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+QK+pc6sfz8=" - }, - "tailRoleNameLabel": { - "$ref": "AAAAAAFq+QK+pc6tfec=" - }, - "tailPropertyLabel": { - "$ref": "AAAAAAFq+QK+pc6unMw=" - }, - "tailMultiplicityLabel": { - "$ref": "AAAAAAFq+QK+pc6vRag=" - }, - "headRoleNameLabel": { - "$ref": "AAAAAAFq+QK+pc6w6Rk=" - }, - "headPropertyLabel": { - "$ref": "AAAAAAFq+QK+pc6x2io=" - }, - "headMultiplicityLabel": { - "$ref": "AAAAAAFq+QK+pc6yv+s=" - }, - "tailQualifiersCompartment": { - "$ref": "AAAAAAFq+QK+pc6zdKY=" - }, - "headQualifiersCompartment": { - "$ref": "AAAAAAFq+QK+pc60nvU=" - } - }, - { - "_type": "UMLGeneralizationView", - "_id": "AAAAAAFq+QODVM+VsgA=", - "_parent": { - "$ref": "AAAAAAFq+PxeHsuubSY=" - }, - "model": { - "$ref": "AAAAAAFq+QODVM+TKFA=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+QODVM+WxM0=", - "_parent": { - "$ref": "AAAAAAFq+QODVM+VsgA=" - }, - "model": { - "$ref": "AAAAAAFq+QODVM+TKFA=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 328, - "top": 393, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+QODVM+VsgA=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+QODVM+XuhM=", - "_parent": { - "$ref": "AAAAAAFq+QODVM+VsgA=" - }, - "model": { - "$ref": "AAAAAAFq+QODVM+TKFA=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 313, - "top": 393, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+QODVM+VsgA=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+QODVM+YMCg=", - "_parent": { - "$ref": "AAAAAAFq+QODVM+VsgA=" - }, - "model": { - "$ref": "AAAAAAFq+QODVM+TKFA=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 357, - "top": 394, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+QODVM+VsgA=" - }, - "edgePosition": 1 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+PzplcvrVRM=" - }, - "tail": { - "$ref": "AAAAAAFq+Pz1vcwU+F4=" - }, - "lineStyle": 1, - "points": "343:447;344:353", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+QODVM+WxM0=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+QODVM+XuhM=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+QODVM+YMCg=" - } - }, - { - "_type": "UMLDependencyView", - "_id": "AAAAAAFq+QOy2c+1PQQ=", - "_parent": { - "$ref": "AAAAAAFq+PxeHsuubSY=" - }, - "model": { - "$ref": "AAAAAAFq+QOy2c+zGUQ=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+QOy2c+21hE=", - "_parent": { - "$ref": "AAAAAAFq+QOy2c+1PQQ=" - }, - "model": { - "$ref": "AAAAAAFq+QOy2c+zGUQ=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 455, - "top": 459, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+QOy2c+1PQQ=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+QOy2c+3RQc=", - "_parent": { - "$ref": "AAAAAAFq+QOy2c+1PQQ=" - }, - "model": { - "$ref": "AAAAAAFq+QOy2c+zGUQ=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 455, - "top": 444, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+QOy2c+1PQQ=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+QOy2c+4bu8=", - "_parent": { - "$ref": "AAAAAAFq+QOy2c+1PQQ=" - }, - "model": { - "$ref": "AAAAAAFq+QOy2c+zGUQ=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 455, - "top": 489, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+QOy2c+1PQQ=" - }, - "edgePosition": 1 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+Pz6OMw9ioU=" - }, - "tail": { - "$ref": "AAAAAAFq+Pz1vcwU+F4=" - }, - "lineStyle": 1, - "points": "399:480;511:480", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+QOy2c+21hE=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+QOy2c+3RQc=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+QOy2c+4bu8=" - } - } - ] - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+PzhIcvAPHM=", - "_parent": { - "$ref": "AAAAAAFq+PxeHsute7g=" - }, - "name": "Director", - "isAbstract": true - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+PzplcvpJyU=", - "_parent": { - "$ref": "AAAAAAFq+PxeHsute7g=" - }, - "name": "Builder", - "ownedElements": [ - { - "_type": "UMLAssociation", - "_id": "AAAAAAFq+QK+pc6lEtw=", - "_parent": { - "$ref": "AAAAAAFq+PzplcvpJyU=" - }, - "end1": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFq+QK+pc6mUbE=", - "_parent": { - "$ref": "AAAAAAFq+QK+pc6lEtw=" - }, - "reference": { - "$ref": "AAAAAAFq+PzplcvpJyU=" - } - }, - "end2": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFq+QK+pc6nkU8=", - "_parent": { - "$ref": "AAAAAAFq+QK+pc6lEtw=" - }, - "reference": { - "$ref": "AAAAAAFq+PzhIcvAPHM=" - }, - "navigable": false, - "aggregation": "shared" - } - } - ], - "isAbstract": true - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+Pz1vcwSBNM=", - "_parent": { - "$ref": "AAAAAAFq+PxeHsute7g=" - }, - "name": "ConcreteBuilder", - "ownedElements": [ - { - "_type": "UMLGeneralization", - "_id": "AAAAAAFq+QODVM+TKFA=", - "_parent": { - "$ref": "AAAAAAFq+Pz1vcwSBNM=" - }, - "source": { - "$ref": "AAAAAAFq+Pz1vcwSBNM=" - }, - "target": { - "$ref": "AAAAAAFq+PzplcvpJyU=" - } - }, - { - "_type": "UMLDependency", - "_id": "AAAAAAFq+QOy2c+zGUQ=", - "_parent": { - "$ref": "AAAAAAFq+Pz1vcwSBNM=" - }, - "source": { - "$ref": "AAAAAAFq+Pz1vcwSBNM=" - }, - "target": { - "$ref": "AAAAAAFq+Pz6OMw7pCM=" - } - } - ] - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+Pz6OMw7pCM=", - "_parent": { - "$ref": "AAAAAAFq+PxeHsute7g=" - }, - "name": "Product" - } - ] - }, - { - "_type": "UMLModel", - "_id": "AAAAAAFq+VpMjNAiUuc=", - "_parent": { - "$ref": "AAAAAAFF+h6SjaM2Hec=" - }, - "name": "结构型模式——装饰者模式", - "ownedElements": [ - { - "_type": "UMLClassDiagram", - "_id": "AAAAAAFq+VpMjNAjslg=", - "_parent": { - "$ref": "AAAAAAFq+VpMjNAiUuc=" - }, - "name": "装饰者模式", - "ownedViews": [ - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+VqLDdA3K0M=", - "_parent": { - "$ref": "AAAAAAFq+VpMjNAjslg=" - }, - "model": { - "$ref": "AAAAAAFq+VqLDdA1gfk=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+VqLDtA4UXk=", - "_parent": { - "$ref": "AAAAAAFq+VqLDdA3K0M=" - }, - "model": { - "$ref": "AAAAAAFq+VqLDdA1gfk=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+VqLDtA5Tpo=", - "_parent": { - "$ref": "AAAAAAFq+VqLDtA4UXk=" - }, - "visible": false, - "font": "Arial;13;0", - "top": 16, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+VqLDtA6rP0=", - "_parent": { - "$ref": "AAAAAAFq+VqLDtA4UXk=" - }, - "font": "Arial;13;3", - "left": 213, - "top": 263, - "width": 103, - "height": 13, - "text": "Component" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+VqLDtA7SY0=", - "_parent": { - "$ref": "AAAAAAFq+VqLDtA4UXk=" - }, - "visible": false, - "font": "Arial;13;0", - "top": 16, - "width": 194.27001953125, - "height": 13, - "text": "(from 结构型模式——装饰者模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+VqLDtA8nlw=", - "_parent": { - "$ref": "AAAAAAFq+VqLDtA4UXk=" - }, - "visible": false, - "font": "Arial;13;0", - "top": 16, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 208, - "top": 256, - "width": 113, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+VqLDtA5Tpo=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+VqLDtA6rP0=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+VqLDtA7SY0=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+VqLDtA8nlw=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+VqLDtA9lBg=", - "_parent": { - "$ref": "AAAAAAFq+VqLDdA3K0M=" - }, - "model": { - "$ref": "AAAAAAFq+VqLDdA1gfk=" - }, - "font": "Arial;13;0", - "left": 208, - "top": 281, - "width": 113, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+VqLDtA+MUM=", - "_parent": { - "$ref": "AAAAAAFq+VqLDdA3K0M=" - }, - "model": { - "$ref": "AAAAAAFq+VqLDdA1gfk=" - }, - "font": "Arial;13;0", - "left": 208, - "top": 291, - "width": 113, - "height": 10 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+VqLDtA/688=", - "_parent": { - "$ref": "AAAAAAFq+VqLDdA3K0M=" - }, - "model": { - "$ref": "AAAAAAFq+VqLDdA1gfk=" - }, - "visible": false, - "font": "Arial;13;0", - "top": 8, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+VqLDtBAlcQ=", - "_parent": { - "$ref": "AAAAAAFq+VqLDdA3K0M=" - }, - "model": { - "$ref": "AAAAAAFq+VqLDdA1gfk=" - }, - "visible": false, - "font": "Arial;13;0", - "top": 8, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 208, - "top": 256, - "width": 113, - "height": 49, - "nameCompartment": { - "$ref": "AAAAAAFq+VqLDtA4UXk=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+VqLDtA9lBg=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+VqLDtA+MUM=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+VqLDtA/688=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+VqLDtBAlcQ=" - } - }, - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+VqQUNBgoqc=", - "_parent": { - "$ref": "AAAAAAFq+VpMjNAjslg=" - }, - "model": { - "$ref": "AAAAAAFq+VqQUNBeFQQ=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+VqQUNBhgjc=", - "_parent": { - "$ref": "AAAAAAFq+VqQUNBgoqc=" - }, - "model": { - "$ref": "AAAAAAFq+VqQUNBeFQQ=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+VqQUNBitXE=", - "_parent": { - "$ref": "AAAAAAFq+VqQUNBhgjc=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -128, - "top": -80, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+VqQUNBjwaU=", - "_parent": { - "$ref": "AAAAAAFq+VqQUNBhgjc=" - }, - "font": "Arial;13;1", - "left": 69, - "top": 407, - "width": 135, - "height": 13, - "text": "ConcreteComponent" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+VqQUNBkyvA=", - "_parent": { - "$ref": "AAAAAAFq+VqQUNBhgjc=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -128, - "top": -80, - "width": 194.27001953125, - "height": 13, - "text": "(from 结构型模式——装饰者模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+VqQUNBlSz0=", - "_parent": { - "$ref": "AAAAAAFq+VqQUNBhgjc=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -128, - "top": -80, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 64, - "top": 400, - "width": 145, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+VqQUNBitXE=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+VqQUNBjwaU=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+VqQUNBkyvA=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+VqQUNBlSz0=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+VqQUNBmD8I=", - "_parent": { - "$ref": "AAAAAAFq+VqQUNBgoqc=" - }, - "model": { - "$ref": "AAAAAAFq+VqQUNBeFQQ=" - }, - "font": "Arial;13;0", - "left": 64, - "top": 425, - "width": 145, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+VqQUNBnieo=", - "_parent": { - "$ref": "AAAAAAFq+VqQUNBgoqc=" - }, - "model": { - "$ref": "AAAAAAFq+VqQUNBeFQQ=" - }, - "font": "Arial;13;0", - "left": 64, - "top": 435, - "width": 145, - "height": 10 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+VqQUNBoxko=", - "_parent": { - "$ref": "AAAAAAFq+VqQUNBgoqc=" - }, - "model": { - "$ref": "AAAAAAFq+VqQUNBeFQQ=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -64, - "top": -40, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+VqQUNBpEKU=", - "_parent": { - "$ref": "AAAAAAFq+VqQUNBgoqc=" - }, - "model": { - "$ref": "AAAAAAFq+VqQUNBeFQQ=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -64, - "top": -40, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 64, - "top": 400, - "width": 145, - "height": 49, - "nameCompartment": { - "$ref": "AAAAAAFq+VqQUNBhgjc=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+VqQUNBmD8I=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+VqQUNBnieo=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+VqQUNBoxko=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+VqQUNBpEKU=" - } - }, - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+VqUp9CJsSo=", - "_parent": { - "$ref": "AAAAAAFq+VpMjNAjslg=" - }, - "model": { - "$ref": "AAAAAAFq+VqUp9CH4+I=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+VqUp9CK8+o=", - "_parent": { - "$ref": "AAAAAAFq+VqUp9CJsSo=" - }, - "model": { - "$ref": "AAAAAAFq+VqUp9CH4+I=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+VqUp9CLt8U=", - "_parent": { - "$ref": "AAAAAAFq+VqUp9CK8+o=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -224, - "top": -208, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+VqUp9CMR7w=", - "_parent": { - "$ref": "AAAAAAFq+VqUp9CK8+o=" - }, - "font": "Arial;13;1", - "left": 373, - "top": 375, - "width": 87, - "height": 13, - "text": "Decorator" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+VqUp9CN6kE=", - "_parent": { - "$ref": "AAAAAAFq+VqUp9CK8+o=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -224, - "top": -208, - "width": 194.27001953125, - "height": 13, - "text": "(from 结构型模式——装饰者模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+VqUp9COO4Q=", - "_parent": { - "$ref": "AAAAAAFq+VqUp9CK8+o=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -224, - "top": -208, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 368, - "top": 368, - "width": 97, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+VqUp9CLt8U=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+VqUp9CMR7w=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+VqUp9CN6kE=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+VqUp9COO4Q=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+VqUp9CP/fo=", - "_parent": { - "$ref": "AAAAAAFq+VqUp9CJsSo=" - }, - "model": { - "$ref": "AAAAAAFq+VqUp9CH4+I=" - }, - "font": "Arial;13;0", - "left": 368, - "top": 393, - "width": 97, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+VqUp9CQq94=", - "_parent": { - "$ref": "AAAAAAFq+VqUp9CJsSo=" - }, - "model": { - "$ref": "AAAAAAFq+VqUp9CH4+I=" - }, - "font": "Arial;13;0", - "left": 368, - "top": 403, - "width": 97, - "height": 10 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+VqUp9CRKZ4=", - "_parent": { - "$ref": "AAAAAAFq+VqUp9CJsSo=" - }, - "model": { - "$ref": "AAAAAAFq+VqUp9CH4+I=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -112, - "top": -104, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+VqUp9CSIpQ=", - "_parent": { - "$ref": "AAAAAAFq+VqUp9CJsSo=" - }, - "model": { - "$ref": "AAAAAAFq+VqUp9CH4+I=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -112, - "top": -104, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 368, - "top": 368, - "width": 97, - "height": 49, - "nameCompartment": { - "$ref": "AAAAAAFq+VqUp9CK8+o=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+VqUp9CP/fo=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+VqUp9CQq94=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+VqUp9CRKZ4=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+VqUp9CSIpQ=" - } - }, - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+VqZ1tCyX/o=", - "_parent": { - "$ref": "AAAAAAFq+VpMjNAjslg=" - }, - "model": { - "$ref": "AAAAAAFq+VqZ1tCw1tc=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+VqZ1tCz16g=", - "_parent": { - "$ref": "AAAAAAFq+VqZ1tCyX/o=" - }, - "model": { - "$ref": "AAAAAAFq+VqZ1tCw1tc=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+VqZ1tC0g+8=", - "_parent": { - "$ref": "AAAAAAFq+VqZ1tCz16g=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -128, - "top": -224, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+VqZ1tC1LkE=", - "_parent": { - "$ref": "AAAAAAFq+VqZ1tCz16g=" - }, - "font": "Arial;13;1", - "left": 357, - "top": 503, - "width": 117.75537109375, - "height": 13, - "text": "ConcreteDecorator" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+VqZ1tC22KE=", - "_parent": { - "$ref": "AAAAAAFq+VqZ1tCz16g=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -128, - "top": -224, - "width": 194.27001953125, - "height": 13, - "text": "(from 结构型模式——装饰者模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+VqZ1tC3QTc=", - "_parent": { - "$ref": "AAAAAAFq+VqZ1tCz16g=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -128, - "top": -224, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 352, - "top": 496, - "width": 127.75537109375, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+VqZ1tC0g+8=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+VqZ1tC1LkE=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+VqZ1tC22KE=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+VqZ1tC3QTc=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+VqZ1tC4/TM=", - "_parent": { - "$ref": "AAAAAAFq+VqZ1tCyX/o=" - }, - "model": { - "$ref": "AAAAAAFq+VqZ1tCw1tc=" - }, - "font": "Arial;13;0", - "left": 352, - "top": 521, - "width": 127.75537109375, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+VqZ1tC5jlE=", - "_parent": { - "$ref": "AAAAAAFq+VqZ1tCyX/o=" - }, - "model": { - "$ref": "AAAAAAFq+VqZ1tCw1tc=" - }, - "font": "Arial;13;0", - "left": 352, - "top": 531, - "width": 127.75537109375, - "height": 10 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+VqZ1tC6uHM=", - "_parent": { - "$ref": "AAAAAAFq+VqZ1tCyX/o=" - }, - "model": { - "$ref": "AAAAAAFq+VqZ1tCw1tc=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -64, - "top": -112, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+VqZ1tC7XLE=", - "_parent": { - "$ref": "AAAAAAFq+VqZ1tCyX/o=" - }, - "model": { - "$ref": "AAAAAAFq+VqZ1tCw1tc=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -64, - "top": -112, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 352, - "top": 496, - "width": 127.75537109375, - "height": 49, - "nameCompartment": { - "$ref": "AAAAAAFq+VqZ1tCz16g=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+VqZ1tC4/TM=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+VqZ1tC5jlE=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+VqZ1tC6uHM=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+VqZ1tC7XLE=" - } - }, - { - "_type": "UMLGeneralizationView", - "_id": "AAAAAAFq+VsU39DlTfw=", - "_parent": { - "$ref": "AAAAAAFq+VpMjNAjslg=" - }, - "model": { - "$ref": "AAAAAAFq+VsU3tDjjNI=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+VsU39Dm+UY=", - "_parent": { - "$ref": "AAAAAAFq+VsU39DlTfw=" - }, - "model": { - "$ref": "AAAAAAFq+VsU3tDjjNI=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 196, - "top": 363, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+VsU39DlTfw=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+VsU39Dn8NM=", - "_parent": { - "$ref": "AAAAAAFq+VsU39DlTfw=" - }, - "model": { - "$ref": "AAAAAAFq+VsU3tDjjNI=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 196, - "top": 348, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+VsU39DlTfw=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+VsU39DoPZg=", - "_parent": { - "$ref": "AAAAAAFq+VsU39DlTfw=" - }, - "model": { - "$ref": "AAAAAAFq+VsU3tDjjNI=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 196, - "top": 393, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+VsU39DlTfw=" - }, - "edgePosition": 1 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+VqLDdA3K0M=" - }, - "tail": { - "$ref": "AAAAAAFq+VqQUNBgoqc=" - }, - "points": "128:400;128:384;264:384;264:304", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+VsU39Dm+UY=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+VsU39Dn8NM=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+VsU39DoPZg=" - } - }, - { - "_type": "UMLGeneralizationView", - "_id": "AAAAAAFq+VsdL9D2EAE=", - "_parent": { - "$ref": "AAAAAAFq+VpMjNAjslg=" - }, - "model": { - "$ref": "AAAAAAFq+VsdL9D02Rc=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+VsdL9D33u8=", - "_parent": { - "$ref": "AAAAAAFq+VsdL9D2EAE=" - }, - "model": { - "$ref": "AAAAAAFq+VsdL9D02Rc=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 249, - "top": 377, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+VsdL9D2EAE=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+VsdL9D4uHs=", - "_parent": { - "$ref": "AAAAAAFq+VsdL9D2EAE=" - }, - "model": { - "$ref": "AAAAAAFq+VsdL9D02Rc=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 234, - "top": 377, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+VsdL9D2EAE=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+VsdL9D5MX4=", - "_parent": { - "$ref": "AAAAAAFq+VsdL9D2EAE=" - }, - "model": { - "$ref": "AAAAAAFq+VsdL9D02Rc=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 278, - "top": 378, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+VsdL9D2EAE=" - }, - "edgePosition": 1 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+VqLDdA3K0M=" - }, - "tail": { - "$ref": "AAAAAAFq+VqUp9CJsSo=" - }, - "points": "368:384;264:384;264:304", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+VsdL9D33u8=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+VsdL9D4uHs=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+VsdL9D5MX4=" - } - }, - { - "_type": "UMLGeneralizationView", - "_id": "AAAAAAFq+VwiR9GTm+s=", - "_parent": { - "$ref": "AAAAAAFq+VpMjNAjslg=" - }, - "model": { - "$ref": "AAAAAAFq+VwiR9GRuIw=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+VwiR9GU8zQ=", - "_parent": { - "$ref": "AAAAAAFq+VwiR9GTm+s=" - }, - "model": { - "$ref": "AAAAAAFq+VwiR9GRuIw=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 400, - "top": 449, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+VwiR9GTm+s=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+VwiR9GVXHs=", - "_parent": { - "$ref": "AAAAAAFq+VwiR9GTm+s=" - }, - "model": { - "$ref": "AAAAAAFq+VwiR9GRuIw=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 385, - "top": 449, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+VwiR9GTm+s=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+VwiR9GWhR8=", - "_parent": { - "$ref": "AAAAAAFq+VwiR9GTm+s=" - }, - "model": { - "$ref": "AAAAAAFq+VwiR9GRuIw=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 429, - "top": 450, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+VwiR9GTm+s=" - }, - "edgePosition": 1 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+VqUp9CJsSo=" - }, - "tail": { - "$ref": "AAAAAAFq+VqZ1tCyX/o=" - }, - "lineStyle": 1, - "points": "415:495;416:417", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+VwiR9GU8zQ=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+VwiR9GVXHs=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+VwiR9GWhR8=" - } - }, - { - "_type": "UMLAssociationView", - "_id": "AAAAAAFq+Vw8Q9GmE8E=", - "_parent": { - "$ref": "AAAAAAFq+VpMjNAjslg=" - }, - "model": { - "$ref": "AAAAAAFq+Vw8Q9Gihwk=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+Vw8Q9GnwOA=", - "_parent": { - "$ref": "AAAAAAFq+Vw8Q9GmE8E=" - }, - "model": { - "$ref": "AAAAAAFq+Vw8Q9Gihwk=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 521, - "top": 333, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+Vw8Q9GmE8E=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+Vw8Q9Gof5E=", - "_parent": { - "$ref": "AAAAAAFq+Vw8Q9GmE8E=" - }, - "model": { - "$ref": "AAAAAAFq+Vw8Q9Gihwk=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 506, - "top": 333, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+Vw8Q9GmE8E=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+Vw8Q9Gpyz8=", - "_parent": { - "$ref": "AAAAAAFq+Vw8Q9GmE8E=" - }, - "model": { - "$ref": "AAAAAAFq+Vw8Q9Gihwk=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 550, - "top": 334, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+Vw8Q9GmE8E=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+Vw8Q9Gq3lM=", - "_parent": { - "$ref": "AAAAAAFq+Vw8Q9GmE8E=" - }, - "model": { - "$ref": "AAAAAAFq+Vw8Q9GjUpI=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 489, - "top": 371, - "height": 13, - "alpha": 0.5235987755982988, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+Vw8Q9GmE8E=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+Vw8Q9Gr904=", - "_parent": { - "$ref": "AAAAAAFq+Vw8Q9GmE8E=" - }, - "model": { - "$ref": "AAAAAAFq+Vw8Q9GjUpI=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 492, - "top": 357, - "height": 13, - "alpha": 0.7853981633974483, - "distance": 40, - "hostEdge": { - "$ref": "AAAAAAFq+Vw8Q9GmE8E=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+Vw8Q9GsroI=", - "_parent": { - "$ref": "AAAAAAFq+Vw8Q9GmE8E=" - }, - "model": { - "$ref": "AAAAAAFq+Vw8Q9GjUpI=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 485, - "top": 398, - "height": 13, - "alpha": -0.5235987755982988, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFq+Vw8Q9GmE8E=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+Vw8Q9Gt+40=", - "_parent": { - "$ref": "AAAAAAFq+Vw8Q9GmE8E=" - }, - "model": { - "$ref": "AAAAAAFq+Vw8Q9GkeeE=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 345, - "top": 296, - "height": 13, - "alpha": -0.5235987755982988, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+Vw8Q9GmE8E=" - } - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+Vw8RNGug34=", - "_parent": { - "$ref": "AAAAAAFq+Vw8Q9GmE8E=" - }, - "model": { - "$ref": "AAAAAAFq+Vw8Q9GkeeE=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 348, - "top": 310, - "height": 13, - "alpha": -0.7853981633974483, - "distance": 40, - "hostEdge": { - "$ref": "AAAAAAFq+Vw8Q9GmE8E=" - } - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+Vw8RNGv0bI=", - "_parent": { - "$ref": "AAAAAAFq+Vw8Q9GmE8E=" - }, - "model": { - "$ref": "AAAAAAFq+Vw8Q9GkeeE=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 341, - "top": 269, - "height": 13, - "alpha": 0.5235987755982988, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFq+Vw8Q9GmE8E=" - } - }, - { - "_type": "UMLQualifierCompartmentView", - "_id": "AAAAAAFq+Vw8RNGwVnc=", - "_parent": { - "$ref": "AAAAAAFq+Vw8Q9GmE8E=" - }, - "model": { - "$ref": "AAAAAAFq+Vw8Q9GjUpI=" - }, - "visible": false, - "font": "Arial;13;0", - "top": 8, - "width": 10, - "height": 10 - }, - { - "_type": "UMLQualifierCompartmentView", - "_id": "AAAAAAFq+Vw8RNGxwuQ=", - "_parent": { - "$ref": "AAAAAAFq+Vw8Q9GmE8E=" - }, - "model": { - "$ref": "AAAAAAFq+Vw8Q9GkeeE=" - }, - "visible": false, - "font": "Arial;13;0", - "top": 8, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+VqLDdA3K0M=" - }, - "tail": { - "$ref": "AAAAAAFq+VqUp9CJsSo=" - }, - "points": "464:392;536:392;536:288;320:288", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+Vw8Q9GnwOA=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+Vw8Q9Gof5E=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+Vw8Q9Gpyz8=" - }, - "tailRoleNameLabel": { - "$ref": "AAAAAAFq+Vw8Q9Gq3lM=" - }, - "tailPropertyLabel": { - "$ref": "AAAAAAFq+Vw8Q9Gr904=" - }, - "tailMultiplicityLabel": { - "$ref": "AAAAAAFq+Vw8Q9GsroI=" - }, - "headRoleNameLabel": { - "$ref": "AAAAAAFq+Vw8Q9Gt+40=" - }, - "headPropertyLabel": { - "$ref": "AAAAAAFq+Vw8RNGug34=" - }, - "headMultiplicityLabel": { - "$ref": "AAAAAAFq+Vw8RNGv0bI=" - }, - "tailQualifiersCompartment": { - "$ref": "AAAAAAFq+Vw8RNGwVnc=" - }, - "headQualifiersCompartment": { - "$ref": "AAAAAAFq+Vw8RNGxwuQ=" - } - } - ] - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+VqLDdA1gfk=", - "_parent": { - "$ref": "AAAAAAFq+VpMjNAiUuc=" - }, - "name": "Component", - "isAbstract": true - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+VqQUNBeFQQ=", - "_parent": { - "$ref": "AAAAAAFq+VpMjNAiUuc=" - }, - "name": "ConcreteComponent", - "ownedElements": [ - { - "_type": "UMLGeneralization", - "_id": "AAAAAAFq+VsU3tDjjNI=", - "_parent": { - "$ref": "AAAAAAFq+VqQUNBeFQQ=" - }, - "source": { - "$ref": "AAAAAAFq+VqQUNBeFQQ=" - }, - "target": { - "$ref": "AAAAAAFq+VqLDdA1gfk=" - } - } - ] - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+VqUp9CH4+I=", - "_parent": { - "$ref": "AAAAAAFq+VpMjNAiUuc=" - }, - "name": "Decorator", - "ownedElements": [ - { - "_type": "UMLGeneralization", - "_id": "AAAAAAFq+VsdL9D02Rc=", - "_parent": { - "$ref": "AAAAAAFq+VqUp9CH4+I=" - }, - "source": { - "$ref": "AAAAAAFq+VqUp9CH4+I=" - }, - "target": { - "$ref": "AAAAAAFq+VqLDdA1gfk=" - } - }, - { - "_type": "UMLAssociation", - "_id": "AAAAAAFq+Vw8Q9Gihwk=", - "_parent": { - "$ref": "AAAAAAFq+VqUp9CH4+I=" - }, - "end1": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFq+Vw8Q9GjUpI=", - "_parent": { - "$ref": "AAAAAAFq+Vw8Q9Gihwk=" - }, - "reference": { - "$ref": "AAAAAAFq+VqUp9CH4+I=" - }, - "navigable": false, - "aggregation": "shared" - }, - "end2": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFq+Vw8Q9GkeeE=", - "_parent": { - "$ref": "AAAAAAFq+Vw8Q9Gihwk=" - }, - "reference": { - "$ref": "AAAAAAFq+VqLDdA1gfk=" - } - } - } - ] - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+VqZ1tCw1tc=", - "_parent": { - "$ref": "AAAAAAFq+VpMjNAiUuc=" - }, - "name": "ConcreteDecorator", - "ownedElements": [ - { - "_type": "UMLGeneralization", - "_id": "AAAAAAFq+VwiR9GRuIw=", - "_parent": { - "$ref": "AAAAAAFq+VqZ1tCw1tc=" - }, - "source": { - "$ref": "AAAAAAFq+VqZ1tCw1tc=" - }, - "target": { - "$ref": "AAAAAAFq+VqUp9CH4+I=" - } - } - ] - } - ] - }, - { - "_type": "UMLModel", - "_id": "AAAAAAFq+WWQOdPWSZQ=", - "_parent": { - "$ref": "AAAAAAFF+h6SjaM2Hec=" - }, - "name": "结构型模式——适配器模式", - "ownedElements": [ - { - "_type": "UMLClassDiagram", - "_id": "AAAAAAFq+WWQOdPXFHY=", - "_parent": { - "$ref": "AAAAAAFq+WWQOdPWSZQ=" - }, - "name": "类适配器", - "ownedViews": [ - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+YVM9tijb28=", - "_parent": { - "$ref": "AAAAAAFq+WWQOdPXFHY=" - }, - "model": { - "$ref": "AAAAAAFq+WXvAdP8SLU=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+YVM9tikhUQ=", - "_parent": { - "$ref": "AAAAAAFq+YVM9tijb28=" - }, - "model": { - "$ref": "AAAAAAFq+WXvAdP8SLU=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+YVM9tilJ4I=", - "_parent": { - "$ref": "AAAAAAFq+YVM9tikhUQ=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -364, - "top": -54, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+YVM9time8Q=", - "_parent": { - "$ref": "AAAAAAFq+YVM9tikhUQ=" - }, - "font": "Arial;13;1", - "left": 69, - "top": 215, - "width": 73.919921875, - "height": 13, - "text": "Client" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+YVM9tinrJ4=", - "_parent": { - "$ref": "AAAAAAFq+YVM9tikhUQ=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -364, - "top": -54, - "width": 194.27001953125, - "height": 13, - "text": "(from 结构型模式——适配器模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+YVM9tioPb8=", - "_parent": { - "$ref": "AAAAAAFq+YVM9tikhUQ=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -364, - "top": -54, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 64, - "top": 208, - "width": 83.919921875, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+YVM9tilJ4I=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+YVM9time8Q=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+YVM9tinrJ4=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+YVM9tioPb8=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+YVM9tip4cs=", - "_parent": { - "$ref": "AAAAAAFq+YVM9tijb28=" - }, - "model": { - "$ref": "AAAAAAFq+WXvAdP8SLU=" - }, - "font": "Arial;13;0", - "left": 64, - "top": 233, - "width": 83.919921875, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+YVM9tiqVWU=", - "_parent": { - "$ref": "AAAAAAFq+YVM9tijb28=" - }, - "model": { - "$ref": "AAAAAAFq+WXvAdP8SLU=" - }, - "font": "Arial;13;0", - "left": 64, - "top": 243, - "width": 83.919921875, - "height": 10 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+YVM9tirbd4=", - "_parent": { - "$ref": "AAAAAAFq+YVM9tijb28=" - }, - "model": { - "$ref": "AAAAAAFq+WXvAdP8SLU=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -152, - "top": 8, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+YVM9tisbcs=", - "_parent": { - "$ref": "AAAAAAFq+YVM9tijb28=" - }, - "model": { - "$ref": "AAAAAAFq+WXvAdP8SLU=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -152, - "top": 8, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 64, - "top": 208, - "width": 83.919921875, - "height": 65, - "nameCompartment": { - "$ref": "AAAAAAFq+YVM9tikhUQ=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+YVM9tip4cs=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+YVM9tiqVWU=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+YVM9tirbd4=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+YVM9tisbcs=" - } - }, - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+YVM9ti4Fek=", - "_parent": { - "$ref": "AAAAAAFq+WWQOdPXFHY=" - }, - "model": { - "$ref": "AAAAAAFq+Wjb1NRQ2KA=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+YVM9ti5kks=", - "_parent": { - "$ref": "AAAAAAFq+YVM9ti4Fek=" - }, - "model": { - "$ref": "AAAAAAFq+Wjb1NRQ2KA=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+YVM9ti6ppo=", - "_parent": { - "$ref": "AAAAAAFq+YVM9ti5kks=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 28, - "top": -74, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+YVM9ti7ztE=", - "_parent": { - "$ref": "AAAAAAFq+YVM9ti5kks=" - }, - "font": "Arial;13;1", - "left": 481, - "top": 213, - "width": 119, - "height": 13, - "text": "Adaptee" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+YVM9ti8OoY=", - "_parent": { - "$ref": "AAAAAAFq+YVM9ti5kks=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 28, - "top": -74, - "width": 194.27001953125, - "height": 13, - "text": "(from 结构型模式——适配器模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+YVM9ti9eCQ=", - "_parent": { - "$ref": "AAAAAAFq+YVM9ti5kks=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 28, - "top": -74, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 476, - "top": 206, - "width": 129, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+YVM9ti6ppo=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+YVM9ti7ztE=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+YVM9ti8OoY=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+YVM9ti9eCQ=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+YVM9ti+qZ8=", - "_parent": { - "$ref": "AAAAAAFq+YVM9ti4Fek=" - }, - "model": { - "$ref": "AAAAAAFq+Wjb1NRQ2KA=" - }, - "font": "Arial;13;0", - "left": 476, - "top": 231, - "width": 129, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+YVM9ti/AK8=", - "_parent": { - "$ref": "AAAAAAFq+YVM9ti4Fek=" - }, - "model": { - "$ref": "AAAAAAFq+Wjb1NRQ2KA=" - }, - "subViews": [ - { - "_type": "UMLOperationView", - "_id": "AAAAAAFq+YVM9tjAnxI=", - "_parent": { - "$ref": "AAAAAAFq+YVM9ti/AK8=" - }, - "model": { - "$ref": "AAAAAAFq+WpQkNTjauU=" - }, - "font": "Arial;13;0", - "left": 481, - "top": 246, - "width": 119, - "height": 13, - "text": "+adapteeRequest()", - "horizontalAlignment": 0 - } - ], - "font": "Arial;13;0", - "left": 476, - "top": 241, - "width": 129, - "height": 23 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+YVM9tjBb5M=", - "_parent": { - "$ref": "AAAAAAFq+YVM9ti4Fek=" - }, - "model": { - "$ref": "AAAAAAFq+Wjb1NRQ2KA=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 44, - "top": -2, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+YVM9tjCITM=", - "_parent": { - "$ref": "AAAAAAFq+YVM9ti4Fek=" - }, - "model": { - "$ref": "AAAAAAFq+Wjb1NRQ2KA=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 44, - "top": -2, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 476, - "top": 206, - "width": 129, - "height": 65, - "nameCompartment": { - "$ref": "AAAAAAFq+YVM9ti5kks=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+YVM9ti+qZ8=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+YVM9ti/AK8=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+YVM9tjBb5M=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+YVM9tjCITM=" - } - }, - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+YVM9tjDGIc=", - "_parent": { - "$ref": "AAAAAAFq+WWQOdPXFHY=" - }, - "model": { - "$ref": "AAAAAAFq+WjjWdR51ug=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+YVM9tjEHXc=", - "_parent": { - "$ref": "AAAAAAFq+YVM9tjDGIc=" - }, - "model": { - "$ref": "AAAAAAFq+WjjWdR51ug=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+YVM9tjFKZY=", - "_parent": { - "$ref": "AAAAAAFq+YVM9tjEHXc=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 84, - "top": -42, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+YVM9tjGPpo=", - "_parent": { - "$ref": "AAAAAAFq+YVM9tjEHXc=" - }, - "font": "Arial;13;1", - "left": 381, - "top": 357, - "width": 103, - "height": 13, - "text": "Adapter" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+YVM9tjHrpg=", - "_parent": { - "$ref": "AAAAAAFq+YVM9tjEHXc=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 84, - "top": -42, - "width": 194.27001953125, - "height": 13, - "text": "(from 结构型模式——适配器模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+YVM9tjIQS4=", - "_parent": { - "$ref": "AAAAAAFq+YVM9tjEHXc=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 84, - "top": -42, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 376, - "top": 350, - "width": 113, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+YVM9tjFKZY=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+YVM9tjGPpo=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+YVM9tjHrpg=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+YVM9tjIQS4=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+YVM9tjJGlk=", - "_parent": { - "$ref": "AAAAAAFq+YVM9tjDGIc=" - }, - "model": { - "$ref": "AAAAAAFq+WjjWdR51ug=" - }, - "subViews": [ - { - "_type": "UMLAttributeView", - "_id": "AAAAAAFq+glOoOMqkGc=", - "_parent": { - "$ref": "AAAAAAFq+YVM9tjJGlk=" - }, - "model": { - "$ref": "AAAAAAFq+gV2HuIz1IE=" - }, - "font": "Arial;13;0", - "left": 381, - "top": 380, - "width": 103, - "height": 13, - "text": "+adaptee", - "horizontalAlignment": 0 - } - ], - "font": "Arial;13;0", - "left": 376, - "top": 375, - "width": 113, - "height": 23 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+YVM9tjKWXA=", - "_parent": { - "$ref": "AAAAAAFq+YVM9tjDGIc=" - }, - "model": { - "$ref": "AAAAAAFq+WjjWdR51ug=" - }, - "subViews": [ - { - "_type": "UMLOperationView", - "_id": "AAAAAAFq+YVM9tjLJgQ=", - "_parent": { - "$ref": "AAAAAAFq+YVM9tjKWXA=" - }, - "model": { - "$ref": "AAAAAAFq+WqFStTq9O0=" - }, - "font": "Arial;13;0", - "left": 381, - "top": 403, - "width": 103, - "height": 13, - "text": "+request()", - "horizontalAlignment": 0 - } - ], - "font": "Arial;13;0", - "left": 376, - "top": 398, - "width": 113, - "height": 23 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+YVM9tjM6l8=", - "_parent": { - "$ref": "AAAAAAFq+YVM9tjDGIc=" - }, - "model": { - "$ref": "AAAAAAFq+WjjWdR51ug=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 72, - "top": 14, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+YVM9tjNkBM=", - "_parent": { - "$ref": "AAAAAAFq+YVM9tjDGIc=" - }, - "model": { - "$ref": "AAAAAAFq+WjjWdR51ug=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 72, - "top": 14, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 376, - "top": 350, - "width": 113, - "height": 71, - "nameCompartment": { - "$ref": "AAAAAAFq+YVM9tjEHXc=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+YVM9tjJGlk=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+YVM9tjKWXA=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+YVM9tjM6l8=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+YVM9tjNkBM=" - } - }, - { - "_type": "UMLNoteView", - "_id": "AAAAAAFq+YVM9tjOLmo=", - "_parent": { - "$ref": "AAAAAAFq+WWQOdPXFHY=" - }, - "font": "Arial;13;0", - "left": 288, - "top": 462, - "width": 193, - "height": 33, - "text": "adapteeRequest();" - }, - { - "_type": "UMLNoteLinkView", - "_id": "AAAAAAFq+YVM9tjPUcI=", - "_parent": { - "$ref": "AAAAAAFq+WWQOdPXFHY=" - }, - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+YVM9tjDGIc=" - }, - "tail": { - "$ref": "AAAAAAFq+YVM9tjOLmo=" - }, - "lineStyle": 1, - "points": "393:461;413:421" - }, - { - "_type": "UMLInterfaceView", - "_id": "AAAAAAFq+YVtW9m2g9U=", - "_parent": { - "$ref": "AAAAAAFq+WWQOdPXFHY=" - }, - "model": { - "$ref": "AAAAAAFq+YVtWtm05OQ=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+YVtW9m3H6Q=", - "_parent": { - "$ref": "AAAAAAFq+YVtW9m2g9U=" - }, - "model": { - "$ref": "AAAAAAFq+YVtWtm05OQ=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+YVtW9m4B2A=", - "_parent": { - "$ref": "AAAAAAFq+YVtW9m3H6Q=" - }, - "font": "Arial;13;0", - "left": 245, - "top": 205, - "width": 87, - "height": 13, - "text": "«interface»" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+YVtW9m5Rk0=", - "_parent": { - "$ref": "AAAAAAFq+YVtW9m3H6Q=" - }, - "font": "Arial;13;1", - "left": 245, - "top": 220, - "width": 87, - "height": 13, - "text": "Target" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+YVtW9m6kX0=", - "_parent": { - "$ref": "AAAAAAFq+YVtW9m3H6Q=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -16, - "top": -80, - "width": 194.27001953125, - "height": 13, - "text": "(from 结构型模式——适配器模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+YVtW9m7x6A=", - "_parent": { - "$ref": "AAAAAAFq+YVtW9m3H6Q=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -16, - "top": -80, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 240, - "top": 200, - "width": 97, - "height": 38, - "stereotypeLabel": { - "$ref": "AAAAAAFq+YVtW9m4B2A=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+YVtW9m5Rk0=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+YVtW9m6kX0=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+YVtW9m7x6A=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+YVtW9m8uAk=", - "_parent": { - "$ref": "AAAAAAFq+YVtW9m2g9U=" - }, - "model": { - "$ref": "AAAAAAFq+YVtWtm05OQ=" - }, - "font": "Arial;13;0", - "left": 240, - "top": 238, - "width": 97, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+YVtW9m9Dco=", - "_parent": { - "$ref": "AAAAAAFq+YVtW9m2g9U=" - }, - "model": { - "$ref": "AAAAAAFq+YVtWtm05OQ=" - }, - "subViews": [ - { - "_type": "UMLOperationView", - "_id": "AAAAAAFq+ZG4XttQK7s=", - "_parent": { - "$ref": "AAAAAAFq+YVtW9m9Dco=" - }, - "model": { - "$ref": "AAAAAAFq+ZG4OdtKLl4=" - }, - "font": "Arial;13;0", - "left": 245, - "top": 253, - "width": 87, - "height": 13, - "text": "+request()", - "horizontalAlignment": 0 - } - ], - "font": "Arial;13;0", - "left": 240, - "top": 248, - "width": 97, - "height": 23 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+YVtW9m+dMo=", - "_parent": { - "$ref": "AAAAAAFq+YVtW9m2g9U=" - }, - "model": { - "$ref": "AAAAAAFq+YVtWtm05OQ=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 240, - "top": 271, - "width": 113, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+YVtW9m/l+0=", - "_parent": { - "$ref": "AAAAAAFq+YVtW9m2g9U=" - }, - "model": { - "$ref": "AAAAAAFq+YVtWtm05OQ=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -8, - "top": -40, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 240, - "top": 200, - "width": 97, - "height": 81, - "nameCompartment": { - "$ref": "AAAAAAFq+YVtW9m3H6Q=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+YVtW9m8uAk=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+YVtW9m9Dco=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+YVtW9m+dMo=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+YVtW9m/l+0=" - } - }, - { - "_type": "UMLDependencyView", - "_id": "AAAAAAFq+YiCDdpawUU=", - "_parent": { - "$ref": "AAAAAAFq+WWQOdPXFHY=" - }, - "model": { - "$ref": "AAAAAAFq+YiCDNpYfQY=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+YiCDdpbn+Y=", - "_parent": { - "$ref": "AAAAAAFq+YiCDdpawUU=" - }, - "model": { - "$ref": "AAAAAAFq+YiCDNpYfQY=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 193, - "top": 217, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+YiCDdpawUU=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+YiCDdpcZbA=", - "_parent": { - "$ref": "AAAAAAFq+YiCDdpawUU=" - }, - "model": { - "$ref": "AAAAAAFq+YiCDNpYfQY=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 193, - "top": 202, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+YiCDdpawUU=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+YiCDdpd9GE=", - "_parent": { - "$ref": "AAAAAAFq+YiCDdpawUU=" - }, - "model": { - "$ref": "AAAAAAFq+YiCDNpYfQY=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 193, - "top": 247, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+YiCDdpawUU=" - }, - "edgePosition": 1 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+YVtW9m2g9U=" - }, - "tail": { - "$ref": "AAAAAAFq+YVM9tijb28=" - }, - "points": "147:238;240:238", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+YiCDdpbn+Y=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+YiCDdpcZbA=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+YiCDdpd9GE=" - } - }, - { - "_type": "UMLInterfaceRealizationView", - "_id": "AAAAAAFq+ZAzbNq2bOU=", - "_parent": { - "$ref": "AAAAAAFq+WWQOdPXFHY=" - }, - "model": { - "$ref": "AAAAAAFq+ZAzbNq14HQ=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+ZAzbNq3boI=", - "_parent": { - "$ref": "AAAAAAFq+ZAzbNq2bOU=" - }, - "model": { - "$ref": "AAAAAAFq+ZAzbNq14HQ=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 285, - "top": 375, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+ZAzbNq2bOU=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+ZAzbNq4yWE=", - "_parent": { - "$ref": "AAAAAAFq+ZAzbNq2bOU=" - }, - "model": { - "$ref": "AAAAAAFq+ZAzbNq14HQ=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 270, - "top": 375, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+ZAzbNq2bOU=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+ZAzbNq5++k=", - "_parent": { - "$ref": "AAAAAAFq+ZAzbNq2bOU=" - }, - "model": { - "$ref": "AAAAAAFq+ZAzbNq14HQ=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 315, - "top": 376, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+ZAzbNq2bOU=" - }, - "edgePosition": 1 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+YVtW9m2g9U=" - }, - "tail": { - "$ref": "AAAAAAFq+YVM9tjDGIc=" - }, - "points": "376:382;300:382;300:280", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+ZAzbNq3boI=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+ZAzbNq4yWE=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+ZAzbNq5++k=" - } - }, - { - "_type": "UMLGeneralizationView", - "_id": "AAAAAAFq+e+nueHJevc=", - "_parent": { - "$ref": "AAAAAAFq+WWQOdPXFHY=" - }, - "model": { - "$ref": "AAAAAAFq+e+nuOHHzao=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+e+nueHK1IU=", - "_parent": { - "$ref": "AAAAAAFq+e+nueHJevc=" - }, - "model": { - "$ref": "AAAAAAFq+e+nuOHHzao=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 529, - "top": 375, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+e+nueHJevc=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+e+nueHLxHY=", - "_parent": { - "$ref": "AAAAAAFq+e+nueHJevc=" - }, - "model": { - "$ref": "AAAAAAFq+e+nuOHHzao=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 514, - "top": 375, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+e+nueHJevc=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+e+nueHMnrY=", - "_parent": { - "$ref": "AAAAAAFq+e+nueHJevc=" - }, - "model": { - "$ref": "AAAAAAFq+e+nuOHHzao=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 559, - "top": 376, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+e+nueHJevc=" - }, - "edgePosition": 1 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+YVM9ti4Fek=" - }, - "tail": { - "$ref": "AAAAAAFq+YVM9tjDGIc=" - }, - "points": "488:382;544:382;544:270", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+e+nueHK1IU=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+e+nueHLxHY=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+e+nueHMnrY=" - } - } - ] - }, - { - "_type": "UMLClassDiagram", - "_id": "AAAAAAFq+WXAE9Ps07Q=", - "_parent": { - "$ref": "AAAAAAFq+WWQOdPWSZQ=" - }, - "name": "对象适配器", - "ownedViews": [ - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+WXvAdP+DeI=", - "_parent": { - "$ref": "AAAAAAFq+WXAE9Ps07Q=" - }, - "model": { - "$ref": "AAAAAAFq+WXvAdP8SLU=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+WXvAdP/tWM=", - "_parent": { - "$ref": "AAAAAAFq+WXvAdP+DeI=" - }, - "model": { - "$ref": "AAAAAAFq+WXvAdP8SLU=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+WXvAdQASDA=", - "_parent": { - "$ref": "AAAAAAFq+WXvAdP/tWM=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -256, - "top": -16, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+WXvAdQB7hw=", - "_parent": { - "$ref": "AAAAAAFq+WXvAdP/tWM=" - }, - "font": "Arial;13;1", - "left": 93, - "top": 199, - "width": 73.919921875, - "height": 13, - "text": "Client" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+WXvAdQCLcU=", - "_parent": { - "$ref": "AAAAAAFq+WXvAdP/tWM=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -256, - "top": -16, - "width": 194.27001953125, - "height": 13, - "text": "(from 结构型模式——适配器模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+WXvAdQDg1U=", - "_parent": { - "$ref": "AAAAAAFq+WXvAdP/tWM=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -256, - "top": -16, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 88, - "top": 192, - "width": 83.919921875, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+WXvAdQASDA=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+WXvAdQB7hw=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+WXvAdQCLcU=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+WXvAdQDg1U=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+WXvAdQEquk=", - "_parent": { - "$ref": "AAAAAAFq+WXvAdP+DeI=" - }, - "model": { - "$ref": "AAAAAAFq+WXvAdP8SLU=" - }, - "font": "Arial;13;0", - "left": 88, - "top": 217, - "width": 83.919921875, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+WXvAdQFiA0=", - "_parent": { - "$ref": "AAAAAAFq+WXvAdP+DeI=" - }, - "model": { - "$ref": "AAAAAAFq+WXvAdP8SLU=" - }, - "font": "Arial;13;0", - "left": 88, - "top": 227, - "width": 83.919921875, - "height": 10 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+WXvAdQGmcQ=", - "_parent": { - "$ref": "AAAAAAFq+WXvAdP+DeI=" - }, - "model": { - "$ref": "AAAAAAFq+WXvAdP8SLU=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -128, - "top": -8, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+WXvAdQHqKw=", - "_parent": { - "$ref": "AAAAAAFq+WXvAdP+DeI=" - }, - "model": { - "$ref": "AAAAAAFq+WXvAdP8SLU=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -128, - "top": -8, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 88, - "top": 192, - "width": 83.919921875, - "height": 65, - "nameCompartment": { - "$ref": "AAAAAAFq+WXvAdP/tWM=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+WXvAdQEquk=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+WXvAdQFiA0=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+WXvAdQGmcQ=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+WXvAdQHqKw=" - } - }, - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+Wjb1dRSr0g=", - "_parent": { - "$ref": "AAAAAAFq+WXAE9Ps07Q=" - }, - "model": { - "$ref": "AAAAAAFq+Wjb1NRQ2KA=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+Wjb1dRTiQ4=", - "_parent": { - "$ref": "AAAAAAFq+Wjb1dRSr0g=" - }, - "model": { - "$ref": "AAAAAAFq+Wjb1NRQ2KA=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+Wjb1dRU/YI=", - "_parent": { - "$ref": "AAAAAAFq+Wjb1dRTiQ4=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 64, - "top": -32, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+Wjb1dRVbrQ=", - "_parent": { - "$ref": "AAAAAAFq+Wjb1dRTiQ4=" - }, - "font": "Arial;13;1", - "left": 469, - "top": 199, - "width": 119, - "height": 13, - "text": "Adaptee" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+Wjb1dRW/uY=", - "_parent": { - "$ref": "AAAAAAFq+Wjb1dRTiQ4=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 64, - "top": -32, - "width": 194.27001953125, - "height": 13, - "text": "(from 结构型模式——适配器模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+Wjb1dRXfdE=", - "_parent": { - "$ref": "AAAAAAFq+Wjb1dRTiQ4=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 64, - "top": -32, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 464, - "top": 192, - "width": 129, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+Wjb1dRU/YI=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+Wjb1dRVbrQ=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+Wjb1dRW/uY=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+Wjb1dRXfdE=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+Wjb1tRY9fc=", - "_parent": { - "$ref": "AAAAAAFq+Wjb1dRSr0g=" - }, - "model": { - "$ref": "AAAAAAFq+Wjb1NRQ2KA=" - }, - "font": "Arial;13;0", - "left": 464, - "top": 217, - "width": 129, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+Wjb1tRZ+0I=", - "_parent": { - "$ref": "AAAAAAFq+Wjb1dRSr0g=" - }, - "model": { - "$ref": "AAAAAAFq+Wjb1NRQ2KA=" - }, - "subViews": [ - { - "_type": "UMLOperationView", - "_id": "AAAAAAFq+WpQtNTmge0=", - "_parent": { - "$ref": "AAAAAAFq+Wjb1tRZ+0I=" - }, - "model": { - "$ref": "AAAAAAFq+WpQkNTjauU=" - }, - "font": "Arial;13;0", - "left": 469, - "top": 232, - "width": 119, - "height": 13, - "text": "+adapteeRequest()", - "horizontalAlignment": 0 - } - ], - "font": "Arial;13;0", - "left": 464, - "top": 227, - "width": 129, - "height": 23 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+Wjb1tRapD0=", - "_parent": { - "$ref": "AAAAAAFq+Wjb1dRSr0g=" - }, - "model": { - "$ref": "AAAAAAFq+Wjb1NRQ2KA=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 32, - "top": -16, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+Wjb1tRbnVw=", - "_parent": { - "$ref": "AAAAAAFq+Wjb1dRSr0g=" - }, - "model": { - "$ref": "AAAAAAFq+Wjb1NRQ2KA=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 32, - "top": -16, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 464, - "top": 192, - "width": 129, - "height": 65, - "nameCompartment": { - "$ref": "AAAAAAFq+Wjb1dRTiQ4=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+Wjb1tRY9fc=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+Wjb1tRZ+0I=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+Wjb1tRapD0=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+Wjb1tRbnVw=" - } - }, - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+WjjWdR7Fy0=", - "_parent": { - "$ref": "AAAAAAFq+WXAE9Ps07Q=" - }, - "model": { - "$ref": "AAAAAAFq+WjjWdR51ug=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+WjjWdR8V5s=", - "_parent": { - "$ref": "AAAAAAFq+WjjWdR7Fy0=" - }, - "model": { - "$ref": "AAAAAAFq+WjjWdR51ug=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+WjjWdR9cig=", - "_parent": { - "$ref": "AAAAAAFq+WjjWdR8V5s=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 160, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+WjjWdR+iVU=", - "_parent": { - "$ref": "AAAAAAFq+WjjWdR8V5s=" - }, - "font": "Arial;13;1", - "left": 389, - "top": 343, - "width": 103, - "height": 13, - "text": "Adapter" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+WjjWdR/jMM=", - "_parent": { - "$ref": "AAAAAAFq+WjjWdR8V5s=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 160, - "width": 194.27001953125, - "height": 13, - "text": "(from 结构型模式——适配器模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+WjjWdSAKWQ=", - "_parent": { - "$ref": "AAAAAAFq+WjjWdR8V5s=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 160, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 384, - "top": 336, - "width": 113, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+WjjWdR9cig=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+WjjWdR+iVU=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+WjjWdR/jMM=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+WjjWdSAKWQ=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+WjjWdSBHWc=", - "_parent": { - "$ref": "AAAAAAFq+WjjWdR7Fy0=" - }, - "model": { - "$ref": "AAAAAAFq+WjjWdR51ug=" - }, - "subViews": [ - { - "_type": "UMLAttributeView", - "_id": "AAAAAAFq+gV2QuI2tzQ=", - "_parent": { - "$ref": "AAAAAAFq+WjjWdSBHWc=" - }, - "model": { - "$ref": "AAAAAAFq+gV2HuIz1IE=" - }, - "font": "Arial;13;0", - "left": 389, - "top": 366, - "width": 103, - "height": 13, - "text": "+adaptee", - "horizontalAlignment": 0 - } - ], - "font": "Arial;13;0", - "left": 384, - "top": 361, - "width": 113, - "height": 23 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+WjjWdSCuuE=", - "_parent": { - "$ref": "AAAAAAFq+WjjWdR7Fy0=" - }, - "model": { - "$ref": "AAAAAAFq+WjjWdR51ug=" - }, - "subViews": [ - { - "_type": "UMLOperationView", - "_id": "AAAAAAFq+WqFctTtBZY=", - "_parent": { - "$ref": "AAAAAAFq+WjjWdSCuuE=" - }, - "model": { - "$ref": "AAAAAAFq+WqFStTq9O0=" - }, - "font": "Arial;13;0", - "left": 389, - "top": 389, - "width": 103, - "height": 13, - "text": "+request()", - "horizontalAlignment": 0 - } - ], - "font": "Arial;13;0", - "left": 384, - "top": 384, - "width": 113, - "height": 23 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+WjjWdSD8Rk=", - "_parent": { - "$ref": "AAAAAAFq+WjjWdR7Fy0=" - }, - "model": { - "$ref": "AAAAAAFq+WjjWdR51ug=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 80, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+WjjWdSEVC0=", - "_parent": { - "$ref": "AAAAAAFq+WjjWdR7Fy0=" - }, - "model": { - "$ref": "AAAAAAFq+WjjWdR51ug=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 80, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 384, - "top": 336, - "width": 113, - "height": 71, - "nameCompartment": { - "$ref": "AAAAAAFq+WjjWdR8V5s=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+WjjWdSBHWc=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+WjjWdSCuuE=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+WjjWdSD8Rk=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+WjjWdSEVC0=" - } - }, - { - "_type": "UMLNoteView", - "_id": "AAAAAAFq+WnBx9TUXgk=", - "_parent": { - "$ref": "AAAAAAFq+WXAE9Ps07Q=" - }, - "font": "Arial;13;0", - "left": 320, - "top": 448, - "width": 193, - "height": 33, - "text": "adaptee.adapteeRequest();" - }, - { - "_type": "UMLNoteLinkView", - "_id": "AAAAAAFq+WnztdTYyu4=", - "_parent": { - "$ref": "AAAAAAFq+WXAE9Ps07Q=" - }, - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+WjjWdR7Fy0=" - }, - "tail": { - "$ref": "AAAAAAFq+WnBx9TUXgk=" - }, - "lineStyle": 1, - "points": "420:447;431:407" - }, - { - "_type": "UMLAssociationView", - "_id": "AAAAAAFq+WzhVtU3owQ=", - "_parent": { - "$ref": "AAAAAAFq+WXAE9Ps07Q=" - }, - "model": { - "$ref": "AAAAAAFq+WzhVtUzjr8=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+WzhV9U4728=", - "_parent": { - "$ref": "AAAAAAFq+WzhVtU3owQ=" - }, - "model": { - "$ref": "AAAAAAFq+WzhVtUzjr8=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 546, - "top": 360, - "width": 54.58349609375, - "height": 13, - "alpha": -1.5444865271766737, - "distance": 38.01315561749642, - "hostEdge": { - "$ref": "AAAAAAFq+WzhVtU3owQ=" - }, - "edgePosition": 1, - "text": "+adaptee" - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+WzhV9U5lsY=", - "_parent": { - "$ref": "AAAAAAFq+WzhVtU3owQ=" - }, - "model": { - "$ref": "AAAAAAFq+WzhVtUzjr8=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 506, - "top": 361, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+WzhVtU3owQ=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+WzhV9U68LI=", - "_parent": { - "$ref": "AAAAAAFq+WzhVtU3owQ=" - }, - "model": { - "$ref": "AAAAAAFq+WzhVtUzjr8=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 551, - "top": 362, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+WzhVtU3owQ=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+WzhV9U7fWI=", - "_parent": { - "$ref": "AAAAAAFq+WzhVtU3owQ=" - }, - "model": { - "$ref": "AAAAAAFq+WzhVtU0fYw=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 521, - "top": 347, - "height": 13, - "alpha": 0.5235987755982988, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+WzhVtU3owQ=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+WzhV9U8AQo=", - "_parent": { - "$ref": "AAAAAAFq+WzhVtU3owQ=" - }, - "model": { - "$ref": "AAAAAAFq+WzhVtU0fYw=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 524, - "top": 333, - "height": 13, - "alpha": 0.7853981633974483, - "distance": 40, - "hostEdge": { - "$ref": "AAAAAAFq+WzhVtU3owQ=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+WzhV9U9tnQ=", - "_parent": { - "$ref": "AAAAAAFq+WzhVtU3owQ=" - }, - "model": { - "$ref": "AAAAAAFq+WzhVtU0fYw=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 517, - "top": 374, - "height": 13, - "alpha": -0.5235987755982988, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFq+WzhVtU3owQ=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+WzhV9U+OPg=", - "_parent": { - "$ref": "AAAAAAFq+WzhVtU3owQ=" - }, - "model": { - "$ref": "AAAAAAFq+WzhVtU1okE=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 521, - "top": 275, - "height": 13, - "alpha": -0.5235987755982988, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+WzhVtU3owQ=" - } - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+WzhV9U/5k8=", - "_parent": { - "$ref": "AAAAAAFq+WzhVtU3owQ=" - }, - "model": { - "$ref": "AAAAAAFq+WzhVtU1okE=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 507, - "top": 278, - "height": 13, - "alpha": -0.7853981633974483, - "distance": 40, - "hostEdge": { - "$ref": "AAAAAAFq+WzhVtU3owQ=" - } - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+WzhV9VAo8M=", - "_parent": { - "$ref": "AAAAAAFq+WzhVtU3owQ=" - }, - "model": { - "$ref": "AAAAAAFq+WzhVtU1okE=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 548, - "top": 271, - "height": 13, - "alpha": 0.5235987755982988, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFq+WzhVtU3owQ=" - } - }, - { - "_type": "UMLQualifierCompartmentView", - "_id": "AAAAAAFq+WzhV9VBknw=", - "_parent": { - "$ref": "AAAAAAFq+WzhVtU3owQ=" - }, - "model": { - "$ref": "AAAAAAFq+WzhVtU0fYw=" - }, - "visible": false, - "font": "Arial;13;0", - "width": 10, - "height": 10 - }, - { - "_type": "UMLQualifierCompartmentView", - "_id": "AAAAAAFq+WzhV9VC8tU=", - "_parent": { - "$ref": "AAAAAAFq+WzhVtU3owQ=" - }, - "model": { - "$ref": "AAAAAAFq+WzhVtU1okE=" - }, - "visible": false, - "font": "Arial;13;0", - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+Wjb1dRSr0g=" - }, - "tail": { - "$ref": "AAAAAAFq+WjjWdR7Fy0=" - }, - "points": "496:368;536:368;536:256", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+WzhV9U4728=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+WzhV9U5lsY=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+WzhV9U68LI=" - }, - "tailRoleNameLabel": { - "$ref": "AAAAAAFq+WzhV9U7fWI=" - }, - "tailPropertyLabel": { - "$ref": "AAAAAAFq+WzhV9U8AQo=" - }, - "tailMultiplicityLabel": { - "$ref": "AAAAAAFq+WzhV9U9tnQ=" - }, - "headRoleNameLabel": { - "$ref": "AAAAAAFq+WzhV9U+OPg=" - }, - "headPropertyLabel": { - "$ref": "AAAAAAFq+WzhV9U/5k8=" - }, - "headMultiplicityLabel": { - "$ref": "AAAAAAFq+WzhV9VAo8M=" - }, - "tailQualifiersCompartment": { - "$ref": "AAAAAAFq+WzhV9VBknw=" - }, - "headQualifiersCompartment": { - "$ref": "AAAAAAFq+WzhV9VC8tU=" - } - }, - { - "_type": "UMLInterfaceView", - "_id": "AAAAAAFq+esTWd4nYxo=", - "_parent": { - "$ref": "AAAAAAFq+WXAE9Ps07Q=" - }, - "model": { - "$ref": "AAAAAAFq+esTWd4lBqo=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+esTWd4of0E=", - "_parent": { - "$ref": "AAAAAAFq+esTWd4nYxo=" - }, - "model": { - "$ref": "AAAAAAFq+esTWd4lBqo=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+esTWd4pHN0=", - "_parent": { - "$ref": "AAAAAAFq+esTWd4of0E=" - }, - "font": "Arial;13;0", - "left": 269, - "top": 197, - "width": 95, - "height": 13, - "text": "«interface»" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+esTWd4qNl0=", - "_parent": { - "$ref": "AAAAAAFq+esTWd4of0E=" - }, - "font": "Arial;13;1", - "left": 269, - "top": 212, - "width": 95, - "height": 13, - "text": "Target" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+esTWd4riMo=", - "_parent": { - "$ref": "AAAAAAFq+esTWd4of0E=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 48, - "width": 194.27001953125, - "height": 13, - "text": "(from 结构型模式——适配器模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+esTWt4se+E=", - "_parent": { - "$ref": "AAAAAAFq+esTWd4of0E=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 48, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 264, - "top": 192, - "width": 105, - "height": 38, - "stereotypeLabel": { - "$ref": "AAAAAAFq+esTWd4pHN0=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+esTWd4qNl0=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+esTWd4riMo=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+esTWt4se+E=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+esTWt4tKKs=", - "_parent": { - "$ref": "AAAAAAFq+esTWd4nYxo=" - }, - "model": { - "$ref": "AAAAAAFq+esTWd4lBqo=" - }, - "font": "Arial;13;0", - "left": 264, - "top": 230, - "width": 105, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+esTWt4utGU=", - "_parent": { - "$ref": "AAAAAAFq+esTWd4nYxo=" - }, - "model": { - "$ref": "AAAAAAFq+esTWd4lBqo=" - }, - "subViews": [ - { - "_type": "UMLOperationView", - "_id": "AAAAAAFq+euydN6VDCs=", - "_parent": { - "$ref": "AAAAAAFq+esTWt4utGU=" - }, - "model": { - "$ref": "AAAAAAFq+euyO96PNPI=" - }, - "font": "Arial;13;0", - "left": 269, - "top": 245, - "width": 95, - "height": 13, - "text": "+request()", - "horizontalAlignment": 0 - } - ], - "font": "Arial;13;0", - "left": 264, - "top": 240, - "width": 105, - "height": 23 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+esTWt4v8pI=", - "_parent": { - "$ref": "AAAAAAFq+esTWd4nYxo=" - }, - "model": { - "$ref": "AAAAAAFq+esTWd4lBqo=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 24, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+esTWt4w7xA=", - "_parent": { - "$ref": "AAAAAAFq+esTWd4nYxo=" - }, - "model": { - "$ref": "AAAAAAFq+esTWd4lBqo=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 24, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "showShadow": false, - "containerChangeable": true, - "left": 264, - "top": 192, - "width": 105, - "height": 71, - "nameCompartment": { - "$ref": "AAAAAAFq+esTWd4of0E=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+esTWt4tKKs=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+esTWt4utGU=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+esTWt4v8pI=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+esTWt4w7xA=" - } - }, - { - "_type": "UMLDependencyView", - "_id": "AAAAAAFq+ezhwd/+mZg=", - "_parent": { - "$ref": "AAAAAAFq+WXAE9Ps07Q=" - }, - "model": { - "$ref": "AAAAAAFq+ezhwN/8bCs=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+ezhwd//F0M=", - "_parent": { - "$ref": "AAAAAAFq+ezhwd/+mZg=" - }, - "model": { - "$ref": "AAAAAAFq+ezhwN/8bCs=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 217, - "top": 204, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+ezhwd/+mZg=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+ezhweAAcTQ=", - "_parent": { - "$ref": "AAAAAAFq+ezhwd/+mZg=" - }, - "model": { - "$ref": "AAAAAAFq+ezhwN/8bCs=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 217, - "top": 189, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+ezhwd/+mZg=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+ezhweABfhg=", - "_parent": { - "$ref": "AAAAAAFq+ezhwd/+mZg=" - }, - "model": { - "$ref": "AAAAAAFq+ezhwN/8bCs=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 216, - "top": 233, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+ezhwd/+mZg=" - }, - "edgePosition": 1 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+esTWd4nYxo=" - }, - "tail": { - "$ref": "AAAAAAFq+WXvAdP+DeI=" - }, - "lineStyle": 1, - "points": "172:225;263:226", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+ezhwd//F0M=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+ezhweAAcTQ=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+ezhweABfhg=" - } - }, - { - "_type": "UMLInterfaceRealizationView", - "_id": "AAAAAAFq+ez3NuAdHpI=", - "_parent": { - "$ref": "AAAAAAFq+WXAE9Ps07Q=" - }, - "model": { - "$ref": "AAAAAAFq+ez3NuAcXkM=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+ez3NuAeNyY=", - "_parent": { - "$ref": "AAAAAAFq+ez3NuAdHpI=" - }, - "model": { - "$ref": "AAAAAAFq+ez3NuAcXkM=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 289, - "top": 361, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+ez3NuAdHpI=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+ez3NuAfMwM=", - "_parent": { - "$ref": "AAAAAAFq+ez3NuAdHpI=" - }, - "model": { - "$ref": "AAAAAAFq+ez3NuAcXkM=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 274, - "top": 361, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+ez3NuAdHpI=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+ez3NuAgy+I=", - "_parent": { - "$ref": "AAAAAAFq+ez3NuAdHpI=" - }, - "model": { - "$ref": "AAAAAAFq+ez3NuAcXkM=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 319, - "top": 362, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+ez3NuAdHpI=" - }, - "edgePosition": 1 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+esTWd4nYxo=" - }, - "tail": { - "$ref": "AAAAAAFq+WjjWdR7Fy0=" - }, - "points": "384:368;304:368;304:262", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+ez3NuAeNyY=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+ez3NuAfMwM=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+ez3NuAgy+I=" - } - } - ] - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+WXvAdP8SLU=", - "_parent": { - "$ref": "AAAAAAFq+WWQOdPWSZQ=" - }, - "name": "Client", - "ownedElements": [ - { - "_type": "UMLDependency", - "_id": "AAAAAAFq+YiCDNpYfQY=", - "_parent": { - "$ref": "AAAAAAFq+WXvAdP8SLU=" - }, - "source": { - "$ref": "AAAAAAFq+WXvAdP8SLU=" - }, - "target": { - "$ref": "AAAAAAFq+YVtWtm05OQ=" - } - }, - { - "_type": "UMLDependency", - "_id": "AAAAAAFq+ezhwN/8bCs=", - "_parent": { - "$ref": "AAAAAAFq+WXvAdP8SLU=" - }, - "source": { - "$ref": "AAAAAAFq+WXvAdP8SLU=" - }, - "target": { - "$ref": "AAAAAAFq+esTWd4lBqo=" - } - } - ] - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+Wjb1NRQ2KA=", - "_parent": { - "$ref": "AAAAAAFq+WWQOdPWSZQ=" - }, - "name": "Adaptee", - "operations": [ - { - "_type": "UMLOperation", - "_id": "AAAAAAFq+WpQkNTjauU=", - "_parent": { - "$ref": "AAAAAAFq+Wjb1NRQ2KA=" - }, - "name": "adapteeRequest" - } - ] - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+WjjWdR51ug=", - "_parent": { - "$ref": "AAAAAAFq+WWQOdPWSZQ=" - }, - "name": "Adapter", - "ownedElements": [ - { - "_type": "UMLAssociation", - "_id": "AAAAAAFq+WzhVtUzjr8=", - "_parent": { - "$ref": "AAAAAAFq+WjjWdR51ug=" - }, - "end1": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFq+WzhVtU0fYw=", - "_parent": { - "$ref": "AAAAAAFq+WzhVtUzjr8=" - }, - "reference": { - "$ref": "AAAAAAFq+WjjWdR51ug=" - }, - "navigable": false, - "aggregation": "shared" - }, - "end2": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFq+WzhVtU1okE=", - "_parent": { - "$ref": "AAAAAAFq+WzhVtUzjr8=" - }, - "reference": { - "$ref": "AAAAAAFq+Wjb1NRQ2KA=" - } - } - }, - { - "_type": "UMLInterfaceRealization", - "_id": "AAAAAAFq+ZAzbNq14HQ=", - "_parent": { - "$ref": "AAAAAAFq+WjjWdR51ug=" - }, - "source": { - "$ref": "AAAAAAFq+WjjWdR51ug=" - }, - "target": { - "$ref": "AAAAAAFq+YVtWtm05OQ=" - } - }, - { - "_type": "UMLInterfaceRealization", - "_id": "AAAAAAFq+ez3NuAcXkM=", - "_parent": { - "$ref": "AAAAAAFq+WjjWdR51ug=" - }, - "source": { - "$ref": "AAAAAAFq+WjjWdR51ug=" - }, - "target": { - "$ref": "AAAAAAFq+esTWd4lBqo=" - } - }, - { - "_type": "UMLGeneralization", - "_id": "AAAAAAFq+e+nuOHHzao=", - "_parent": { - "$ref": "AAAAAAFq+WjjWdR51ug=" - }, - "source": { - "$ref": "AAAAAAFq+WjjWdR51ug=" - }, - "target": { - "$ref": "AAAAAAFq+Wjb1NRQ2KA=" - } - } - ], - "attributes": [ - { - "_type": "UMLAttribute", - "_id": "AAAAAAFq+gV2HuIz1IE=", - "_parent": { - "$ref": "AAAAAAFq+WjjWdR51ug=" - }, - "name": "adaptee", - "type": "" - } - ], - "operations": [ - { - "_type": "UMLOperation", - "_id": "AAAAAAFq+WqFStTq9O0=", - "_parent": { - "$ref": "AAAAAAFq+WjjWdR51ug=" - }, - "name": "request" - } - ] - }, - { - "_type": "UMLInterface", - "_id": "AAAAAAFq+YVtWtm05OQ=", - "_parent": { - "$ref": "AAAAAAFq+WWQOdPWSZQ=" - }, - "name": "Target", - "operations": [ - { - "_type": "UMLOperation", - "_id": "AAAAAAFq+ZG4OdtKLl4=", - "_parent": { - "$ref": "AAAAAAFq+YVtWtm05OQ=" - }, - "name": "request" - } - ] - }, - { - "_type": "UMLInterface", - "_id": "AAAAAAFq+esTWd4lBqo=", - "_parent": { - "$ref": "AAAAAAFq+WWQOdPWSZQ=" - }, - "name": "Target", - "operations": [ - { - "_type": "UMLOperation", - "_id": "AAAAAAFq+euyO96PNPI=", - "_parent": { - "$ref": "AAAAAAFq+esTWd4lBqo=" - }, - "name": "request" - } - ] - } - ] - }, - { - "_type": "UMLModel", - "_id": "AAAAAAFq+jAIIPRy99Y=", - "_parent": { - "$ref": "AAAAAAFF+h6SjaM2Hec=" - }, - "name": "结构型模式——享元模式", - "ownedElements": [ - { - "_type": "UMLClassDiagram", - "_id": "AAAAAAFq+jAIIfRzMS0=", - "_parent": { - "$ref": "AAAAAAFq+jAIIPRy99Y=" - }, - "name": "享元模式", - "ownedViews": [ - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+jCdw/SoTn8=", - "_parent": { - "$ref": "AAAAAAFq+jAIIfRzMS0=" - }, - "model": { - "$ref": "AAAAAAFq+jCdw/Smqfc=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+jCdw/SpTko=", - "_parent": { - "$ref": "AAAAAAFq+jCdw/SoTn8=" - }, - "model": { - "$ref": "AAAAAAFq+jCdw/Smqfc=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+jCdw/SqFpQ=", - "_parent": { - "$ref": "AAAAAAFq+jCdw/SpTko=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -176, - "top": -16, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+jCdw/SrxXM=", - "_parent": { - "$ref": "AAAAAAFq+jCdw/SpTko=" - }, - "font": "Arial;13;1", - "left": 85, - "top": 311, - "width": 167, - "height": 13, - "text": "FlyweightFactory" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+jCdw/SsVOs=", - "_parent": { - "$ref": "AAAAAAFq+jCdw/SpTko=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -176, - "top": -16, - "width": 181.27001953125, - "height": 13, - "text": "(from 结构型模式——享元模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+jCdw/StokY=", - "_parent": { - "$ref": "AAAAAAFq+jCdw/SpTko=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -176, - "top": -16, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 80, - "top": 304, - "width": 177, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+jCdw/SqFpQ=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+jCdw/SrxXM=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+jCdw/SsVOs=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+jCdw/StokY=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+jCdw/Su6eM=", - "_parent": { - "$ref": "AAAAAAFq+jCdw/SoTn8=" - }, - "model": { - "$ref": "AAAAAAFq+jCdw/Smqfc=" - }, - "font": "Arial;13;0", - "left": 80, - "top": 329, - "width": 177, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+jCdw/SvUug=", - "_parent": { - "$ref": "AAAAAAFq+jCdw/SoTn8=" - }, - "model": { - "$ref": "AAAAAAFq+jCdw/Smqfc=" - }, - "subViews": [ - { - "_type": "UMLOperationView", - "_id": "AAAAAAFq+jFDxfV+O28=", - "_parent": { - "$ref": "AAAAAAFq+jCdw/SvUug=" - }, - "model": { - "$ref": "AAAAAAFq+jFDovV7xaY=" - }, - "font": "Arial;13;0", - "left": 85, - "top": 344, - "width": 167, - "height": 13, - "text": "+GetFlyweight(key)", - "horizontalAlignment": 0 - } - ], - "font": "Arial;13;0", - "left": 80, - "top": 339, - "width": 177, - "height": 23 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+jCdxPSwDas=", - "_parent": { - "$ref": "AAAAAAFq+jCdw/SoTn8=" - }, - "model": { - "$ref": "AAAAAAFq+jCdw/Smqfc=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -88, - "top": -8, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+jCdxPSxIUM=", - "_parent": { - "$ref": "AAAAAAFq+jCdw/SoTn8=" - }, - "model": { - "$ref": "AAAAAAFq+jCdw/Smqfc=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -88, - "top": -8, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 80, - "top": 304, - "width": 177, - "height": 65, - "nameCompartment": { - "$ref": "AAAAAAFq+jCdw/SpTko=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+jCdw/Su6eM=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+jCdw/SvUug=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+jCdxPSwDas=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+jCdxPSxIUM=" - } - }, - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+jCuJPTRV8E=", - "_parent": { - "$ref": "AAAAAAFq+jAIIfRzMS0=" - }, - "model": { - "$ref": "AAAAAAFq+jCuJPTPBYg=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+jCuJPTSu4Q=", - "_parent": { - "$ref": "AAAAAAFq+jCuJPTRV8E=" - }, - "model": { - "$ref": "AAAAAAFq+jCuJPTPBYg=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+jCuJPTTgrI=", - "_parent": { - "$ref": "AAAAAAFq+jCuJPTSu4Q=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -160, - "top": -48, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+jCuJPTU8hg=", - "_parent": { - "$ref": "AAAAAAFq+jCuJPTSu4Q=" - }, - "font": "Arial;13;1", - "left": 389, - "top": 311, - "width": 87, - "height": 13, - "text": "Flyweight" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+jCuJPTV0rs=", - "_parent": { - "$ref": "AAAAAAFq+jCuJPTSu4Q=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -160, - "top": -48, - "width": 181.27001953125, - "height": 13, - "text": "(from 结构型模式——享元模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+jCuJPTWpXA=", - "_parent": { - "$ref": "AAAAAAFq+jCuJPTSu4Q=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -160, - "top": -48, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 384, - "top": 304, - "width": 97, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+jCuJPTTgrI=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+jCuJPTU8hg=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+jCuJPTV0rs=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+jCuJPTWpXA=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+jCuJPTXXIQ=", - "_parent": { - "$ref": "AAAAAAFq+jCuJPTRV8E=" - }, - "model": { - "$ref": "AAAAAAFq+jCuJPTPBYg=" - }, - "font": "Arial;13;0", - "left": 384, - "top": 329, - "width": 97, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+jCuJPTYeQQ=", - "_parent": { - "$ref": "AAAAAAFq+jCuJPTRV8E=" - }, - "model": { - "$ref": "AAAAAAFq+jCuJPTPBYg=" - }, - "subViews": [ - { - "_type": "UMLOperationView", - "_id": "AAAAAAFq+jH4x/WN0rI=", - "_parent": { - "$ref": "AAAAAAFq+jCuJPTYeQQ=" - }, - "model": { - "$ref": "AAAAAAFq+jH4ovWK0mw=" - }, - "font": "Arial;13;0", - "left": 389, - "top": 344, - "width": 87, - "height": 13, - "text": "+Operation()", - "horizontalAlignment": 0 - } - ], - "font": "Arial;13;0", - "left": 384, - "top": 339, - "width": 97, - "height": 23 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+jCuJPTZ6a4=", - "_parent": { - "$ref": "AAAAAAFq+jCuJPTRV8E=" - }, - "model": { - "$ref": "AAAAAAFq+jCuJPTPBYg=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -80, - "top": -24, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+jCuJPTapdU=", - "_parent": { - "$ref": "AAAAAAFq+jCuJPTRV8E=" - }, - "model": { - "$ref": "AAAAAAFq+jCuJPTPBYg=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -80, - "top": -24, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 384, - "top": 304, - "width": 97, - "height": 65, - "nameCompartment": { - "$ref": "AAAAAAFq+jCuJPTSu4Q=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+jCuJPTXXIQ=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+jCuJPTYeQQ=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+jCuJPTZ6a4=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+jCuJPTapdU=" - } - }, - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+jCzBfT6NVw=", - "_parent": { - "$ref": "AAAAAAFq+jAIIfRzMS0=" - }, - "model": { - "$ref": "AAAAAAFq+jCzBPT4MuY=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+jCzBfT7qso=", - "_parent": { - "$ref": "AAAAAAFq+jCzBfT6NVw=" - }, - "model": { - "$ref": "AAAAAAFq+jCzBPT4MuY=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+jCzBfT8XFY=", - "_parent": { - "$ref": "AAAAAAFq+jCzBfT7qso=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -80, - "top": 32, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+jCzBfT9xrs=", - "_parent": { - "$ref": "AAAAAAFq+jCzBfT7qso=" - }, - "font": "Arial;13;1", - "left": 101, - "top": 567, - "width": 87, - "height": 13, - "text": "Client" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+jCzBfT+Xj4=", - "_parent": { - "$ref": "AAAAAAFq+jCzBfT7qso=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -80, - "top": 32, - "width": 181.27001953125, - "height": 13, - "text": "(from 结构型模式——享元模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+jCzBfT/SVM=", - "_parent": { - "$ref": "AAAAAAFq+jCzBfT7qso=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -80, - "top": 32, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 96, - "top": 560, - "width": 97, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+jCzBfT8XFY=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+jCzBfT9xrs=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+jCzBfT+Xj4=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+jCzBfT/SVM=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+jCzBfUA3Kg=", - "_parent": { - "$ref": "AAAAAAFq+jCzBfT6NVw=" - }, - "model": { - "$ref": "AAAAAAFq+jCzBPT4MuY=" - }, - "font": "Arial;13;0", - "left": 96, - "top": 585, - "width": 97, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+jCzBfUBcwU=", - "_parent": { - "$ref": "AAAAAAFq+jCzBfT6NVw=" - }, - "model": { - "$ref": "AAAAAAFq+jCzBPT4MuY=" - }, - "font": "Arial;13;0", - "left": 96, - "top": 595, - "width": 97, - "height": 10 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+jCzBfUCgTU=", - "_parent": { - "$ref": "AAAAAAFq+jCzBfT6NVw=" - }, - "model": { - "$ref": "AAAAAAFq+jCzBPT4MuY=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -40, - "top": 16, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+jCzBfUD/mk=", - "_parent": { - "$ref": "AAAAAAFq+jCzBfT6NVw=" - }, - "model": { - "$ref": "AAAAAAFq+jCzBPT4MuY=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -40, - "top": 16, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 96, - "top": 560, - "width": 97, - "height": 49, - "nameCompartment": { - "$ref": "AAAAAAFq+jCzBfT7qso=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+jCzBfUA3Kg=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+jCzBfUBcwU=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+jCzBfUCgTU=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+jCzBfUD/mk=" - } - }, - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+jC4KvUjVg0=", - "_parent": { - "$ref": "AAAAAAFq+jAIIfRzMS0=" - }, - "model": { - "$ref": "AAAAAAFq+jC4KfUheEw=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+jC4KvUku50=", - "_parent": { - "$ref": "AAAAAAFq+jC4KvUjVg0=" - }, - "model": { - "$ref": "AAAAAAFq+jC4KfUheEw=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+jC4KvUlz38=", - "_parent": { - "$ref": "AAAAAAFq+jC4KvUku50=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -384, - "top": -192, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+jC4KvUm0zE=", - "_parent": { - "$ref": "AAAAAAFq+jC4KvUku50=" - }, - "font": "Arial;13;1", - "left": 237, - "top": 487, - "width": 175, - "height": 13, - "text": "ConcreteFlyweight" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+jC4KvUnlSQ=", - "_parent": { - "$ref": "AAAAAAFq+jC4KvUku50=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -384, - "top": -192, - "width": 181.27001953125, - "height": 13, - "text": "(from 结构型模式——享元模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+jC4KvUo0WE=", - "_parent": { - "$ref": "AAAAAAFq+jC4KvUku50=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -384, - "top": -192, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 232, - "top": 480, - "width": 185, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+jC4KvUlz38=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+jC4KvUm0zE=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+jC4KvUnlSQ=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+jC4KvUo0WE=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+jC4KvUpl3o=", - "_parent": { - "$ref": "AAAAAAFq+jC4KvUjVg0=" - }, - "model": { - "$ref": "AAAAAAFq+jC4KfUheEw=" - }, - "font": "Arial;13;0", - "left": 232, - "top": 505, - "width": 185, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+jC4KvUqU8Q=", - "_parent": { - "$ref": "AAAAAAFq+jC4KvUjVg0=" - }, - "model": { - "$ref": "AAAAAAFq+jC4KfUheEw=" - }, - "font": "Arial;13;0", - "left": 232, - "top": 515, - "width": 185, - "height": 10 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+jC4KvUr0io=", - "_parent": { - "$ref": "AAAAAAFq+jC4KvUjVg0=" - }, - "model": { - "$ref": "AAAAAAFq+jC4KfUheEw=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -192, - "top": -96, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+jC4KvUs5wA=", - "_parent": { - "$ref": "AAAAAAFq+jC4KvUjVg0=" - }, - "model": { - "$ref": "AAAAAAFq+jC4KfUheEw=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -192, - "top": -96, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 232, - "top": 480, - "width": 185, - "height": 65, - "nameCompartment": { - "$ref": "AAAAAAFq+jC4KvUku50=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+jC4KvUpl3o=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+jC4KvUqU8Q=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+jC4KvUr0io=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+jC4KvUs5wA=" - } - }, - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+jDDLvVMpV4=", - "_parent": { - "$ref": "AAAAAAFq+jAIIfRzMS0=" - }, - "model": { - "$ref": "AAAAAAFq+jDDLvVK/5w=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+jDDLvVNats=", - "_parent": { - "$ref": "AAAAAAFq+jDDLvVMpV4=" - }, - "model": { - "$ref": "AAAAAAFq+jDDLvVK/5w=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+jDDLvVObR4=", - "_parent": { - "$ref": "AAAAAAFq+jDDLvVNats=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -384, - "top": -240, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+jDDMPVPKUU=", - "_parent": { - "$ref": "AAAAAAFq+jDDLvVNats=" - }, - "font": "Arial;13;1", - "left": 453, - "top": 487, - "width": 183, - "height": 13, - "text": "UnsharedConcreteFlyweight" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+jDDMPVQBWw=", - "_parent": { - "$ref": "AAAAAAFq+jDDLvVNats=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -384, - "top": -240, - "width": 181.27001953125, - "height": 13, - "text": "(from 结构型模式——享元模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+jDDMPVRKMQ=", - "_parent": { - "$ref": "AAAAAAFq+jDDLvVNats=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -384, - "top": -240, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 448, - "top": 480, - "width": 193, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+jDDLvVObR4=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+jDDMPVPKUU=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+jDDMPVQBWw=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+jDDMPVRKMQ=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+jDDMPVSh28=", - "_parent": { - "$ref": "AAAAAAFq+jDDLvVMpV4=" - }, - "model": { - "$ref": "AAAAAAFq+jDDLvVK/5w=" - }, - "font": "Arial;13;0", - "left": 448, - "top": 505, - "width": 193, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+jDDMPVTK2M=", - "_parent": { - "$ref": "AAAAAAFq+jDDLvVMpV4=" - }, - "model": { - "$ref": "AAAAAAFq+jDDLvVK/5w=" - }, - "font": "Arial;13;0", - "left": 448, - "top": 515, - "width": 193, - "height": 10 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+jDDMPVU79g=", - "_parent": { - "$ref": "AAAAAAFq+jDDLvVMpV4=" - }, - "model": { - "$ref": "AAAAAAFq+jDDLvVK/5w=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -192, - "top": -120, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+jDDMPVVjyo=", - "_parent": { - "$ref": "AAAAAAFq+jDDLvVMpV4=" - }, - "model": { - "$ref": "AAAAAAFq+jDDLvVK/5w=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -192, - "top": -120, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 448, - "top": 480, - "width": 193, - "height": 65, - "nameCompartment": { - "$ref": "AAAAAAFq+jDDLvVNats=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+jDDMPVSh28=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+jDDMPVTK2M=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+jDDMPVU79g=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+jDDMPVVjyo=" - } - }, - { - "_type": "UMLAssociationView", - "_id": "AAAAAAFq+jKsjvWfHjw=", - "_parent": { - "$ref": "AAAAAAFq+jAIIfRzMS0=" - }, - "model": { - "$ref": "AAAAAAFq+jKsjvWbGC8=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+jKsj/WgqoQ=", - "_parent": { - "$ref": "AAAAAAFq+jKsjvWfHjw=" - }, - "model": { - "$ref": "AAAAAAFq+jKsjvWbGC8=" - }, - "font": "Arial;13;0", - "left": 288, - "top": 315, - "width": 64.669921875, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+jKsjvWfHjw=" - }, - "edgePosition": 1, - "text": "+flyweights" - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+jKsj/WhZoo=", - "_parent": { - "$ref": "AAAAAAFq+jKsjvWfHjw=" - }, - "model": { - "$ref": "AAAAAAFq+jKsjvWbGC8=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 285, - "top": 300, - "width": 71.5380859375, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+jKsjvWfHjw=" - }, - "edgePosition": 1, - "text": "«flyweights»" - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+jKsj/WiZIo=", - "_parent": { - "$ref": "AAAAAAFq+jKsjvWfHjw=" - }, - "model": { - "$ref": "AAAAAAFq+jKsjvWbGC8=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 320, - "top": 345, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+jKsjvWfHjw=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+jKsj/WjLX4=", - "_parent": { - "$ref": "AAAAAAFq+jKsjvWfHjw=" - }, - "model": { - "$ref": "AAAAAAFq+jKsjvWc0U4=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 282, - "top": 315, - "height": 13, - "alpha": 0.5235987755982988, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+jKsjvWfHjw=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+jKsj/WkWCQ=", - "_parent": { - "$ref": "AAAAAAFq+jKsjvWfHjw=" - }, - "model": { - "$ref": "AAAAAAFq+jKsjvWc0U4=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 285, - "top": 301, - "height": 13, - "alpha": 0.7853981633974483, - "distance": 40, - "hostEdge": { - "$ref": "AAAAAAFq+jKsjvWfHjw=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+jKsj/Wl5TM=", - "_parent": { - "$ref": "AAAAAAFq+jKsjvWfHjw=" - }, - "model": { - "$ref": "AAAAAAFq+jKsjvWc0U4=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 278, - "top": 342, - "height": 13, - "alpha": -0.5235987755982988, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFq+jKsjvWfHjw=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+jKsj/WmNvc=", - "_parent": { - "$ref": "AAAAAAFq+jKsjvWfHjw=" - }, - "model": { - "$ref": "AAAAAAFq+jKsjvWdLKg=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 357, - "top": 315, - "height": 13, - "alpha": -0.5235987755982988, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+jKsjvWfHjw=" - } - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+jKsj/Wndck=", - "_parent": { - "$ref": "AAAAAAFq+jKsjvWfHjw=" - }, - "model": { - "$ref": "AAAAAAFq+jKsjvWdLKg=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 354, - "top": 301, - "height": 13, - "alpha": -0.7853981633974483, - "distance": 40, - "hostEdge": { - "$ref": "AAAAAAFq+jKsjvWfHjw=" - } - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+jKsj/Wo4o8=", - "_parent": { - "$ref": "AAAAAAFq+jKsjvWfHjw=" - }, - "model": { - "$ref": "AAAAAAFq+jKsjvWdLKg=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 361, - "top": 342, - "height": 13, - "alpha": 0.5235987755982988, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFq+jKsjvWfHjw=" - } - }, - { - "_type": "UMLQualifierCompartmentView", - "_id": "AAAAAAFq+jKsj/WpaNQ=", - "_parent": { - "$ref": "AAAAAAFq+jKsjvWfHjw=" - }, - "model": { - "$ref": "AAAAAAFq+jKsjvWc0U4=" - }, - "visible": false, - "font": "Arial;13;0", - "width": 10, - "height": 10 - }, - { - "_type": "UMLQualifierCompartmentView", - "_id": "AAAAAAFq+jKsj/WqOIA=", - "_parent": { - "$ref": "AAAAAAFq+jKsjvWfHjw=" - }, - "model": { - "$ref": "AAAAAAFq+jKsjvWdLKg=" - }, - "visible": false, - "font": "Arial;13;0", - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+jCuJPTRV8E=" - }, - "tail": { - "$ref": "AAAAAAFq+jCdw/SoTn8=" - }, - "lineStyle": 1, - "points": "257:336;383:336", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+jKsj/WgqoQ=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+jKsj/WhZoo=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+jKsj/WiZIo=" - }, - "tailRoleNameLabel": { - "$ref": "AAAAAAFq+jKsj/WjLX4=" - }, - "tailPropertyLabel": { - "$ref": "AAAAAAFq+jKsj/WkWCQ=" - }, - "tailMultiplicityLabel": { - "$ref": "AAAAAAFq+jKsj/Wl5TM=" - }, - "headRoleNameLabel": { - "$ref": "AAAAAAFq+jKsj/WmNvc=" - }, - "headPropertyLabel": { - "$ref": "AAAAAAFq+jKsj/Wndck=" - }, - "headMultiplicityLabel": { - "$ref": "AAAAAAFq+jKsj/Wo4o8=" - }, - "tailQualifiersCompartment": { - "$ref": "AAAAAAFq+jKsj/WpaNQ=" - }, - "headQualifiersCompartment": { - "$ref": "AAAAAAFq+jKsj/WqOIA=" - } - }, - { - "_type": "UMLAssociationView", - "_id": "AAAAAAFq+jOenPaHw2I=", - "_parent": { - "$ref": "AAAAAAFq+jAIIfRzMS0=" - }, - "model": { - "$ref": "AAAAAAFq+jOemvaDG+s=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+jOenPaITWM=", - "_parent": { - "$ref": "AAAAAAFq+jOenPaHw2I=" - }, - "model": { - "$ref": "AAAAAAFq+jOemvaDG+s=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 135, - "top": 457, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+jOenPaHw2I=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+jOenPaJfvQ=", - "_parent": { - "$ref": "AAAAAAFq+jOenPaHw2I=" - }, - "model": { - "$ref": "AAAAAAFq+jOemvaDG+s=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 120, - "top": 457, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+jOenPaHw2I=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+jOenPaK59Y=", - "_parent": { - "$ref": "AAAAAAFq+jOenPaHw2I=" - }, - "model": { - "$ref": "AAAAAAFq+jOemvaDG+s=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 165, - "top": 458, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+jOenPaHw2I=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+jOenPaLZCA=", - "_parent": { - "$ref": "AAAAAAFq+jOenPaHw2I=" - }, - "model": { - "$ref": "AAAAAAFq+jOemvaEdQc=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 135, - "top": 528, - "height": 13, - "alpha": 0.5235987755982988, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+jOenPaHw2I=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+jOenPaMxlo=", - "_parent": { - "$ref": "AAAAAAFq+jOenPaHw2I=" - }, - "model": { - "$ref": "AAAAAAFq+jOemvaEdQc=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 121, - "top": 525, - "height": 13, - "alpha": 0.7853981633974483, - "distance": 40, - "hostEdge": { - "$ref": "AAAAAAFq+jOenPaHw2I=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+jOenPaNYjY=", - "_parent": { - "$ref": "AAAAAAFq+jOenPaHw2I=" - }, - "model": { - "$ref": "AAAAAAFq+jOemvaEdQc=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 162, - "top": 532, - "height": 13, - "alpha": -0.5235987755982988, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFq+jOenPaHw2I=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+jOenPaOCEs=", - "_parent": { - "$ref": "AAAAAAFq+jOenPaHw2I=" - }, - "model": { - "$ref": "AAAAAAFq+jOemvaFGcE=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 135, - "top": 387, - "height": 13, - "alpha": -0.5235987755982988, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+jOenPaHw2I=" - } - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+jOenPaPvZ8=", - "_parent": { - "$ref": "AAAAAAFq+jOenPaHw2I=" - }, - "model": { - "$ref": "AAAAAAFq+jOemvaFGcE=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 121, - "top": 390, - "height": 13, - "alpha": -0.7853981633974483, - "distance": 40, - "hostEdge": { - "$ref": "AAAAAAFq+jOenPaHw2I=" - } - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+jOenPaQ9Jo=", - "_parent": { - "$ref": "AAAAAAFq+jOenPaHw2I=" - }, - "model": { - "$ref": "AAAAAAFq+jOemvaFGcE=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 162, - "top": 383, - "height": 13, - "alpha": 0.5235987755982988, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFq+jOenPaHw2I=" - } - }, - { - "_type": "UMLQualifierCompartmentView", - "_id": "AAAAAAFq+jOenPaRRes=", - "_parent": { - "$ref": "AAAAAAFq+jOenPaHw2I=" - }, - "model": { - "$ref": "AAAAAAFq+jOemvaEdQc=" - }, - "visible": false, - "font": "Arial;13;0", - "width": 10, - "height": 10 - }, - { - "_type": "UMLQualifierCompartmentView", - "_id": "AAAAAAFq+jOenPaSVhE=", - "_parent": { - "$ref": "AAAAAAFq+jOenPaHw2I=" - }, - "model": { - "$ref": "AAAAAAFq+jOemvaFGcE=" - }, - "visible": false, - "font": "Arial;13;0", - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+jCdw/SoTn8=" - }, - "tail": { - "$ref": "AAAAAAFq+jCzBfT6NVw=" - }, - "points": "150:560;150:368", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+jOenPaITWM=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+jOenPaJfvQ=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+jOenPaK59Y=" - }, - "tailRoleNameLabel": { - "$ref": "AAAAAAFq+jOenPaLZCA=" - }, - "tailPropertyLabel": { - "$ref": "AAAAAAFq+jOenPaMxlo=" - }, - "tailMultiplicityLabel": { - "$ref": "AAAAAAFq+jOenPaNYjY=" - }, - "headRoleNameLabel": { - "$ref": "AAAAAAFq+jOenPaOCEs=" - }, - "headPropertyLabel": { - "$ref": "AAAAAAFq+jOenPaPvZ8=" - }, - "headMultiplicityLabel": { - "$ref": "AAAAAAFq+jOenPaQ9Jo=" - }, - "tailQualifiersCompartment": { - "$ref": "AAAAAAFq+jOenPaRRes=" - }, - "headQualifiersCompartment": { - "$ref": "AAAAAAFq+jOenPaSVhE=" - } - }, - { - "_type": "UMLAssociationView", - "_id": "AAAAAAFq+jP6gfc8n9s=", - "_parent": { - "$ref": "AAAAAAFq+jAIIfRzMS0=" - }, - "model": { - "$ref": "AAAAAAFq+jP6gfc4dA4=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+jP6gfc9yt8=", - "_parent": { - "$ref": "AAAAAAFq+jP6gfc8n9s=" - }, - "model": { - "$ref": "AAAAAAFq+jP6gfc4dA4=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 305, - "top": 577, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+jP6gfc8n9s=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+jP6gfc+O74=", - "_parent": { - "$ref": "AAAAAAFq+jP6gfc8n9s=" - }, - "model": { - "$ref": "AAAAAAFq+jP6gfc4dA4=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 290, - "top": 577, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+jP6gfc8n9s=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+jP6gvc/DHs=", - "_parent": { - "$ref": "AAAAAAFq+jP6gfc8n9s=" - }, - "model": { - "$ref": "AAAAAAFq+jP6gfc4dA4=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 334, - "top": 578, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+jP6gfc8n9s=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+jP6gvdAiGM=", - "_parent": { - "$ref": "AAAAAAFq+jP6gfc8n9s=" - }, - "model": { - "$ref": "AAAAAAFq+jP6gfc5GCU=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 217, - "top": 563, - "height": 13, - "alpha": 0.5235987755982988, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+jP6gfc8n9s=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+jP6gvdBy2M=", - "_parent": { - "$ref": "AAAAAAFq+jP6gfc8n9s=" - }, - "model": { - "$ref": "AAAAAAFq+jP6gfc5GCU=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 220, - "top": 549, - "height": 13, - "alpha": 0.7853981633974483, - "distance": 40, - "hostEdge": { - "$ref": "AAAAAAFq+jP6gfc8n9s=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+jP6gvdCcr4=", - "_parent": { - "$ref": "AAAAAAFq+jP6gfc8n9s=" - }, - "model": { - "$ref": "AAAAAAFq+jP6gfc5GCU=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 213, - "top": 590, - "height": 13, - "alpha": -0.5235987755982988, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFq+jP6gfc8n9s=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+jP6gvdDSBQ=", - "_parent": { - "$ref": "AAAAAAFq+jP6gfc8n9s=" - }, - "model": { - "$ref": "AAAAAAFq+jP6gfc6l/8=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 305, - "top": 563, - "height": 13, - "alpha": -0.5235987755982988, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+jP6gfc8n9s=" - } - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+jP6gvdE1DE=", - "_parent": { - "$ref": "AAAAAAFq+jP6gfc8n9s=" - }, - "model": { - "$ref": "AAAAAAFq+jP6gfc6l/8=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 291, - "top": 566, - "height": 13, - "alpha": -0.7853981633974483, - "distance": 40, - "hostEdge": { - "$ref": "AAAAAAFq+jP6gfc8n9s=" - } - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+jP6gvdFLuY=", - "_parent": { - "$ref": "AAAAAAFq+jP6gfc8n9s=" - }, - "model": { - "$ref": "AAAAAAFq+jP6gfc6l/8=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 332, - "top": 559, - "height": 13, - "alpha": 0.5235987755982988, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFq+jP6gfc8n9s=" - } - }, - { - "_type": "UMLQualifierCompartmentView", - "_id": "AAAAAAFq+jP6gvdGy0s=", - "_parent": { - "$ref": "AAAAAAFq+jP6gfc8n9s=" - }, - "model": { - "$ref": "AAAAAAFq+jP6gfc5GCU=" - }, - "visible": false, - "font": "Arial;13;0", - "width": 10, - "height": 10 - }, - { - "_type": "UMLQualifierCompartmentView", - "_id": "AAAAAAFq+jP6gvdHjIE=", - "_parent": { - "$ref": "AAAAAAFq+jP6gfc8n9s=" - }, - "model": { - "$ref": "AAAAAAFq+jP6gfc6l/8=" - }, - "visible": false, - "font": "Arial;13;0", - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+jC4KvUjVg0=" - }, - "tail": { - "$ref": "AAAAAAFq+jCzBfT6NVw=" - }, - "points": "192:584;320:584;320:544", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+jP6gfc9yt8=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+jP6gfc+O74=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+jP6gvc/DHs=" - }, - "tailRoleNameLabel": { - "$ref": "AAAAAAFq+jP6gvdAiGM=" - }, - "tailPropertyLabel": { - "$ref": "AAAAAAFq+jP6gvdBy2M=" - }, - "tailMultiplicityLabel": { - "$ref": "AAAAAAFq+jP6gvdCcr4=" - }, - "headRoleNameLabel": { - "$ref": "AAAAAAFq+jP6gvdDSBQ=" - }, - "headPropertyLabel": { - "$ref": "AAAAAAFq+jP6gvdE1DE=" - }, - "headMultiplicityLabel": { - "$ref": "AAAAAAFq+jP6gvdFLuY=" - }, - "tailQualifiersCompartment": { - "$ref": "AAAAAAFq+jP6gvdGy0s=" - }, - "headQualifiersCompartment": { - "$ref": "AAAAAAFq+jP6gvdHjIE=" - } - }, - { - "_type": "UMLAssociationView", - "_id": "AAAAAAFq+jQF//eLlDQ=", - "_parent": { - "$ref": "AAAAAAFq+jAIIfRzMS0=" - }, - "model": { - "$ref": "AAAAAAFq+jQF//eH0BM=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+jQF//eMECo=", - "_parent": { - "$ref": "AAAAAAFq+jQF//eLlDQ=" - }, - "model": { - "$ref": "AAAAAAFq+jQF//eH0BM=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 529, - "top": 577, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+jQF//eLlDQ=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+jQF//eNwgg=", - "_parent": { - "$ref": "AAAAAAFq+jQF//eLlDQ=" - }, - "model": { - "$ref": "AAAAAAFq+jQF//eH0BM=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 514, - "top": 577, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+jQF//eLlDQ=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+jQF//eOWsA=", - "_parent": { - "$ref": "AAAAAAFq+jQF//eLlDQ=" - }, - "model": { - "$ref": "AAAAAAFq+jQF//eH0BM=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 558, - "top": 578, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+jQF//eLlDQ=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+jQF//eP2OM=", - "_parent": { - "$ref": "AAAAAAFq+jQF//eLlDQ=" - }, - "model": { - "$ref": "AAAAAAFq+jQF//eIMG8=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 217, - "top": 563, - "height": 13, - "alpha": 0.5235987755982988, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+jQF//eLlDQ=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+jQF//eQF9s=", - "_parent": { - "$ref": "AAAAAAFq+jQF//eLlDQ=" - }, - "model": { - "$ref": "AAAAAAFq+jQF//eIMG8=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 220, - "top": 549, - "height": 13, - "alpha": 0.7853981633974483, - "distance": 40, - "hostEdge": { - "$ref": "AAAAAAFq+jQF//eLlDQ=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+jQF//eRjqk=", - "_parent": { - "$ref": "AAAAAAFq+jQF//eLlDQ=" - }, - "model": { - "$ref": "AAAAAAFq+jQF//eIMG8=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 213, - "top": 590, - "height": 13, - "alpha": -0.5235987755982988, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFq+jQF//eLlDQ=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+jQF//eSqEc=", - "_parent": { - "$ref": "AAAAAAFq+jQF//eLlDQ=" - }, - "model": { - "$ref": "AAAAAAFq+jQF//eJ8jc=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 529, - "top": 563, - "height": 13, - "alpha": -0.5235987755982988, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+jQF//eLlDQ=" - } - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+jQF//eTFu8=", - "_parent": { - "$ref": "AAAAAAFq+jQF//eLlDQ=" - }, - "model": { - "$ref": "AAAAAAFq+jQF//eJ8jc=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 515, - "top": 566, - "height": 13, - "alpha": -0.7853981633974483, - "distance": 40, - "hostEdge": { - "$ref": "AAAAAAFq+jQF//eLlDQ=" - } - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+jQF//eUyLw=", - "_parent": { - "$ref": "AAAAAAFq+jQF//eLlDQ=" - }, - "model": { - "$ref": "AAAAAAFq+jQF//eJ8jc=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 556, - "top": 559, - "height": 13, - "alpha": 0.5235987755982988, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFq+jQF//eLlDQ=" - } - }, - { - "_type": "UMLQualifierCompartmentView", - "_id": "AAAAAAFq+jQF//eVCyE=", - "_parent": { - "$ref": "AAAAAAFq+jQF//eLlDQ=" - }, - "model": { - "$ref": "AAAAAAFq+jQF//eIMG8=" - }, - "visible": false, - "font": "Arial;13;0", - "width": 10, - "height": 10 - }, - { - "_type": "UMLQualifierCompartmentView", - "_id": "AAAAAAFq+jQF//eWHik=", - "_parent": { - "$ref": "AAAAAAFq+jQF//eLlDQ=" - }, - "model": { - "$ref": "AAAAAAFq+jQF//eJ8jc=" - }, - "visible": false, - "font": "Arial;13;0", - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+jDDLvVMpV4=" - }, - "tail": { - "$ref": "AAAAAAFq+jCzBfT6NVw=" - }, - "points": "192:584;544:584;544:544", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+jQF//eMECo=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+jQF//eNwgg=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+jQF//eOWsA=" - }, - "tailRoleNameLabel": { - "$ref": "AAAAAAFq+jQF//eP2OM=" - }, - "tailPropertyLabel": { - "$ref": "AAAAAAFq+jQF//eQF9s=" - }, - "tailMultiplicityLabel": { - "$ref": "AAAAAAFq+jQF//eRjqk=" - }, - "headRoleNameLabel": { - "$ref": "AAAAAAFq+jQF//eSqEc=" - }, - "headPropertyLabel": { - "$ref": "AAAAAAFq+jQF//eTFu8=" - }, - "headMultiplicityLabel": { - "$ref": "AAAAAAFq+jQF//eUyLw=" - }, - "tailQualifiersCompartment": { - "$ref": "AAAAAAFq+jQF//eVCyE=" - }, - "headQualifiersCompartment": { - "$ref": "AAAAAAFq+jQF//eWHik=" - } - }, - { - "_type": "UMLGeneralizationView", - "_id": "AAAAAAFq+jQcLPf5Vng=", - "_parent": { - "$ref": "AAAAAAFq+jAIIfRzMS0=" - }, - "model": { - "$ref": "AAAAAAFq+jQcLPf32Nk=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+jQcLPf6k94=", - "_parent": { - "$ref": "AAAAAAFq+jQcLPf5Vng=" - }, - "model": { - "$ref": "AAAAAAFq+jQcLPf32Nk=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 396, - "top": 379, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+jQcLPf5Vng=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+jQcLPf78pU=", - "_parent": { - "$ref": "AAAAAAFq+jQcLPf5Vng=" - }, - "model": { - "$ref": "AAAAAAFq+jQcLPf32Nk=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 396, - "top": 364, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+jQcLPf5Vng=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+jQcLPf8Ngc=", - "_parent": { - "$ref": "AAAAAAFq+jQcLPf5Vng=" - }, - "model": { - "$ref": "AAAAAAFq+jQcLPf32Nk=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 396, - "top": 409, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+jQcLPf5Vng=" - }, - "edgePosition": 1 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+jCuJPTRV8E=" - }, - "tail": { - "$ref": "AAAAAAFq+jC4KvUjVg0=" - }, - "points": "360:480;360:400;432:400;432:368", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+jQcLPf6k94=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+jQcLPf78pU=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+jQcLPf8Ngc=" - } - }, - { - "_type": "UMLGeneralizationView", - "_id": "AAAAAAFq+jQmsfgu/io=", - "_parent": { - "$ref": "AAAAAAFq+jAIIfRzMS0=" - }, - "model": { - "$ref": "AAAAAAFq+jQmsfgslkA=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+jQmsfgvlKI=", - "_parent": { - "$ref": "AAAAAAFq+jQmsfgu/io=" - }, - "model": { - "$ref": "AAAAAAFq+jQmsfgslkA=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 467, - "top": 409, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+jQmsfgu/io=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+jQmsfgwHeE=", - "_parent": { - "$ref": "AAAAAAFq+jQmsfgu/io=" - }, - "model": { - "$ref": "AAAAAAFq+jQmsfgslkA=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 467, - "top": 424, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+jQmsfgu/io=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+jQmsfgxg0g=", - "_parent": { - "$ref": "AAAAAAFq+jQmsfgu/io=" - }, - "model": { - "$ref": "AAAAAAFq+jQmsfgslkA=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 468, - "top": 379, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+jQmsfgu/io=" - }, - "edgePosition": 1 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+jCuJPTRV8E=" - }, - "tail": { - "$ref": "AAAAAAFq+jDDLvVMpV4=" - }, - "points": "504:480;504:400;432:400;432:368", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+jQmsfgvlKI=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+jQmsfgwHeE=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+jQmsfgxg0g=" - } - } - ] - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+jCdw/Smqfc=", - "_parent": { - "$ref": "AAAAAAFq+jAIIPRy99Y=" - }, - "name": "FlyweightFactory", - "ownedElements": [ - { - "_type": "UMLAssociation", - "_id": "AAAAAAFq+jKsjvWbGC8=", - "_parent": { - "$ref": "AAAAAAFq+jCdw/Smqfc=" - }, - "name": "flyweights", - "end1": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFq+jKsjvWc0U4=", - "_parent": { - "$ref": "AAAAAAFq+jKsjvWbGC8=" - }, - "reference": { - "$ref": "AAAAAAFq+jCdw/Smqfc=" - }, - "navigable": false, - "aggregation": "shared" - }, - "end2": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFq+jKsjvWdLKg=", - "_parent": { - "$ref": "AAAAAAFq+jKsjvWbGC8=" - }, - "reference": { - "$ref": "AAAAAAFq+jCuJPTPBYg=" - } - } - } - ], - "operations": [ - { - "_type": "UMLOperation", - "_id": "AAAAAAFq+jFDovV7xaY=", - "_parent": { - "$ref": "AAAAAAFq+jCdw/Smqfc=" - }, - "name": "GetFlyweight", - "parameters": [ - { - "_type": "UMLParameter", - "_id": "AAAAAAFq+jG1RfWCldk=", - "_parent": { - "$ref": "AAAAAAFq+jFDovV7xaY=" - }, - "name": "key" - } - ] - } - ] - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+jCuJPTPBYg=", - "_parent": { - "$ref": "AAAAAAFq+jAIIPRy99Y=" - }, - "name": "Flyweight", - "operations": [ - { - "_type": "UMLOperation", - "_id": "AAAAAAFq+jH4ovWK0mw=", - "_parent": { - "$ref": "AAAAAAFq+jCuJPTPBYg=" - }, - "name": "Operation" - } - ] - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+jCzBPT4MuY=", - "_parent": { - "$ref": "AAAAAAFq+jAIIPRy99Y=" - }, - "name": "Client", - "ownedElements": [ - { - "_type": "UMLAssociation", - "_id": "AAAAAAFq+jOemvaDG+s=", - "_parent": { - "$ref": "AAAAAAFq+jCzBPT4MuY=" - }, - "end1": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFq+jOemvaEdQc=", - "_parent": { - "$ref": "AAAAAAFq+jOemvaDG+s=" - }, - "reference": { - "$ref": "AAAAAAFq+jCzBPT4MuY=" - }, - "navigable": false - }, - "end2": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFq+jOemvaFGcE=", - "_parent": { - "$ref": "AAAAAAFq+jOemvaDG+s=" - }, - "reference": { - "$ref": "AAAAAAFq+jCdw/Smqfc=" - } - } - }, - { - "_type": "UMLAssociation", - "_id": "AAAAAAFq+jP6gfc4dA4=", - "_parent": { - "$ref": "AAAAAAFq+jCzBPT4MuY=" - }, - "end1": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFq+jP6gfc5GCU=", - "_parent": { - "$ref": "AAAAAAFq+jP6gfc4dA4=" - }, - "reference": { - "$ref": "AAAAAAFq+jCzBPT4MuY=" - }, - "navigable": false - }, - "end2": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFq+jP6gfc6l/8=", - "_parent": { - "$ref": "AAAAAAFq+jP6gfc4dA4=" - }, - "reference": { - "$ref": "AAAAAAFq+jC4KfUheEw=" - } - } - }, - { - "_type": "UMLAssociation", - "_id": "AAAAAAFq+jQF//eH0BM=", - "_parent": { - "$ref": "AAAAAAFq+jCzBPT4MuY=" - }, - "end1": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFq+jQF//eIMG8=", - "_parent": { - "$ref": "AAAAAAFq+jQF//eH0BM=" - }, - "reference": { - "$ref": "AAAAAAFq+jCzBPT4MuY=" - }, - "navigable": false - }, - "end2": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFq+jQF//eJ8jc=", - "_parent": { - "$ref": "AAAAAAFq+jQF//eH0BM=" - }, - "reference": { - "$ref": "AAAAAAFq+jDDLvVK/5w=" - } - } - } - ] - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+jC4KfUheEw=", - "_parent": { - "$ref": "AAAAAAFq+jAIIPRy99Y=" - }, - "name": "ConcreteFlyweight", - "ownedElements": [ - { - "_type": "UMLGeneralization", - "_id": "AAAAAAFq+jQcLPf32Nk=", - "_parent": { - "$ref": "AAAAAAFq+jC4KfUheEw=" - }, - "source": { - "$ref": "AAAAAAFq+jC4KfUheEw=" - }, - "target": { - "$ref": "AAAAAAFq+jCuJPTPBYg=" - } - } - ] - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+jDDLvVK/5w=", - "_parent": { - "$ref": "AAAAAAFq+jAIIPRy99Y=" - }, - "name": "UnsharedConcreteFlyweight", - "ownedElements": [ - { - "_type": "UMLGeneralization", - "_id": "AAAAAAFq+jQmsfgslkA=", - "_parent": { - "$ref": "AAAAAAFq+jDDLvVK/5w=" - }, - "source": { - "$ref": "AAAAAAFq+jDDLvVK/5w=" - }, - "target": { - "$ref": "AAAAAAFq+jCuJPTPBYg=" - } - } - ] - } - ] - }, - { - "_type": "UMLModel", - "_id": "AAAAAAFq+jeqt/5k3R4=", - "_parent": { - "$ref": "AAAAAAFF+h6SjaM2Hec=" - }, - "name": "结构型模式——组合模式", - "ownedElements": [ - { - "_type": "UMLClassDiagram", - "_id": "AAAAAAFq+jeqt/5l4BM=", - "_parent": { - "$ref": "AAAAAAFq+jeqt/5k3R4=" - }, - "name": "组合模式", - "ownedViews": [ - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+jf3d/6mzt4=", - "_parent": { - "$ref": "AAAAAAFq+jeqt/5l4BM=" - }, - "model": { - "$ref": "AAAAAAFq+jf3d/6k1Lo=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+jf3eP6nhCI=", - "_parent": { - "$ref": "AAAAAAFq+jf3d/6mzt4=" - }, - "model": { - "$ref": "AAAAAAFq+jf3d/6k1Lo=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+jf3eP6otmI=", - "_parent": { - "$ref": "AAAAAAFq+jf3eP6nhCI=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -80, - "top": 48, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+jf3eP6pYfI=", - "_parent": { - "$ref": "AAAAAAFq+jf3eP6nhCI=" - }, - "font": "Arial;13;1", - "left": 45, - "top": 383, - "width": 55, - "height": 13, - "text": "Client" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+jf3eP6qVko=", - "_parent": { - "$ref": "AAAAAAFq+jf3eP6nhCI=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -80, - "top": 48, - "width": 181.27001953125, - "height": 13, - "text": "(from 结构型模式——组合模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+jf3eP6rDjg=", - "_parent": { - "$ref": "AAAAAAFq+jf3eP6nhCI=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -80, - "top": 48, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 40, - "top": 376, - "width": 65, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+jf3eP6otmI=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+jf3eP6pYfI=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+jf3eP6qVko=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+jf3eP6rDjg=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+jf3eP6sDVk=", - "_parent": { - "$ref": "AAAAAAFq+jf3d/6mzt4=" - }, - "model": { - "$ref": "AAAAAAFq+jf3d/6k1Lo=" - }, - "font": "Arial;13;0", - "left": 40, - "top": 401, - "width": 65, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+jf3eP6t904=", - "_parent": { - "$ref": "AAAAAAFq+jf3d/6mzt4=" - }, - "model": { - "$ref": "AAAAAAFq+jf3d/6k1Lo=" - }, - "font": "Arial;13;0", - "left": 40, - "top": 411, - "width": 65, - "height": 10 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+jf3eP6u7u8=", - "_parent": { - "$ref": "AAAAAAFq+jf3d/6mzt4=" - }, - "model": { - "$ref": "AAAAAAFq+jf3d/6k1Lo=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -40, - "top": 24, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+jf3eP6vOD4=", - "_parent": { - "$ref": "AAAAAAFq+jf3d/6mzt4=" - }, - "model": { - "$ref": "AAAAAAFq+jf3d/6k1Lo=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -40, - "top": 24, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 40, - "top": 376, - "width": 65, - "height": 49, - "nameCompartment": { - "$ref": "AAAAAAFq+jf3eP6nhCI=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+jf3eP6sDVk=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+jf3eP6t904=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+jf3eP6u7u8=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+jf3eP6vOD4=" - } - }, - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+jf8+f7PeYY=", - "_parent": { - "$ref": "AAAAAAFq+jeqt/5l4BM=" - }, - "model": { - "$ref": "AAAAAAFq+jf8+f7NOv8=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+jf8+v7Q8xA=", - "_parent": { - "$ref": "AAAAAAFq+jf8+f7PeYY=" - }, - "model": { - "$ref": "AAAAAAFq+jf8+f7NOv8=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+jf8+v7RzNo=", - "_parent": { - "$ref": "AAAAAAFq+jf8+v7Q8xA=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 48, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+jf8+v7SWiE=", - "_parent": { - "$ref": "AAAAAAFq+jf8+v7Q8xA=" - }, - "font": "Arial;13;1", - "left": 181, - "top": 583, - "width": 87, - "height": 13, - "text": "Leaf" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+jf8+v7T+go=", - "_parent": { - "$ref": "AAAAAAFq+jf8+v7Q8xA=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 48, - "width": 181.27001953125, - "height": 13, - "text": "(from 结构型模式——组合模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+jf8+v7U5jI=", - "_parent": { - "$ref": "AAAAAAFq+jf8+v7Q8xA=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 48, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 176, - "top": 576, - "width": 97, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+jf8+v7RzNo=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+jf8+v7SWiE=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+jf8+v7T+go=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+jf8+v7U5jI=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+jf8+v7VTms=", - "_parent": { - "$ref": "AAAAAAFq+jf8+f7PeYY=" - }, - "model": { - "$ref": "AAAAAAFq+jf8+f7NOv8=" - }, - "font": "Arial;13;0", - "left": 176, - "top": 601, - "width": 97, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+jf8+v7WD7Y=", - "_parent": { - "$ref": "AAAAAAFq+jf8+f7PeYY=" - }, - "model": { - "$ref": "AAAAAAFq+jf8+f7NOv8=" - }, - "font": "Arial;13;0", - "left": 176, - "top": 611, - "width": 97, - "height": 10 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+jf8+v7XFG0=", - "_parent": { - "$ref": "AAAAAAFq+jf8+f7PeYY=" - }, - "model": { - "$ref": "AAAAAAFq+jf8+f7NOv8=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 24, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+jf8+v7YQhc=", - "_parent": { - "$ref": "AAAAAAFq+jf8+f7PeYY=" - }, - "model": { - "$ref": "AAAAAAFq+jf8+f7NOv8=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 24, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 176, - "top": 576, - "width": 97, - "height": 57, - "nameCompartment": { - "$ref": "AAAAAAFq+jf8+v7Q8xA=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+jf8+v7VTms=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+jf8+v7WD7Y=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+jf8+v7XFG0=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+jf8+v7YQhc=" - } - }, - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+jgByP74Xeo=", - "_parent": { - "$ref": "AAAAAAFq+jeqt/5l4BM=" - }, - "model": { - "$ref": "AAAAAAFq+jgByP72S7g=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+jgByP75f4I=", - "_parent": { - "$ref": "AAAAAAFq+jgByP74Xeo=" - }, - "model": { - "$ref": "AAAAAAFq+jgByP72S7g=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+jgByP76XYk=", - "_parent": { - "$ref": "AAAAAAFq+jgByP75f4I=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -336, - "top": -128, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+jgByP77+kg=", - "_parent": { - "$ref": "AAAAAAFq+jgByP75f4I=" - }, - "font": "Arial;13;1", - "left": 381, - "top": 583, - "width": 103, - "height": 13, - "text": "Composite" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+jgByf78F+8=", - "_parent": { - "$ref": "AAAAAAFq+jgByP75f4I=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -336, - "top": -128, - "width": 181.27001953125, - "height": 13, - "text": "(from 结构型模式——组合模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+jgByf79Nzw=", - "_parent": { - "$ref": "AAAAAAFq+jgByP75f4I=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -336, - "top": -128, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 376, - "top": 576, - "width": 113, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+jgByP76XYk=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+jgByP77+kg=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+jgByf78F+8=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+jgByf79Nzw=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+jgByf7+6IA=", - "_parent": { - "$ref": "AAAAAAFq+jgByP74Xeo=" - }, - "model": { - "$ref": "AAAAAAFq+jgByP72S7g=" - }, - "font": "Arial;13;0", - "left": 376, - "top": 601, - "width": 113, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+jgByf7/COw=", - "_parent": { - "$ref": "AAAAAAFq+jgByP74Xeo=" - }, - "model": { - "$ref": "AAAAAAFq+jgByP72S7g=" - }, - "font": "Arial;13;0", - "left": 376, - "top": 611, - "width": 113, - "height": 10 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+jgByf8AONg=", - "_parent": { - "$ref": "AAAAAAFq+jgByP74Xeo=" - }, - "model": { - "$ref": "AAAAAAFq+jgByP72S7g=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -168, - "top": -64, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+jgByf8BwQA=", - "_parent": { - "$ref": "AAAAAAFq+jgByP74Xeo=" - }, - "model": { - "$ref": "AAAAAAFq+jgByP72S7g=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -168, - "top": -64, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 376, - "top": 576, - "width": 113, - "height": 65, - "nameCompartment": { - "$ref": "AAAAAAFq+jgByP75f4I=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+jgByf7+6IA=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+jgByf7/COw=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+jgByf8AONg=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+jgByf8BwQA=" - } - }, - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+jgLGv8hSKo=", - "_parent": { - "$ref": "AAAAAAFq+jeqt/5l4BM=" - }, - "model": { - "$ref": "AAAAAAFq+jgLGv8fRh8=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+jgLGv8i61Q=", - "_parent": { - "$ref": "AAAAAAFq+jgLGv8hSKo=" - }, - "model": { - "$ref": "AAAAAAFq+jgLGv8fRh8=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+jgLGv8jlwc=", - "_parent": { - "$ref": "AAAAAAFq+jgLGv8i61Q=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -432, - "top": -112, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+jgLGv8kGtQ=", - "_parent": { - "$ref": "AAAAAAFq+jgLGv8i61Q=" - }, - "font": "Arial;13;1", - "left": 245, - "top": 359, - "width": 199.798828125, - "height": 13, - "text": "Component" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+jgLGv8lvos=", - "_parent": { - "$ref": "AAAAAAFq+jgLGv8i61Q=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -432, - "top": -112, - "width": 181.27001953125, - "height": 13, - "text": "(from 结构型模式——组合模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+jgLGv8m1oo=", - "_parent": { - "$ref": "AAAAAAFq+jgLGv8i61Q=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -432, - "top": -112, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 240, - "top": 352, - "width": 209.798828125, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+jgLGv8jlwc=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+jgLGv8kGtQ=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+jgLGv8lvos=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+jgLGv8m1oo=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+jgLGv8nJFI=", - "_parent": { - "$ref": "AAAAAAFq+jgLGv8hSKo=" - }, - "model": { - "$ref": "AAAAAAFq+jgLGv8fRh8=" - }, - "font": "Arial;13;0", - "left": 240, - "top": 377, - "width": 209.798828125, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+jgLGv8o8FE=", - "_parent": { - "$ref": "AAAAAAFq+jgLGv8hSKo=" - }, - "model": { - "$ref": "AAAAAAFq+jgLGv8fRh8=" - }, - "subViews": [ - { - "_type": "UMLOperationView", - "_id": "AAAAAAFq+jjjKv9ZKF0=", - "_parent": { - "$ref": "AAAAAAFq+jgLGv8o8FE=" - }, - "model": { - "$ref": "AAAAAAFq+jjjAf9WhSg=" - }, - "font": "Arial;13;0", - "left": 245, - "top": 392, - "width": 199.798828125, - "height": 13, - "text": "+Add(Component component)", - "horizontalAlignment": 0 - }, - { - "_type": "UMLOperationView", - "_id": "AAAAAAFq+jjuwP9fxqk=", - "_parent": { - "$ref": "AAAAAAFq+jgLGv8o8FE=" - }, - "model": { - "$ref": "AAAAAAFq+jjunv9cfSE=" - }, - "font": "Arial;13;0", - "left": 245, - "top": 407, - "width": 199.798828125, - "height": 13, - "text": "+Remove(Component component)", - "horizontalAlignment": 0 - }, - { - "_type": "UMLOperationView", - "_id": "AAAAAAFq+jj29/9lNGU=", - "_parent": { - "$ref": "AAAAAAFq+jgLGv8o8FE=" - }, - "model": { - "$ref": "AAAAAAFq+jj21P9ilI4=" - }, - "font": "Arial;13;0", - "left": 245, - "top": 422, - "width": 199.798828125, - "height": 13, - "text": "+Display()", - "horizontalAlignment": 0 - } - ], - "font": "Arial;13;0", - "left": 240, - "top": 387, - "width": 209.798828125, - "height": 53 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+jgLGv8p+RI=", - "_parent": { - "$ref": "AAAAAAFq+jgLGv8hSKo=" - }, - "model": { - "$ref": "AAAAAAFq+jgLGv8fRh8=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -216, - "top": -56, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+jgLGv8qmdI=", - "_parent": { - "$ref": "AAAAAAFq+jgLGv8hSKo=" - }, - "model": { - "$ref": "AAAAAAFq+jgLGv8fRh8=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -216, - "top": -56, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 240, - "top": 352, - "width": 209.798828125, - "height": 97, - "nameCompartment": { - "$ref": "AAAAAAFq+jgLGv8i61Q=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+jgLGv8nJFI=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+jgLGv8o8FE=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+jgLGv8p+RI=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+jgLGv8qmdI=" - } - }, - { - "_type": "UMLAssociationView", - "_id": "AAAAAAFq+jodDf98wfs=", - "_parent": { - "$ref": "AAAAAAFq+jeqt/5l4BM=" - }, - "model": { - "$ref": "AAAAAAFq+jodDf94llQ=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+jodDf99Uik=", - "_parent": { - "$ref": "AAAAAAFq+jodDf98wfs=" - }, - "model": { - "$ref": "AAAAAAFq+jodDf94llQ=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 172, - "top": 379, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+jodDf98wfs=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+jodDf9+PlY=", - "_parent": { - "$ref": "AAAAAAFq+jodDf98wfs=" - }, - "model": { - "$ref": "AAAAAAFq+jodDf94llQ=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 172, - "top": 364, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+jodDf98wfs=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+jodDf9/P+M=", - "_parent": { - "$ref": "AAAAAAFq+jodDf98wfs=" - }, - "model": { - "$ref": "AAAAAAFq+jodDf94llQ=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 172, - "top": 409, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+jodDf98wfs=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+jodDv+A1Lk=", - "_parent": { - "$ref": "AAAAAAFq+jodDf98wfs=" - }, - "model": { - "$ref": "AAAAAAFq+jodDf95p0E=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 130, - "top": 379, - "height": 13, - "alpha": 0.5235987755982988, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+jodDf98wfs=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+jodDv+BdzQ=", - "_parent": { - "$ref": "AAAAAAFq+jodDf98wfs=" - }, - "model": { - "$ref": "AAAAAAFq+jodDf95p0E=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 133, - "top": 365, - "height": 13, - "alpha": 0.7853981633974483, - "distance": 40, - "hostEdge": { - "$ref": "AAAAAAFq+jodDf98wfs=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+jodDv+CIoU=", - "_parent": { - "$ref": "AAAAAAFq+jodDf98wfs=" - }, - "model": { - "$ref": "AAAAAAFq+jodDf95p0E=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 126, - "top": 406, - "height": 13, - "alpha": -0.5235987755982988, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFq+jodDf98wfs=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+jodDv+Dt80=", - "_parent": { - "$ref": "AAAAAAFq+jodDf98wfs=" - }, - "model": { - "$ref": "AAAAAAFq+jodDf96Xh4=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 213, - "top": 379, - "height": 13, - "alpha": -0.5235987755982988, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+jodDf98wfs=" - } - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+jodDv+ExhY=", - "_parent": { - "$ref": "AAAAAAFq+jodDf98wfs=" - }, - "model": { - "$ref": "AAAAAAFq+jodDf96Xh4=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 210, - "top": 365, - "height": 13, - "alpha": -0.7853981633974483, - "distance": 40, - "hostEdge": { - "$ref": "AAAAAAFq+jodDf98wfs=" - } - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+jodDv+FMGI=", - "_parent": { - "$ref": "AAAAAAFq+jodDf98wfs=" - }, - "model": { - "$ref": "AAAAAAFq+jodDf96Xh4=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 217, - "top": 406, - "height": 13, - "alpha": 0.5235987755982988, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFq+jodDf98wfs=" - } - }, - { - "_type": "UMLQualifierCompartmentView", - "_id": "AAAAAAFq+jodDv+GeD0=", - "_parent": { - "$ref": "AAAAAAFq+jodDf98wfs=" - }, - "model": { - "$ref": "AAAAAAFq+jodDf95p0E=" - }, - "visible": false, - "font": "Arial;13;0", - "width": 10, - "height": 10 - }, - { - "_type": "UMLQualifierCompartmentView", - "_id": "AAAAAAFq+jodDv+HuAw=", - "_parent": { - "$ref": "AAAAAAFq+jodDf98wfs=" - }, - "model": { - "$ref": "AAAAAAFq+jodDf96Xh4=" - }, - "visible": false, - "font": "Arial;13;0", - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+jgLGv8hSKo=" - }, - "tail": { - "$ref": "AAAAAAFq+jf3d/6mzt4=" - }, - "lineStyle": 1, - "points": "105:400;239:400", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+jodDf99Uik=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+jodDf9+PlY=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+jodDf9/P+M=" - }, - "tailRoleNameLabel": { - "$ref": "AAAAAAFq+jodDv+A1Lk=" - }, - "tailPropertyLabel": { - "$ref": "AAAAAAFq+jodDv+BdzQ=" - }, - "tailMultiplicityLabel": { - "$ref": "AAAAAAFq+jodDv+CIoU=" - }, - "headRoleNameLabel": { - "$ref": "AAAAAAFq+jodDv+Dt80=" - }, - "headPropertyLabel": { - "$ref": "AAAAAAFq+jodDv+ExhY=" - }, - "headMultiplicityLabel": { - "$ref": "AAAAAAFq+jodDv+FMGI=" - }, - "tailQualifiersCompartment": { - "$ref": "AAAAAAFq+jodDv+GeD0=" - }, - "headQualifiersCompartment": { - "$ref": "AAAAAAFq+jodDv+HuAw=" - } - }, - { - "_type": "UMLGeneralizationView", - "_id": "AAAAAAFq+jqYhwAefKE=", - "_parent": { - "$ref": "AAAAAAFq+jeqt/5l4BM=" - }, - "model": { - "$ref": "AAAAAAFq+jqYhgAcpjs=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+jqYhwAfdiw=", - "_parent": { - "$ref": "AAAAAAFq+jqYhwAefKE=" - }, - "model": { - "$ref": "AAAAAAFq+jqYhgAcpjs=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 280, - "top": 475, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+jqYhwAefKE=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+jqYhwAgdio=", - "_parent": { - "$ref": "AAAAAAFq+jqYhwAefKE=" - }, - "model": { - "$ref": "AAAAAAFq+jqYhgAcpjs=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 280, - "top": 460, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+jqYhwAefKE=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+jqYhwAhgRM=", - "_parent": { - "$ref": "AAAAAAFq+jqYhwAefKE=" - }, - "model": { - "$ref": "AAAAAAFq+jqYhgAcpjs=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 280, - "top": 505, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+jqYhwAefKE=" - }, - "edgePosition": 1 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+jgLGv8hSKo=" - }, - "tail": { - "$ref": "AAAAAAFq+jf8+f7PeYY=" - }, - "points": "224:576;224:496;336:496;336:448", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+jqYhwAfdiw=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+jqYhwAgdio=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+jqYhwAhgRM=" - } - }, - { - "_type": "UMLGeneralizationView", - "_id": "AAAAAAFq+jqhlQA4Vy8=", - "_parent": { - "$ref": "AAAAAAFq+jeqt/5l4BM=" - }, - "model": { - "$ref": "AAAAAAFq+jqhlQA2N2w=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+jqhlQA5McI=", - "_parent": { - "$ref": "AAAAAAFq+jqhlQA4Vy8=" - }, - "model": { - "$ref": "AAAAAAFq+jqhlQA2N2w=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 375, - "top": 505, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+jqhlQA4Vy8=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+jqhlQA6foM=", - "_parent": { - "$ref": "AAAAAAFq+jqhlQA4Vy8=" - }, - "model": { - "$ref": "AAAAAAFq+jqhlQA2N2w=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 375, - "top": 520, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+jqhlQA4Vy8=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+jqhlQA7q5o=", - "_parent": { - "$ref": "AAAAAAFq+jqhlQA4Vy8=" - }, - "model": { - "$ref": "AAAAAAFq+jqhlQA2N2w=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 376, - "top": 475, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+jqhlQA4Vy8=" - }, - "edgePosition": 1 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+jgLGv8hSKo=" - }, - "tail": { - "$ref": "AAAAAAFq+jgByP74Xeo=" - }, - "points": "416:576;416:496;336:496;336:448", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+jqhlQA5McI=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+jqhlQA6foM=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+jqhlQA7q5o=" - } - }, - { - "_type": "UMLAssociationView", - "_id": "AAAAAAFq+juqLAIU4Dw=", - "_parent": { - "$ref": "AAAAAAFq+jeqt/5l4BM=" - }, - "model": { - "$ref": "AAAAAAFq+juqKwIQFzI=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+juqLAIVt/Q=", - "_parent": { - "$ref": "AAAAAAFq+juqLAIU4Dw=" - }, - "model": { - "$ref": "AAAAAAFq+juqKwIQFzI=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 591, - "top": 497, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+juqLAIU4Dw=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+juqLAIW9WI=", - "_parent": { - "$ref": "AAAAAAFq+juqLAIU4Dw=" - }, - "model": { - "$ref": "AAAAAAFq+juqKwIQFzI=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 606, - "top": 497, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+juqLAIU4Dw=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+juqLAIXtv0=", - "_parent": { - "$ref": "AAAAAAFq+juqLAIU4Dw=" - }, - "model": { - "$ref": "AAAAAAFq+juqKwIQFzI=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 561, - "top": 498, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+juqLAIU4Dw=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+juqLAIYZ7U=", - "_parent": { - "$ref": "AAAAAAFq+juqLAIU4Dw=" - }, - "model": { - "$ref": "AAAAAAFq+juqKwIRr48=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 474, - "top": 379, - "height": 13, - "alpha": 0.5235987755982988, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+juqLAIU4Dw=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+juqLAIZbEE=", - "_parent": { - "$ref": "AAAAAAFq+juqLAIU4Dw=" - }, - "model": { - "$ref": "AAAAAAFq+juqKwIRr48=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 477, - "top": 365, - "height": 13, - "alpha": 0.7853981633974483, - "distance": 40, - "hostEdge": { - "$ref": "AAAAAAFq+juqLAIU4Dw=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+juqLAIal90=", - "_parent": { - "$ref": "AAAAAAFq+juqLAIU4Dw=" - }, - "model": { - "$ref": "AAAAAAFq+juqKwIRr48=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 470, - "top": 406, - "height": 13, - "alpha": -0.5235987755982988, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFq+juqLAIU4Dw=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+juqLAIbSs0=", - "_parent": { - "$ref": "AAAAAAFq+juqLAIU4Dw=" - }, - "model": { - "$ref": "AAAAAAFq+juqKwISrA0=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 513, - "top": 616, - "height": 13, - "alpha": -0.5235987755982988, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+juqLAIU4Dw=" - } - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+juqLAIc15Y=", - "_parent": { - "$ref": "AAAAAAFq+juqLAIU4Dw=" - }, - "model": { - "$ref": "AAAAAAFq+juqKwISrA0=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 516, - "top": 630, - "height": 13, - "alpha": -0.7853981633974483, - "distance": 40, - "hostEdge": { - "$ref": "AAAAAAFq+juqLAIU4Dw=" - } - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+juqLAIdWMk=", - "_parent": { - "$ref": "AAAAAAFq+juqLAIU4Dw=" - }, - "model": { - "$ref": "AAAAAAFq+juqKwISrA0=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 509, - "top": 589, - "height": 13, - "alpha": 0.5235987755982988, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFq+juqLAIU4Dw=" - } - }, - { - "_type": "UMLQualifierCompartmentView", - "_id": "AAAAAAFq+juqLAIeQaU=", - "_parent": { - "$ref": "AAAAAAFq+juqLAIU4Dw=" - }, - "model": { - "$ref": "AAAAAAFq+juqKwIRr48=" - }, - "visible": false, - "font": "Arial;13;0", - "width": 10, - "height": 10 - }, - { - "_type": "UMLQualifierCompartmentView", - "_id": "AAAAAAFq+juqLAIf60g=", - "_parent": { - "$ref": "AAAAAAFq+juqLAIU4Dw=" - }, - "model": { - "$ref": "AAAAAAFq+juqKwISrA0=" - }, - "visible": false, - "font": "Arial;13;0", - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+jgByP74Xeo=" - }, - "tail": { - "$ref": "AAAAAAFq+jgLGv8hSKo=" - }, - "points": "449:400;576:400;576:608;488:608", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+juqLAIVt/Q=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+juqLAIW9WI=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+juqLAIXtv0=" - }, - "tailRoleNameLabel": { - "$ref": "AAAAAAFq+juqLAIYZ7U=" - }, - "tailPropertyLabel": { - "$ref": "AAAAAAFq+juqLAIZbEE=" - }, - "tailMultiplicityLabel": { - "$ref": "AAAAAAFq+juqLAIal90=" - }, - "headRoleNameLabel": { - "$ref": "AAAAAAFq+juqLAIbSs0=" - }, - "headPropertyLabel": { - "$ref": "AAAAAAFq+juqLAIc15Y=" - }, - "headMultiplicityLabel": { - "$ref": "AAAAAAFq+juqLAIdWMk=" - }, - "tailQualifiersCompartment": { - "$ref": "AAAAAAFq+juqLAIeQaU=" - }, - "headQualifiersCompartment": { - "$ref": "AAAAAAFq+juqLAIf60g=" - } - } - ] - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+jf3d/6k1Lo=", - "_parent": { - "$ref": "AAAAAAFq+jeqt/5k3R4=" - }, - "name": "Client", - "ownedElements": [ - { - "_type": "UMLAssociation", - "_id": "AAAAAAFq+jodDf94llQ=", - "_parent": { - "$ref": "AAAAAAFq+jf3d/6k1Lo=" - }, - "end1": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFq+jodDf95p0E=", - "_parent": { - "$ref": "AAAAAAFq+jodDf94llQ=" - }, - "reference": { - "$ref": "AAAAAAFq+jf3d/6k1Lo=" - }, - "navigable": false - }, - "end2": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFq+jodDf96Xh4=", - "_parent": { - "$ref": "AAAAAAFq+jodDf94llQ=" - }, - "reference": { - "$ref": "AAAAAAFq+jgLGv8fRh8=" - } - } - } - ] - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+jf8+f7NOv8=", - "_parent": { - "$ref": "AAAAAAFq+jeqt/5k3R4=" - }, - "name": "Leaf", - "ownedElements": [ - { - "_type": "UMLGeneralization", - "_id": "AAAAAAFq+jqYhgAcpjs=", - "_parent": { - "$ref": "AAAAAAFq+jf8+f7NOv8=" - }, - "source": { - "$ref": "AAAAAAFq+jf8+f7NOv8=" - }, - "target": { - "$ref": "AAAAAAFq+jgLGv8fRh8=" - } - } - ] - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+jgByP72S7g=", - "_parent": { - "$ref": "AAAAAAFq+jeqt/5k3R4=" - }, - "name": "Composite", - "ownedElements": [ - { - "_type": "UMLGeneralization", - "_id": "AAAAAAFq+jqhlQA2N2w=", - "_parent": { - "$ref": "AAAAAAFq+jgByP72S7g=" - }, - "source": { - "$ref": "AAAAAAFq+jgByP72S7g=" - }, - "target": { - "$ref": "AAAAAAFq+jgLGv8fRh8=" - } - } - ] - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+jgLGv8fRh8=", - "_parent": { - "$ref": "AAAAAAFq+jeqt/5k3R4=" - }, - "name": "Component", - "ownedElements": [ - { - "_type": "UMLAssociation", - "_id": "AAAAAAFq+juqKwIQFzI=", - "_parent": { - "$ref": "AAAAAAFq+jgLGv8fRh8=" - }, - "end1": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFq+juqKwIRr48=", - "_parent": { - "$ref": "AAAAAAFq+juqKwIQFzI=" - }, - "reference": { - "$ref": "AAAAAAFq+jgLGv8fRh8=" - } - }, - "end2": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFq+juqKwISrA0=", - "_parent": { - "$ref": "AAAAAAFq+juqKwIQFzI=" - }, - "reference": { - "$ref": "AAAAAAFq+jgByP72S7g=" - }, - "navigable": false, - "aggregation": "shared" - } - } - ], - "operations": [ - { - "_type": "UMLOperation", - "_id": "AAAAAAFq+jjjAf9WhSg=", - "_parent": { - "$ref": "AAAAAAFq+jgLGv8fRh8=" - }, - "name": "Add", - "parameters": [ - { - "_type": "UMLParameter", - "_id": "AAAAAAFq+jlsLv9r63k=", - "_parent": { - "$ref": "AAAAAAFq+jjjAf9WhSg=" - }, - "name": "Component component" - } - ] - }, - { - "_type": "UMLOperation", - "_id": "AAAAAAFq+jjunv9cfSE=", - "_parent": { - "$ref": "AAAAAAFq+jgLGv8fRh8=" - }, - "name": "Remove", - "parameters": [ - { - "_type": "UMLParameter", - "_id": "AAAAAAFq+jnOw/9vJok=", - "_parent": { - "$ref": "AAAAAAFq+jjunv9cfSE=" - }, - "name": "Component component" - } - ] - }, - { - "_type": "UMLOperation", - "_id": "AAAAAAFq+jj21P9ilI4=", - "_parent": { - "$ref": "AAAAAAFq+jgLGv8fRh8=" - }, - "name": "Display" - } - ] - } - ] - }, - { - "_type": "UMLModel", - "_id": "AAAAAAFq+j6bzQNn5yE=", - "_parent": { - "$ref": "AAAAAAFF+h6SjaM2Hec=" - }, - "name": "结构型模式——桥接模式", - "ownedElements": [ - { - "_type": "UMLClassDiagram", - "_id": "AAAAAAFq+j6bzgNoWMc=", - "_parent": { - "$ref": "AAAAAAFq+j6bzQNn5yE=" - }, - "name": "桥接模式", - "ownedViews": [ - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+j7ZOAOpfcQ=", - "_parent": { - "$ref": "AAAAAAFq+j6bzgNoWMc=" - }, - "model": { - "$ref": "AAAAAAFq+j7ZNwOnnhw=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+j7ZOAOqIOY=", - "_parent": { - "$ref": "AAAAAAFq+j7ZOAOpfcQ=" - }, - "model": { - "$ref": "AAAAAAFq+j7ZNwOnnhw=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+j7ZOAOrXgE=", - "_parent": { - "$ref": "AAAAAAFq+j7ZOAOqIOY=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -16, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+j7ZOAOsvcU=", - "_parent": { - "$ref": "AAAAAAFq+j7ZOAOqIOY=" - }, - "font": "Arial;13;3", - "left": 117, - "top": 263, - "width": 103, - "height": 13, - "text": "Abstraction" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+j7ZOAOtIoU=", - "_parent": { - "$ref": "AAAAAAFq+j7ZOAOqIOY=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -16, - "width": 181.27001953125, - "height": 13, - "text": "(from 结构型模式——桥接模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+j7ZOAOuqrg=", - "_parent": { - "$ref": "AAAAAAFq+j7ZOAOqIOY=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -16, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 112, - "top": 256, - "width": 113, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+j7ZOAOrXgE=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+j7ZOAOsvcU=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+j7ZOAOtIoU=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+j7ZOAOuqrg=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+j7ZOAOvSmU=", - "_parent": { - "$ref": "AAAAAAFq+j7ZOAOpfcQ=" - }, - "model": { - "$ref": "AAAAAAFq+j7ZNwOnnhw=" - }, - "font": "Arial;13;0", - "left": 112, - "top": 281, - "width": 113, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+j7ZOAOwf6g=", - "_parent": { - "$ref": "AAAAAAFq+j7ZOAOpfcQ=" - }, - "model": { - "$ref": "AAAAAAFq+j7ZNwOnnhw=" - }, - "subViews": [ - { - "_type": "UMLOperationView", - "_id": "AAAAAAFq+j+CbwRdGDA=", - "_parent": { - "$ref": "AAAAAAFq+j7ZOAOwf6g=" - }, - "model": { - "$ref": "AAAAAAFq+j+CSwRaImc=" - }, - "font": "Arial;13;0", - "left": 117, - "top": 296, - "width": 103, - "height": 13, - "text": "+Operation()", - "horizontalAlignment": 0 - } - ], - "font": "Arial;13;0", - "left": 112, - "top": 291, - "width": 113, - "height": 23 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+j7ZOAOxbDs=", - "_parent": { - "$ref": "AAAAAAFq+j7ZOAOpfcQ=" - }, - "model": { - "$ref": "AAAAAAFq+j7ZNwOnnhw=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -8, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+j7ZOAOyli8=", - "_parent": { - "$ref": "AAAAAAFq+j7ZOAOpfcQ=" - }, - "model": { - "$ref": "AAAAAAFq+j7ZNwOnnhw=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -8, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 112, - "top": 256, - "width": 113, - "height": 65, - "nameCompartment": { - "$ref": "AAAAAAFq+j7ZOAOqIOY=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+j7ZOAOvSmU=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+j7ZOAOwf6g=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+j7ZOAOxbDs=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+j7ZOAOyli8=" - } - }, - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+j7dQgPSw6g=", - "_parent": { - "$ref": "AAAAAAFq+j6bzgNoWMc=" - }, - "model": { - "$ref": "AAAAAAFq+j7dQgPQb9k=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+j7dQgPTaZg=", - "_parent": { - "$ref": "AAAAAAFq+j7dQgPSw6g=" - }, - "model": { - "$ref": "AAAAAAFq+j7dQgPQb9k=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+j7dQgPUghE=", - "_parent": { - "$ref": "AAAAAAFq+j7dQgPTaZg=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -176, - "top": -48, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+j7dQgPVtxs=", - "_parent": { - "$ref": "AAAAAAFq+j7dQgPTaZg=" - }, - "font": "Arial;13;3", - "left": 389, - "top": 263, - "width": 119, - "height": 13, - "text": "Implementor" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+j7dQgPW2WI=", - "_parent": { - "$ref": "AAAAAAFq+j7dQgPTaZg=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -176, - "top": -48, - "width": 181.27001953125, - "height": 13, - "text": "(from 结构型模式——桥接模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+j7dQgPXSKE=", - "_parent": { - "$ref": "AAAAAAFq+j7dQgPTaZg=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -176, - "top": -48, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 384, - "top": 256, - "width": 129, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+j7dQgPUghE=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+j7dQgPVtxs=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+j7dQgPW2WI=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+j7dQgPXSKE=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+j7dQgPYLsI=", - "_parent": { - "$ref": "AAAAAAFq+j7dQgPSw6g=" - }, - "model": { - "$ref": "AAAAAAFq+j7dQgPQb9k=" - }, - "font": "Arial;13;0", - "left": 384, - "top": 281, - "width": 129, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+j7dQgPZ74k=", - "_parent": { - "$ref": "AAAAAAFq+j7dQgPSw6g=" - }, - "model": { - "$ref": "AAAAAAFq+j7dQgPQb9k=" - }, - "subViews": [ - { - "_type": "UMLOperationView", - "_id": "AAAAAAFq+j/wpARpkHU=", - "_parent": { - "$ref": "AAAAAAFq+j7dQgPZ74k=" - }, - "model": { - "$ref": "AAAAAAFq+j/wgARmvAA=" - }, - "font": "Arial;13;0", - "left": 389, - "top": 296, - "width": 119, - "height": 13, - "text": "+OperationImpl()", - "horizontalAlignment": 0 - } - ], - "font": "Arial;13;0", - "left": 384, - "top": 291, - "width": 129, - "height": 23 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+j7dQgPafdw=", - "_parent": { - "$ref": "AAAAAAFq+j7dQgPSw6g=" - }, - "model": { - "$ref": "AAAAAAFq+j7dQgPQb9k=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -88, - "top": -24, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+j7dQgPb7Uc=", - "_parent": { - "$ref": "AAAAAAFq+j7dQgPSw6g=" - }, - "model": { - "$ref": "AAAAAAFq+j7dQgPQb9k=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -88, - "top": -24, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 384, - "top": 256, - "width": 129, - "height": 65, - "nameCompartment": { - "$ref": "AAAAAAFq+j7dQgPTaZg=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+j7dQgPYLsI=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+j7dQgPZ74k=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+j7dQgPafdw=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+j7dQgPb7Uc=" - } - }, - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+j76cAP9XkE=", - "_parent": { - "$ref": "AAAAAAFq+j6bzgNoWMc=" - }, - "model": { - "$ref": "AAAAAAFq+j76cAP72Bc=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+j76cAP+49o=", - "_parent": { - "$ref": "AAAAAAFq+j76cAP9XkE=" - }, - "model": { - "$ref": "AAAAAAFq+j76cAP72Bc=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+j76cAP/cPA=", - "_parent": { - "$ref": "AAAAAAFq+j76cAP+49o=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -240, - "top": 32, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+j76cAQAELg=", - "_parent": { - "$ref": "AAAAAAFq+j76cAP+49o=" - }, - "font": "Arial;13;1", - "left": 101, - "top": 471, - "width": 135, - "height": 13, - "text": "RefinedAbstraction" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+j76cAQBVr8=", - "_parent": { - "$ref": "AAAAAAFq+j76cAP+49o=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -240, - "top": 32, - "width": 181.27001953125, - "height": 13, - "text": "(from 结构型模式——桥接模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+j76cAQCqbU=", - "_parent": { - "$ref": "AAAAAAFq+j76cAP+49o=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -240, - "top": 32, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 96, - "top": 464, - "width": 145, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+j76cAP/cPA=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+j76cAQAELg=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+j76cAQBVr8=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+j76cAQCqbU=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+j76cAQDMC4=", - "_parent": { - "$ref": "AAAAAAFq+j76cAP9XkE=" - }, - "model": { - "$ref": "AAAAAAFq+j76cAP72Bc=" - }, - "font": "Arial;13;0", - "left": 96, - "top": 489, - "width": 145, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+j76cAQEyng=", - "_parent": { - "$ref": "AAAAAAFq+j76cAP9XkE=" - }, - "model": { - "$ref": "AAAAAAFq+j76cAP72Bc=" - }, - "font": "Arial;13;0", - "left": 96, - "top": 499, - "width": 145, - "height": 10 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+j76cAQFRO8=", - "_parent": { - "$ref": "AAAAAAFq+j76cAP9XkE=" - }, - "model": { - "$ref": "AAAAAAFq+j76cAP72Bc=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -120, - "top": 16, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+j76cAQGv40=", - "_parent": { - "$ref": "AAAAAAFq+j76cAP9XkE=" - }, - "model": { - "$ref": "AAAAAAFq+j76cAP72Bc=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -120, - "top": 16, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 96, - "top": 464, - "width": 145, - "height": 65, - "nameCompartment": { - "$ref": "AAAAAAFq+j76cAP+49o=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+j76cAQDMC4=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+j76cAQEyng=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+j76cAQFRO8=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+j76cAQGv40=" - } - }, - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+j799AQmsyw=", - "_parent": { - "$ref": "AAAAAAFq+j6bzgNoWMc=" - }, - "model": { - "$ref": "AAAAAAFq+j799AQkD7k=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+j799AQnLF4=", - "_parent": { - "$ref": "AAAAAAFq+j799AQmsyw=" - }, - "model": { - "$ref": "AAAAAAFq+j799AQkD7k=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+j799AQo+GI=", - "_parent": { - "$ref": "AAAAAAFq+j799AQnLF4=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -288, - "top": 48, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+j799AQpYRo=", - "_parent": { - "$ref": "AAAAAAFq+j799AQnLF4=" - }, - "font": "Arial;13;1", - "left": 373, - "top": 471, - "width": 151, - "height": 13, - "text": "ConcreteImplementor" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+j799AQqax4=", - "_parent": { - "$ref": "AAAAAAFq+j799AQnLF4=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -288, - "top": 48, - "width": 181.27001953125, - "height": 13, - "text": "(from 结构型模式——桥接模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+j799AQrptQ=", - "_parent": { - "$ref": "AAAAAAFq+j799AQnLF4=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -288, - "top": 48, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 368, - "top": 464, - "width": 161, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+j799AQo+GI=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+j799AQpYRo=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+j799AQqax4=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+j799AQrptQ=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+j799AQsSAY=", - "_parent": { - "$ref": "AAAAAAFq+j799AQmsyw=" - }, - "model": { - "$ref": "AAAAAAFq+j799AQkD7k=" - }, - "font": "Arial;13;0", - "left": 368, - "top": 489, - "width": 161, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+j799AQt+WI=", - "_parent": { - "$ref": "AAAAAAFq+j799AQmsyw=" - }, - "model": { - "$ref": "AAAAAAFq+j799AQkD7k=" - }, - "font": "Arial;13;0", - "left": 368, - "top": 499, - "width": 161, - "height": 10 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+j799AQuTkM=", - "_parent": { - "$ref": "AAAAAAFq+j799AQmsyw=" - }, - "model": { - "$ref": "AAAAAAFq+j799AQkD7k=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -144, - "top": 24, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+j799AQvDq0=", - "_parent": { - "$ref": "AAAAAAFq+j799AQmsyw=" - }, - "model": { - "$ref": "AAAAAAFq+j799AQkD7k=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -144, - "top": 24, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 368, - "top": 464, - "width": 161, - "height": 65, - "nameCompartment": { - "$ref": "AAAAAAFq+j799AQnLF4=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+j799AQsSAY=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+j799AQt+WI=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+j799AQuTkM=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+j799AQvDq0=" - } - }, - { - "_type": "UMLGeneralizationView", - "_id": "AAAAAAFq+kAcJgRvahI=", - "_parent": { - "$ref": "AAAAAAFq+j6bzgNoWMc=" - }, - "model": { - "$ref": "AAAAAAFq+kAcJgRtJNE=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+kAcJgRwZww=", - "_parent": { - "$ref": "AAAAAAFq+kAcJgRvahI=" - }, - "model": { - "$ref": "AAAAAAFq+kAcJgRtJNE=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 153, - "top": 385, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+kAcJgRvahI=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+kAcJgRxtbk=", - "_parent": { - "$ref": "AAAAAAFq+kAcJgRvahI=" - }, - "model": { - "$ref": "AAAAAAFq+kAcJgRtJNE=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 138, - "top": 385, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+kAcJgRvahI=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+kAcJgRy6ig=", - "_parent": { - "$ref": "AAAAAAFq+kAcJgRvahI=" - }, - "model": { - "$ref": "AAAAAAFq+kAcJgRtJNE=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 182, - "top": 386, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+kAcJgRvahI=" - }, - "edgePosition": 1 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+j7ZOAOpfcQ=" - }, - "tail": { - "$ref": "AAAAAAFq+j76cAP9XkE=" - }, - "lineStyle": 1, - "points": "168:463;168:321", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+kAcJgRwZww=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+kAcJgRxtbk=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+kAcJgRy6ig=" - } - }, - { - "_type": "UMLGeneralizationView", - "_id": "AAAAAAFq+kAkIASAeM0=", - "_parent": { - "$ref": "AAAAAAFq+j6bzgNoWMc=" - }, - "model": { - "$ref": "AAAAAAFq+kAkIAR+xK0=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+kAkIASBu1M=", - "_parent": { - "$ref": "AAAAAAFq+kAkIASAeM0=" - }, - "model": { - "$ref": "AAAAAAFq+kAkIAR+xK0=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 433, - "top": 385, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+kAkIASAeM0=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+kAkIASCi88=", - "_parent": { - "$ref": "AAAAAAFq+kAkIASAeM0=" - }, - "model": { - "$ref": "AAAAAAFq+kAkIAR+xK0=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 418, - "top": 385, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+kAkIASAeM0=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+kAkIASDOSM=", - "_parent": { - "$ref": "AAAAAAFq+kAkIASAeM0=" - }, - "model": { - "$ref": "AAAAAAFq+kAkIAR+xK0=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 462, - "top": 386, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+kAkIASAeM0=" - }, - "edgePosition": 1 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+j7dQgPSw6g=" - }, - "tail": { - "$ref": "AAAAAAFq+j799AQmsyw=" - }, - "lineStyle": 1, - "points": "448:463;448:321", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+kAkIASBu1M=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+kAkIASCi88=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+kAkIASDOSM=" - } - }, - { - "_type": "UMLAssociationView", - "_id": "AAAAAAFq+kBHKASVfqQ=", - "_parent": { - "$ref": "AAAAAAFq+j6bzgNoWMc=" - }, - "model": { - "$ref": "AAAAAAFq+kBHJwSRo34=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+kBHKASWm58=", - "_parent": { - "$ref": "AAAAAAFq+kBHKASVfqQ=" - }, - "model": { - "$ref": "AAAAAAFq+kBHJwSRo34=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 304, - "top": 267, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+kBHKASVfqQ=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+kBHKASXpGo=", - "_parent": { - "$ref": "AAAAAAFq+kBHKASVfqQ=" - }, - "model": { - "$ref": "AAAAAAFq+kBHJwSRo34=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 304, - "top": 252, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+kBHKASVfqQ=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+kBHKASYF80=", - "_parent": { - "$ref": "AAAAAAFq+kBHKASVfqQ=" - }, - "model": { - "$ref": "AAAAAAFq+kBHJwSRo34=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 304, - "top": 297, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+kBHKASVfqQ=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+kBHKASZRU0=", - "_parent": { - "$ref": "AAAAAAFq+kBHKASVfqQ=" - }, - "model": { - "$ref": "AAAAAAFq+kBHJwSSb7M=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 250, - "top": 267, - "height": 13, - "alpha": 0.5235987755982988, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+kBHKASVfqQ=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+kBHKASazTo=", - "_parent": { - "$ref": "AAAAAAFq+kBHKASVfqQ=" - }, - "model": { - "$ref": "AAAAAAFq+kBHJwSSb7M=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 253, - "top": 253, - "height": 13, - "alpha": 0.7853981633974483, - "distance": 40, - "hostEdge": { - "$ref": "AAAAAAFq+kBHKASVfqQ=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+kBHKASb8Ms=", - "_parent": { - "$ref": "AAAAAAFq+kBHKASVfqQ=" - }, - "model": { - "$ref": "AAAAAAFq+kBHJwSSb7M=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 246, - "top": 294, - "height": 13, - "alpha": -0.5235987755982988, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFq+kBHKASVfqQ=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+kBHKAScZos=", - "_parent": { - "$ref": "AAAAAAFq+kBHKASVfqQ=" - }, - "model": { - "$ref": "AAAAAAFq+kBHJwSTJg0=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 357, - "top": 267, - "height": 13, - "alpha": -0.5235987755982988, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+kBHKASVfqQ=" - } - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+kBHKASdO5o=", - "_parent": { - "$ref": "AAAAAAFq+kBHKASVfqQ=" - }, - "model": { - "$ref": "AAAAAAFq+kBHJwSTJg0=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 354, - "top": 253, - "height": 13, - "alpha": -0.7853981633974483, - "distance": 40, - "hostEdge": { - "$ref": "AAAAAAFq+kBHKASVfqQ=" - } - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+kBHKASepjQ=", - "_parent": { - "$ref": "AAAAAAFq+kBHKASVfqQ=" - }, - "model": { - "$ref": "AAAAAAFq+kBHJwSTJg0=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 361, - "top": 294, - "height": 13, - "alpha": 0.5235987755982988, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFq+kBHKASVfqQ=" - } - }, - { - "_type": "UMLQualifierCompartmentView", - "_id": "AAAAAAFq+kBHKASfnmA=", - "_parent": { - "$ref": "AAAAAAFq+kBHKASVfqQ=" - }, - "model": { - "$ref": "AAAAAAFq+kBHJwSSb7M=" - }, - "visible": false, - "font": "Arial;13;0", - "width": 10, - "height": 10 - }, - { - "_type": "UMLQualifierCompartmentView", - "_id": "AAAAAAFq+kBHKASglIw=", - "_parent": { - "$ref": "AAAAAAFq+kBHKASVfqQ=" - }, - "model": { - "$ref": "AAAAAAFq+kBHJwSTJg0=" - }, - "visible": false, - "font": "Arial;13;0", - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+j7dQgPSw6g=" - }, - "tail": { - "$ref": "AAAAAAFq+j7ZOAOpfcQ=" - }, - "lineStyle": 1, - "points": "225:288;383:288", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+kBHKASWm58=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+kBHKASXpGo=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+kBHKASYF80=" - }, - "tailRoleNameLabel": { - "$ref": "AAAAAAFq+kBHKASZRU0=" - }, - "tailPropertyLabel": { - "$ref": "AAAAAAFq+kBHKASazTo=" - }, - "tailMultiplicityLabel": { - "$ref": "AAAAAAFq+kBHKASb8Ms=" - }, - "headRoleNameLabel": { - "$ref": "AAAAAAFq+kBHKAScZos=" - }, - "headPropertyLabel": { - "$ref": "AAAAAAFq+kBHKASdO5o=" - }, - "headMultiplicityLabel": { - "$ref": "AAAAAAFq+kBHKASepjQ=" - }, - "tailQualifiersCompartment": { - "$ref": "AAAAAAFq+kBHKASfnmA=" - }, - "headQualifiersCompartment": { - "$ref": "AAAAAAFq+kBHKASglIw=" - } - } - ] - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+j7ZNwOnnhw=", - "_parent": { - "$ref": "AAAAAAFq+j6bzQNn5yE=" - }, - "name": "Abstraction", - "ownedElements": [ - { - "_type": "UMLAssociation", - "_id": "AAAAAAFq+kBHJwSRo34=", - "_parent": { - "$ref": "AAAAAAFq+j7ZNwOnnhw=" - }, - "end1": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFq+kBHJwSSb7M=", - "_parent": { - "$ref": "AAAAAAFq+kBHJwSRo34=" - }, - "reference": { - "$ref": "AAAAAAFq+j7ZNwOnnhw=" - }, - "navigable": false, - "aggregation": "shared" - }, - "end2": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFq+kBHJwSTJg0=", - "_parent": { - "$ref": "AAAAAAFq+kBHJwSRo34=" - }, - "reference": { - "$ref": "AAAAAAFq+j7dQgPQb9k=" - } - } - } - ], - "operations": [ - { - "_type": "UMLOperation", - "_id": "AAAAAAFq+j+CSwRaImc=", - "_parent": { - "$ref": "AAAAAAFq+j7ZNwOnnhw=" - }, - "name": "Operation" - } - ], - "isAbstract": true - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+j7dQgPQb9k=", - "_parent": { - "$ref": "AAAAAAFq+j6bzQNn5yE=" - }, - "name": "Implementor", - "operations": [ - { - "_type": "UMLOperation", - "_id": "AAAAAAFq+j/wgARmvAA=", - "_parent": { - "$ref": "AAAAAAFq+j7dQgPQb9k=" - }, - "name": "OperationImpl" - } - ], - "isAbstract": true - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+j76cAP72Bc=", - "_parent": { - "$ref": "AAAAAAFq+j6bzQNn5yE=" - }, - "name": "RefinedAbstraction", - "ownedElements": [ - { - "_type": "UMLGeneralization", - "_id": "AAAAAAFq+kAcJgRtJNE=", - "_parent": { - "$ref": "AAAAAAFq+j76cAP72Bc=" - }, - "source": { - "$ref": "AAAAAAFq+j76cAP72Bc=" - }, - "target": { - "$ref": "AAAAAAFq+j7ZNwOnnhw=" - } - } - ] - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+j799AQkD7k=", - "_parent": { - "$ref": "AAAAAAFq+j6bzQNn5yE=" - }, - "name": "ConcreteImplementor", - "ownedElements": [ - { - "_type": "UMLGeneralization", - "_id": "AAAAAAFq+kAkIAR+xK0=", - "_parent": { - "$ref": "AAAAAAFq+j799AQkD7k=" - }, - "source": { - "$ref": "AAAAAAFq+j799AQkD7k=" - }, - "target": { - "$ref": "AAAAAAFq+j7dQgPQb9k=" - } - } - ] - } - ] - }, - { - "_type": "UMLModel", - "_id": "AAAAAAFq+ka2OwVBYGY=", - "_parent": { - "$ref": "AAAAAAFF+h6SjaM2Hec=" - }, - "name": "行为型模式——迭代器模式", - "ownedElements": [ - { - "_type": "UMLClassDiagram", - "_id": "AAAAAAFq+ka2OwVC4TY=", - "_parent": { - "$ref": "AAAAAAFq+ka2OwVBYGY=" - }, - "name": "迭代器模式", - "ownedViews": [ - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+kgW8wWDC2c=", - "_parent": { - "$ref": "AAAAAAFq+ka2OwVC4TY=" - }, - "model": { - "$ref": "AAAAAAFq+kgW8wWBRfM=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+kgW8wWEB28=", - "_parent": { - "$ref": "AAAAAAFq+kgW8wWDC2c=" - }, - "model": { - "$ref": "AAAAAAFq+kgW8wWBRfM=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+kgW8wWF4Vc=", - "_parent": { - "$ref": "AAAAAAFq+kgW8wWEB28=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -48, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+kgW8wWGbpQ=", - "_parent": { - "$ref": "AAAAAAFq+kgW8wWEB28=" - }, - "font": "Arial;13;1", - "left": 133, - "top": 983, - "width": 119, - "height": 13, - "text": "Aggregate" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+kgW9AWHxSM=", - "_parent": { - "$ref": "AAAAAAFq+kgW8wWEB28=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -48, - "width": 194.27001953125, - "height": 13, - "text": "(from 行为型模式——迭代器模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+kgW9AWIs4s=", - "_parent": { - "$ref": "AAAAAAFq+kgW8wWEB28=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -48, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 128, - "top": 976, - "width": 129, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+kgW8wWF4Vc=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+kgW8wWGbpQ=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+kgW9AWHxSM=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+kgW9AWIs4s=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+kgW9AWJYEc=", - "_parent": { - "$ref": "AAAAAAFq+kgW8wWDC2c=" - }, - "model": { - "$ref": "AAAAAAFq+kgW8wWBRfM=" - }, - "font": "Arial;13;0", - "left": 128, - "top": 1001, - "width": 129, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+kgW9AWK8ho=", - "_parent": { - "$ref": "AAAAAAFq+kgW8wWDC2c=" - }, - "model": { - "$ref": "AAAAAAFq+kgW8wWBRfM=" - }, - "subViews": [ - { - "_type": "UMLOperationView", - "_id": "AAAAAAFq+k2jeQaORfQ=", - "_parent": { - "$ref": "AAAAAAFq+kgW9AWK8ho=" - }, - "model": { - "$ref": "AAAAAAFq+k2jVAaL1UY=" - }, - "font": "Arial;13;0", - "left": 133, - "top": 1016, - "width": 119, - "height": 13, - "text": "+CreateIterator()", - "horizontalAlignment": 0 - } - ], - "font": "Arial;13;0", - "left": 128, - "top": 1011, - "width": 129, - "height": 23 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+kgW9AWLRZY=", - "_parent": { - "$ref": "AAAAAAFq+kgW8wWDC2c=" - }, - "model": { - "$ref": "AAAAAAFq+kgW8wWBRfM=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -24, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+kgW9AWMjuQ=", - "_parent": { - "$ref": "AAAAAAFq+kgW8wWDC2c=" - }, - "model": { - "$ref": "AAAAAAFq+kgW8wWBRfM=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -24, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 128, - "top": 976, - "width": 129, - "height": 65, - "nameCompartment": { - "$ref": "AAAAAAFq+kgW8wWEB28=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+kgW9AWJYEc=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+kgW9AWK8ho=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+kgW9AWLRZY=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+kgW9AWMjuQ=" - } - }, - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+kgd4QWs9PE=", - "_parent": { - "$ref": "AAAAAAFq+ka2OwVC4TY=" - }, - "model": { - "$ref": "AAAAAAFq+kgd4QWqy1w=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+kgd4QWtlmU=", - "_parent": { - "$ref": "AAAAAAFq+kgd4QWs9PE=" - }, - "model": { - "$ref": "AAAAAAFq+kgd4QWqy1w=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+kgd4QWuZGU=", - "_parent": { - "$ref": "AAAAAAFq+kgd4QWtlmU=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -128, - "top": -32, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+kgd4QWv/gI=", - "_parent": { - "$ref": "AAAAAAFq+kgd4QWtlmU=" - }, - "font": "Arial;13;1", - "left": 405, - "top": 983, - "width": 119, - "height": 13, - "text": "Iterator" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+kgd4QWwCaw=", - "_parent": { - "$ref": "AAAAAAFq+kgd4QWtlmU=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -128, - "top": -32, - "width": 194.27001953125, - "height": 13, - "text": "(from 行为型模式——迭代器模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+kgd4QWxOVY=", - "_parent": { - "$ref": "AAAAAAFq+kgd4QWtlmU=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -128, - "top": -32, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 400, - "top": 976, - "width": 129, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+kgd4QWuZGU=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+kgd4QWv/gI=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+kgd4QWwCaw=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+kgd4QWxOVY=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+kgd4QWy7Jk=", - "_parent": { - "$ref": "AAAAAAFq+kgd4QWs9PE=" - }, - "model": { - "$ref": "AAAAAAFq+kgd4QWqy1w=" - }, - "font": "Arial;13;0", - "left": 400, - "top": 1001, - "width": 129, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+kgd4QWzLA0=", - "_parent": { - "$ref": "AAAAAAFq+kgd4QWs9PE=" - }, - "model": { - "$ref": "AAAAAAFq+kgd4QWqy1w=" - }, - "subViews": [ - { - "_type": "UMLOperationView", - "_id": "AAAAAAFq+kxVFAZ5xJQ=", - "_parent": { - "$ref": "AAAAAAFq+kgd4QWzLA0=" - }, - "model": { - "$ref": "AAAAAAFq+kxU7wZ2L08=" - }, - "font": "Arial;13;0", - "left": 405, - "top": 1016, - "width": 119, - "height": 13, - "text": "+next()", - "horizontalAlignment": 0 - }, - { - "_type": "UMLOperationView", - "_id": "AAAAAAFq+kxk6QZ/5+Q=", - "_parent": { - "$ref": "AAAAAAFq+kgd4QWzLA0=" - }, - "model": { - "$ref": "AAAAAAFq+kxkvQZ8bnY=" - }, - "font": "Arial;13;0", - "left": 405, - "top": 1031, - "width": 119, - "height": 13, - "text": "+hasnext()", - "horizontalAlignment": 0 - }, - { - "_type": "UMLOperationView", - "_id": "AAAAAAFq+kxsuAaFeto=", - "_parent": { - "$ref": "AAAAAAFq+kgd4QWzLA0=" - }, - "model": { - "$ref": "AAAAAAFq+kxslAaCsTU=" - }, - "font": "Arial;13;0", - "left": 405, - "top": 1046, - "width": 119, - "height": 13, - "text": "+remove()", - "horizontalAlignment": 0 - } - ], - "font": "Arial;13;0", - "left": 400, - "top": 1011, - "width": 129, - "height": 53 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+kgd4QW0EXs=", - "_parent": { - "$ref": "AAAAAAFq+kgd4QWs9PE=" - }, - "model": { - "$ref": "AAAAAAFq+kgd4QWqy1w=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -64, - "top": -16, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+kgd4QW1zMY=", - "_parent": { - "$ref": "AAAAAAFq+kgd4QWs9PE=" - }, - "model": { - "$ref": "AAAAAAFq+kgd4QWqy1w=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -64, - "top": -16, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 400, - "top": 976, - "width": 129, - "height": 97, - "nameCompartment": { - "$ref": "AAAAAAFq+kgd4QWtlmU=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+kgd4QWy7Jk=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+kgd4QWzLA0=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+kgd4QW0EXs=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+kgd4QW1zMY=" - } - }, - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+kglCgXV6zM=", - "_parent": { - "$ref": "AAAAAAFq+ka2OwVC4TY=" - }, - "model": { - "$ref": "AAAAAAFq+kglCgXT97U=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+kglCgXW/eI=", - "_parent": { - "$ref": "AAAAAAFq+kglCgXV6zM=" - }, - "model": { - "$ref": "AAAAAAFq+kglCgXT97U=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+kglCgXXT5s=", - "_parent": { - "$ref": "AAAAAAFq+kglCgXW/eI=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -144, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+kglCgXYFpk=", - "_parent": { - "$ref": "AAAAAAFq+kglCgXW/eI=" - }, - "font": "Arial;13;1", - "left": 125, - "top": 1159, - "width": 135, - "height": 13, - "text": "ConcreteAggregate" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+kglCgXZz3s=", - "_parent": { - "$ref": "AAAAAAFq+kglCgXW/eI=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -144, - "width": 194.27001953125, - "height": 13, - "text": "(from 行为型模式——迭代器模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+kglCgXaaZk=", - "_parent": { - "$ref": "AAAAAAFq+kglCgXW/eI=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -144, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 120, - "top": 1152, - "width": 145, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+kglCgXXT5s=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+kglCgXYFpk=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+kglCgXZz3s=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+kglCgXaaZk=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+kglCgXb7kQ=", - "_parent": { - "$ref": "AAAAAAFq+kglCgXV6zM=" - }, - "model": { - "$ref": "AAAAAAFq+kglCgXT97U=" - }, - "font": "Arial;13;0", - "left": 120, - "top": 1177, - "width": 145, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+kglCgXcELc=", - "_parent": { - "$ref": "AAAAAAFq+kglCgXV6zM=" - }, - "model": { - "$ref": "AAAAAAFq+kglCgXT97U=" - }, - "subViews": [ - { - "_type": "UMLOperationView", - "_id": "AAAAAAFq+k3mogaVtmc=", - "_parent": { - "$ref": "AAAAAAFq+kglCgXcELc=" - }, - "model": { - "$ref": "AAAAAAFq+k3meQaSK7E=" - }, - "font": "Arial;13;0", - "left": 125, - "top": 1192, - "width": 135, - "height": 13, - "text": "+CreateIterator()", - "horizontalAlignment": 0 - } - ], - "font": "Arial;13;0", - "left": 120, - "top": 1187, - "width": 145, - "height": 23 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+kglCgXdwhY=", - "_parent": { - "$ref": "AAAAAAFq+kglCgXV6zM=" - }, - "model": { - "$ref": "AAAAAAFq+kglCgXT97U=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -72, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+kglCgXexnA=", - "_parent": { - "$ref": "AAAAAAFq+kglCgXV6zM=" - }, - "model": { - "$ref": "AAAAAAFq+kglCgXT97U=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -72, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 120, - "top": 1152, - "width": 145, - "height": 65, - "nameCompartment": { - "$ref": "AAAAAAFq+kglCgXW/eI=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+kglCgXb7kQ=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+kglCgXcELc=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+kglCgXdwhY=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+kglCgXexnA=" - } - }, - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+kgqUAX+zv8=", - "_parent": { - "$ref": "AAAAAAFq+ka2OwVC4TY=" - }, - "model": { - "$ref": "AAAAAAFq+kgqUAX8I70=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+kgqUAX/QOE=", - "_parent": { - "$ref": "AAAAAAFq+kgqUAX+zv8=" - }, - "model": { - "$ref": "AAAAAAFq+kgqUAX8I70=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+kgqUAYAZtk=", - "_parent": { - "$ref": "AAAAAAFq+kgqUAX/QOE=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -240, - "top": -48, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+kgqUAYBSpQ=", - "_parent": { - "$ref": "AAAAAAFq+kgqUAX/QOE=" - }, - "font": "Arial;13;1", - "left": 405, - "top": 1159, - "width": 119, - "height": 13, - "text": "ConcreteIterator" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+kgqUAYC3dE=", - "_parent": { - "$ref": "AAAAAAFq+kgqUAX/QOE=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -240, - "top": -48, - "width": 194.27001953125, - "height": 13, - "text": "(from 行为型模式——迭代器模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+kgqUAYD0mc=", - "_parent": { - "$ref": "AAAAAAFq+kgqUAX/QOE=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -240, - "top": -48, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 400, - "top": 1152, - "width": 129, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+kgqUAYAZtk=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+kgqUAYBSpQ=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+kgqUAYC3dE=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+kgqUAYD0mc=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+kgqUAYEuBA=", - "_parent": { - "$ref": "AAAAAAFq+kgqUAX+zv8=" - }, - "model": { - "$ref": "AAAAAAFq+kgqUAX8I70=" - }, - "font": "Arial;13;0", - "left": 400, - "top": 1177, - "width": 129, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+kgqUAYFnfE=", - "_parent": { - "$ref": "AAAAAAFq+kgqUAX+zv8=" - }, - "model": { - "$ref": "AAAAAAFq+kgqUAX8I70=" - }, - "font": "Arial;13;0", - "left": 400, - "top": 1187, - "width": 129, - "height": 10 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+kgqUAYGZek=", - "_parent": { - "$ref": "AAAAAAFq+kgqUAX+zv8=" - }, - "model": { - "$ref": "AAAAAAFq+kgqUAX8I70=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -120, - "top": -24, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+kgqUAYH4h4=", - "_parent": { - "$ref": "AAAAAAFq+kgqUAX+zv8=" - }, - "model": { - "$ref": "AAAAAAFq+kgqUAX8I70=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -120, - "top": -24, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 400, - "top": 1152, - "width": 129, - "height": 65, - "nameCompartment": { - "$ref": "AAAAAAFq+kgqUAX/QOE=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+kgqUAYEuBA=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+kgqUAYFnfE=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+kgqUAYGZek=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+kgqUAYH4h4=" - } - }, - { - "_type": "UMLGeneralizationView", - "_id": "AAAAAAFq+kmhjwYuAEQ=", - "_parent": { - "$ref": "AAAAAAFq+ka2OwVC4TY=" - }, - "model": { - "$ref": "AAAAAAFq+kmhjwYstd0=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+kmhkAYvkL4=", - "_parent": { - "$ref": "AAAAAAFq+kmhjwYuAEQ=" - }, - "model": { - "$ref": "AAAAAAFq+kmhjwYstd0=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 177, - "top": 1089, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+kmhjwYuAEQ=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+kmhkAYwYq0=", - "_parent": { - "$ref": "AAAAAAFq+kmhjwYuAEQ=" - }, - "model": { - "$ref": "AAAAAAFq+kmhjwYstd0=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 162, - "top": 1089, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+kmhjwYuAEQ=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+kmhkAYxu5o=", - "_parent": { - "$ref": "AAAAAAFq+kmhjwYuAEQ=" - }, - "model": { - "$ref": "AAAAAAFq+kmhjwYstd0=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 206, - "top": 1090, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+kmhjwYuAEQ=" - }, - "edgePosition": 1 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+kgW8wWDC2c=" - }, - "tail": { - "$ref": "AAAAAAFq+kglCgXV6zM=" - }, - "lineStyle": 1, - "points": "192:1151;192:1041", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+kmhkAYvkL4=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+kmhkAYwYq0=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+kmhkAYxu5o=" - } - }, - { - "_type": "UMLGeneralizationView", - "_id": "AAAAAAFq+kmq6wY/1tk=", - "_parent": { - "$ref": "AAAAAAFq+ka2OwVC4TY=" - }, - "model": { - "$ref": "AAAAAAFq+kmq6wY98O4=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+kmq6wZA3SA=", - "_parent": { - "$ref": "AAAAAAFq+kmq6wY/1tk=" - }, - "model": { - "$ref": "AAAAAAFq+kmq6wY98O4=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 449, - "top": 1105, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+kmq6wY/1tk=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+kmq7AZBp4Y=", - "_parent": { - "$ref": "AAAAAAFq+kmq6wY/1tk=" - }, - "model": { - "$ref": "AAAAAAFq+kmq6wY98O4=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 434, - "top": 1105, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+kmq6wY/1tk=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+kmq7AZCUaY=", - "_parent": { - "$ref": "AAAAAAFq+kmq6wY/1tk=" - }, - "model": { - "$ref": "AAAAAAFq+kmq6wY98O4=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 478, - "top": 1106, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+kmq6wY/1tk=" - }, - "edgePosition": 1 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+kgd4QWs9PE=" - }, - "tail": { - "$ref": "AAAAAAFq+kgqUAX+zv8=" - }, - "lineStyle": 1, - "points": "464:1151;464:1073", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+kmq6wZA3SA=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+kmq7AZBp4Y=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+kmq7AZCUaY=" - } - }, - { - "_type": "UMLDependencyView", - "_id": "AAAAAAFq+knOIQZR+fY=", - "_parent": { - "$ref": "AAAAAAFq+ka2OwVC4TY=" - }, - "model": { - "$ref": "AAAAAAFq+knOIQZPaqw=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+knOIQZSxmI=", - "_parent": { - "$ref": "AAAAAAFq+knOIQZR+fY=" - }, - "model": { - "$ref": "AAAAAAFq+knOIQZPaqw=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 332, - "top": 1163, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+knOIQZR+fY=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+knOIQZTOsc=", - "_parent": { - "$ref": "AAAAAAFq+knOIQZR+fY=" - }, - "model": { - "$ref": "AAAAAAFq+knOIQZPaqw=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 332, - "top": 1148, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+knOIQZR+fY=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+knOIQZUn+o=", - "_parent": { - "$ref": "AAAAAAFq+knOIQZR+fY=" - }, - "model": { - "$ref": "AAAAAAFq+knOIQZPaqw=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 332, - "top": 1193, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+knOIQZR+fY=" - }, - "edgePosition": 1 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+kgqUAX+zv8=" - }, - "tail": { - "$ref": "AAAAAAFq+kglCgXV6zM=" - }, - "lineStyle": 1, - "points": "265:1184;399:1184", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+knOIQZSxmI=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+knOIQZTOsc=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+knOIQZUn+o=" - } - } - ] - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+kgW8wWBRfM=", - "_parent": { - "$ref": "AAAAAAFq+ka2OwVBYGY=" - }, - "name": "Aggregate", - "operations": [ - { - "_type": "UMLOperation", - "_id": "AAAAAAFq+k2jVAaL1UY=", - "_parent": { - "$ref": "AAAAAAFq+kgW8wWBRfM=" - }, - "name": "CreateIterator" - } - ] - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+kgd4QWqy1w=", - "_parent": { - "$ref": "AAAAAAFq+ka2OwVBYGY=" - }, - "name": "Iterator", - "operations": [ - { - "_type": "UMLOperation", - "_id": "AAAAAAFq+kxU7wZ2L08=", - "_parent": { - "$ref": "AAAAAAFq+kgd4QWqy1w=" - }, - "name": "next" - }, - { - "_type": "UMLOperation", - "_id": "AAAAAAFq+kxkvQZ8bnY=", - "_parent": { - "$ref": "AAAAAAFq+kgd4QWqy1w=" - }, - "name": "hasnext" - }, - { - "_type": "UMLOperation", - "_id": "AAAAAAFq+kxslAaCsTU=", - "_parent": { - "$ref": "AAAAAAFq+kgd4QWqy1w=" - }, - "name": "remove" - } - ] - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+kglCgXT97U=", - "_parent": { - "$ref": "AAAAAAFq+ka2OwVBYGY=" - }, - "name": "ConcreteAggregate", - "ownedElements": [ - { - "_type": "UMLGeneralization", - "_id": "AAAAAAFq+kmhjwYstd0=", - "_parent": { - "$ref": "AAAAAAFq+kglCgXT97U=" - }, - "source": { - "$ref": "AAAAAAFq+kglCgXT97U=" - }, - "target": { - "$ref": "AAAAAAFq+kgW8wWBRfM=" - } - }, - { - "_type": "UMLDependency", - "_id": "AAAAAAFq+knOIQZPaqw=", - "_parent": { - "$ref": "AAAAAAFq+kglCgXT97U=" - }, - "source": { - "$ref": "AAAAAAFq+kglCgXT97U=" - }, - "target": { - "$ref": "AAAAAAFq+kgqUAX8I70=" - } - } - ], - "operations": [ - { - "_type": "UMLOperation", - "_id": "AAAAAAFq+k3meQaSK7E=", - "_parent": { - "$ref": "AAAAAAFq+kglCgXT97U=" - }, - "name": "CreateIterator" - } - ] - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+kgqUAX8I70=", - "_parent": { - "$ref": "AAAAAAFq+ka2OwVBYGY=" - }, - "name": "ConcreteIterator", - "ownedElements": [ - { - "_type": "UMLGeneralization", - "_id": "AAAAAAFq+kmq6wY98O4=", - "_parent": { - "$ref": "AAAAAAFq+kgqUAX8I70=" - }, - "source": { - "$ref": "AAAAAAFq+kgqUAX8I70=" - }, - "target": { - "$ref": "AAAAAAFq+kgd4QWqy1w=" - } - } - ] - } - ] - }, - { - "_type": "UMLModel", - "_id": "AAAAAAFq+glN5+MWrd8=", - "_parent": { - "$ref": "AAAAAAFF+h6SjaM2Hec=" - }, - "name": "行为型模式——解释器模式", - "ownedElements": [ - { - "_type": "UMLPackage", - "_id": "AAAAAAFq+hU11OrNmn8=", - "_parent": { - "$ref": "AAAAAAFq+glN5+MWrd8=" - }, - "name": "解释器模式", - "ownedElements": [ - { - "_type": "UMLClassDiagram", - "_id": "AAAAAAFq+glN5+MXA1w=", - "_parent": { - "$ref": "AAAAAAFq+hU11OrNmn8=" - }, - "name": "解释器模式", - "ownedViews": [ - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+gm0zeM0/JI=", - "_parent": { - "$ref": "AAAAAAFq+glN5+MXA1w=" - }, - "model": { - "$ref": "AAAAAAFq+gm0zOMywKQ=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+gm0zeM1WiM=", - "_parent": { - "$ref": "AAAAAAFq+gm0zeM0/JI=" - }, - "model": { - "$ref": "AAAAAAFq+gm0zOMywKQ=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+gm0zeM2VHE=", - "_parent": { - "$ref": "AAAAAAFq+gm0zeM1WiM=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -288, - "top": -64, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+gm0zeM33oI=", - "_parent": { - "$ref": "AAAAAAFq+gm0zeM1WiM=" - }, - "font": "Arial;13;1", - "left": 365, - "top": 167, - "width": 103, - "height": 13, - "text": "Context" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+gm0zeM4nP4=", - "_parent": { - "$ref": "AAAAAAFq+gm0zeM1WiM=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -288, - "top": -64, - "width": 194.27001953125, - "height": 13, - "text": "(from 解释器模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+gm0zeM5hYQ=", - "_parent": { - "$ref": "AAAAAAFq+gm0zeM1WiM=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -288, - "top": -64, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 360, - "top": 160, - "width": 113, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+gm0zeM2VHE=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+gm0zeM33oI=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+gm0zeM4nP4=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+gm0zeM5hYQ=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+gm0zeM6LPs=", - "_parent": { - "$ref": "AAAAAAFq+gm0zeM0/JI=" - }, - "model": { - "$ref": "AAAAAAFq+gm0zOMywKQ=" - }, - "font": "Arial;13;0", - "left": 360, - "top": 185, - "width": 113, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+gm0zeM7Fg0=", - "_parent": { - "$ref": "AAAAAAFq+gm0zeM0/JI=" - }, - "model": { - "$ref": "AAAAAAFq+gm0zOMywKQ=" - }, - "font": "Arial;13;0", - "left": 360, - "top": 195, - "width": 113, - "height": 10 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+gm0zeM89bQ=", - "_parent": { - "$ref": "AAAAAAFq+gm0zeM0/JI=" - }, - "model": { - "$ref": "AAAAAAFq+gm0zOMywKQ=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -144, - "top": -32, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+gm0zeM9nNA=", - "_parent": { - "$ref": "AAAAAAFq+gm0zeM0/JI=" - }, - "model": { - "$ref": "AAAAAAFq+gm0zOMywKQ=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -144, - "top": -32, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 360, - "top": 160, - "width": 113, - "height": 65, - "nameCompartment": { - "$ref": "AAAAAAFq+gm0zeM1WiM=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+gm0zeM6LPs=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+gm0zeM7Fg0=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+gm0zeM89bQ=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+gm0zeM9nNA=" - } - }, - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+gm70eNdirY=", - "_parent": { - "$ref": "AAAAAAFq+glN5+MXA1w=" - }, - "model": { - "$ref": "AAAAAAFq+gm70eNbXq8=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+gm70eNekL4=", - "_parent": { - "$ref": "AAAAAAFq+gm70eNdirY=" - }, - "model": { - "$ref": "AAAAAAFq+gm70eNbXq8=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+gm70eNfr4o=", - "_parent": { - "$ref": "AAAAAAFq+gm70eNekL4=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -336, - "top": -96, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+gm70eNg2Xc=", - "_parent": { - "$ref": "AAAAAAFq+gm70eNekL4=" - }, - "font": "Arial;13;1", - "left": 149, - "top": 311, - "width": 87, - "height": 13, - "text": "Client" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+gm70eNh2ic=", - "_parent": { - "$ref": "AAAAAAFq+gm70eNekL4=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -336, - "top": -96, - "width": 194.27001953125, - "height": 13, - "text": "(from 解释器模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+gm70eNiOE8=", - "_parent": { - "$ref": "AAAAAAFq+gm70eNekL4=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -336, - "top": -96, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 144, - "top": 304, - "width": 97, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+gm70eNfr4o=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+gm70eNg2Xc=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+gm70eNh2ic=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+gm70eNiOE8=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+gm70eNjkKI=", - "_parent": { - "$ref": "AAAAAAFq+gm70eNdirY=" - }, - "model": { - "$ref": "AAAAAAFq+gm70eNbXq8=" - }, - "font": "Arial;13;0", - "left": 144, - "top": 329, - "width": 97, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+gm70uNk0yA=", - "_parent": { - "$ref": "AAAAAAFq+gm70eNdirY=" - }, - "model": { - "$ref": "AAAAAAFq+gm70eNbXq8=" - }, - "font": "Arial;13;0", - "left": 144, - "top": 339, - "width": 97, - "height": 10 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+gm70uNlK+8=", - "_parent": { - "$ref": "AAAAAAFq+gm70eNdirY=" - }, - "model": { - "$ref": "AAAAAAFq+gm70eNbXq8=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -168, - "top": -48, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+gm70uNm8Ig=", - "_parent": { - "$ref": "AAAAAAFq+gm70eNdirY=" - }, - "model": { - "$ref": "AAAAAAFq+gm70eNbXq8=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -168, - "top": -48, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 144, - "top": 304, - "width": 97, - "height": 65, - "nameCompartment": { - "$ref": "AAAAAAFq+gm70eNekL4=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+gm70eNjkKI=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+gm70uNk0yA=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+gm70uNlK+8=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+gm70uNm8Ig=" - } - }, - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+gnB0OOGFUE=", - "_parent": { - "$ref": "AAAAAAFq+glN5+MXA1w=" - }, - "model": { - "$ref": "AAAAAAFq+gnB0OOEYNU=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+gnB0OOH+6U=", - "_parent": { - "$ref": "AAAAAAFq+gnB0OOGFUE=" - }, - "model": { - "$ref": "AAAAAAFq+gnB0OOEYNU=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+gnB0OOIHuU=", - "_parent": { - "$ref": "AAAAAAFq+gnB0OOH+6U=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -544, - "top": -176, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+gnB0OOJxL4=", - "_parent": { - "$ref": "AAAAAAFq+gnB0OOH+6U=" - }, - "font": "Arial;13;1", - "left": 357, - "top": 311, - "width": 167, - "height": 13, - "text": "AbstractExpression" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+gnB0OOKjbo=", - "_parent": { - "$ref": "AAAAAAFq+gnB0OOH+6U=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -544, - "top": -176, - "width": 194.27001953125, - "height": 13, - "text": "(from 解释器模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+gnB0OOL6OU=", - "_parent": { - "$ref": "AAAAAAFq+gnB0OOH+6U=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -544, - "top": -176, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 352, - "top": 304, - "width": 177, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+gnB0OOIHuU=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+gnB0OOJxL4=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+gnB0OOKjbo=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+gnB0OOL6OU=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+gnB0OOMbIc=", - "_parent": { - "$ref": "AAAAAAFq+gnB0OOGFUE=" - }, - "model": { - "$ref": "AAAAAAFq+gnB0OOEYNU=" - }, - "font": "Arial;13;0", - "left": 352, - "top": 329, - "width": 177, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+gnB0OON5Jo=", - "_parent": { - "$ref": "AAAAAAFq+gnB0OOGFUE=" - }, - "model": { - "$ref": "AAAAAAFq+gnB0OOEYNU=" - }, - "subViews": [ - { - "_type": "UMLOperationView", - "_id": "AAAAAAFq+gsAJuQdD5I=", - "_parent": { - "$ref": "AAAAAAFq+gnB0OON5Jo=" - }, - "model": { - "$ref": "AAAAAAFq+gr/+OQaCIM=" - }, - "font": "Arial;13;0", - "left": 357, - "top": 344, - "width": 167, - "height": 13, - "text": "+interpret(Context ctx)", - "horizontalAlignment": 0 - } - ], - "font": "Arial;13;0", - "left": 352, - "top": 339, - "width": 177, - "height": 23 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+gnB0OOOHXc=", - "_parent": { - "$ref": "AAAAAAFq+gnB0OOGFUE=" - }, - "model": { - "$ref": "AAAAAAFq+gnB0OOEYNU=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -272, - "top": -88, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+gnB0OOPNtk=", - "_parent": { - "$ref": "AAAAAAFq+gnB0OOGFUE=" - }, - "model": { - "$ref": "AAAAAAFq+gnB0OOEYNU=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -272, - "top": -88, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 352, - "top": 304, - "width": 177, - "height": 65, - "nameCompartment": { - "$ref": "AAAAAAFq+gnB0OOH+6U=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+gnB0OOMbIc=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+gnB0OON5Jo=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+gnB0OOOHXc=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+gnB0OOPNtk=" - } - }, - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+gnH/+Ovotw=", - "_parent": { - "$ref": "AAAAAAFq+glN5+MXA1w=" - }, - "model": { - "$ref": "AAAAAAFq+gnH/+OtIIQ=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+gnH/+Ow0u8=", - "_parent": { - "$ref": "AAAAAAFq+gnH/+Ovotw=" - }, - "model": { - "$ref": "AAAAAAFq+gnH/+OtIIQ=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+gnH/+OxMuI=", - "_parent": { - "$ref": "AAAAAAFq+gnH/+Ow0u8=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -272, - "top": -160, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+gnH/+Oys8U=", - "_parent": { - "$ref": "AAAAAAFq+gnH/+Ow0u8=" - }, - "font": "Arial;13;1", - "left": 181, - "top": 471, - "width": 167, - "height": 13, - "text": "TerminalExpression" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+gnH/+OzeLU=", - "_parent": { - "$ref": "AAAAAAFq+gnH/+Ow0u8=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -272, - "top": -160, - "width": 194.27001953125, - "height": 13, - "text": "(from 解释器模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+gnH/+O01eA=", - "_parent": { - "$ref": "AAAAAAFq+gnH/+Ow0u8=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -272, - "top": -160, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 176, - "top": 464, - "width": 177, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+gnH/+OxMuI=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+gnH/+Oys8U=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+gnH/+OzeLU=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+gnH/+O01eA=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+gnH/+O13+g=", - "_parent": { - "$ref": "AAAAAAFq+gnH/+Ovotw=" - }, - "model": { - "$ref": "AAAAAAFq+gnH/+OtIIQ=" - }, - "font": "Arial;13;0", - "left": 176, - "top": 489, - "width": 177, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+gnH/+O2m1w=", - "_parent": { - "$ref": "AAAAAAFq+gnH/+Ovotw=" - }, - "model": { - "$ref": "AAAAAAFq+gnH/+OtIIQ=" - }, - "subViews": [ - { - "_type": "UMLOperationView", - "_id": "AAAAAAFq+g4G3OQw4DI=", - "_parent": { - "$ref": "AAAAAAFq+gnH/+O2m1w=" - }, - "model": { - "$ref": "AAAAAAFq+g4GuOQtQBQ=" - }, - "font": "Arial;13;0", - "left": 181, - "top": 504, - "width": 167, - "height": 13, - "text": "+interpret(Context ctx)", - "horizontalAlignment": 0 - } - ], - "font": "Arial;13;0", - "left": 176, - "top": 499, - "width": 177, - "height": 23 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+gnH/+O3IYE=", - "_parent": { - "$ref": "AAAAAAFq+gnH/+Ovotw=" - }, - "model": { - "$ref": "AAAAAAFq+gnH/+OtIIQ=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -136, - "top": -80, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+gnH/+O4zec=", - "_parent": { - "$ref": "AAAAAAFq+gnH/+Ovotw=" - }, - "model": { - "$ref": "AAAAAAFq+gnH/+OtIIQ=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -136, - "top": -80, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 176, - "top": 464, - "width": 177, - "height": 65, - "nameCompartment": { - "$ref": "AAAAAAFq+gnH/+Ow0u8=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+gnH/+O13+g=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+gnH/+O2m1w=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+gnH/+O3IYE=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+gnH/+O4zec=" - } - }, - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+gnNJOPYO6I=", - "_parent": { - "$ref": "AAAAAAFq+glN5+MXA1w=" - }, - "model": { - "$ref": "AAAAAAFq+gnNJOPWiBY=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+gnNJOPZj50=", - "_parent": { - "$ref": "AAAAAAFq+gnNJOPYO6I=" - }, - "model": { - "$ref": "AAAAAAFq+gnNJOPWiBY=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+gnNJOPaFWU=", - "_parent": { - "$ref": "AAAAAAFq+gnNJOPZj50=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -336, - "top": -176, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+gnNJOPbfH4=", - "_parent": { - "$ref": "AAAAAAFq+gnNJOPZj50=" - }, - "font": "Arial;13;1", - "left": 501, - "top": 471, - "width": 167, - "height": 13, - "text": "NonterminalExpression" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+gnNJOPc0p4=", - "_parent": { - "$ref": "AAAAAAFq+gnNJOPZj50=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -336, - "top": -176, - "width": 194.27001953125, - "height": 13, - "text": "(from 解释器模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+gnNJOPdc+w=", - "_parent": { - "$ref": "AAAAAAFq+gnNJOPZj50=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -336, - "top": -176, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 496, - "top": 464, - "width": 177, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+gnNJOPaFWU=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+gnNJOPbfH4=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+gnNJOPc0p4=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+gnNJOPdc+w=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+gnNJOPeeAw=", - "_parent": { - "$ref": "AAAAAAFq+gnNJOPYO6I=" - }, - "model": { - "$ref": "AAAAAAFq+gnNJOPWiBY=" - }, - "font": "Arial;13;0", - "left": 496, - "top": 489, - "width": 177, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+gnNJOPfKeE=", - "_parent": { - "$ref": "AAAAAAFq+gnNJOPYO6I=" - }, - "model": { - "$ref": "AAAAAAFq+gnNJOPWiBY=" - }, - "subViews": [ - { - "_type": "UMLOperationView", - "_id": "AAAAAAFq+g7IDeRFKXM=", - "_parent": { - "$ref": "AAAAAAFq+gnNJOPfKeE=" - }, - "model": { - "$ref": "AAAAAAFq+g7H5+RCpA8=" - }, - "font": "Arial;13;0", - "left": 501, - "top": 504, - "width": 167, - "height": 13, - "text": "+interpret(Context ctx)", - "horizontalAlignment": 0 - } - ], - "font": "Arial;13;0", - "left": 496, - "top": 499, - "width": 177, - "height": 23 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+gnNJOPgUUw=", - "_parent": { - "$ref": "AAAAAAFq+gnNJOPYO6I=" - }, - "model": { - "$ref": "AAAAAAFq+gnNJOPWiBY=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -168, - "top": -88, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+gnNJOPhuTk=", - "_parent": { - "$ref": "AAAAAAFq+gnNJOPYO6I=" - }, - "model": { - "$ref": "AAAAAAFq+gnNJOPWiBY=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -168, - "top": -88, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 496, - "top": 464, - "width": 177, - "height": 65, - "nameCompartment": { - "$ref": "AAAAAAFq+gnNJOPZj50=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+gnNJOPeeAw=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+gnNJOPfKeE=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+gnNJOPgUUw=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+gnNJOPhuTk=" - } - }, - { - "_type": "UMLAssociationView", - "_id": "AAAAAAFq+g9xRuRWMuk=", - "_parent": { - "$ref": "AAAAAAFq+glN5+MXA1w=" - }, - "model": { - "$ref": "AAAAAAFq+g9xReRSRpQ=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+g9xRuRXFNA=", - "_parent": { - "$ref": "AAAAAAFq+g9xRuRWMuk=" - }, - "model": { - "$ref": "AAAAAAFq+g9xReRSRpQ=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 192, - "top": 171, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+g9xRuRWMuk=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+g9xRuRYHeA=", - "_parent": { - "$ref": "AAAAAAFq+g9xRuRWMuk=" - }, - "model": { - "$ref": "AAAAAAFq+g9xReRSRpQ=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 192, - "top": 156, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+g9xRuRWMuk=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+g9xRuRZ/So=", - "_parent": { - "$ref": "AAAAAAFq+g9xRuRWMuk=" - }, - "model": { - "$ref": "AAAAAAFq+g9xReRSRpQ=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 192, - "top": 201, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+g9xRuRWMuk=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+g9xRuRaqlY=", - "_parent": { - "$ref": "AAAAAAFq+g9xRuRWMuk=" - }, - "model": { - "$ref": "AAAAAAFq+g9xReRT3Lo=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 177, - "top": 272, - "height": 13, - "alpha": 0.5235987755982988, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+g9xRuRWMuk=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+g9xRuRbaWk=", - "_parent": { - "$ref": "AAAAAAFq+g9xRuRWMuk=" - }, - "model": { - "$ref": "AAAAAAFq+g9xReRT3Lo=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 163, - "top": 269, - "height": 13, - "alpha": 0.7853981633974483, - "distance": 40, - "hostEdge": { - "$ref": "AAAAAAFq+g9xRuRWMuk=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+g9xRuRcSCo=", - "_parent": { - "$ref": "AAAAAAFq+g9xRuRWMuk=" - }, - "model": { - "$ref": "AAAAAAFq+g9xReRT3Lo=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 204, - "top": 276, - "height": 13, - "alpha": -0.5235987755982988, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFq+g9xRuRWMuk=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+g9xRuRdpqE=", - "_parent": { - "$ref": "AAAAAAFq+g9xRuRWMuk=" - }, - "model": { - "$ref": "AAAAAAFq+g9xReRU5fU=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 334, - "top": 171, - "height": 13, - "alpha": -0.5235987755982988, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+g9xRuRWMuk=" - } - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+g9xRuReLxs=", - "_parent": { - "$ref": "AAAAAAFq+g9xRuRWMuk=" - }, - "model": { - "$ref": "AAAAAAFq+g9xReRU5fU=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 331, - "top": 157, - "height": 13, - "alpha": -0.7853981633974483, - "distance": 40, - "hostEdge": { - "$ref": "AAAAAAFq+g9xRuRWMuk=" - } - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+g9xRuRfFhI=", - "_parent": { - "$ref": "AAAAAAFq+g9xRuRWMuk=" - }, - "model": { - "$ref": "AAAAAAFq+g9xReRU5fU=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 338, - "top": 198, - "height": 13, - "alpha": 0.5235987755982988, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFq+g9xRuRWMuk=" - } - }, - { - "_type": "UMLQualifierCompartmentView", - "_id": "AAAAAAFq+g9xRuRgQ7o=", - "_parent": { - "$ref": "AAAAAAFq+g9xRuRWMuk=" - }, - "model": { - "$ref": "AAAAAAFq+g9xReRT3Lo=" - }, - "visible": false, - "font": "Arial;13;0", - "width": 10, - "height": 10 - }, - { - "_type": "UMLQualifierCompartmentView", - "_id": "AAAAAAFq+g9xRuRhpUU=", - "_parent": { - "$ref": "AAAAAAFq+g9xRuRWMuk=" - }, - "model": { - "$ref": "AAAAAAFq+g9xReRU5fU=" - }, - "visible": false, - "font": "Arial;13;0", - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+gm0zeM0/JI=" - }, - "tail": { - "$ref": "AAAAAAFq+gm70eNdirY=" - }, - "points": "192:304;192:192;360:192", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+g9xRuRXFNA=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+g9xRuRYHeA=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+g9xRuRZ/So=" - }, - "tailRoleNameLabel": { - "$ref": "AAAAAAFq+g9xRuRaqlY=" - }, - "tailPropertyLabel": { - "$ref": "AAAAAAFq+g9xRuRbaWk=" - }, - "tailMultiplicityLabel": { - "$ref": "AAAAAAFq+g9xRuRcSCo=" - }, - "headRoleNameLabel": { - "$ref": "AAAAAAFq+g9xRuRdpqE=" - }, - "headPropertyLabel": { - "$ref": "AAAAAAFq+g9xRuReLxs=" - }, - "headMultiplicityLabel": { - "$ref": "AAAAAAFq+g9xRuRfFhI=" - }, - "tailQualifiersCompartment": { - "$ref": "AAAAAAFq+g9xRuRgQ7o=" - }, - "headQualifiersCompartment": { - "$ref": "AAAAAAFq+g9xRuRhpUU=" - } - }, - { - "_type": "UMLAssociationView", - "_id": "AAAAAAFq+hBUdeVyHvA=", - "_parent": { - "$ref": "AAAAAAFq+glN5+MXA1w=" - }, - "model": { - "$ref": "AAAAAAFq+hBUdeVuvjA=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+hBUdeVzumI=", - "_parent": { - "$ref": "AAAAAAFq+hBUdeVyHvA=" - }, - "model": { - "$ref": "AAAAAAFq+hBUdeVuvjA=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 296, - "top": 315, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+hBUdeVyHvA=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+hBUdeV0jBw=", - "_parent": { - "$ref": "AAAAAAFq+hBUdeVyHvA=" - }, - "model": { - "$ref": "AAAAAAFq+hBUdeVuvjA=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 296, - "top": 300, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+hBUdeVyHvA=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+hBUdeV1zCE=", - "_parent": { - "$ref": "AAAAAAFq+hBUdeVyHvA=" - }, - "model": { - "$ref": "AAAAAAFq+hBUdeVuvjA=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 296, - "top": 345, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+hBUdeVyHvA=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+hBUdeV2BpY=", - "_parent": { - "$ref": "AAAAAAFq+hBUdeVyHvA=" - }, - "model": { - "$ref": "AAAAAAFq+hBUdeVvecM=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 266, - "top": 315, - "height": 13, - "alpha": 0.5235987755982988, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+hBUdeVyHvA=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+hBUdeV32Tg=", - "_parent": { - "$ref": "AAAAAAFq+hBUdeVyHvA=" - }, - "model": { - "$ref": "AAAAAAFq+hBUdeVvecM=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 269, - "top": 301, - "height": 13, - "alpha": 0.7853981633974483, - "distance": 40, - "hostEdge": { - "$ref": "AAAAAAFq+hBUdeVyHvA=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+hBUdeV4Jvs=", - "_parent": { - "$ref": "AAAAAAFq+hBUdeVyHvA=" - }, - "model": { - "$ref": "AAAAAAFq+hBUdeVvecM=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 262, - "top": 342, - "height": 13, - "alpha": -0.5235987755982988, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFq+hBUdeVyHvA=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+hBUdeV51yM=", - "_parent": { - "$ref": "AAAAAAFq+hBUdeVyHvA=" - }, - "model": { - "$ref": "AAAAAAFq+hBUdeVwoZQ=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 325, - "top": 315, - "height": 13, - "alpha": -0.5235987755982988, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+hBUdeVyHvA=" - } - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+hBUdeV6jBg=", - "_parent": { - "$ref": "AAAAAAFq+hBUdeVyHvA=" - }, - "model": { - "$ref": "AAAAAAFq+hBUdeVwoZQ=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 322, - "top": 301, - "height": 13, - "alpha": -0.7853981633974483, - "distance": 40, - "hostEdge": { - "$ref": "AAAAAAFq+hBUdeVyHvA=" - } - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+hBUdeV7fS8=", - "_parent": { - "$ref": "AAAAAAFq+hBUdeVyHvA=" - }, - "model": { - "$ref": "AAAAAAFq+hBUdeVwoZQ=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 329, - "top": 342, - "height": 13, - "alpha": 0.5235987755982988, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFq+hBUdeVyHvA=" - } - }, - { - "_type": "UMLQualifierCompartmentView", - "_id": "AAAAAAFq+hBUdeV8bEA=", - "_parent": { - "$ref": "AAAAAAFq+hBUdeVyHvA=" - }, - "model": { - "$ref": "AAAAAAFq+hBUdeVvecM=" - }, - "visible": false, - "font": "Arial;13;0", - "width": 10, - "height": 10 - }, - { - "_type": "UMLQualifierCompartmentView", - "_id": "AAAAAAFq+hBUdeV9h+k=", - "_parent": { - "$ref": "AAAAAAFq+hBUdeVyHvA=" - }, - "model": { - "$ref": "AAAAAAFq+hBUdeVwoZQ=" - }, - "visible": false, - "font": "Arial;13;0", - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+gnB0OOGFUE=" - }, - "tail": { - "$ref": "AAAAAAFq+gm70eNdirY=" - }, - "lineStyle": 1, - "points": "241:336;351:336", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+hBUdeVzumI=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+hBUdeV0jBw=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+hBUdeV1zCE=" - }, - "tailRoleNameLabel": { - "$ref": "AAAAAAFq+hBUdeV2BpY=" - }, - "tailPropertyLabel": { - "$ref": "AAAAAAFq+hBUdeV32Tg=" - }, - "tailMultiplicityLabel": { - "$ref": "AAAAAAFq+hBUdeV4Jvs=" - }, - "headRoleNameLabel": { - "$ref": "AAAAAAFq+hBUdeV51yM=" - }, - "headPropertyLabel": { - "$ref": "AAAAAAFq+hBUdeV6jBg=" - }, - "headMultiplicityLabel": { - "$ref": "AAAAAAFq+hBUdeV7fS8=" - }, - "tailQualifiersCompartment": { - "$ref": "AAAAAAFq+hBUdeV8bEA=" - }, - "headQualifiersCompartment": { - "$ref": "AAAAAAFq+hBUdeV9h+k=" - } - }, - { - "_type": "UMLAssociationView", - "_id": "AAAAAAFq+hCCTeXEV9c=", - "_parent": { - "$ref": "AAAAAAFq+glN5+MXA1w=" - }, - "model": { - "$ref": "AAAAAAFq+hCCTOXAOZM=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+hCCTeXFKSs=", - "_parent": { - "$ref": "AAAAAAFq+hCCTeXEV9c=" - }, - "model": { - "$ref": "AAAAAAFq+hCCTOXAOZM=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 623, - "top": 345, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+hCCTeXEV9c=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+hCCTeXGN9Q=", - "_parent": { - "$ref": "AAAAAAFq+hCCTeXEV9c=" - }, - "model": { - "$ref": "AAAAAAFq+hCCTOXAOZM=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 623, - "top": 360, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+hCCTeXEV9c=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+hCCTeXH7Ss=", - "_parent": { - "$ref": "AAAAAAFq+hCCTeXEV9c=" - }, - "model": { - "$ref": "AAAAAAFq+hCCTOXAOZM=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 624, - "top": 315, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+hCCTeXEV9c=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+hCCTeXIyAw=", - "_parent": { - "$ref": "AAAAAAFq+hCCTeXEV9c=" - }, - "model": { - "$ref": "AAAAAAFq+hCCTOXBUFg=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 609, - "top": 432, - "height": 13, - "alpha": 0.5235987755982988, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+hCCTeXEV9c=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+hCCTeXJuoQ=", - "_parent": { - "$ref": "AAAAAAFq+hCCTeXEV9c=" - }, - "model": { - "$ref": "AAAAAAFq+hCCTOXBUFg=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 595, - "top": 429, - "height": 13, - "alpha": 0.7853981633974483, - "distance": 40, - "hostEdge": { - "$ref": "AAAAAAFq+hCCTeXEV9c=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+hCCTeXKtyw=", - "_parent": { - "$ref": "AAAAAAFq+hCCTeXEV9c=" - }, - "model": { - "$ref": "AAAAAAFq+hCCTOXBUFg=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 636, - "top": 436, - "height": 13, - "alpha": -0.5235987755982988, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFq+hCCTeXEV9c=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+hCCTeXLftY=", - "_parent": { - "$ref": "AAAAAAFq+hCCTeXEV9c=" - }, - "model": { - "$ref": "AAAAAAFq+hCCTOXCB3w=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 553, - "top": 344, - "height": 13, - "alpha": -0.5235987755982988, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+hCCTeXEV9c=" - } - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+hCCTeXMArY=", - "_parent": { - "$ref": "AAAAAAFq+hCCTeXEV9c=" - }, - "model": { - "$ref": "AAAAAAFq+hCCTOXCB3w=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 556, - "top": 358, - "height": 13, - "alpha": -0.7853981633974483, - "distance": 40, - "hostEdge": { - "$ref": "AAAAAAFq+hCCTeXEV9c=" - } - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+hCCTeXNu9E=", - "_parent": { - "$ref": "AAAAAAFq+hCCTeXEV9c=" - }, - "model": { - "$ref": "AAAAAAFq+hCCTOXCB3w=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 549, - "top": 317, - "height": 13, - "alpha": 0.5235987755982988, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFq+hCCTeXEV9c=" - } - }, - { - "_type": "UMLQualifierCompartmentView", - "_id": "AAAAAAFq+hCCTeXOTQg=", - "_parent": { - "$ref": "AAAAAAFq+hCCTeXEV9c=" - }, - "model": { - "$ref": "AAAAAAFq+hCCTOXBUFg=" - }, - "visible": false, - "font": "Arial;13;0", - "width": 10, - "height": 10 - }, - { - "_type": "UMLQualifierCompartmentView", - "_id": "AAAAAAFq+hCCTeXPQYY=", - "_parent": { - "$ref": "AAAAAAFq+hCCTeXEV9c=" - }, - "model": { - "$ref": "AAAAAAFq+hCCTOXCB3w=" - }, - "visible": false, - "font": "Arial;13;0", - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+gnB0OOGFUE=" - }, - "tail": { - "$ref": "AAAAAAFq+gnNJOPYO6I=" - }, - "points": "624:464;624:336;528:336", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+hCCTeXFKSs=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+hCCTeXGN9Q=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+hCCTeXH7Ss=" - }, - "tailRoleNameLabel": { - "$ref": "AAAAAAFq+hCCTeXIyAw=" - }, - "tailPropertyLabel": { - "$ref": "AAAAAAFq+hCCTeXJuoQ=" - }, - "tailMultiplicityLabel": { - "$ref": "AAAAAAFq+hCCTeXKtyw=" - }, - "headRoleNameLabel": { - "$ref": "AAAAAAFq+hCCTeXLftY=" - }, - "headPropertyLabel": { - "$ref": "AAAAAAFq+hCCTeXMArY=" - }, - "headMultiplicityLabel": { - "$ref": "AAAAAAFq+hCCTeXNu9E=" - }, - "tailQualifiersCompartment": { - "$ref": "AAAAAAFq+hCCTeXOTQg=" - }, - "headQualifiersCompartment": { - "$ref": "AAAAAAFq+hCCTeXPQYY=" - } - }, - { - "_type": "UMLGeneralizationView", - "_id": "AAAAAAFq+hFOxOd+yUE=", - "_parent": { - "$ref": "AAAAAAFq+glN5+MXA1w=" - }, - "model": { - "$ref": "AAAAAAFq+hFOxOd8qI8=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+hFOxOd/hO8=", - "_parent": { - "$ref": "AAAAAAFq+hFOxOd+yUE=" - }, - "model": { - "$ref": "AAAAAAFq+hFOxOd8qI8=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 385, - "top": 489, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+hFOxOd+yUE=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+hFOxOeAGcc=", - "_parent": { - "$ref": "AAAAAAFq+hFOxOd+yUE=" - }, - "model": { - "$ref": "AAAAAAFq+hFOxOd8qI8=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 370, - "top": 489, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+hFOxOd+yUE=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+hFOxOeBBec=", - "_parent": { - "$ref": "AAAAAAFq+hFOxOd+yUE=" - }, - "model": { - "$ref": "AAAAAAFq+hFOxOd8qI8=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 415, - "top": 490, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+hFOxOd+yUE=" - }, - "edgePosition": 1 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+gnB0OOGFUE=" - }, - "tail": { - "$ref": "AAAAAAFq+gnH/+Ovotw=" - }, - "points": "352:496;400:496;400:368", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+hFOxOd/hO8=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+hFOxOeAGcc=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+hFOxOeBBec=" - } - }, - { - "_type": "UMLGeneralizationView", - "_id": "AAAAAAFq+hFd8OeqgoI=", - "_parent": { - "$ref": "AAAAAAFq+glN5+MXA1w=" - }, - "model": { - "$ref": "AAAAAAFq+hFd8OeoSJs=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+hFd8OerRyw=", - "_parent": { - "$ref": "AAAAAAFq+hFd8OeqgoI=" - }, - "model": { - "$ref": "AAAAAAFq+hFd8OeoSJs=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 449, - "top": 489, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+hFd8OeqgoI=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+hFd8OesL/Y=", - "_parent": { - "$ref": "AAAAAAFq+hFd8OeqgoI=" - }, - "model": { - "$ref": "AAAAAAFq+hFd8OeoSJs=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 434, - "top": 489, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+hFd8OeqgoI=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+hFd8OetpHY=", - "_parent": { - "$ref": "AAAAAAFq+hFd8OeqgoI=" - }, - "model": { - "$ref": "AAAAAAFq+hFd8OeoSJs=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 479, - "top": 490, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+hFd8OeqgoI=" - }, - "edgePosition": 1 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+gnB0OOGFUE=" - }, - "tail": { - "$ref": "AAAAAAFq+gnNJOPYO6I=" - }, - "points": "496:496;464:496;464:368", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+hFd8OerRyw=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+hFd8OesL/Y=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+hFd8OetpHY=" - } - } - ] - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+gm70eNbXq8=", - "_parent": { - "$ref": "AAAAAAFq+hU11OrNmn8=" - }, - "name": "Client", - "ownedElements": [ - { - "_type": "UMLAssociation", - "_id": "AAAAAAFq+g9xReRSRpQ=", - "_parent": { - "$ref": "AAAAAAFq+gm70eNbXq8=" - }, - "end1": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFq+g9xReRT3Lo=", - "_parent": { - "$ref": "AAAAAAFq+g9xReRSRpQ=" - }, - "reference": { - "$ref": "AAAAAAFq+gm70eNbXq8=" - }, - "navigable": false - }, - "end2": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFq+g9xReRU5fU=", - "_parent": { - "$ref": "AAAAAAFq+g9xReRSRpQ=" - }, - "reference": { - "$ref": "AAAAAAFq+gm0zOMywKQ=" - } - } - }, - { - "_type": "UMLAssociation", - "_id": "AAAAAAFq+hBUdeVuvjA=", - "_parent": { - "$ref": "AAAAAAFq+gm70eNbXq8=" - }, - "end1": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFq+hBUdeVvecM=", - "_parent": { - "$ref": "AAAAAAFq+hBUdeVuvjA=" - }, - "reference": { - "$ref": "AAAAAAFq+gm70eNbXq8=" - }, - "navigable": false - }, - "end2": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFq+hBUdeVwoZQ=", - "_parent": { - "$ref": "AAAAAAFq+hBUdeVuvjA=" - }, - "reference": { - "$ref": "AAAAAAFq+gnB0OOEYNU=" - } - } - } - ] - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+gnB0OOEYNU=", - "_parent": { - "$ref": "AAAAAAFq+hU11OrNmn8=" - }, - "name": "AbstractExpression", - "operations": [ - { - "_type": "UMLOperation", - "_id": "AAAAAAFq+gr/+OQaCIM=", - "_parent": { - "$ref": "AAAAAAFq+gnB0OOEYNU=" - }, - "name": "interpret", - "parameters": [ - { - "_type": "UMLParameter", - "_id": "AAAAAAFq+g1wjOQnBz4=", - "_parent": { - "$ref": "AAAAAAFq+gr/+OQaCIM=" - }, - "name": "Context ctx" - } - ] - } - ] - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+gnH/+OtIIQ=", - "_parent": { - "$ref": "AAAAAAFq+hU11OrNmn8=" - }, - "name": "TerminalExpression", - "ownedElements": [ - { - "_type": "UMLGeneralization", - "_id": "AAAAAAFq+hFOxOd8qI8=", - "_parent": { - "$ref": "AAAAAAFq+gnH/+OtIIQ=" - }, - "source": { - "$ref": "AAAAAAFq+gnH/+OtIIQ=" - }, - "target": { - "$ref": "AAAAAAFq+gnB0OOEYNU=" - } - } - ], - "operations": [ - { - "_type": "UMLOperation", - "_id": "AAAAAAFq+g4GuOQtQBQ=", - "_parent": { - "$ref": "AAAAAAFq+gnH/+OtIIQ=" - }, - "name": "interpret", - "parameters": [ - { - "_type": "UMLParameter", - "_id": "AAAAAAFq+g4+DeQ0ask=", - "_parent": { - "$ref": "AAAAAAFq+g4GuOQtQBQ=" - }, - "name": "Context ctx" - } - ] - } - ] - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+gnNJOPWiBY=", - "_parent": { - "$ref": "AAAAAAFq+hU11OrNmn8=" - }, - "name": "NonterminalExpression", - "ownedElements": [ - { - "_type": "UMLAssociation", - "_id": "AAAAAAFq+hCCTOXAOZM=", - "_parent": { - "$ref": "AAAAAAFq+gnNJOPWiBY=" - }, - "end1": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFq+hCCTOXBUFg=", - "_parent": { - "$ref": "AAAAAAFq+hCCTOXAOZM=" - }, - "reference": { - "$ref": "AAAAAAFq+gnNJOPWiBY=" - }, - "navigable": false, - "aggregation": "shared" - }, - "end2": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFq+hCCTOXCB3w=", - "_parent": { - "$ref": "AAAAAAFq+hCCTOXAOZM=" - }, - "reference": { - "$ref": "AAAAAAFq+gnB0OOEYNU=" - } - } - }, - { - "_type": "UMLGeneralization", - "_id": "AAAAAAFq+hFd8OeoSJs=", - "_parent": { - "$ref": "AAAAAAFq+gnNJOPWiBY=" - }, - "source": { - "$ref": "AAAAAAFq+gnNJOPWiBY=" - }, - "target": { - "$ref": "AAAAAAFq+gnB0OOEYNU=" - } - } - ], - "operations": [ - { - "_type": "UMLOperation", - "_id": "AAAAAAFq+g7H5+RCpA8=", - "_parent": { - "$ref": "AAAAAAFq+gnNJOPWiBY=" - }, - "name": "interpret", - "parameters": [ - { - "_type": "UMLParameter", - "_id": "AAAAAAFq+g8ok+RLnP4=", - "_parent": { - "$ref": "AAAAAAFq+g7H5+RCpA8=" - }, - "name": "Context ctx" - } - ] - } - ] - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+gm0zOMywKQ=", - "_parent": { - "$ref": "AAAAAAFq+hU11OrNmn8=" - }, - "name": "Context" - } - ] - }, - { - "_type": "UMLPackage", - "_id": "AAAAAAFq+hXmI+uZVMA=", - "_parent": { - "$ref": "AAAAAAFq+glN5+MWrd8=" - }, - "name": "模式实例", - "ownedElements": [ - { - "_type": "UMLClassDiagram", - "_id": "AAAAAAFq+hK5NuleC6k=", - "_parent": { - "$ref": "AAAAAAFq+hXmI+uZVMA=" - }, - "name": "模式实例", - "ownedViews": [ - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+hY+2Oug9xU=", - "_parent": { - "$ref": "AAAAAAFq+hK5NuleC6k=" - }, - "model": { - "$ref": "AAAAAAFq+hY+1+ueQ9g=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+hY+2OuhEU8=", - "_parent": { - "$ref": "AAAAAAFq+hY+2Oug9xU=" - }, - "model": { - "$ref": "AAAAAAFq+hY+1+ueQ9g=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+hY+2OuiET4=", - "_parent": { - "$ref": "AAAAAAFq+hY+2OuhEU8=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -176, - "top": 48, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+hY+2Oujex8=", - "_parent": { - "$ref": "AAAAAAFq+hY+2OuhEU8=" - }, - "font": "Arial;13;1", - "left": 85, - "top": 167, - "width": 55, - "height": 13, - "text": "Client" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+hY+2Ouk62Q=", - "_parent": { - "$ref": "AAAAAAFq+hY+2OuhEU8=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -176, - "top": 48, - "width": 90.27001953125, - "height": 13, - "text": "(from 模式实例)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+hY+2OulgqY=", - "_parent": { - "$ref": "AAAAAAFq+hY+2OuhEU8=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -176, - "top": 48, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 80, - "top": 160, - "width": 65, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+hY+2OuiET4=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+hY+2Oujex8=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+hY+2Ouk62Q=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+hY+2OulgqY=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+hY+2OumvuQ=", - "_parent": { - "$ref": "AAAAAAFq+hY+2Oug9xU=" - }, - "model": { - "$ref": "AAAAAAFq+hY+1+ueQ9g=" - }, - "font": "Arial;13;0", - "left": 80, - "top": 185, - "width": 65, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+hY+2OunnGg=", - "_parent": { - "$ref": "AAAAAAFq+hY+2Oug9xU=" - }, - "model": { - "$ref": "AAAAAAFq+hY+1+ueQ9g=" - }, - "font": "Arial;13;0", - "left": 80, - "top": 195, - "width": 65, - "height": 10 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+hY+2OuoaaA=", - "_parent": { - "$ref": "AAAAAAFq+hY+2Oug9xU=" - }, - "model": { - "$ref": "AAAAAAFq+hY+1+ueQ9g=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -88, - "top": 24, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+hY+2Oupcgw=", - "_parent": { - "$ref": "AAAAAAFq+hY+2Oug9xU=" - }, - "model": { - "$ref": "AAAAAAFq+hY+1+ueQ9g=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -88, - "top": 24, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 80, - "top": 160, - "width": 65, - "height": 49, - "nameCompartment": { - "$ref": "AAAAAAFq+hY+2OuhEU8=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+hY+2OumvuQ=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+hY+2OunnGg=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+hY+2OuoaaA=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+hY+2Oupcgw=" - } - }, - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+hZD5uvJA54=", - "_parent": { - "$ref": "AAAAAAFq+hK5NuleC6k=" - }, - "model": { - "$ref": "AAAAAAFq+hZD5uvHBkQ=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+hZD5uvKAF0=", - "_parent": { - "$ref": "AAAAAAFq+hZD5uvJA54=" - }, - "model": { - "$ref": "AAAAAAFq+hZD5uvHBkQ=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+hZD5uvLoag=", - "_parent": { - "$ref": "AAAAAAFq+hZD5uvKAF0=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -240, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+hZD5uvM91I=", - "_parent": { - "$ref": "AAAAAAFq+hZD5uvKAF0=" - }, - "font": "Arial;13;1", - "left": 53, - "top": 279, - "width": 167, - "height": 13, - "text": "Calculator" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+hZD5uvNdw0=", - "_parent": { - "$ref": "AAAAAAFq+hZD5uvKAF0=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -240, - "width": 90.27001953125, - "height": 13, - "text": "(from 模式实例)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+hZD5uvOgt0=", - "_parent": { - "$ref": "AAAAAAFq+hZD5uvKAF0=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -240, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 48, - "top": 272, - "width": 177, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+hZD5uvLoag=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+hZD5uvM91I=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+hZD5uvNdw0=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+hZD5uvOgt0=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+hZD5uvPbGI=", - "_parent": { - "$ref": "AAAAAAFq+hZD5uvJA54=" - }, - "model": { - "$ref": "AAAAAAFq+hZD5uvHBkQ=" - }, - "subViews": [ - { - "_type": "UMLAttributeView", - "_id": "AAAAAAFq+hdpMezxW0o=", - "_parent": { - "$ref": "AAAAAAFq+hZD5uvPbGI=" - }, - "model": { - "$ref": "AAAAAAFq+hdpDOzuGsM=" - }, - "font": "Arial;13;0", - "left": 53, - "top": 302, - "width": 167, - "height": 13, - "text": "+statement: String", - "horizontalAlignment": 0 - }, - { - "_type": "UMLAttributeView", - "_id": "AAAAAAFq+hf/oO0C1j8=", - "_parent": { - "$ref": "AAAAAAFq+hZD5uvPbGI=" - }, - "model": { - "$ref": "AAAAAAFq+hf/fez/Bt8=" - }, - "font": "Arial;13;0", - "left": 53, - "top": 317, - "width": 167, - "height": 13, - "text": "+node: Node", - "horizontalAlignment": 0 - } - ], - "font": "Arial;13;0", - "left": 48, - "top": 297, - "width": 177, - "height": 38 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+hZD5uvQobw=", - "_parent": { - "$ref": "AAAAAAFq+hZD5uvJA54=" - }, - "model": { - "$ref": "AAAAAAFq+hZD5uvHBkQ=" - }, - "subViews": [ - { - "_type": "UMLOperationView", - "_id": "AAAAAAFq+hgy7u0J1I0=", - "_parent": { - "$ref": "AAAAAAFq+hZD5uvQobw=" - }, - "model": { - "$ref": "AAAAAAFq+hgyw+0Gh2w=" - }, - "font": "Arial;13;0", - "left": 53, - "top": 340, - "width": 167, - "height": 13, - "text": "+build(String statement)", - "horizontalAlignment": 0 - }, - { - "_type": "UMLOperationView", - "_id": "AAAAAAFq+hi5iu0U5m0=", - "_parent": { - "$ref": "AAAAAAFq+hZD5uvQobw=" - }, - "model": { - "$ref": "AAAAAAFq+hi5ZO0Rr7s=" - }, - "font": "Arial;13;0", - "left": 53, - "top": 355, - "width": 167, - "height": 13, - "text": "+compute()", - "horizontalAlignment": 0 - } - ], - "font": "Arial;13;0", - "left": 48, - "top": 335, - "width": 177, - "height": 38 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+hZD5uvR9yg=", - "_parent": { - "$ref": "AAAAAAFq+hZD5uvJA54=" - }, - "model": { - "$ref": "AAAAAAFq+hZD5uvHBkQ=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -120, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+hZD5uvSv18=", - "_parent": { - "$ref": "AAAAAAFq+hZD5uvJA54=" - }, - "model": { - "$ref": "AAAAAAFq+hZD5uvHBkQ=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -120, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 48, - "top": 272, - "width": 177, - "height": 113, - "nameCompartment": { - "$ref": "AAAAAAFq+hZD5uvKAF0=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+hZD5uvPbGI=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+hZD5uvQobw=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+hZD5uvR9yg=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+hZD5uvSv18=" - } - }, - { - "_type": "UMLInterfaceView", - "_id": "AAAAAAFq+hZJlOvyDUI=", - "_parent": { - "$ref": "AAAAAAFq+hK5NuleC6k=" - }, - "model": { - "$ref": "AAAAAAFq+hZJlOvwQWI=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+hZJlOvzUOk=", - "_parent": { - "$ref": "AAAAAAFq+hZJlOvyDUI=" - }, - "model": { - "$ref": "AAAAAAFq+hZJlOvwQWI=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+hZJlOv0MI4=", - "_parent": { - "$ref": "AAAAAAFq+hZJlOvzUOk=" - }, - "font": "Arial;13;0", - "left": 325, - "top": 293, - "width": 119, - "height": 13, - "text": "«interface»" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+hZJlOv112Y=", - "_parent": { - "$ref": "AAAAAAFq+hZJlOvzUOk=" - }, - "font": "Arial;13;1", - "left": 325, - "top": 308, - "width": 119, - "height": 13, - "text": "Node" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+hZJlOv2VpQ=", - "_parent": { - "$ref": "AAAAAAFq+hZJlOvzUOk=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -208, - "top": 48, - "width": 90.27001953125, - "height": 13, - "text": "(from 模式实例)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+hZJlOv3ec8=", - "_parent": { - "$ref": "AAAAAAFq+hZJlOvzUOk=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -208, - "top": 48, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 320, - "top": 288, - "width": 129, - "height": 38, - "stereotypeLabel": { - "$ref": "AAAAAAFq+hZJlOv0MI4=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+hZJlOv112Y=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+hZJlOv2VpQ=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+hZJlOv3ec8=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+hZJlOv4UlU=", - "_parent": { - "$ref": "AAAAAAFq+hZJlOvyDUI=" - }, - "model": { - "$ref": "AAAAAAFq+hZJlOvwQWI=" - }, - "font": "Arial;13;0", - "left": 320, - "top": 326, - "width": 129, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+hZJlOv5VS8=", - "_parent": { - "$ref": "AAAAAAFq+hZJlOvyDUI=" - }, - "model": { - "$ref": "AAAAAAFq+hZJlOvwQWI=" - }, - "subViews": [ - { - "_type": "UMLOperationView", - "_id": "AAAAAAFq+hjuSe0bygM=", - "_parent": { - "$ref": "AAAAAAFq+hZJlOv5VS8=" - }, - "model": { - "$ref": "AAAAAAFq+hjuJO0YwSo=" - }, - "font": "Arial;13;0", - "left": 325, - "top": 341, - "width": 119, - "height": 13, - "text": "+Interpret()", - "horizontalAlignment": 0 - } - ], - "font": "Arial;13;0", - "left": 320, - "top": 336, - "width": 129, - "height": 23 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+hZJlOv6swg=", - "_parent": { - "$ref": "AAAAAAFq+hZJlOvyDUI=" - }, - "model": { - "$ref": "AAAAAAFq+hZJlOvwQWI=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -104, - "top": 24, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+hZJlOv7n4U=", - "_parent": { - "$ref": "AAAAAAFq+hZJlOvyDUI=" - }, - "model": { - "$ref": "AAAAAAFq+hZJlOvwQWI=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -104, - "top": 24, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 320, - "top": 288, - "width": 129, - "height": 81, - "nameCompartment": { - "$ref": "AAAAAAFq+hZJlOvzUOk=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+hZJlOv4UlU=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+hZJlOv5VS8=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+hZJlOv6swg=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+hZJlOv7n4U=" - } - }, - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+hZWoewbeIE=", - "_parent": { - "$ref": "AAAAAAFq+hK5NuleC6k=" - }, - "model": { - "$ref": "AAAAAAFq+hZWoewZKZY=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+hZWoewczSo=", - "_parent": { - "$ref": "AAAAAAFq+hZWoewbeIE=" - }, - "model": { - "$ref": "AAAAAAFq+hZWoewZKZY=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+hZWoewdeG8=", - "_parent": { - "$ref": "AAAAAAFq+hZWoewczSo=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -144, - "top": -32, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+hZWoewebkc=", - "_parent": { - "$ref": "AAAAAAFq+hZWoewczSo=" - }, - "font": "Arial;13;1", - "left": 165, - "top": 455, - "width": 119, - "height": 13, - "text": "ValueNode" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+hZWoewfHew=", - "_parent": { - "$ref": "AAAAAAFq+hZWoewczSo=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -144, - "top": -32, - "width": 90.27001953125, - "height": 13, - "text": "(from 模式实例)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+hZWoewgLAs=", - "_parent": { - "$ref": "AAAAAAFq+hZWoewczSo=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -144, - "top": -32, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 160, - "top": 448, - "width": 129, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+hZWoewdeG8=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+hZWoewebkc=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+hZWoewfHew=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+hZWoewgLAs=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+hZWoewhmK0=", - "_parent": { - "$ref": "AAAAAAFq+hZWoewbeIE=" - }, - "model": { - "$ref": "AAAAAAFq+hZWoewZKZY=" - }, - "font": "Arial;13;0", - "left": 160, - "top": 473, - "width": 129, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+hZWoewiIHA=", - "_parent": { - "$ref": "AAAAAAFq+hZWoewbeIE=" - }, - "model": { - "$ref": "AAAAAAFq+hZWoewZKZY=" - }, - "subViews": [ - { - "_type": "UMLOperationView", - "_id": "AAAAAAFq+hm+fO0k6r8=", - "_parent": { - "$ref": "AAAAAAFq+hZWoewiIHA=" - }, - "model": { - "$ref": "AAAAAAFq+hm+WO0hm2k=" - }, - "font": "Arial;13;0", - "left": 165, - "top": 488, - "width": 119, - "height": 13, - "text": "+Interpret()", - "horizontalAlignment": 0 - } - ], - "font": "Arial;13;0", - "left": 160, - "top": 483, - "width": 129, - "height": 23 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+hZWoewj5lM=", - "_parent": { - "$ref": "AAAAAAFq+hZWoewbeIE=" - }, - "model": { - "$ref": "AAAAAAFq+hZWoewZKZY=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -72, - "top": -16, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+hZWoewkM6E=", - "_parent": { - "$ref": "AAAAAAFq+hZWoewbeIE=" - }, - "model": { - "$ref": "AAAAAAFq+hZWoewZKZY=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -72, - "top": -16, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 160, - "top": 448, - "width": 129, - "height": 73, - "nameCompartment": { - "$ref": "AAAAAAFq+hZWoewczSo=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+hZWoewhmK0=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+hZWoewiIHA=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+hZWoewj5lM=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+hZWoewkM6E=" - } - }, - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+hZfHOxE23w=", - "_parent": { - "$ref": "AAAAAAFq+hK5NuleC6k=" - }, - "model": { - "$ref": "AAAAAAFq+hZfGuxC3lc=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+hZfHOxFA8w=", - "_parent": { - "$ref": "AAAAAAFq+hZfHOxE23w=" - }, - "model": { - "$ref": "AAAAAAFq+hZfGuxC3lc=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+hZfHOxGWvs=", - "_parent": { - "$ref": "AAAAAAFq+hZfHOxFA8w=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -80, - "top": -32, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+hZfHOxHvm0=", - "_parent": { - "$ref": "AAAAAAFq+hZfHOxFA8w=" - }, - "font": "Arial;13;1", - "left": 421, - "top": 455, - "width": 223, - "height": 13, - "text": "SymboINode" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+hZfHOxItJA=", - "_parent": { - "$ref": "AAAAAAFq+hZfHOxFA8w=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -80, - "top": -32, - "width": 90.27001953125, - "height": 13, - "text": "(from 模式实例)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+hZfHOxJ2A4=", - "_parent": { - "$ref": "AAAAAAFq+hZfHOxFA8w=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -80, - "top": -32, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 416, - "top": 448, - "width": 233, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+hZfHOxGWvs=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+hZfHOxHvm0=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+hZfHOxItJA=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+hZfHOxJ2A4=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+hZfHOxKZaE=", - "_parent": { - "$ref": "AAAAAAFq+hZfHOxE23w=" - }, - "model": { - "$ref": "AAAAAAFq+hZfGuxC3lc=" - }, - "subViews": [ - { - "_type": "UMLAttributeView", - "_id": "AAAAAAFq+hop7e0yicE=", - "_parent": { - "$ref": "AAAAAAFq+hZfHOxKZaE=" - }, - "model": { - "$ref": "AAAAAAFq+hopv+0vXRg=" - }, - "font": "Arial;13;0", - "left": 421, - "top": 478, - "width": 223, - "height": 13, - "text": "+left: Node", - "horizontalAlignment": 0 - }, - { - "_type": "UMLAttributeView", - "_id": "AAAAAAFq+ho3s+04D1g=", - "_parent": { - "$ref": "AAAAAAFq+hZfHOxKZaE=" - }, - "model": { - "$ref": "AAAAAAFq+ho3kO016Js=" - }, - "font": "Arial;13;0", - "left": 421, - "top": 493, - "width": 223, - "height": 13, - "text": "+right: Node", - "horizontalAlignment": 0 - } - ], - "font": "Arial;13;0", - "left": 416, - "top": 473, - "width": 233, - "height": 38 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+hZfHOxLSZs=", - "_parent": { - "$ref": "AAAAAAFq+hZfHOxE23w=" - }, - "model": { - "$ref": "AAAAAAFq+hZfGuxC3lc=" - }, - "subViews": [ - { - "_type": "UMLOperationView", - "_id": "AAAAAAFq+hniKO0r8Tc=", - "_parent": { - "$ref": "AAAAAAFq+hZfHOxLSZs=" - }, - "model": { - "$ref": "AAAAAAFq+hniBe0oWIE=" - }, - "font": "Arial;13;0", - "left": 421, - "top": 516, - "width": 223, - "height": 13, - "text": "+SymboINode(Node left, Node right)", - "horizontalAlignment": 0 - } - ], - "font": "Arial;13;0", - "left": 416, - "top": 511, - "width": 233, - "height": 23 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+hZfHOxM6Rg=", - "_parent": { - "$ref": "AAAAAAFq+hZfHOxE23w=" - }, - "model": { - "$ref": "AAAAAAFq+hZfGuxC3lc=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -40, - "top": -16, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+hZfHOxNqUc=", - "_parent": { - "$ref": "AAAAAAFq+hZfHOxE23w=" - }, - "model": { - "$ref": "AAAAAAFq+hZfGuxC3lc=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -40, - "top": -16, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 416, - "top": 448, - "width": 233, - "height": 97, - "nameCompartment": { - "$ref": "AAAAAAFq+hZfHOxFA8w=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+hZfHOxKZaE=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+hZfHOxLSZs=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+hZfHOxM6Rg=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+hZfHOxNqUc=" - } - }, - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+hZnXuxtU4s=", - "_parent": { - "$ref": "AAAAAAFq+hK5NuleC6k=" - }, - "model": { - "$ref": "AAAAAAFq+hZnXexrkkc=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+hZnXuxufm8=", - "_parent": { - "$ref": "AAAAAAFq+hZnXuxtU4s=" - }, - "model": { - "$ref": "AAAAAAFq+hZnXexrkkc=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+hZnXuxvI9E=", - "_parent": { - "$ref": "AAAAAAFq+hZnXuxufm8=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -544, - "top": -16, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+hZnXuxwHIc=", - "_parent": { - "$ref": "AAAAAAFq+hZnXuxufm8=" - }, - "font": "Arial;13;1", - "left": 125, - "top": 599, - "width": 187.509765625, - "height": 13, - "text": "MulNode" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+hZnXuxx+rM=", - "_parent": { - "$ref": "AAAAAAFq+hZnXuxufm8=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -544, - "top": -16, - "width": 90.27001953125, - "height": 13, - "text": "(from 模式实例)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+hZnXuxyR7k=", - "_parent": { - "$ref": "AAAAAAFq+hZnXuxufm8=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -544, - "top": -16, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 120, - "top": 592, - "width": 197.509765625, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+hZnXuxvI9E=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+hZnXuxwHIc=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+hZnXuxx+rM=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+hZnXuxyR7k=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+hZnXuxz26I=", - "_parent": { - "$ref": "AAAAAAFq+hZnXuxtU4s=" - }, - "model": { - "$ref": "AAAAAAFq+hZnXexrkkc=" - }, - "font": "Arial;13;0", - "left": 120, - "top": 617, - "width": 197.509765625, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+hZnXux0G+s=", - "_parent": { - "$ref": "AAAAAAFq+hZnXuxtU4s=" - }, - "model": { - "$ref": "AAAAAAFq+hZnXexrkkc=" - }, - "subViews": [ - { - "_type": "UMLOperationView", - "_id": "AAAAAAFq+iCb9+1yc10=", - "_parent": { - "$ref": "AAAAAAFq+hZnXux0G+s=" - }, - "model": { - "$ref": "AAAAAAFq+iCby+1vc7U=" - }, - "font": "Arial;13;0", - "left": 125, - "top": 632, - "width": 187.509765625, - "height": 13, - "text": "+MulNode(Node left, Node right)", - "horizontalAlignment": 0 - }, - { - "_type": "UMLOperationView", - "_id": "AAAAAAFq+iEqYu1/Xps=", - "_parent": { - "$ref": "AAAAAAFq+hZnXux0G+s=" - }, - "model": { - "$ref": "AAAAAAFq+iEqPO18Y4A=" - }, - "font": "Arial;13;0", - "left": 125, - "top": 647, - "width": 187.509765625, - "height": 13, - "text": "+interpret()", - "horizontalAlignment": 0 - } - ], - "font": "Arial;13;0", - "left": 120, - "top": 627, - "width": 197.509765625, - "height": 38 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+hZnXux1BAY=", - "_parent": { - "$ref": "AAAAAAFq+hZnXuxtU4s=" - }, - "model": { - "$ref": "AAAAAAFq+hZnXexrkkc=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -272, - "top": -8, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+hZnXux2b3Y=", - "_parent": { - "$ref": "AAAAAAFq+hZnXuxtU4s=" - }, - "model": { - "$ref": "AAAAAAFq+hZnXexrkkc=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -272, - "top": -8, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 120, - "top": 592, - "width": 197.509765625, - "height": 73, - "nameCompartment": { - "$ref": "AAAAAAFq+hZnXuxufm8=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+hZnXuxz26I=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+hZnXux0G+s=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+hZnXux1BAY=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+hZnXux2b3Y=" - } - }, - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+hZtVOyWEbs=", - "_parent": { - "$ref": "AAAAAAFq+hK5NuleC6k=" - }, - "model": { - "$ref": "AAAAAAFq+hZtVOyUoVQ=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+hZtVOyX5sQ=", - "_parent": { - "$ref": "AAAAAAFq+hZtVOyWEbs=" - }, - "model": { - "$ref": "AAAAAAFq+hZtVOyUoVQ=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+hZtVOyYlRw=", - "_parent": { - "$ref": "AAAAAAFq+hZtVOyX5sQ=" - }, - "visible": false, - "font": "Arial;13;0", - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+hZtVOyZ47g=", - "_parent": { - "$ref": "AAAAAAFq+hZtVOyX5sQ=" - }, - "font": "Arial;13;1", - "left": 613, - "top": 631, - "width": 187.509765625, - "height": 13, - "text": "ModNode" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+hZtVOyasNo=", - "_parent": { - "$ref": "AAAAAAFq+hZtVOyX5sQ=" - }, - "visible": false, - "font": "Arial;13;0", - "width": 90.27001953125, - "height": 13, - "text": "(from 模式实例)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+hZtVOybYpU=", - "_parent": { - "$ref": "AAAAAAFq+hZtVOyX5sQ=" - }, - "visible": false, - "font": "Arial;13;0", - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 608, - "top": 624, - "width": 197.509765625, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+hZtVOyYlRw=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+hZtVOyZ47g=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+hZtVOyasNo=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+hZtVOybYpU=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+hZtVOycZ78=", - "_parent": { - "$ref": "AAAAAAFq+hZtVOyWEbs=" - }, - "model": { - "$ref": "AAAAAAFq+hZtVOyUoVQ=" - }, - "font": "Arial;13;0", - "left": 608, - "top": 649, - "width": 197.509765625, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+hZtVOydGG4=", - "_parent": { - "$ref": "AAAAAAFq+hZtVOyWEbs=" - }, - "model": { - "$ref": "AAAAAAFq+hZtVOyUoVQ=" - }, - "subViews": [ - { - "_type": "UMLOperationView", - "_id": "AAAAAAFq+iG7VO2ItDE=", - "_parent": { - "$ref": "AAAAAAFq+hZtVOydGG4=" - }, - "model": { - "$ref": "AAAAAAFq+iG7L+2FZHw=" - }, - "font": "Arial;13;0", - "left": 613, - "top": 664, - "width": 187.509765625, - "height": 13, - "text": "+MulNode(Node left, Node right)", - "horizontalAlignment": 0 - }, - { - "_type": "UMLOperationView", - "_id": "AAAAAAFq+iIlsu2VWBM=", - "_parent": { - "$ref": "AAAAAAFq+hZtVOydGG4=" - }, - "model": { - "$ref": "AAAAAAFq+iIlju2S/ec=" - }, - "font": "Arial;13;0", - "left": 613, - "top": 679, - "width": 187.509765625, - "height": 13, - "text": "+interpret()", - "horizontalAlignment": 0 - } - ], - "font": "Arial;13;0", - "left": 608, - "top": 659, - "width": 197.509765625, - "height": 38 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+hZtVOye72g=", - "_parent": { - "$ref": "AAAAAAFq+hZtVOyWEbs=" - }, - "model": { - "$ref": "AAAAAAFq+hZtVOyUoVQ=" - }, - "visible": false, - "font": "Arial;13;0", - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+hZtVOyfYmI=", - "_parent": { - "$ref": "AAAAAAFq+hZtVOyWEbs=" - }, - "model": { - "$ref": "AAAAAAFq+hZtVOyUoVQ=" - }, - "visible": false, - "font": "Arial;13;0", - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 608, - "top": 624, - "width": 197.509765625, - "height": 73, - "nameCompartment": { - "$ref": "AAAAAAFq+hZtVOyX5sQ=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+hZtVOycZ78=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+hZtVOydGG4=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+hZtVOye72g=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+hZtVOyfYmI=" - } - }, - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+hZ1lOy/30o=", - "_parent": { - "$ref": "AAAAAAFq+hK5NuleC6k=" - }, - "model": { - "$ref": "AAAAAAFq+hZ1k+y9HK8=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+hZ1lOzAxaU=", - "_parent": { - "$ref": "AAAAAAFq+hZ1lOy/30o=" - }, - "model": { - "$ref": "AAAAAAFq+hZ1k+y9HK8=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+hZ1lOzBQ/0=", - "_parent": { - "$ref": "AAAAAAFq+hZ1lOzAxaU=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -128, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+hZ1lOzCNk4=", - "_parent": { - "$ref": "AAAAAAFq+hZ1lOzAxaU=" - }, - "font": "Arial;13;1", - "left": 437, - "top": 727, - "width": 185.3388671875, - "height": 13, - "text": "DivNode" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+hZ1lOzDM5U=", - "_parent": { - "$ref": "AAAAAAFq+hZ1lOzAxaU=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -128, - "width": 90.27001953125, - "height": 13, - "text": "(from 模式实例)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+hZ1lOzEzGo=", - "_parent": { - "$ref": "AAAAAAFq+hZ1lOzAxaU=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -128, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 432, - "top": 720, - "width": 195.3388671875, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+hZ1lOzBQ/0=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+hZ1lOzCNk4=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+hZ1lOzDM5U=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+hZ1lOzEzGo=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+hZ1lOzFdeQ=", - "_parent": { - "$ref": "AAAAAAFq+hZ1lOy/30o=" - }, - "model": { - "$ref": "AAAAAAFq+hZ1k+y9HK8=" - }, - "font": "Arial;13;0", - "left": 432, - "top": 745, - "width": 195.3388671875, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+hZ1lOzG/qA=", - "_parent": { - "$ref": "AAAAAAFq+hZ1lOy/30o=" - }, - "model": { - "$ref": "AAAAAAFq+hZ1k+y9HK8=" - }, - "subViews": [ - { - "_type": "UMLOperationView", - "_id": "AAAAAAFq+iKGce2ez84=", - "_parent": { - "$ref": "AAAAAAFq+hZ1lOzG/qA=" - }, - "model": { - "$ref": "AAAAAAFq+iKGSe2bwFE=" - }, - "font": "Arial;13;0", - "left": 437, - "top": 760, - "width": 185.3388671875, - "height": 13, - "text": "+DivNode(Node left, Node right)", - "horizontalAlignment": 0 - }, - { - "_type": "UMLOperationView", - "_id": "AAAAAAFq+iKTR+2kjwo=", - "_parent": { - "$ref": "AAAAAAFq+hZ1lOzG/qA=" - }, - "model": { - "$ref": "AAAAAAFq+iKTIe2hnbM=" - }, - "font": "Arial;13;0", - "left": 437, - "top": 775, - "width": 185.3388671875, - "height": 13, - "text": "+interpret()", - "horizontalAlignment": 0 - } - ], - "font": "Arial;13;0", - "left": 432, - "top": 755, - "width": 195.3388671875, - "height": 38 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+hZ1lOzHFKo=", - "_parent": { - "$ref": "AAAAAAFq+hZ1lOy/30o=" - }, - "model": { - "$ref": "AAAAAAFq+hZ1k+y9HK8=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -64, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+hZ1lOzI4Ok=", - "_parent": { - "$ref": "AAAAAAFq+hZ1lOy/30o=" - }, - "model": { - "$ref": "AAAAAAFq+hZ1k+y9HK8=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -64, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 432, - "top": 720, - "width": 195.3388671875, - "height": 73, - "nameCompartment": { - "$ref": "AAAAAAFq+hZ1lOzAxaU=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+hZ1lOzFdeQ=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+hZ1lOzG/qA=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+hZ1lOzHFKo=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+hZ1lOzI4Ok=" - } - }, - { - "_type": "UMLAssociationView", - "_id": "AAAAAAFq+ic7+e3Gp60=", - "_parent": { - "$ref": "AAAAAAFq+hK5NuleC6k=" - }, - "model": { - "$ref": "AAAAAAFq+ic7+e3C+G0=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+ic7+u3Hpoc=", - "_parent": { - "$ref": "AAAAAAFq+ic7+e3Gp60=" - }, - "model": { - "$ref": "AAAAAAFq+ic7+e3C+G0=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 130, - "top": 233, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+ic7+e3Gp60=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+ic7+u3IGaA=", - "_parent": { - "$ref": "AAAAAAFq+ic7+e3Gp60=" - }, - "model": { - "$ref": "AAAAAAFq+ic7+e3C+G0=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 145, - "top": 233, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+ic7+e3Gp60=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+ic7+u3JtNM=", - "_parent": { - "$ref": "AAAAAAFq+ic7+e3Gp60=" - }, - "model": { - "$ref": "AAAAAAFq+ic7+e3C+G0=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 101, - "top": 234, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+ic7+e3Gp60=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+ic7+u3Klls=", - "_parent": { - "$ref": "AAAAAAFq+ic7+e3Gp60=" - }, - "model": { - "$ref": "AAAAAAFq+ic7+e3D8PY=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 131, - "top": 227, - "height": 13, - "alpha": 0.5235987755982988, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+ic7+e3Gp60=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+ic7+u3LHd4=", - "_parent": { - "$ref": "AAAAAAFq+ic7+e3Gp60=" - }, - "model": { - "$ref": "AAAAAAFq+ic7+e3D8PY=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 144, - "top": 230, - "height": 13, - "alpha": 0.7853981633974483, - "distance": 40, - "hostEdge": { - "$ref": "AAAAAAFq+ic7+e3Gp60=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+ic7+u3M8aM=", - "_parent": { - "$ref": "AAAAAAFq+ic7+e3Gp60=" - }, - "model": { - "$ref": "AAAAAAFq+ic7+e3D8PY=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 103, - "top": 223, - "height": 13, - "alpha": -0.5235987755982988, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFq+ic7+e3Gp60=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+ic7+u3NEOk=", - "_parent": { - "$ref": "AAAAAAFq+ic7+e3Gp60=" - }, - "model": { - "$ref": "AAAAAAFq+ic7+e3EDkc=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 131, - "top": 240, - "height": 13, - "alpha": -0.5235987755982988, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+ic7+e3Gp60=" - } - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+ic7+u3OycY=", - "_parent": { - "$ref": "AAAAAAFq+ic7+e3Gp60=" - }, - "model": { - "$ref": "AAAAAAFq+ic7+e3EDkc=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 144, - "top": 237, - "height": 13, - "alpha": -0.7853981633974483, - "distance": 40, - "hostEdge": { - "$ref": "AAAAAAFq+ic7+e3Gp60=" - } - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+ic7+u3P5/I=", - "_parent": { - "$ref": "AAAAAAFq+ic7+e3Gp60=" - }, - "model": { - "$ref": "AAAAAAFq+ic7+e3EDkc=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 103, - "top": 244, - "height": 13, - "alpha": 0.5235987755982988, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFq+ic7+e3Gp60=" - } - }, - { - "_type": "UMLQualifierCompartmentView", - "_id": "AAAAAAFq+ic7++3QEQQ=", - "_parent": { - "$ref": "AAAAAAFq+ic7+e3Gp60=" - }, - "model": { - "$ref": "AAAAAAFq+ic7+e3D8PY=" - }, - "visible": false, - "font": "Arial;13;0", - "width": 10, - "height": 10 - }, - { - "_type": "UMLQualifierCompartmentView", - "_id": "AAAAAAFq+ic7++3RitY=", - "_parent": { - "$ref": "AAAAAAFq+ic7+e3Gp60=" - }, - "model": { - "$ref": "AAAAAAFq+ic7+e3EDkc=" - }, - "visible": false, - "font": "Arial;13;0", - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+hZD5uvJA54=" - }, - "tail": { - "$ref": "AAAAAAFq+hY+2Oug9xU=" - }, - "points": "116:208;116:272", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+ic7+u3Hpoc=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+ic7+u3IGaA=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+ic7+u3JtNM=" - }, - "tailRoleNameLabel": { - "$ref": "AAAAAAFq+ic7+u3Klls=" - }, - "tailPropertyLabel": { - "$ref": "AAAAAAFq+ic7+u3LHd4=" - }, - "tailMultiplicityLabel": { - "$ref": "AAAAAAFq+ic7+u3M8aM=" - }, - "headRoleNameLabel": { - "$ref": "AAAAAAFq+ic7+u3NEOk=" - }, - "headPropertyLabel": { - "$ref": "AAAAAAFq+ic7+u3OycY=" - }, - "headMultiplicityLabel": { - "$ref": "AAAAAAFq+ic7+u3P5/I=" - }, - "tailQualifiersCompartment": { - "$ref": "AAAAAAFq+ic7++3QEQQ=" - }, - "headQualifiersCompartment": { - "$ref": "AAAAAAFq+ic7++3RitY=" - } - }, - { - "_type": "UMLAssociationView", - "_id": "AAAAAAFq+idZCe4cm8M=", - "_parent": { - "$ref": "AAAAAAFq+hK5NuleC6k=" - }, - "model": { - "$ref": "AAAAAAFq+idZCe4YYF0=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+idZCe4dBNE=", - "_parent": { - "$ref": "AAAAAAFq+idZCe4cm8M=" - }, - "model": { - "$ref": "AAAAAAFq+idZCe4YYF0=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 272, - "top": 307, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+idZCe4cm8M=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+idZCe4eg54=", - "_parent": { - "$ref": "AAAAAAFq+idZCe4cm8M=" - }, - "model": { - "$ref": "AAAAAAFq+idZCe4YYF0=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 272, - "top": 292, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+idZCe4cm8M=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+idZCe4f/jQ=", - "_parent": { - "$ref": "AAAAAAFq+idZCe4cm8M=" - }, - "model": { - "$ref": "AAAAAAFq+idZCe4YYF0=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 272, - "top": 337, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+idZCe4cm8M=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+idZCe4g3lU=", - "_parent": { - "$ref": "AAAAAAFq+idZCe4cm8M=" - }, - "model": { - "$ref": "AAAAAAFq+idZCe4ZIFI=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 250, - "top": 307, - "height": 13, - "alpha": 0.5235987755982988, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+idZCe4cm8M=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+idZCe4hLwY=", - "_parent": { - "$ref": "AAAAAAFq+idZCe4cm8M=" - }, - "model": { - "$ref": "AAAAAAFq+idZCe4ZIFI=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 253, - "top": 293, - "height": 13, - "alpha": 0.7853981633974483, - "distance": 40, - "hostEdge": { - "$ref": "AAAAAAFq+idZCe4cm8M=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+idZCe4iojM=", - "_parent": { - "$ref": "AAAAAAFq+idZCe4cm8M=" - }, - "model": { - "$ref": "AAAAAAFq+idZCe4ZIFI=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 246, - "top": 334, - "height": 13, - "alpha": -0.5235987755982988, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFq+idZCe4cm8M=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+idZCe4j/G8=", - "_parent": { - "$ref": "AAAAAAFq+idZCe4cm8M=" - }, - "model": { - "$ref": "AAAAAAFq+idZCe4a3Ow=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 293, - "top": 307, - "height": 13, - "alpha": -0.5235987755982988, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+idZCe4cm8M=" - } - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+idZCe4k2PE=", - "_parent": { - "$ref": "AAAAAAFq+idZCe4cm8M=" - }, - "model": { - "$ref": "AAAAAAFq+idZCe4a3Ow=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 290, - "top": 293, - "height": 13, - "alpha": -0.7853981633974483, - "distance": 40, - "hostEdge": { - "$ref": "AAAAAAFq+idZCe4cm8M=" - } - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+idZCe4ltiQ=", - "_parent": { - "$ref": "AAAAAAFq+idZCe4cm8M=" - }, - "model": { - "$ref": "AAAAAAFq+idZCe4a3Ow=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 297, - "top": 334, - "height": 13, - "alpha": 0.5235987755982988, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFq+idZCe4cm8M=" - } - }, - { - "_type": "UMLQualifierCompartmentView", - "_id": "AAAAAAFq+idZCe4m8mU=", - "_parent": { - "$ref": "AAAAAAFq+idZCe4cm8M=" - }, - "model": { - "$ref": "AAAAAAFq+idZCe4ZIFI=" - }, - "visible": false, - "font": "Arial;13;0", - "width": 10, - "height": 10 - }, - { - "_type": "UMLQualifierCompartmentView", - "_id": "AAAAAAFq+idZCe4nE/E=", - "_parent": { - "$ref": "AAAAAAFq+idZCe4cm8M=" - }, - "model": { - "$ref": "AAAAAAFq+idZCe4a3Ow=" - }, - "visible": false, - "font": "Arial;13;0", - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+hZJlOvyDUI=" - }, - "tail": { - "$ref": "AAAAAAFq+hZD5uvJA54=" - }, - "lineStyle": 1, - "points": "225:328;319:328", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+idZCe4dBNE=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+idZCe4eg54=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+idZCe4f/jQ=" - }, - "tailRoleNameLabel": { - "$ref": "AAAAAAFq+idZCe4g3lU=" - }, - "tailPropertyLabel": { - "$ref": "AAAAAAFq+idZCe4hLwY=" - }, - "tailMultiplicityLabel": { - "$ref": "AAAAAAFq+idZCe4iojM=" - }, - "headRoleNameLabel": { - "$ref": "AAAAAAFq+idZCe4j/G8=" - }, - "headPropertyLabel": { - "$ref": "AAAAAAFq+idZCe4k2PE=" - }, - "headMultiplicityLabel": { - "$ref": "AAAAAAFq+idZCe4ltiQ=" - }, - "tailQualifiersCompartment": { - "$ref": "AAAAAAFq+idZCe4m8mU=" - }, - "headQualifiersCompartment": { - "$ref": "AAAAAAFq+idZCe4nE/E=" - } - }, - { - "_type": "UMLAssociationView", - "_id": "AAAAAAFq+id4QO5ukkY=", - "_parent": { - "$ref": "AAAAAAFq+hK5NuleC6k=" - }, - "model": { - "$ref": "AAAAAAFq+id4P+5qH+A=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+id4QO5v190=", - "_parent": { - "$ref": "AAAAAAFq+id4QO5ukkY=" - }, - "model": { - "$ref": "AAAAAAFq+id4P+5qH+A=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 527, - "top": 337, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+id4QO5ukkY=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+id4QO5woOE=", - "_parent": { - "$ref": "AAAAAAFq+id4QO5ukkY=" - }, - "model": { - "$ref": "AAAAAAFq+id4P+5qH+A=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 527, - "top": 352, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+id4QO5ukkY=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+id4QO5xOd8=", - "_parent": { - "$ref": "AAAAAAFq+id4QO5ukkY=" - }, - "model": { - "$ref": "AAAAAAFq+id4P+5qH+A=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 528, - "top": 307, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+id4QO5ukkY=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+id4QO5yIBI=", - "_parent": { - "$ref": "AAAAAAFq+id4QO5ukkY=" - }, - "model": { - "$ref": "AAAAAAFq+id4QO5refY=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 513, - "top": 416, - "height": 13, - "alpha": 0.5235987755982988, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+id4QO5ukkY=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+id4QO5zGkg=", - "_parent": { - "$ref": "AAAAAAFq+id4QO5ukkY=" - }, - "model": { - "$ref": "AAAAAAFq+id4QO5refY=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 499, - "top": 413, - "height": 13, - "alpha": 0.7853981633974483, - "distance": 40, - "hostEdge": { - "$ref": "AAAAAAFq+id4QO5ukkY=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+id4QO50784=", - "_parent": { - "$ref": "AAAAAAFq+id4QO5ukkY=" - }, - "model": { - "$ref": "AAAAAAFq+id4QO5refY=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 540, - "top": 420, - "height": 13, - "alpha": -0.5235987755982988, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFq+id4QO5ukkY=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+id4QO51tbI=", - "_parent": { - "$ref": "AAAAAAFq+id4QO5ukkY=" - }, - "model": { - "$ref": "AAAAAAFq+id4QO5srXw=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 473, - "top": 336, - "height": 13, - "alpha": -0.5235987755982988, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+id4QO5ukkY=" - } - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+id4QO52NXc=", - "_parent": { - "$ref": "AAAAAAFq+id4QO5ukkY=" - }, - "model": { - "$ref": "AAAAAAFq+id4QO5srXw=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 476, - "top": 350, - "height": 13, - "alpha": -0.7853981633974483, - "distance": 40, - "hostEdge": { - "$ref": "AAAAAAFq+id4QO5ukkY=" - } - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+id4QO53R58=", - "_parent": { - "$ref": "AAAAAAFq+id4QO5ukkY=" - }, - "model": { - "$ref": "AAAAAAFq+id4QO5srXw=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 469, - "top": 309, - "height": 13, - "alpha": 0.5235987755982988, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFq+id4QO5ukkY=" - } - }, - { - "_type": "UMLQualifierCompartmentView", - "_id": "AAAAAAFq+id4QO54wUA=", - "_parent": { - "$ref": "AAAAAAFq+id4QO5ukkY=" - }, - "model": { - "$ref": "AAAAAAFq+id4QO5refY=" - }, - "visible": false, - "font": "Arial;13;0", - "width": 10, - "height": 10 - }, - { - "_type": "UMLQualifierCompartmentView", - "_id": "AAAAAAFq+id4QO55qng=", - "_parent": { - "$ref": "AAAAAAFq+id4QO5ukkY=" - }, - "model": { - "$ref": "AAAAAAFq+id4QO5srXw=" - }, - "visible": false, - "font": "Arial;13;0", - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+hZJlOvyDUI=" - }, - "tail": { - "$ref": "AAAAAAFq+hZfHOxE23w=" - }, - "points": "528:448;528:328;448:328", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+id4QO5v190=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+id4QO5woOE=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+id4QO5xOd8=" - }, - "tailRoleNameLabel": { - "$ref": "AAAAAAFq+id4QO5yIBI=" - }, - "tailPropertyLabel": { - "$ref": "AAAAAAFq+id4QO5zGkg=" - }, - "tailMultiplicityLabel": { - "$ref": "AAAAAAFq+id4QO50784=" - }, - "headRoleNameLabel": { - "$ref": "AAAAAAFq+id4QO51tbI=" - }, - "headPropertyLabel": { - "$ref": "AAAAAAFq+id4QO52NXc=" - }, - "headMultiplicityLabel": { - "$ref": "AAAAAAFq+id4QO53R58=" - }, - "tailQualifiersCompartment": { - "$ref": "AAAAAAFq+id4QO54wUA=" - }, - "headQualifiersCompartment": { - "$ref": "AAAAAAFq+id4QO55qng=" - } - }, - { - "_type": "UMLDependencyView", - "_id": "AAAAAAFq+ihXkPDG+28=", - "_parent": { - "$ref": "AAAAAAFq+hK5NuleC6k=" - }, - "model": { - "$ref": "AAAAAAFq+ihXkPDEFUk=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+ihXkPDHsIM=", - "_parent": { - "$ref": "AAAAAAFq+ihXkPDG+28=" - }, - "model": { - "$ref": "AAAAAAFq+ihXkPDEFUk=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 329, - "top": 473, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+ihXkPDG+28=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+ihXkPDIPoU=", - "_parent": { - "$ref": "AAAAAAFq+ihXkPDG+28=" - }, - "model": { - "$ref": "AAAAAAFq+ihXkPDEFUk=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 314, - "top": 473, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+ihXkPDG+28=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+ihXkPDJr4w=", - "_parent": { - "$ref": "AAAAAAFq+ihXkPDG+28=" - }, - "model": { - "$ref": "AAAAAAFq+ihXkPDEFUk=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 359, - "top": 474, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+ihXkPDG+28=" - }, - "edgePosition": 1 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+hZJlOvyDUI=" - }, - "tail": { - "$ref": "AAAAAAFq+hZWoewbeIE=" - }, - "points": "288:480;344:480;344:368", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+ihXkPDHsIM=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+ihXkPDIPoU=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+ihXkPDJr4w=" - } - }, - { - "_type": "UMLDependencyView", - "_id": "AAAAAAFq+ihgjvDyCFI=", - "_parent": { - "$ref": "AAAAAAFq+hK5NuleC6k=" - }, - "model": { - "$ref": "AAAAAAFq+ihgjvDwRQ4=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+ihgjvDzheA=", - "_parent": { - "$ref": "AAAAAAFq+ihgjvDyCFI=" - }, - "model": { - "$ref": "AAAAAAFq+ihgjvDwRQ4=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 353, - "top": 473, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+ihgjvDyCFI=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+ihgjvD0fkU=", - "_parent": { - "$ref": "AAAAAAFq+ihgjvDyCFI=" - }, - "model": { - "$ref": "AAAAAAFq+ihgjvDwRQ4=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 338, - "top": 473, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+ihgjvDyCFI=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+ihgjvD1Gmw=", - "_parent": { - "$ref": "AAAAAAFq+ihgjvDyCFI=" - }, - "model": { - "$ref": "AAAAAAFq+ihgjvDwRQ4=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 383, - "top": 474, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+ihgjvDyCFI=" - }, - "edgePosition": 1 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+hZJlOvyDUI=" - }, - "tail": { - "$ref": "AAAAAAFq+hZfHOxE23w=" - }, - "points": "416:480;368:480;368:368", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+ihgjvDzheA=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+ihgjvD0fkU=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+ihgjvD1Gmw=" - } - }, - { - "_type": "UMLGeneralizationView", - "_id": "AAAAAAFq+ij/dvKSlEk=", - "_parent": { - "$ref": "AAAAAAFq+hK5NuleC6k=" - }, - "model": { - "$ref": "AAAAAAFq+ij/dfKQSlM=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+ij/dvKT/l4=", - "_parent": { - "$ref": "AAAAAAFq+ij/dvKSlEk=" - }, - "model": { - "$ref": "AAAAAAFq+ij/dfKQSlM=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 449, - "top": 621, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+ij/dvKSlEk=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+ij/dvKUZpc=", - "_parent": { - "$ref": "AAAAAAFq+ij/dvKSlEk=" - }, - "model": { - "$ref": "AAAAAAFq+ij/dfKQSlM=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 434, - "top": 621, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+ij/dvKSlEk=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+ij/dvKVUso=", - "_parent": { - "$ref": "AAAAAAFq+ij/dvKSlEk=" - }, - "model": { - "$ref": "AAAAAAFq+ij/dfKQSlM=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 478, - "top": 622, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+ij/dvKSlEk=" - }, - "edgePosition": 1 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+hZfHOxE23w=" - }, - "tail": { - "$ref": "AAAAAAFq+hZnXuxtU4s=" - }, - "points": "317:628;464:628;464:544", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+ij/dvKT/l4=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+ij/dvKUZpc=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+ij/dvKVUso=" - } - }, - { - "_type": "UMLGeneralizationView", - "_id": "AAAAAAFq+ikk+fMIuoA=", - "_parent": { - "$ref": "AAAAAAFq+hK5NuleC6k=" - }, - "model": { - "$ref": "AAAAAAFq+ikk+fMGqn4=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+ikk+fMJtr8=", - "_parent": { - "$ref": "AAAAAAFq+ikk+fMIuoA=" - }, - "model": { - "$ref": "AAAAAAFq+ikk+fMGqn4=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 569, - "top": 653, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+ikk+fMIuoA=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+ikk+fMKWVo=", - "_parent": { - "$ref": "AAAAAAFq+ikk+fMIuoA=" - }, - "model": { - "$ref": "AAAAAAFq+ikk+fMGqn4=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 554, - "top": 653, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+ikk+fMIuoA=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+ikk+fMLG7Y=", - "_parent": { - "$ref": "AAAAAAFq+ikk+fMIuoA=" - }, - "model": { - "$ref": "AAAAAAFq+ikk+fMGqn4=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 599, - "top": 654, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+ikk+fMIuoA=" - }, - "edgePosition": 1 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+hZfHOxE23w=" - }, - "tail": { - "$ref": "AAAAAAFq+hZtVOyWEbs=" - }, - "points": "608:660;584:660;584:544", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+ikk+fMJtr8=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+ikk+fMKWVo=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+ikk+fMLG7Y=" - } - }, - { - "_type": "UMLGeneralizationView", - "_id": "AAAAAAFq+iksMvM06aU=", - "_parent": { - "$ref": "AAAAAAFq+hK5NuleC6k=" - }, - "model": { - "$ref": "AAAAAAFq+iksMvMyl3E=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+iksMvM1SkM=", - "_parent": { - "$ref": "AAAAAAFq+iksMvM06aU=" - }, - "model": { - "$ref": "AAAAAAFq+iksMvMyl3E=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 510, - "top": 625, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+iksMvM06aU=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+iksMvM2JS4=", - "_parent": { - "$ref": "AAAAAAFq+iksMvM06aU=" - }, - "model": { - "$ref": "AAAAAAFq+iksMvMyl3E=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 495, - "top": 625, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+iksMvM06aU=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+iksMvM3qM4=", - "_parent": { - "$ref": "AAAAAAFq+iksMvM06aU=" - }, - "model": { - "$ref": "AAAAAAFq+iksMvMyl3E=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 539, - "top": 626, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+iksMvM06aU=" - }, - "edgePosition": 1 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+hZfHOxE23w=" - }, - "tail": { - "$ref": "AAAAAAFq+hZ1lOy/30o=" - }, - "points": "525:720;525:544", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+iksMvM1SkM=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+iksMvM2JS4=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+iksMvM3qM4=" - } - } - ] - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+hY+1+ueQ9g=", - "_parent": { - "$ref": "AAAAAAFq+hXmI+uZVMA=" - }, - "name": "Client", - "ownedElements": [ - { - "_type": "UMLAssociation", - "_id": "AAAAAAFq+ic7+e3C+G0=", - "_parent": { - "$ref": "AAAAAAFq+hY+1+ueQ9g=" - }, - "end1": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFq+ic7+e3D8PY=", - "_parent": { - "$ref": "AAAAAAFq+ic7+e3C+G0=" - }, - "reference": { - "$ref": "AAAAAAFq+hY+1+ueQ9g=" - }, - "navigable": false - }, - "end2": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFq+ic7+e3EDkc=", - "_parent": { - "$ref": "AAAAAAFq+ic7+e3C+G0=" - }, - "reference": { - "$ref": "AAAAAAFq+hZD5uvHBkQ=" - } - } - } - ] - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+hZD5uvHBkQ=", - "_parent": { - "$ref": "AAAAAAFq+hXmI+uZVMA=" - }, - "name": "Calculator", - "ownedElements": [ - { - "_type": "UMLAssociation", - "_id": "AAAAAAFq+idZCe4YYF0=", - "_parent": { - "$ref": "AAAAAAFq+hZD5uvHBkQ=" - }, - "end1": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFq+idZCe4ZIFI=", - "_parent": { - "$ref": "AAAAAAFq+idZCe4YYF0=" - }, - "reference": { - "$ref": "AAAAAAFq+hZD5uvHBkQ=" - }, - "navigable": false - }, - "end2": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFq+idZCe4a3Ow=", - "_parent": { - "$ref": "AAAAAAFq+idZCe4YYF0=" - }, - "reference": { - "$ref": "AAAAAAFq+hZJlOvwQWI=" - } - } - } - ], - "attributes": [ - { - "_type": "UMLAttribute", - "_id": "AAAAAAFq+hdpDOzuGsM=", - "_parent": { - "$ref": "AAAAAAFq+hZD5uvHBkQ=" - }, - "name": "statement", - "type": "String" - }, - { - "_type": "UMLAttribute", - "_id": "AAAAAAFq+hf/fez/Bt8=", - "_parent": { - "$ref": "AAAAAAFq+hZD5uvHBkQ=" - }, - "name": "node", - "type": { - "$ref": "AAAAAAFq+hZJlOvwQWI=" - } - } - ], - "operations": [ - { - "_type": "UMLOperation", - "_id": "AAAAAAFq+hgyw+0Gh2w=", - "_parent": { - "$ref": "AAAAAAFq+hZD5uvHBkQ=" - }, - "name": "build", - "stereotype": "", - "parameters": [ - { - "_type": "UMLParameter", - "_id": "AAAAAAFq+hhXh+0Nzz8=", - "_parent": { - "$ref": "AAAAAAFq+hgyw+0Gh2w=" - }, - "name": "String statement" - } - ] - }, - { - "_type": "UMLOperation", - "_id": "AAAAAAFq+hi5ZO0Rr7s=", - "_parent": { - "$ref": "AAAAAAFq+hZD5uvHBkQ=" - }, - "name": "compute" - } - ] - }, - { - "_type": "UMLInterface", - "_id": "AAAAAAFq+hZJlOvwQWI=", - "_parent": { - "$ref": "AAAAAAFq+hXmI+uZVMA=" - }, - "name": "Node", - "operations": [ - { - "_type": "UMLOperation", - "_id": "AAAAAAFq+hjuJO0YwSo=", - "_parent": { - "$ref": "AAAAAAFq+hZJlOvwQWI=" - }, - "name": "Interpret" - } - ] - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+hZWoewZKZY=", - "_parent": { - "$ref": "AAAAAAFq+hXmI+uZVMA=" - }, - "name": "ValueNode", - "ownedElements": [ - { - "_type": "UMLDependency", - "_id": "AAAAAAFq+ihXkPDEFUk=", - "_parent": { - "$ref": "AAAAAAFq+hZWoewZKZY=" - }, - "source": { - "$ref": "AAAAAAFq+hZWoewZKZY=" - }, - "target": { - "$ref": "AAAAAAFq+hZJlOvwQWI=" - } - } - ], - "operations": [ - { - "_type": "UMLOperation", - "_id": "AAAAAAFq+hm+WO0hm2k=", - "_parent": { - "$ref": "AAAAAAFq+hZWoewZKZY=" - }, - "name": "Interpret" - } - ] - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+hZfGuxC3lc=", - "_parent": { - "$ref": "AAAAAAFq+hXmI+uZVMA=" - }, - "name": "SymboINode", - "ownedElements": [ - { - "_type": "UMLAssociation", - "_id": "AAAAAAFq+id4P+5qH+A=", - "_parent": { - "$ref": "AAAAAAFq+hZfGuxC3lc=" - }, - "end1": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFq+id4QO5refY=", - "_parent": { - "$ref": "AAAAAAFq+id4P+5qH+A=" - }, - "reference": { - "$ref": "AAAAAAFq+hZfGuxC3lc=" - }, - "navigable": false, - "aggregation": "shared" - }, - "end2": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFq+id4QO5srXw=", - "_parent": { - "$ref": "AAAAAAFq+id4P+5qH+A=" - }, - "reference": { - "$ref": "AAAAAAFq+hZJlOvwQWI=" - }, - "navigable": false - } - }, - { - "_type": "UMLDependency", - "_id": "AAAAAAFq+ihgjvDwRQ4=", - "_parent": { - "$ref": "AAAAAAFq+hZfGuxC3lc=" - }, - "source": { - "$ref": "AAAAAAFq+hZfGuxC3lc=" - }, - "target": { - "$ref": "AAAAAAFq+hZJlOvwQWI=" - } - } - ], - "attributes": [ - { - "_type": "UMLAttribute", - "_id": "AAAAAAFq+hopv+0vXRg=", - "_parent": { - "$ref": "AAAAAAFq+hZfGuxC3lc=" - }, - "name": "left", - "stereotype": "", - "type": { - "$ref": "AAAAAAFq+hZJlOvwQWI=" - } - }, - { - "_type": "UMLAttribute", - "_id": "AAAAAAFq+ho3kO016Js=", - "_parent": { - "$ref": "AAAAAAFq+hZfGuxC3lc=" - }, - "name": "right", - "type": { - "$ref": "AAAAAAFq+hZJlOvwQWI=" - } - } - ], - "operations": [ - { - "_type": "UMLOperation", - "_id": "AAAAAAFq+hniBe0oWIE=", - "_parent": { - "$ref": "AAAAAAFq+hZfGuxC3lc=" - }, - "name": "SymboINode", - "parameters": [ - { - "_type": "UMLParameter", - "_id": "AAAAAAFq+igfifAIqjI=", - "_parent": { - "$ref": "AAAAAAFq+hniBe0oWIE=" - }, - "name": "Node left" - }, - { - "_type": "UMLParameter", - "_id": "AAAAAAFq+igxdPBCTVk=", - "_parent": { - "$ref": "AAAAAAFq+hniBe0oWIE=" - }, - "name": "Node right", - "type": "" - } - ] - } - ] - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+hZnXexrkkc=", - "_parent": { - "$ref": "AAAAAAFq+hXmI+uZVMA=" - }, - "name": "MulNode", - "ownedElements": [ - { - "_type": "UMLGeneralization", - "_id": "AAAAAAFq+ij/dfKQSlM=", - "_parent": { - "$ref": "AAAAAAFq+hZnXexrkkc=" - }, - "source": { - "$ref": "AAAAAAFq+hZnXexrkkc=" - }, - "target": { - "$ref": "AAAAAAFq+hZfGuxC3lc=" - } - } - ], - "operations": [ - { - "_type": "UMLOperation", - "_id": "AAAAAAFq+iCby+1vc7U=", - "_parent": { - "$ref": "AAAAAAFq+hZnXexrkkc=" - }, - "name": "MulNode", - "parameters": [ - { - "_type": "UMLParameter", - "_id": "AAAAAAFq+iDbue12puc=", - "_parent": { - "$ref": "AAAAAAFq+iCby+1vc7U=" - }, - "name": "Node left" - }, - { - "_type": "UMLParameter", - "_id": "AAAAAAFq+iEcAe16WDw=", - "_parent": { - "$ref": "AAAAAAFq+iCby+1vc7U=" - }, - "name": "Node right", - "type": "" - } - ] - }, - { - "_type": "UMLOperation", - "_id": "AAAAAAFq+iEqPO18Y4A=", - "_parent": { - "$ref": "AAAAAAFq+hZnXexrkkc=" - }, - "name": "interpret" - } - ] - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+hZtVOyUoVQ=", - "_parent": { - "$ref": "AAAAAAFq+hXmI+uZVMA=" - }, - "name": "ModNode", - "ownedElements": [ - { - "_type": "UMLGeneralization", - "_id": "AAAAAAFq+ikk+fMGqn4=", - "_parent": { - "$ref": "AAAAAAFq+hZtVOyUoVQ=" - }, - "source": { - "$ref": "AAAAAAFq+hZtVOyUoVQ=" - }, - "target": { - "$ref": "AAAAAAFq+hZfGuxC3lc=" - } - } - ], - "operations": [ - { - "_type": "UMLOperation", - "_id": "AAAAAAFq+iG7L+2FZHw=", - "_parent": { - "$ref": "AAAAAAFq+hZtVOyUoVQ=" - }, - "name": "MulNode", - "parameters": [ - { - "_type": "UMLParameter", - "_id": "AAAAAAFq+iHpE+2MB3Y=", - "_parent": { - "$ref": "AAAAAAFq+iG7L+2FZHw=" - }, - "name": "Node left" - }, - { - "_type": "UMLParameter", - "_id": "AAAAAAFq+iH5s+2Q1e0=", - "_parent": { - "$ref": "AAAAAAFq+iG7L+2FZHw=" - }, - "name": "Node right", - "type": "" - } - ] - }, - { - "_type": "UMLOperation", - "_id": "AAAAAAFq+iIlju2S/ec=", - "_parent": { - "$ref": "AAAAAAFq+hZtVOyUoVQ=" - }, - "name": "interpret" - } - ] - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+hZ1k+y9HK8=", - "_parent": { - "$ref": "AAAAAAFq+hXmI+uZVMA=" - }, - "name": "DivNode", - "ownedElements": [ - { - "_type": "UMLGeneralization", - "_id": "AAAAAAFq+iksMvMyl3E=", - "_parent": { - "$ref": "AAAAAAFq+hZ1k+y9HK8=" - }, - "source": { - "$ref": "AAAAAAFq+hZ1k+y9HK8=" - }, - "target": { - "$ref": "AAAAAAFq+hZfGuxC3lc=" - } - } - ], - "operations": [ - { - "_type": "UMLOperation", - "_id": "AAAAAAFq+iKGSe2bwFE=", - "_parent": { - "$ref": "AAAAAAFq+hZ1k+y9HK8=" - }, - "name": "DivNode", - "parameters": [ - { - "_type": "UMLParameter", - "_id": "AAAAAAFq+iWe/e2ob38=", - "_parent": { - "$ref": "AAAAAAFq+iKGSe2bwFE=" - }, - "name": "Node left" - }, - { - "_type": "UMLParameter", - "_id": "AAAAAAFq+iW3E+2sGwM=", - "_parent": { - "$ref": "AAAAAAFq+iKGSe2bwFE=" - }, - "name": "Node right", - "type": "" - } - ] - }, - { - "_type": "UMLOperation", - "_id": "AAAAAAFq+iKTIe2hnbM=", - "_parent": { - "$ref": "AAAAAAFq+hZ1k+y9HK8=" - }, - "name": "interpret" - } - ] - } - ] - } - ] - }, - { - "_type": "UMLModel", - "_id": "AAAAAAFq+lKo0gatgnM=", - "_parent": { - "$ref": "AAAAAAFF+h6SjaM2Hec=" - }, - "name": "行为型模式——观察者模式", - "ownedElements": [ - { - "_type": "UMLClassDiagram", - "_id": "AAAAAAFq+lKo0gaupNE=", - "_parent": { - "$ref": "AAAAAAFq+lKo0gatgnM=" - }, - "name": "观察者模式", - "ownedViews": [ - { - "_type": "UMLInterfaceView", - "_id": "AAAAAAFq+lVubgbs07o=", - "_parent": { - "$ref": "AAAAAAFq+lKo0gaupNE=" - }, - "model": { - "$ref": "AAAAAAFq+lVubgbqErA=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+lVubgbtDkU=", - "_parent": { - "$ref": "AAAAAAFq+lVubgbs07o=" - }, - "model": { - "$ref": "AAAAAAFq+lVubgbqErA=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+lVubgbuHUY=", - "_parent": { - "$ref": "AAAAAAFq+lVubgbtDkU=" - }, - "font": "Arial;13;0", - "left": 101, - "top": 885, - "width": 119, - "height": 13, - "text": "«interface»" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+lVubgbvI4A=", - "_parent": { - "$ref": "AAAAAAFq+lVubgbtDkU=" - }, - "font": "Arial;13;1", - "left": 101, - "top": 900, - "width": 119, - "height": 13, - "text": "Subject" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+lVubgbwzI0=", - "_parent": { - "$ref": "AAAAAAFq+lVubgbtDkU=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -96, - "top": -96, - "width": 194.27001953125, - "height": 13, - "text": "(from 行为型模式——观察者模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+lVubgbxpMk=", - "_parent": { - "$ref": "AAAAAAFq+lVubgbtDkU=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -96, - "top": -96, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 96, - "top": 880, - "width": 129, - "height": 38, - "stereotypeLabel": { - "$ref": "AAAAAAFq+lVubgbuHUY=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+lVubgbvI4A=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+lVubgbwzI0=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+lVubgbxpMk=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+lVubgbysiw=", - "_parent": { - "$ref": "AAAAAAFq+lVubgbs07o=" - }, - "model": { - "$ref": "AAAAAAFq+lVubgbqErA=" - }, - "font": "Arial;13;0", - "left": 96, - "top": 918, - "width": 129, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+lVubgbzWy8=", - "_parent": { - "$ref": "AAAAAAFq+lVubgbs07o=" - }, - "model": { - "$ref": "AAAAAAFq+lVubgbqErA=" - }, - "subViews": [ - { - "_type": "UMLOperationView", - "_id": "AAAAAAFq+lYbSAeZK24=", - "_parent": { - "$ref": "AAAAAAFq+lVubgbzWy8=" - }, - "model": { - "$ref": "AAAAAAFq+lYbGgeWDIM=" - }, - "font": "Arial;13;0", - "left": 101, - "top": 933, - "width": 119, - "height": 13, - "text": "+registerObserver()", - "horizontalAlignment": 0 - }, - { - "_type": "UMLOperationView", - "_id": "AAAAAAFq+lYmggefX2k=", - "_parent": { - "$ref": "AAAAAAFq+lVubgbzWy8=" - }, - "model": { - "$ref": "AAAAAAFq+lYmXQecEvk=" - }, - "font": "Arial;13;0", - "left": 101, - "top": 948, - "width": 119, - "height": 13, - "text": "+removeObserver()", - "horizontalAlignment": 0 - }, - { - "_type": "UMLOperationView", - "_id": "AAAAAAFq+lYtewelBb8=", - "_parent": { - "$ref": "AAAAAAFq+lVubgbzWy8=" - }, - "model": { - "$ref": "AAAAAAFq+lYtVgei0fg=" - }, - "font": "Arial;13;0", - "left": 101, - "top": 963, - "width": 119, - "height": 13, - "text": "+notifyObserver()", - "horizontalAlignment": 0 - } - ], - "font": "Arial;13;0", - "left": 96, - "top": 928, - "width": 129, - "height": 53 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+lVubgb08oM=", - "_parent": { - "$ref": "AAAAAAFq+lVubgbs07o=" - }, - "model": { - "$ref": "AAAAAAFq+lVubgbqErA=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -48, - "top": -48, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+lVubgb1Nqo=", - "_parent": { - "$ref": "AAAAAAFq+lVubgbs07o=" - }, - "model": { - "$ref": "AAAAAAFq+lVubgbqErA=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -48, - "top": -48, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 96, - "top": 880, - "width": 129, - "height": 113, - "nameCompartment": { - "$ref": "AAAAAAFq+lVubgbtDkU=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+lVubgbysiw=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+lVubgbzWy8=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+lVubgb08oM=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+lVubgb1Nqo=" - } - }, - { - "_type": "UMLInterfaceView", - "_id": "AAAAAAFq+lV0fgcVWow=", - "_parent": { - "$ref": "AAAAAAFq+lKo0gaupNE=" - }, - "model": { - "$ref": "AAAAAAFq+lV0fgcTDCw=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+lV0fgcWSCc=", - "_parent": { - "$ref": "AAAAAAFq+lV0fgcVWow=" - }, - "model": { - "$ref": "AAAAAAFq+lV0fgcTDCw=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+lV0fgcXWSs=", - "_parent": { - "$ref": "AAAAAAFq+lV0fgcWSCc=" - }, - "font": "Arial;13;0", - "left": 421, - "top": 885, - "width": 87, - "height": 13, - "text": "«interface»" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+lV0fgcYbLs=", - "_parent": { - "$ref": "AAAAAAFq+lV0fgcWSCc=" - }, - "font": "Arial;13;1", - "left": 421, - "top": 900, - "width": 87, - "height": 13, - "text": "Observer" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+lV0fgcZ4HU=", - "_parent": { - "$ref": "AAAAAAFq+lV0fgcWSCc=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -48, - "top": -112, - "width": 194.27001953125, - "height": 13, - "text": "(from 行为型模式——观察者模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+lV0fgcaqj0=", - "_parent": { - "$ref": "AAAAAAFq+lV0fgcWSCc=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -48, - "top": -112, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 416, - "top": 880, - "width": 97, - "height": 38, - "stereotypeLabel": { - "$ref": "AAAAAAFq+lV0fgcXWSs=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+lV0fgcYbLs=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+lV0fgcZ4HU=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+lV0fgcaqj0=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+lV0fwcbk0k=", - "_parent": { - "$ref": "AAAAAAFq+lV0fgcVWow=" - }, - "model": { - "$ref": "AAAAAAFq+lV0fgcTDCw=" - }, - "font": "Arial;13;0", - "left": 416, - "top": 918, - "width": 97, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+lV0fwccte4=", - "_parent": { - "$ref": "AAAAAAFq+lV0fgcVWow=" - }, - "model": { - "$ref": "AAAAAAFq+lV0fgcTDCw=" - }, - "subViews": [ - { - "_type": "UMLOperationView", - "_id": "AAAAAAFq+lY3eQerx8g=", - "_parent": { - "$ref": "AAAAAAFq+lV0fwccte4=" - }, - "model": { - "$ref": "AAAAAAFq+lY3VAeoa+c=" - }, - "font": "Arial;13;0", - "left": 421, - "top": 933, - "width": 87, - "height": 13, - "text": "+update()", - "horizontalAlignment": 0 - } - ], - "font": "Arial;13;0", - "left": 416, - "top": 928, - "width": 97, - "height": 23 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+lV0fwcd5Ws=", - "_parent": { - "$ref": "AAAAAAFq+lV0fgcVWow=" - }, - "model": { - "$ref": "AAAAAAFq+lV0fgcTDCw=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -24, - "top": -56, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+lV0fwcePAc=", - "_parent": { - "$ref": "AAAAAAFq+lV0fgcVWow=" - }, - "model": { - "$ref": "AAAAAAFq+lV0fgcTDCw=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -24, - "top": -56, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 416, - "top": 880, - "width": 97, - "height": 81, - "nameCompartment": { - "$ref": "AAAAAAFq+lV0fgcWSCc=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+lV0fwcbk0k=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+lV0fwccte4=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+lV0fwcd5Ws=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+lV0fwcePAc=" - } - }, - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+lWAPgc+jFM=", - "_parent": { - "$ref": "AAAAAAFq+lKo0gaupNE=" - }, - "model": { - "$ref": "AAAAAAFq+lWAPgc83BA=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+lWAPwc/0Ic=", - "_parent": { - "$ref": "AAAAAAFq+lWAPgc+jFM=" - }, - "model": { - "$ref": "AAAAAAFq+lWAPgc83BA=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+lWAPwdA5U0=", - "_parent": { - "$ref": "AAAAAAFq+lWAPwc/0Ic=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -80, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+lWAPwdBfTA=", - "_parent": { - "$ref": "AAAAAAFq+lWAPwc/0Ic=" - }, - "font": "Arial;13;1", - "left": 101, - "top": 1079, - "width": 119, - "height": 13, - "text": "ConcreteSubject" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+lWAPwdCPO0=", - "_parent": { - "$ref": "AAAAAAFq+lWAPwc/0Ic=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -80, - "width": 194.27001953125, - "height": 13, - "text": "(from 行为型模式——观察者模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+lWAPwdD7DA=", - "_parent": { - "$ref": "AAAAAAFq+lWAPwc/0Ic=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -80, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 96, - "top": 1072, - "width": 129, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+lWAPwdA5U0=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+lWAPwdBfTA=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+lWAPwdCPO0=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+lWAPwdD7DA=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+lWAPwdE22E=", - "_parent": { - "$ref": "AAAAAAFq+lWAPgc+jFM=" - }, - "model": { - "$ref": "AAAAAAFq+lWAPgc83BA=" - }, - "font": "Arial;13;0", - "left": 96, - "top": 1097, - "width": 129, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+lWAPwdFbUU=", - "_parent": { - "$ref": "AAAAAAFq+lWAPgc+jFM=" - }, - "model": { - "$ref": "AAAAAAFq+lWAPgc83BA=" - }, - "subViews": [ - { - "_type": "UMLOperationView", - "_id": "AAAAAAFq+la6Lge4g9Y=", - "_parent": { - "$ref": "AAAAAAFq+lWAPwdFbUU=" - }, - "model": { - "$ref": "AAAAAAFq+la6CQe1dnk=" - }, - "font": "Arial;13;0", - "left": 101, - "top": 1112, - "width": 119, - "height": 13, - "text": "+registerObserver()", - "horizontalAlignment": 0 - }, - { - "_type": "UMLOperationView", - "_id": "AAAAAAFq+lbAtQe+D7Q=", - "_parent": { - "$ref": "AAAAAAFq+lWAPwdFbUU=" - }, - "model": { - "$ref": "AAAAAAFq+lbAkge7bdo=" - }, - "font": "Arial;13;0", - "left": 101, - "top": 1127, - "width": 119, - "height": 13, - "text": "+removeObserver()", - "horizontalAlignment": 0 - }, - { - "_type": "UMLOperationView", - "_id": "AAAAAAFq+lbGSAfEO9o=", - "_parent": { - "$ref": "AAAAAAFq+lWAPwdFbUU=" - }, - "model": { - "$ref": "AAAAAAFq+lbGJQfBYgA=" - }, - "font": "Arial;13;0", - "left": 101, - "top": 1142, - "width": 119, - "height": 13, - "text": "+notifyObserver()", - "horizontalAlignment": 0 - } - ], - "font": "Arial;13;0", - "left": 96, - "top": 1107, - "width": 129, - "height": 53 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+lWAPwdGY2o=", - "_parent": { - "$ref": "AAAAAAFq+lWAPgc+jFM=" - }, - "model": { - "$ref": "AAAAAAFq+lWAPgc83BA=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -40, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+lWAPwdHXBE=", - "_parent": { - "$ref": "AAAAAAFq+lWAPgc+jFM=" - }, - "model": { - "$ref": "AAAAAAFq+lWAPgc83BA=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -40, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 96, - "top": 1072, - "width": 129, - "height": 97, - "nameCompartment": { - "$ref": "AAAAAAFq+lWAPwc/0Ic=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+lWAPwdE22E=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+lWAPwdFbUU=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+lWAPwdGY2o=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+lWAPwdHXBE=" - } - }, - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+lWEuAdnJWA=", - "_parent": { - "$ref": "AAAAAAFq+lKo0gaupNE=" - }, - "model": { - "$ref": "AAAAAAFq+lWEuAdlul0=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+lWEuAdoHFw=", - "_parent": { - "$ref": "AAAAAAFq+lWEuAdnJWA=" - }, - "model": { - "$ref": "AAAAAAFq+lWEuAdlul0=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+lWEuAdpn90=", - "_parent": { - "$ref": "AAAAAAFq+lWEuAdoHFw=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -176, - "top": 32, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+lWEuAdqeRU=", - "_parent": { - "$ref": "AAAAAAFq+lWEuAdoHFw=" - }, - "font": "Arial;13;1", - "left": 405, - "top": 1095, - "width": 119, - "height": 13, - "text": "ConcreteObserver" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+lWEuAdrBvc=", - "_parent": { - "$ref": "AAAAAAFq+lWEuAdoHFw=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -176, - "top": 32, - "width": 194.27001953125, - "height": 13, - "text": "(from 行为型模式——观察者模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+lWEuAdsw1k=", - "_parent": { - "$ref": "AAAAAAFq+lWEuAdoHFw=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -176, - "top": 32, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 400, - "top": 1088, - "width": 129, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+lWEuAdpn90=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+lWEuAdqeRU=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+lWEuAdrBvc=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+lWEuAdsw1k=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+lWEuAdtenI=", - "_parent": { - "$ref": "AAAAAAFq+lWEuAdnJWA=" - }, - "model": { - "$ref": "AAAAAAFq+lWEuAdlul0=" - }, - "font": "Arial;13;0", - "left": 400, - "top": 1113, - "width": 129, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+lWEuAdu7mc=", - "_parent": { - "$ref": "AAAAAAFq+lWEuAdnJWA=" - }, - "model": { - "$ref": "AAAAAAFq+lWEuAdlul0=" - }, - "subViews": [ - { - "_type": "UMLOperationView", - "_id": "AAAAAAFq+lbOSAfK7dE=", - "_parent": { - "$ref": "AAAAAAFq+lWEuAdu7mc=" - }, - "model": { - "$ref": "AAAAAAFq+lbOHwfHThA=" - }, - "font": "Arial;13;0", - "left": 405, - "top": 1128, - "width": 119, - "height": 13, - "text": "+update()", - "horizontalAlignment": 0 - } - ], - "font": "Arial;13;0", - "left": 400, - "top": 1123, - "width": 129, - "height": 23 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+lWEuAdvizY=", - "_parent": { - "$ref": "AAAAAAFq+lWEuAdnJWA=" - }, - "model": { - "$ref": "AAAAAAFq+lWEuAdlul0=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -88, - "top": 16, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+lWEuAdwkRo=", - "_parent": { - "$ref": "AAAAAAFq+lWEuAdnJWA=" - }, - "model": { - "$ref": "AAAAAAFq+lWEuAdlul0=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -88, - "top": 16, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 400, - "top": 1088, - "width": 129, - "height": 65, - "nameCompartment": { - "$ref": "AAAAAAFq+lWEuAdoHFw=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+lWEuAdtenI=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+lWEuAdu7mc=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+lWEuAdvizY=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+lWEuAdwkRo=" - } - }, - { - "_type": "UMLInterfaceRealizationView", - "_id": "AAAAAAFq+lgfygfXN3M=", - "_parent": { - "$ref": "AAAAAAFq+lKo0gaupNE=" - }, - "model": { - "$ref": "AAAAAAFq+lgfygfW2pY=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+lgfygfYtEw=", - "_parent": { - "$ref": "AAAAAAFq+lgfygfXN3M=" - }, - "model": { - "$ref": "AAAAAAFq+lgfygfW2pY=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 145, - "top": 1025, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+lgfygfXN3M=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+lgfygfZHLI=", - "_parent": { - "$ref": "AAAAAAFq+lgfygfXN3M=" - }, - "model": { - "$ref": "AAAAAAFq+lgfygfW2pY=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 130, - "top": 1025, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+lgfygfXN3M=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+lgfygfaXEk=", - "_parent": { - "$ref": "AAAAAAFq+lgfygfXN3M=" - }, - "model": { - "$ref": "AAAAAAFq+lgfygfW2pY=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 174, - "top": 1026, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+lgfygfXN3M=" - }, - "edgePosition": 1 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+lVubgbs07o=" - }, - "tail": { - "$ref": "AAAAAAFq+lWAPgc+jFM=" - }, - "lineStyle": 1, - "points": "160:1071;160:993", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+lgfygfYtEw=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+lgfygfZHLI=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+lgfygfaXEk=" - } - }, - { - "_type": "UMLInterfaceRealizationView", - "_id": "AAAAAAFq+lgoQgfojR4=", - "_parent": { - "$ref": "AAAAAAFq+lKo0gaupNE=" - }, - "model": { - "$ref": "AAAAAAFq+lgoQgfngnM=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+lgoQgfpNV8=", - "_parent": { - "$ref": "AAAAAAFq+lgoQgfojR4=" - }, - "model": { - "$ref": "AAAAAAFq+lgoQgfngnM=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 449, - "top": 1017, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+lgoQgfojR4=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+lgoQgfqvxA=", - "_parent": { - "$ref": "AAAAAAFq+lgoQgfojR4=" - }, - "model": { - "$ref": "AAAAAAFq+lgoQgfngnM=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 434, - "top": 1017, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+lgoQgfojR4=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+lgoQgfrEEk=", - "_parent": { - "$ref": "AAAAAAFq+lgoQgfojR4=" - }, - "model": { - "$ref": "AAAAAAFq+lgoQgfngnM=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 478, - "top": 1018, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+lgoQgfojR4=" - }, - "edgePosition": 1 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+lV0fgcVWow=" - }, - "tail": { - "$ref": "AAAAAAFq+lWEuAdnJWA=" - }, - "lineStyle": 1, - "points": "464:1087;464:961", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+lgoQgfpNV8=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+lgoQgfqvxA=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+lgoQgfrEEk=" - } - }, - { - "_type": "UMLDependencyView", - "_id": "AAAAAAFq+lixIAgBt9k=", - "_parent": { - "$ref": "AAAAAAFq+lKo0gaupNE=" - }, - "model": { - "$ref": "AAAAAAFq+lixHwf/X3U=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+lixIAgCXxc=", - "_parent": { - "$ref": "AAAAAAFq+lixIAgBt9k=" - }, - "model": { - "$ref": "AAAAAAFq+lixHwf/X3U=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 311, - "top": 1129, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+lixIAgBt9k=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+lixIAgDijU=", - "_parent": { - "$ref": "AAAAAAFq+lixIAgBt9k=" - }, - "model": { - "$ref": "AAAAAAFq+lixHwf/X3U=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 311, - "top": 1144, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+lixIAgBt9k=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+lixIAgEw6Q=", - "_parent": { - "$ref": "AAAAAAFq+lixIAgBt9k=" - }, - "model": { - "$ref": "AAAAAAFq+lixHwf/X3U=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 312, - "top": 1099, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+lixIAgBt9k=" - }, - "edgePosition": 1 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+lWAPgc+jFM=" - }, - "tail": { - "$ref": "AAAAAAFq+lWEuAdnJWA=" - }, - "lineStyle": 1, - "points": "399:1120;225:1120", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+lixIAgCXxc=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+lixIAgDijU=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+lixIAgEw6Q=" - } - }, - { - "_type": "UMLDependencyView", - "_id": "AAAAAAFq+ljAlwgSZag=", - "_parent": { - "$ref": "AAAAAAFq+lKo0gaupNE=" - }, - "model": { - "$ref": "AAAAAAFq+ljAlwgQGCA=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+ljAmAgTnls=", - "_parent": { - "$ref": "AAAAAAFq+ljAlwgSZag=" - }, - "model": { - "$ref": "AAAAAAFq+ljAlwgQGCA=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 320, - "top": 912, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+ljAlwgSZag=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+ljAmAgUc/w=", - "_parent": { - "$ref": "AAAAAAFq+ljAlwgSZag=" - }, - "model": { - "$ref": "AAAAAAFq+ljAlwgQGCA=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 320, - "top": 897, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+ljAlwgSZag=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+ljAmAgV/cw=", - "_parent": { - "$ref": "AAAAAAFq+ljAlwgSZag=" - }, - "model": { - "$ref": "AAAAAAFq+ljAlwgQGCA=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 320, - "top": 942, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+ljAlwgSZag=" - }, - "edgePosition": 1 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+lV0fgcVWow=" - }, - "tail": { - "$ref": "AAAAAAFq+lVubgbs07o=" - }, - "points": "224:933;416:933", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+ljAmAgTnls=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+ljAmAgUc/w=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+ljAmAgV/cw=" - } - } - ] - }, - { - "_type": "UMLInterface", - "_id": "AAAAAAFq+lVubgbqErA=", - "_parent": { - "$ref": "AAAAAAFq+lKo0gatgnM=" - }, - "name": "Subject", - "ownedElements": [ - { - "_type": "UMLDependency", - "_id": "AAAAAAFq+ljAlwgQGCA=", - "_parent": { - "$ref": "AAAAAAFq+lVubgbqErA=" - }, - "source": { - "$ref": "AAAAAAFq+lVubgbqErA=" - }, - "target": { - "$ref": "AAAAAAFq+lV0fgcTDCw=" - } - } - ], - "operations": [ - { - "_type": "UMLOperation", - "_id": "AAAAAAFq+lYbGgeWDIM=", - "_parent": { - "$ref": "AAAAAAFq+lVubgbqErA=" - }, - "name": "registerObserver" - }, - { - "_type": "UMLOperation", - "_id": "AAAAAAFq+lYmXQecEvk=", - "_parent": { - "$ref": "AAAAAAFq+lVubgbqErA=" - }, - "name": "removeObserver" - }, - { - "_type": "UMLOperation", - "_id": "AAAAAAFq+lYtVgei0fg=", - "_parent": { - "$ref": "AAAAAAFq+lVubgbqErA=" - }, - "name": "notifyObserver" - } - ] - }, - { - "_type": "UMLInterface", - "_id": "AAAAAAFq+lV0fgcTDCw=", - "_parent": { - "$ref": "AAAAAAFq+lKo0gatgnM=" - }, - "name": "Observer", - "operations": [ - { - "_type": "UMLOperation", - "_id": "AAAAAAFq+lY3VAeoa+c=", - "_parent": { - "$ref": "AAAAAAFq+lV0fgcTDCw=" - }, - "name": "update" - } - ] - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+lWAPgc83BA=", - "_parent": { - "$ref": "AAAAAAFq+lKo0gatgnM=" - }, - "name": "ConcreteSubject", - "ownedElements": [ - { - "_type": "UMLInterfaceRealization", - "_id": "AAAAAAFq+lgfygfW2pY=", - "_parent": { - "$ref": "AAAAAAFq+lWAPgc83BA=" - }, - "source": { - "$ref": "AAAAAAFq+lWAPgc83BA=" - }, - "target": { - "$ref": "AAAAAAFq+lVubgbqErA=" - } - } - ], - "operations": [ - { - "_type": "UMLOperation", - "_id": "AAAAAAFq+la6CQe1dnk=", - "_parent": { - "$ref": "AAAAAAFq+lWAPgc83BA=" - }, - "name": "registerObserver" - }, - { - "_type": "UMLOperation", - "_id": "AAAAAAFq+lbAkge7bdo=", - "_parent": { - "$ref": "AAAAAAFq+lWAPgc83BA=" - }, - "name": "removeObserver" - }, - { - "_type": "UMLOperation", - "_id": "AAAAAAFq+lbGJQfBYgA=", - "_parent": { - "$ref": "AAAAAAFq+lWAPgc83BA=" - }, - "name": "notifyObserver" - } - ] - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+lWEuAdlul0=", - "_parent": { - "$ref": "AAAAAAFq+lKo0gatgnM=" - }, - "name": "ConcreteObserver", - "ownedElements": [ - { - "_type": "UMLInterfaceRealization", - "_id": "AAAAAAFq+lgoQgfngnM=", - "_parent": { - "$ref": "AAAAAAFq+lWEuAdlul0=" - }, - "source": { - "$ref": "AAAAAAFq+lWEuAdlul0=" - }, - "target": { - "$ref": "AAAAAAFq+lV0fgcTDCw=" - } - }, - { - "_type": "UMLDependency", - "_id": "AAAAAAFq+lixHwf/X3U=", - "_parent": { - "$ref": "AAAAAAFq+lWEuAdlul0=" - }, - "source": { - "$ref": "AAAAAAFq+lWEuAdlul0=" - }, - "target": { - "$ref": "AAAAAAFq+lWAPgc83BA=" - } - } - ], - "operations": [ - { - "_type": "UMLOperation", - "_id": "AAAAAAFq+lbOHwfHThA=", - "_parent": { - "$ref": "AAAAAAFq+lWEuAdlul0=" - }, - "name": "update" - } - ] - } - ] - }, - { - "_type": "UMLModel", - "_id": "AAAAAAFq+l9WAQgjhFk=", - "_parent": { - "$ref": "AAAAAAFF+h6SjaM2Hec=" - }, - "name": "行为型模式——备忘录模式", - "ownedElements": [ - { - "_type": "UMLClassDiagram", - "_id": "AAAAAAFq+l9WAQgkEOc=", - "_parent": { - "$ref": "AAAAAAFq+l9WAQgjhFk=" - }, - "name": "备忘录模式", - "ownedViews": [ - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+l/ViQhiaRk=", - "_parent": { - "$ref": "AAAAAAFq+l9WAQgkEOc=" - }, - "model": { - "$ref": "AAAAAAFq+l/ViQhg6HU=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+l/ViQhjL78=", - "_parent": { - "$ref": "AAAAAAFq+l/ViQhiaRk=" - }, - "model": { - "$ref": "AAAAAAFq+l/ViQhg6HU=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+l/ViQhknxI=", - "_parent": { - "$ref": "AAAAAAFq+l/ViQhjL78=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -224, - "top": -160, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+l/ViQhl6mA=", - "_parent": { - "$ref": "AAAAAAFq+l/ViQhjL78=" - }, - "font": "Arial;13;1", - "left": 85, - "top": 903, - "width": 183, - "height": 13, - "text": "Originator" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+l/ViQhmz6Q=", - "_parent": { - "$ref": "AAAAAAFq+l/ViQhjL78=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -224, - "top": -160, - "width": 194.27001953125, - "height": 13, - "text": "(from 行为型模式——备忘录模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+l/ViQhnxe4=", - "_parent": { - "$ref": "AAAAAAFq+l/ViQhjL78=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -224, - "top": -160, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 80, - "top": 896, - "width": 193, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+l/ViQhknxI=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+l/ViQhl6mA=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+l/ViQhmz6Q=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+l/ViQhnxe4=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+l/ViQhoxss=", - "_parent": { - "$ref": "AAAAAAFq+l/ViQhiaRk=" - }, - "model": { - "$ref": "AAAAAAFq+l/ViQhg6HU=" - }, - "subViews": [ - { - "_type": "UMLAttributeView", - "_id": "AAAAAAFq+mAq/gjlQXQ=", - "_parent": { - "$ref": "AAAAAAFq+l/ViQhoxss=" - }, - "model": { - "$ref": "AAAAAAFq+mAq1gji7ho=" - }, - "font": "Arial;13;0", - "left": 85, - "top": 926, - "width": 183, - "height": 13, - "text": "+state", - "horizontalAlignment": 0 - } - ], - "font": "Arial;13;0", - "left": 80, - "top": 921, - "width": 193, - "height": 23 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+l/ViQhpJoE=", - "_parent": { - "$ref": "AAAAAAFq+l/ViQhiaRk=" - }, - "model": { - "$ref": "AAAAAAFq+l/ViQhg6HU=" - }, - "subViews": [ - { - "_type": "UMLOperationView", - "_id": "AAAAAAFq+mA2nwjriBo=", - "_parent": { - "$ref": "AAAAAAFq+l/ViQhpJoE=" - }, - "model": { - "$ref": "AAAAAAFq+mA2ewjoO0c=" - }, - "font": "Arial;13;0", - "left": 85, - "top": 949, - "width": 183, - "height": 13, - "text": "+restoreMemento(Memento m)", - "horizontalAlignment": 0 - }, - { - "_type": "UMLOperationView", - "_id": "AAAAAAFq+mA/AAjxXH8=", - "_parent": { - "$ref": "AAAAAAFq+l/ViQhpJoE=" - }, - "model": { - "$ref": "AAAAAAFq+mA+3AjuM5Y=" - }, - "font": "Arial;13;0", - "left": 85, - "top": 964, - "width": 183, - "height": 13, - "text": "+createMemento()", - "horizontalAlignment": 0 - } - ], - "font": "Arial;13;0", - "left": 80, - "top": 944, - "width": 193, - "height": 38 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+l/ViQhqENc=", - "_parent": { - "$ref": "AAAAAAFq+l/ViQhiaRk=" - }, - "model": { - "$ref": "AAAAAAFq+l/ViQhg6HU=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -112, - "top": -80, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+l/ViQhr9u8=", - "_parent": { - "$ref": "AAAAAAFq+l/ViQhiaRk=" - }, - "model": { - "$ref": "AAAAAAFq+l/ViQhg6HU=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -112, - "top": -80, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 80, - "top": 896, - "width": 193, - "height": 97, - "nameCompartment": { - "$ref": "AAAAAAFq+l/ViQhjL78=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+l/ViQhoxss=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+l/ViQhpJoE=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+l/ViQhqENc=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+l/ViQhr9u8=" - } - }, - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+l/k2giMJRc=", - "_parent": { - "$ref": "AAAAAAFq+l9WAQgkEOc=" - }, - "model": { - "$ref": "AAAAAAFq+l/k2giKtgc=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+l/k2giNzFM=", - "_parent": { - "$ref": "AAAAAAFq+l/k2giMJRc=" - }, - "model": { - "$ref": "AAAAAAFq+l/k2giKtgc=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+l/k2giO2eI=", - "_parent": { - "$ref": "AAAAAAFq+l/k2giNzFM=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -160, - "top": -144, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+l/k2giPP/Q=", - "_parent": { - "$ref": "AAAAAAFq+l/k2giNzFM=" - }, - "font": "Arial;13;1", - "left": 421, - "top": 903, - "width": 135, - "height": 13, - "text": "getState" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+l/k2giQ+Vs=", - "_parent": { - "$ref": "AAAAAAFq+l/k2giNzFM=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -160, - "top": -144, - "width": 194.27001953125, - "height": 13, - "text": "(from 行为型模式——备忘录模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+l/k2giR34M=", - "_parent": { - "$ref": "AAAAAAFq+l/k2giNzFM=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -160, - "top": -144, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 416, - "top": 896, - "width": 145, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+l/k2giO2eI=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+l/k2giPP/Q=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+l/k2giQ+Vs=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+l/k2giR34M=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+l/k2giStjU=", - "_parent": { - "$ref": "AAAAAAFq+l/k2giMJRc=" - }, - "model": { - "$ref": "AAAAAAFq+l/k2giKtgc=" - }, - "subViews": [ - { - "_type": "UMLAttributeView", - "_id": "AAAAAAFq+mBG/Aj3h4E=", - "_parent": { - "$ref": "AAAAAAFq+l/k2giStjU=" - }, - "model": { - "$ref": "AAAAAAFq+mBG2Qj0xqE=" - }, - "font": "Arial;13;0", - "left": 421, - "top": 926, - "width": 135, - "height": 13, - "text": "+state", - "horizontalAlignment": 0 - } - ], - "font": "Arial;13;0", - "left": 416, - "top": 921, - "width": 145, - "height": 23 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+l/k2giTmrU=", - "_parent": { - "$ref": "AAAAAAFq+l/k2giMJRc=" - }, - "model": { - "$ref": "AAAAAAFq+l/k2giKtgc=" - }, - "subViews": [ - { - "_type": "UMLOperationView", - "_id": "AAAAAAFq+mBOQQj9Wqo=", - "_parent": { - "$ref": "AAAAAAFq+l/k2giTmrU=" - }, - "model": { - "$ref": "AAAAAAFq+mBOGQj6qr4=" - }, - "font": "Arial;13;0", - "left": 421, - "top": 949, - "width": 135, - "height": 13, - "text": "+getState()", - "horizontalAlignment": 0 - }, - { - "_type": "UMLOperationView", - "_id": "AAAAAAFq+mBWgQkDzKM=", - "_parent": { - "$ref": "AAAAAAFq+l/k2giTmrU=" - }, - "model": { - "$ref": "AAAAAAFq+mBWXQkAm0c=" - }, - "font": "Arial;13;0", - "left": 421, - "top": 964, - "width": 135, - "height": 13, - "text": "+setState(state)", - "horizontalAlignment": 0 - } - ], - "font": "Arial;13;0", - "left": 416, - "top": 944, - "width": 145, - "height": 38 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+l/k2giUU5Q=", - "_parent": { - "$ref": "AAAAAAFq+l/k2giMJRc=" - }, - "model": { - "$ref": "AAAAAAFq+l/k2giKtgc=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -80, - "top": -72, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+l/k2giVEmA=", - "_parent": { - "$ref": "AAAAAAFq+l/k2giMJRc=" - }, - "model": { - "$ref": "AAAAAAFq+l/k2giKtgc=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -80, - "top": -72, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 416, - "top": 896, - "width": 145, - "height": 97, - "nameCompartment": { - "$ref": "AAAAAAFq+l/k2giNzFM=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+l/k2giStjU=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+l/k2giTmrU=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+l/k2giUU5Q=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+l/k2giVEmA=" - } - }, - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+l/pdQi18yk=", - "_parent": { - "$ref": "AAAAAAFq+l9WAQgkEOc=" - }, - "model": { - "$ref": "AAAAAAFq+l/pdQizb28=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+l/pdgi2XLQ=", - "_parent": { - "$ref": "AAAAAAFq+l/pdQi18yk=" - }, - "model": { - "$ref": "AAAAAAFq+l/pdQizb28=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+l/pdgi3z9k=", - "_parent": { - "$ref": "AAAAAAFq+l/pdgi2XLQ=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -288, - "top": -112, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+l/pdgi4FFA=", - "_parent": { - "$ref": "AAAAAAFq+l/pdgi2XLQ=" - }, - "font": "Arial;13;1", - "left": 437, - "top": 1095, - "width": 103, - "height": 13, - "text": "Caretaker" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+l/pdgi5HSs=", - "_parent": { - "$ref": "AAAAAAFq+l/pdgi2XLQ=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -288, - "top": -112, - "width": 194.27001953125, - "height": 13, - "text": "(from 行为型模式——备忘录模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+l/pdgi6gW8=", - "_parent": { - "$ref": "AAAAAAFq+l/pdgi2XLQ=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -288, - "top": -112, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 432, - "top": 1088, - "width": 113, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+l/pdgi3z9k=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+l/pdgi4FFA=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+l/pdgi5HSs=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+l/pdgi6gW8=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+l/pdgi7CGI=", - "_parent": { - "$ref": "AAAAAAFq+l/pdQi18yk=" - }, - "model": { - "$ref": "AAAAAAFq+l/pdQizb28=" - }, - "font": "Arial;13;0", - "left": 432, - "top": 1113, - "width": 113, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+l/pdgi8k5Q=", - "_parent": { - "$ref": "AAAAAAFq+l/pdQi18yk=" - }, - "model": { - "$ref": "AAAAAAFq+l/pdQizb28=" - }, - "font": "Arial;13;0", - "left": 432, - "top": 1123, - "width": 113, - "height": 10 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+l/pdgi95RI=", - "_parent": { - "$ref": "AAAAAAFq+l/pdQi18yk=" - }, - "model": { - "$ref": "AAAAAAFq+l/pdQizb28=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -144, - "top": -56, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+l/pdgi+ol8=", - "_parent": { - "$ref": "AAAAAAFq+l/pdQi18yk=" - }, - "model": { - "$ref": "AAAAAAFq+l/pdQizb28=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -144, - "top": -56, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 432, - "top": 1088, - "width": 113, - "height": 49, - "nameCompartment": { - "$ref": "AAAAAAFq+l/pdgi2XLQ=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+l/pdgi7CGI=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+l/pdgi8k5Q=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+l/pdgi95RI=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+l/pdgi+ol8=" - } - }, - { - "_type": "UMLAssociationView", - "_id": "AAAAAAFq+mIIVwkasts=", - "_parent": { - "$ref": "AAAAAAFq+l9WAQgkEOc=" - }, - "model": { - "$ref": "AAAAAAFq+mIIVwkWX6I=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+mIIVwkb+OY=", - "_parent": { - "$ref": "AAAAAAFq+mIIVwkasts=" - }, - "model": { - "$ref": "AAAAAAFq+mIIVwkWX6I=" - }, - "font": "Arial;13;0", - "left": 408, - "top": 1048, - "width": 61.78173828125, - "height": 13, - "alpha": -4.439380012603229, - "distance": 51.92301994298868, - "hostEdge": { - "$ref": "AAAAAAFq+mIIVwkasts=" - }, - "edgePosition": 1, - "text": "+memento" - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+mIIVwkc2EU=", - "_parent": { - "$ref": "AAAAAAFq+mIIVwkasts=" - }, - "model": { - "$ref": "AAAAAAFq+mIIVwkWX6I=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 458, - "top": 1033, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+mIIVwkasts=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+mIIVwkd8f0=", - "_parent": { - "$ref": "AAAAAAFq+mIIVwkasts=" - }, - "model": { - "$ref": "AAAAAAFq+mIIVwkWX6I=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 502, - "top": 1034, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+mIIVwkasts=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+mIIVwkeWrI=", - "_parent": { - "$ref": "AAAAAAFq+mIIVwkasts=" - }, - "model": { - "$ref": "AAAAAAFq+mIIVwkXOro=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 473, - "top": 1055, - "height": 13, - "alpha": 0.5235987755982988, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+mIIVwkasts=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+mIIVwkf1VE=", - "_parent": { - "$ref": "AAAAAAFq+mIIVwkasts=" - }, - "model": { - "$ref": "AAAAAAFq+mIIVwkXOro=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 459, - "top": 1052, - "height": 13, - "alpha": 0.7853981633974483, - "distance": 40, - "hostEdge": { - "$ref": "AAAAAAFq+mIIVwkasts=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+mIIVwkg6cI=", - "_parent": { - "$ref": "AAAAAAFq+mIIVwkasts=" - }, - "model": { - "$ref": "AAAAAAFq+mIIVwkXOro=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 500, - "top": 1059, - "height": 13, - "alpha": -0.5235987755982988, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFq+mIIVwkasts=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+mIIVwkhY5k=", - "_parent": { - "$ref": "AAAAAAFq+mIIVwkasts=" - }, - "model": { - "$ref": "AAAAAAFq+mIIVwkYDDg=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 473, - "top": 1012, - "height": 13, - "alpha": -0.5235987755982988, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+mIIVwkasts=" - } - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+mIIWAkijHs=", - "_parent": { - "$ref": "AAAAAAFq+mIIVwkasts=" - }, - "model": { - "$ref": "AAAAAAFq+mIIVwkYDDg=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 459, - "top": 1015, - "height": 13, - "alpha": -0.7853981633974483, - "distance": 40, - "hostEdge": { - "$ref": "AAAAAAFq+mIIVwkasts=" - } - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+mIIWAkjya0=", - "_parent": { - "$ref": "AAAAAAFq+mIIVwkasts=" - }, - "model": { - "$ref": "AAAAAAFq+mIIVwkYDDg=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 500, - "top": 1008, - "height": 13, - "alpha": 0.5235987755982988, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFq+mIIVwkasts=" - } - }, - { - "_type": "UMLQualifierCompartmentView", - "_id": "AAAAAAFq+mIIWAkkjwc=", - "_parent": { - "$ref": "AAAAAAFq+mIIVwkasts=" - }, - "model": { - "$ref": "AAAAAAFq+mIIVwkXOro=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 32, - "width": 10, - "height": 10 - }, - { - "_type": "UMLQualifierCompartmentView", - "_id": "AAAAAAFq+mIIWAkl9s8=", - "_parent": { - "$ref": "AAAAAAFq+mIIVwkasts=" - }, - "model": { - "$ref": "AAAAAAFq+mIIVwkYDDg=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 32, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+l/k2giMJRc=" - }, - "tail": { - "$ref": "AAAAAAFq+l/pdQi18yk=" - }, - "lineStyle": 1, - "points": "488:1087;488:993", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+mIIVwkb+OY=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+mIIVwkc2EU=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+mIIVwkd8f0=" - }, - "tailRoleNameLabel": { - "$ref": "AAAAAAFq+mIIVwkeWrI=" - }, - "tailPropertyLabel": { - "$ref": "AAAAAAFq+mIIVwkf1VE=" - }, - "tailMultiplicityLabel": { - "$ref": "AAAAAAFq+mIIVwkg6cI=" - }, - "headRoleNameLabel": { - "$ref": "AAAAAAFq+mIIVwkhY5k=" - }, - "headPropertyLabel": { - "$ref": "AAAAAAFq+mIIWAkijHs=" - }, - "headMultiplicityLabel": { - "$ref": "AAAAAAFq+mIIWAkjya0=" - }, - "tailQualifiersCompartment": { - "$ref": "AAAAAAFq+mIIWAkkjwc=" - }, - "headQualifiersCompartment": { - "$ref": "AAAAAAFq+mIIWAkl9s8=" - } - }, - { - "_type": "UMLDependencyView", - "_id": "AAAAAAFq+mLJXAoUlQ4=", - "_parent": { - "$ref": "AAAAAAFq+l9WAQgkEOc=" - }, - "model": { - "$ref": "AAAAAAFq+mLJWwoSpvc=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+mLJXAoVk4g=", - "_parent": { - "$ref": "AAAAAAFq+mLJXAoUlQ4=" - }, - "model": { - "$ref": "AAAAAAFq+mLJWwoSpvc=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 344, - "top": 923, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+mLJXAoUlQ4=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+mLJXAoWFJs=", - "_parent": { - "$ref": "AAAAAAFq+mLJXAoUlQ4=" - }, - "model": { - "$ref": "AAAAAAFq+mLJWwoSpvc=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 344, - "top": 908, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+mLJXAoUlQ4=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+mLJXAoXo4U=", - "_parent": { - "$ref": "AAAAAAFq+mLJXAoUlQ4=" - }, - "model": { - "$ref": "AAAAAAFq+mLJWwoSpvc=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 344, - "top": 953, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+mLJXAoUlQ4=" - }, - "edgePosition": 1 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+l/k2giMJRc=" - }, - "tail": { - "$ref": "AAAAAAFq+l/ViQhiaRk=" - }, - "lineStyle": 1, - "points": "273:944;415:944", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+mLJXAoVk4g=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+mLJXAoWFJs=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+mLJXAoXo4U=" - } - }, - { - "_type": "UMLNoteView", - "_id": "AAAAAAFq+mLgfQoy5Yg=", - "_parent": { - "$ref": "AAAAAAFq+l9WAQgkEOc=" - }, - "font": "Arial;13;0", - "left": 16, - "top": 1056, - "width": 201, - "height": 33, - "text": "return new Memento(state);" - }, - { - "_type": "UMLNoteView", - "_id": "AAAAAAFq+mOxxgqN3Oo=", - "_parent": { - "$ref": "AAAAAAFq+l9WAQgkEOc=" - }, - "font": "Arial;13;0", - "left": 240, - "top": 1056, - "width": 145, - "height": 33, - "text": "state=m.getState();" - }, - { - "_type": "UMLNoteLinkView", - "_id": "AAAAAAFq+mQbWAryVQw=", - "_parent": { - "$ref": "AAAAAAFq+l9WAQgkEOc=" - }, - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+mLgfQoy5Yg=" - }, - "tail": { - "$ref": "AAAAAAFq+l/ViQhiaRk=" - }, - "lineStyle": 1, - "points": "153:993;124:1055" - }, - { - "_type": "UMLNoteLinkView", - "_id": "AAAAAAFq+mQkhgr4zxc=", - "_parent": { - "$ref": "AAAAAAFq+l9WAQgkEOc=" - }, - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+mOxxgqN3Oo=" - }, - "tail": { - "$ref": "AAAAAAFq+l/ViQhiaRk=" - }, - "lineStyle": 1, - "points": "228:993;294:1055" - } - ] - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+l/ViQhg6HU=", - "_parent": { - "$ref": "AAAAAAFq+l9WAQgjhFk=" - }, - "name": "Originator", - "ownedElements": [ - { - "_type": "UMLDependency", - "_id": "AAAAAAFq+mLJWwoSpvc=", - "_parent": { - "$ref": "AAAAAAFq+l/ViQhg6HU=" - }, - "source": { - "$ref": "AAAAAAFq+l/ViQhg6HU=" - }, - "target": { - "$ref": "AAAAAAFq+l/k2giKtgc=" - } - } - ], - "attributes": [ - { - "_type": "UMLAttribute", - "_id": "AAAAAAFq+mAq1gji7ho=", - "_parent": { - "$ref": "AAAAAAFq+l/ViQhg6HU=" - }, - "name": "state", - "type": "" - } - ], - "operations": [ - { - "_type": "UMLOperation", - "_id": "AAAAAAFq+mA2ewjoO0c=", - "_parent": { - "$ref": "AAAAAAFq+l/ViQhg6HU=" - }, - "name": "restoreMemento", - "parameters": [ - { - "_type": "UMLParameter", - "_id": "AAAAAAFq+mDmwQkI5HY=", - "_parent": { - "$ref": "AAAAAAFq+mA2ewjoO0c=" - }, - "name": "Memento m" - } - ] - }, - { - "_type": "UMLOperation", - "_id": "AAAAAAFq+mA+3AjuM5Y=", - "_parent": { - "$ref": "AAAAAAFq+l/ViQhg6HU=" - }, - "name": "createMemento" - } - ] - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+l/k2giKtgc=", - "_parent": { - "$ref": "AAAAAAFq+l9WAQgjhFk=" - }, - "name": "getState", - "attributes": [ - { - "_type": "UMLAttribute", - "_id": "AAAAAAFq+mBG2Qj0xqE=", - "_parent": { - "$ref": "AAAAAAFq+l/k2giKtgc=" - }, - "name": "state", - "type": "" - } - ], - "operations": [ - { - "_type": "UMLOperation", - "_id": "AAAAAAFq+mBOGQj6qr4=", - "_parent": { - "$ref": "AAAAAAFq+l/k2giKtgc=" - }, - "name": "getState" - }, - { - "_type": "UMLOperation", - "_id": "AAAAAAFq+mBWXQkAm0c=", - "_parent": { - "$ref": "AAAAAAFq+l/k2giKtgc=" - }, - "name": "setState", - "parameters": [ - { - "_type": "UMLParameter", - "_id": "AAAAAAFq+mG88QkRA5c=", - "_parent": { - "$ref": "AAAAAAFq+mBWXQkAm0c=" - }, - "name": "state" - } - ] - } - ] - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+l/pdQizb28=", - "_parent": { - "$ref": "AAAAAAFq+l9WAQgjhFk=" - }, - "name": "Caretaker", - "ownedElements": [ - { - "_type": "UMLAssociation", - "_id": "AAAAAAFq+mIIVwkWX6I=", - "_parent": { - "$ref": "AAAAAAFq+l/pdQizb28=" - }, - "name": "memento", - "end1": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFq+mIIVwkXOro=", - "_parent": { - "$ref": "AAAAAAFq+mIIVwkWX6I=" - }, - "reference": { - "$ref": "AAAAAAFq+l/pdQizb28=" - }, - "navigable": false, - "aggregation": "shared" - }, - "end2": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFq+mIIVwkYDDg=", - "_parent": { - "$ref": "AAAAAAFq+mIIVwkWX6I=" - }, - "reference": { - "$ref": "AAAAAAFq+l/k2giKtgc=" - } - } - } - ] - } - ] - }, - { - "_type": "UMLModel", - "_id": "AAAAAAFq+macVAs29Xg=", - "_parent": { - "$ref": "AAAAAAFF+h6SjaM2Hec=" - }, - "name": "行为型模式——命令模式", - "ownedElements": [ - { - "_type": "UMLClassDiagram", - "_id": "AAAAAAFq+macVQs3dSk=", - "_parent": { - "$ref": "AAAAAAFq+macVAs29Xg=" - }, - "name": "命令模式", - "ownedViews": [ - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+mbXngt7YF8=", - "_parent": { - "$ref": "AAAAAAFq+macVQs3dSk=" - }, - "model": { - "$ref": "AAAAAAFq+mbXngt5jIw=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+mbXngt8a9k=", - "_parent": { - "$ref": "AAAAAAFq+mbXngt7YF8=" - }, - "model": { - "$ref": "AAAAAAFq+mbXngt5jIw=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+mbXngt9mOc=", - "_parent": { - "$ref": "AAAAAAFq+mbXngt8a9k=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -176, - "top": -48, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+mbXngt+Soc=", - "_parent": { - "$ref": "AAAAAAFq+mbXngt8a9k=" - }, - "font": "Arial;13;1", - "left": 77, - "top": 775, - "width": 63, - "height": 13, - "text": "Client" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+mbXngt/d9Y=", - "_parent": { - "$ref": "AAAAAAFq+mbXngt8a9k=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -176, - "top": -48, - "width": 181.27001953125, - "height": 13, - "text": "(from 行为型模式——命令模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+mbXnguAQOI=", - "_parent": { - "$ref": "AAAAAAFq+mbXngt8a9k=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -176, - "top": -48, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 72, - "top": 768, - "width": 73, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+mbXngt9mOc=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+mbXngt+Soc=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+mbXngt/d9Y=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+mbXnguAQOI=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+mbXnguBGC4=", - "_parent": { - "$ref": "AAAAAAFq+mbXngt7YF8=" - }, - "model": { - "$ref": "AAAAAAFq+mbXngt5jIw=" - }, - "font": "Arial;13;0", - "left": 72, - "top": 793, - "width": 73, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+mbXnguCI2Y=", - "_parent": { - "$ref": "AAAAAAFq+mbXngt7YF8=" - }, - "model": { - "$ref": "AAAAAAFq+mbXngt5jIw=" - }, - "font": "Arial;13;0", - "left": 72, - "top": 803, - "width": 73, - "height": 10 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+mbXnguDQUk=", - "_parent": { - "$ref": "AAAAAAFq+mbXngt7YF8=" - }, - "model": { - "$ref": "AAAAAAFq+mbXngt5jIw=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -88, - "top": -24, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+mbXnguE9i0=", - "_parent": { - "$ref": "AAAAAAFq+mbXngt7YF8=" - }, - "model": { - "$ref": "AAAAAAFq+mbXngt5jIw=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -88, - "top": -24, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 72, - "top": 768, - "width": 73, - "height": 65, - "nameCompartment": { - "$ref": "AAAAAAFq+mbXngt8a9k=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+mbXnguBGC4=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+mbXnguCI2Y=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+mbXnguDQUk=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+mbXnguE9i0=" - } - }, - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+mbc+wukVW0=", - "_parent": { - "$ref": "AAAAAAFq+macVQs3dSk=" - }, - "model": { - "$ref": "AAAAAAFq+mbc+wuiaG4=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+mbc+wulxE0=", - "_parent": { - "$ref": "AAAAAAFq+mbc+wukVW0=" - }, - "model": { - "$ref": "AAAAAAFq+mbc+wuiaG4=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+mbc+wumt/Y=", - "_parent": { - "$ref": "AAAAAAFq+mbc+wulxE0=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -288, - "top": -80, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+mbc+wun3jM=", - "_parent": { - "$ref": "AAAAAAFq+mbc+wulxE0=" - }, - "font": "Arial;13;1", - "left": 229, - "top": 775, - "width": 71, - "height": 13, - "text": "Invoker" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+mbc+wuoAMI=", - "_parent": { - "$ref": "AAAAAAFq+mbc+wulxE0=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -288, - "top": -80, - "width": 181.27001953125, - "height": 13, - "text": "(from 行为型模式——命令模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+mbc+wupXcQ=", - "_parent": { - "$ref": "AAAAAAFq+mbc+wulxE0=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -288, - "top": -80, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 224, - "top": 768, - "width": 81, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+mbc+wumt/Y=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+mbc+wun3jM=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+mbc+wuoAMI=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+mbc+wupXcQ=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+mbc+wuqOKo=", - "_parent": { - "$ref": "AAAAAAFq+mbc+wukVW0=" - }, - "model": { - "$ref": "AAAAAAFq+mbc+wuiaG4=" - }, - "font": "Arial;13;0", - "left": 224, - "top": 793, - "width": 81, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+mbc+wurGXk=", - "_parent": { - "$ref": "AAAAAAFq+mbc+wukVW0=" - }, - "model": { - "$ref": "AAAAAAFq+mbc+wuiaG4=" - }, - "font": "Arial;13;0", - "left": 224, - "top": 803, - "width": 81, - "height": 10 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+mbc+wusgG8=", - "_parent": { - "$ref": "AAAAAAFq+mbc+wukVW0=" - }, - "model": { - "$ref": "AAAAAAFq+mbc+wuiaG4=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -144, - "top": -40, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+mbc+wutGP8=", - "_parent": { - "$ref": "AAAAAAFq+mbc+wukVW0=" - }, - "model": { - "$ref": "AAAAAAFq+mbc+wuiaG4=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -144, - "top": -40, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 224, - "top": 768, - "width": 81, - "height": 65, - "nameCompartment": { - "$ref": "AAAAAAFq+mbc+wulxE0=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+mbc+wuqOKo=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+mbc+wurGXk=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+mbc+wusgG8=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+mbc+wutGP8=" - } - }, - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+mbhvQvNubw=", - "_parent": { - "$ref": "AAAAAAFq+macVQs3dSk=" - }, - "model": { - "$ref": "AAAAAAFq+mbhvQvL3v4=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+mbhvQvOvAs=", - "_parent": { - "$ref": "AAAAAAFq+mbhvQvNubw=" - }, - "model": { - "$ref": "AAAAAAFq+mbhvQvL3v4=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+mbhvQvPByM=", - "_parent": { - "$ref": "AAAAAAFq+mbhvQvOvAs=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -128, - "top": -16, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+mbhvQvQ3sY=", - "_parent": { - "$ref": "AAAAAAFq+mbhvQvOvAs=" - }, - "font": "Arial;13;1", - "left": 133, - "top": 951, - "width": 95, - "height": 13, - "text": "Receiver" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+mbhvQvRJ1U=", - "_parent": { - "$ref": "AAAAAAFq+mbhvQvOvAs=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -128, - "top": -16, - "width": 181.27001953125, - "height": 13, - "text": "(from 行为型模式——命令模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+mbhvQvSHpc=", - "_parent": { - "$ref": "AAAAAAFq+mbhvQvOvAs=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -128, - "top": -16, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 128, - "top": 944, - "width": 105, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+mbhvQvPByM=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+mbhvQvQ3sY=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+mbhvQvRJ1U=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+mbhvQvSHpc=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+mbhvQvT+iU=", - "_parent": { - "$ref": "AAAAAAFq+mbhvQvNubw=" - }, - "model": { - "$ref": "AAAAAAFq+mbhvQvL3v4=" - }, - "font": "Arial;13;0", - "left": 128, - "top": 969, - "width": 105, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+mbhvQvU5mc=", - "_parent": { - "$ref": "AAAAAAFq+mbhvQvNubw=" - }, - "model": { - "$ref": "AAAAAAFq+mbhvQvL3v4=" - }, - "subViews": [ - { - "_type": "UMLOperationView", - "_id": "AAAAAAFq+mkPHQy9zok=", - "_parent": { - "$ref": "AAAAAAFq+mbhvQvU5mc=" - }, - "model": { - "$ref": "AAAAAAFq+mkO9wy6QRw=" - }, - "font": "Arial;13;0", - "left": 133, - "top": 984, - "width": 95, - "height": 13, - "text": "+Action()", - "horizontalAlignment": 0 - } - ], - "font": "Arial;13;0", - "left": 128, - "top": 979, - "width": 105, - "height": 23 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+mbhvQvVUao=", - "_parent": { - "$ref": "AAAAAAFq+mbhvQvNubw=" - }, - "model": { - "$ref": "AAAAAAFq+mbhvQvL3v4=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -64, - "top": -8, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+mbhvQvWrsk=", - "_parent": { - "$ref": "AAAAAAFq+mbhvQvNubw=" - }, - "model": { - "$ref": "AAAAAAFq+mbhvQvL3v4=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -64, - "top": -8, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 128, - "top": 944, - "width": 105, - "height": 65, - "nameCompartment": { - "$ref": "AAAAAAFq+mbhvQvOvAs=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+mbhvQvT+iU=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+mbhvQvU5mc=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+mbhvQvVUao=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+mbhvQvWrsk=" - } - }, - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+mbrsAwfkvU=", - "_parent": { - "$ref": "AAAAAAFq+macVQs3dSk=" - }, - "model": { - "$ref": "AAAAAAFq+mbrsAwdnRI=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+mbrsAwg8fE=", - "_parent": { - "$ref": "AAAAAAFq+mbrsAwfkvU=" - }, - "model": { - "$ref": "AAAAAAFq+mbrsAwdnRI=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+mbrsQwh89w=", - "_parent": { - "$ref": "AAAAAAFq+mbrsAwg8fE=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -480, - "top": -80, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+mbrsQwirKA=", - "_parent": { - "$ref": "AAAAAAFq+mbrsAwg8fE=" - }, - "font": "Arial;13;1", - "left": 373, - "top": 951, - "width": 119.9072265625, - "height": 13, - "text": "ConcreteCommand" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+mbrsQwjXKU=", - "_parent": { - "$ref": "AAAAAAFq+mbrsAwg8fE=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -480, - "top": -80, - "width": 181.27001953125, - "height": 13, - "text": "(from 行为型模式——命令模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+mbrsQwk3/I=", - "_parent": { - "$ref": "AAAAAAFq+mbrsAwg8fE=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -480, - "top": -80, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 368, - "top": 944, - "width": 129.9072265625, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+mbrsQwh89w=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+mbrsQwirKA=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+mbrsQwjXKU=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+mbrsQwk3/I=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+mbrsQwleX8=", - "_parent": { - "$ref": "AAAAAAFq+mbrsAwfkvU=" - }, - "model": { - "$ref": "AAAAAAFq+mbrsAwdnRI=" - }, - "subViews": [ - { - "_type": "UMLAttributeView", - "_id": "AAAAAAFq+mizFAy1//M=", - "_parent": { - "$ref": "AAAAAAFq+mbrsQwleX8=" - }, - "model": { - "$ref": "AAAAAAFq+miy7gyy148=" - }, - "font": "Arial;13;0", - "left": 373, - "top": 974, - "width": 119.9072265625, - "height": 13, - "text": "+receiver: Receiver", - "horizontalAlignment": 0 - } - ], - "font": "Arial;13;0", - "left": 368, - "top": 969, - "width": 129.9072265625, - "height": 23 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+mbrsQwmCtM=", - "_parent": { - "$ref": "AAAAAAFq+mbrsAwfkvU=" - }, - "model": { - "$ref": "AAAAAAFq+mbrsAwdnRI=" - }, - "subViews": [ - { - "_type": "UMLOperationView", - "_id": "AAAAAAFq+moLeA4fcfw=", - "_parent": { - "$ref": "AAAAAAFq+mbrsQwmCtM=" - }, - "model": { - "$ref": "AAAAAAFq+moLUw4cvXA=" - }, - "font": "Arial;13;0", - "left": 373, - "top": 997, - "width": 119.9072265625, - "height": 13, - "text": "+Excute()", - "horizontalAlignment": 0 - } - ], - "font": "Arial;13;0", - "left": 368, - "top": 992, - "width": 129.9072265625, - "height": 23 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+mbrsQwnXkM=", - "_parent": { - "$ref": "AAAAAAFq+mbrsAwfkvU=" - }, - "model": { - "$ref": "AAAAAAFq+mbrsAwdnRI=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -240, - "top": -40, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+mbrsQwo0ns=", - "_parent": { - "$ref": "AAAAAAFq+mbrsAwfkvU=" - }, - "model": { - "$ref": "AAAAAAFq+mbrsAwdnRI=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -240, - "top": -40, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 368, - "top": 944, - "width": 129.9072265625, - "height": 71, - "nameCompartment": { - "$ref": "AAAAAAFq+mbrsAwg8fE=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+mbrsQwleX8=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+mbrsQwmCtM=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+mbrsQwnXkM=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+mbrsQwo0ns=" - } - }, - { - "_type": "UMLInterfaceView", - "_id": "AAAAAAFq+md4dAxt/ic=", - "_parent": { - "$ref": "AAAAAAFq+macVQs3dSk=" - }, - "model": { - "$ref": "AAAAAAFq+md4dAxrM1U=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+md4dAxuKvs=", - "_parent": { - "$ref": "AAAAAAFq+md4dAxt/ic=" - }, - "model": { - "$ref": "AAAAAAFq+md4dAxrM1U=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+md4dAxvyJM=", - "_parent": { - "$ref": "AAAAAAFq+md4dAxuKvs=" - }, - "font": "Arial;13;0", - "left": 405, - "top": 773, - "width": 64.32080078125, - "height": 13, - "text": "«interface»" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+md4dAxw1SE=", - "_parent": { - "$ref": "AAAAAAFq+md4dAxuKvs=" - }, - "font": "Arial;13;1", - "left": 405, - "top": 788, - "width": 64.32080078125, - "height": 13, - "text": "Command" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+md4dAxxL+w=", - "_parent": { - "$ref": "AAAAAAFq+md4dAxuKvs=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -64, - "top": 16, - "width": 181.27001953125, - "height": 13, - "text": "(from 行为型模式——命令模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+md4dAxyW3U=", - "_parent": { - "$ref": "AAAAAAFq+md4dAxuKvs=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -64, - "top": 16, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 400, - "top": 768, - "width": 74.32080078125, - "height": 38, - "stereotypeLabel": { - "$ref": "AAAAAAFq+md4dAxvyJM=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+md4dAxw1SE=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+md4dAxxL+w=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+md4dAxyW3U=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+md4dAxzLrg=", - "_parent": { - "$ref": "AAAAAAFq+md4dAxt/ic=" - }, - "model": { - "$ref": "AAAAAAFq+md4dAxrM1U=" - }, - "font": "Arial;13;0", - "left": 400, - "top": 806, - "width": 74.32080078125, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+md4dAx0i2c=", - "_parent": { - "$ref": "AAAAAAFq+md4dAxt/ic=" - }, - "model": { - "$ref": "AAAAAAFq+md4dAxrM1U=" - }, - "subViews": [ - { - "_type": "UMLOperationView", - "_id": "AAAAAAFq+mesMAycy48=", - "_parent": { - "$ref": "AAAAAAFq+md4dAx0i2c=" - }, - "model": { - "$ref": "AAAAAAFq+mesBwyZY7w=" - }, - "font": "Arial;13;2", - "left": 405, - "top": 821, - "width": 64.32080078125, - "height": 13, - "text": "+Excute()", - "horizontalAlignment": 0 - } - ], - "font": "Arial;13;0", - "left": 400, - "top": 816, - "width": 74.32080078125, - "height": 23 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+md4dAx1Ib4=", - "_parent": { - "$ref": "AAAAAAFq+md4dAxt/ic=" - }, - "model": { - "$ref": "AAAAAAFq+md4dAxrM1U=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -32, - "top": 8, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+md4dAx2iR4=", - "_parent": { - "$ref": "AAAAAAFq+md4dAxt/ic=" - }, - "model": { - "$ref": "AAAAAAFq+md4dAxrM1U=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -32, - "top": 8, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 400, - "top": 768, - "width": 74.32080078125, - "height": 71, - "autoResize": true, - "nameCompartment": { - "$ref": "AAAAAAFq+md4dAxuKvs=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+md4dAxzLrg=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+md4dAx0i2c=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+md4dAx1Ib4=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+md4dAx2iR4=" - } - }, - { - "_type": "UMLDependencyView", - "_id": "AAAAAAFq+mlO2gzDS4k=", - "_parent": { - "$ref": "AAAAAAFq+macVQs3dSk=" - }, - "model": { - "$ref": "AAAAAAFq+mlO2QzB3o4=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+mlO2gzETIU=", - "_parent": { - "$ref": "AAAAAAFq+mlO2gzDS4k=" - }, - "model": { - "$ref": "AAAAAAFq+mlO2QzB3o4=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 184, - "top": 779, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+mlO2gzDS4k=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+mlO2gzFfF8=", - "_parent": { - "$ref": "AAAAAAFq+mlO2gzDS4k=" - }, - "model": { - "$ref": "AAAAAAFq+mlO2QzB3o4=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 184, - "top": 764, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+mlO2gzDS4k=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+mlO2gzGfRk=", - "_parent": { - "$ref": "AAAAAAFq+mlO2gzDS4k=" - }, - "model": { - "$ref": "AAAAAAFq+mlO2QzB3o4=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 184, - "top": 809, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+mlO2gzDS4k=" - }, - "edgePosition": 1 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+mbc+wukVW0=" - }, - "tail": { - "$ref": "AAAAAAFq+mbXngt7YF8=" - }, - "lineStyle": 1, - "points": "145:800;223:800", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+mlO2gzETIU=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+mlO2gzFfF8=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+mlO2gzGfRk=" - } - }, - { - "_type": "UMLDependencyView", - "_id": "AAAAAAFq+mlZvgzUXiE=", - "_parent": { - "$ref": "AAAAAAFq+macVQs3dSk=" - }, - "model": { - "$ref": "AAAAAAFq+mlZvgzSjnU=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+mlZvgzVGms=", - "_parent": { - "$ref": "AAAAAAFq+mlZvgzUXiE=" - }, - "model": { - "$ref": "AAAAAAFq+mlZvgzSjnU=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 80, - "top": 955, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+mlZvgzUXiE=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+mlZvgzWcFk=", - "_parent": { - "$ref": "AAAAAAFq+mlZvgzUXiE=" - }, - "model": { - "$ref": "AAAAAAFq+mlZvgzSjnU=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 80, - "top": 940, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+mlZvgzUXiE=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+mlZvgzX1U0=", - "_parent": { - "$ref": "AAAAAAFq+mlZvgzUXiE=" - }, - "model": { - "$ref": "AAAAAAFq+mlZvgzSjnU=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 80, - "top": 985, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+mlZvgzUXiE=" - }, - "edgePosition": 1 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+mbhvQvNubw=" - }, - "tail": { - "$ref": "AAAAAAFq+mbXngt7YF8=" - }, - "points": "80:832;80:976;128:976", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+mlZvgzVGms=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+mlZvgzWcFk=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+mlZvgzX1U0=" - } - }, - { - "_type": "UMLAssociationView", - "_id": "AAAAAAFq+mmNBAznJt4=", - "_parent": { - "$ref": "AAAAAAFq+macVQs3dSk=" - }, - "model": { - "$ref": "AAAAAAFq+mmNBAzjXws=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+mmNBAzolyE=", - "_parent": { - "$ref": "AAAAAAFq+mmNBAznJt4=" - }, - "model": { - "$ref": "AAAAAAFq+mmNBAzjXws=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 352, - "top": 780, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+mmNBAznJt4=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+mmNBAzpbaw=", - "_parent": { - "$ref": "AAAAAAFq+mmNBAznJt4=" - }, - "model": { - "$ref": "AAAAAAFq+mmNBAzjXws=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 352, - "top": 765, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+mmNBAznJt4=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+mmNBAzqXbU=", - "_parent": { - "$ref": "AAAAAAFq+mmNBAznJt4=" - }, - "model": { - "$ref": "AAAAAAFq+mmNBAzjXws=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 351, - "top": 809, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+mmNBAznJt4=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+mmNBQzrS6s=", - "_parent": { - "$ref": "AAAAAAFq+mmNBAznJt4=" - }, - "model": { - "$ref": "AAAAAAFq+mmNBAzkKAo=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 331, - "top": 780, - "height": 13, - "alpha": 0.5235987755982988, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+mmNBAznJt4=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+mmNBQzsQsY=", - "_parent": { - "$ref": "AAAAAAFq+mmNBAznJt4=" - }, - "model": { - "$ref": "AAAAAAFq+mmNBAzkKAo=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 333, - "top": 767, - "height": 13, - "alpha": 0.7853981633974483, - "distance": 40, - "hostEdge": { - "$ref": "AAAAAAFq+mmNBAznJt4=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+mmNBQztnBU=", - "_parent": { - "$ref": "AAAAAAFq+mmNBAznJt4=" - }, - "model": { - "$ref": "AAAAAAFq+mmNBAzkKAo=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 326, - "top": 807, - "height": 13, - "alpha": -0.5235987755982988, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFq+mmNBAznJt4=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+mmNBQzuEMs=", - "_parent": { - "$ref": "AAAAAAFq+mmNBAznJt4=" - }, - "model": { - "$ref": "AAAAAAFq+mmNBAzl9ck=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 373, - "top": 780, - "height": 13, - "alpha": -0.5235987755982988, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+mmNBAznJt4=" - } - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+mmNBQzveLk=", - "_parent": { - "$ref": "AAAAAAFq+mmNBAznJt4=" - }, - "model": { - "$ref": "AAAAAAFq+mmNBAzl9ck=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 371, - "top": 767, - "height": 13, - "alpha": -0.7853981633974483, - "distance": 40, - "hostEdge": { - "$ref": "AAAAAAFq+mmNBAznJt4=" - } - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+mmNBQzw6Qc=", - "_parent": { - "$ref": "AAAAAAFq+mmNBAznJt4=" - }, - "model": { - "$ref": "AAAAAAFq+mmNBAzl9ck=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 377, - "top": 808, - "height": 13, - "alpha": 0.5235987755982988, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFq+mmNBAznJt4=" - } - }, - { - "_type": "UMLQualifierCompartmentView", - "_id": "AAAAAAFq+mmNBQzxk3s=", - "_parent": { - "$ref": "AAAAAAFq+mmNBAznJt4=" - }, - "model": { - "$ref": "AAAAAAFq+mmNBAzkKAo=" - }, - "visible": false, - "font": "Arial;13;0", - "width": 10, - "height": 10 - }, - { - "_type": "UMLQualifierCompartmentView", - "_id": "AAAAAAFq+mmNBQzyCeA=", - "_parent": { - "$ref": "AAAAAAFq+mmNBAznJt4=" - }, - "model": { - "$ref": "AAAAAAFq+mmNBAzl9ck=" - }, - "visible": false, - "font": "Arial;13;0", - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+md4dAxt/ic=" - }, - "tail": { - "$ref": "AAAAAAFq+mbc+wukVW0=" - }, - "lineStyle": 1, - "points": "305:801;399:802", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+mmNBAzolyE=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+mmNBAzpbaw=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+mmNBAzqXbU=" - }, - "tailRoleNameLabel": { - "$ref": "AAAAAAFq+mmNBQzrS6s=" - }, - "tailPropertyLabel": { - "$ref": "AAAAAAFq+mmNBQzsQsY=" - }, - "tailMultiplicityLabel": { - "$ref": "AAAAAAFq+mmNBQztnBU=" - }, - "headRoleNameLabel": { - "$ref": "AAAAAAFq+mmNBQzuEMs=" - }, - "headPropertyLabel": { - "$ref": "AAAAAAFq+mmNBQzveLk=" - }, - "headMultiplicityLabel": { - "$ref": "AAAAAAFq+mmNBQzw6Qc=" - }, - "tailQualifiersCompartment": { - "$ref": "AAAAAAFq+mmNBQzxk3s=" - }, - "headQualifiersCompartment": { - "$ref": "AAAAAAFq+mmNBQzyCeA=" - } - }, - { - "_type": "UMLGeneralizationView", - "_id": "AAAAAAFq+mmcLg0ieuQ=", - "_parent": { - "$ref": "AAAAAAFq+macVQs3dSk=" - }, - "model": { - "$ref": "AAAAAAFq+mmcLQ0gpvI=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+mmcLg0jsLM=", - "_parent": { - "$ref": "AAAAAAFq+mmcLg0ieuQ=" - }, - "model": { - "$ref": "AAAAAAFq+mmcLQ0gpvI=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 420, - "top": 884, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+mmcLg0ieuQ=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+mmcLg0kMao=", - "_parent": { - "$ref": "AAAAAAFq+mmcLg0ieuQ=" - }, - "model": { - "$ref": "AAAAAAFq+mmcLQ0gpvI=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 405, - "top": 884, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+mmcLg0ieuQ=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+mmcLg0lQM0=", - "_parent": { - "$ref": "AAAAAAFq+mmcLg0ieuQ=" - }, - "model": { - "$ref": "AAAAAAFq+mmcLQ0gpvI=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 449, - "top": 885, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+mmcLg0ieuQ=" - }, - "edgePosition": 1 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+md4dAxt/ic=" - }, - "tail": { - "$ref": "AAAAAAFq+mbrsAwfkvU=" - }, - "points": "435:944;435:838", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+mmcLg0jsLM=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+mmcLg0kMao=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+mmcLg0lQM0=" - } - }, - { - "_type": "UMLAssociationView", - "_id": "AAAAAAFq+mmzBg1E3Ks=", - "_parent": { - "$ref": "AAAAAAFq+macVQs3dSk=" - }, - "model": { - "$ref": "AAAAAAFq+mmzBg1AXLI=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+mmzBg1FdaE=", - "_parent": { - "$ref": "AAAAAAFq+mmzBg1E3Ks=" - }, - "model": { - "$ref": "AAAAAAFq+mmzBg1AXLI=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 299, - "top": 986, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+mmzBg1E3Ks=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+mmzBg1G888=", - "_parent": { - "$ref": "AAAAAAFq+mmzBg1E3Ks=" - }, - "model": { - "$ref": "AAAAAAFq+mmzBg1AXLI=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 299, - "top": 1001, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+mmzBg1E3Ks=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+mmzBg1HTno=", - "_parent": { - "$ref": "AAAAAAFq+mmzBg1E3Ks=" - }, - "model": { - "$ref": "AAAAAAFq+mmzBg1AXLI=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 300, - "top": 956, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+mmzBg1E3Ks=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+mmzBg1IYIM=", - "_parent": { - "$ref": "AAAAAAFq+mmzBg1E3Ks=" - }, - "model": { - "$ref": "AAAAAAFq+mmzBg1BtNk=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 340, - "top": 986, - "height": 13, - "alpha": 0.5235987755982988, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+mmzBg1E3Ks=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+mmzBg1J6wo=", - "_parent": { - "$ref": "AAAAAAFq+mmzBg1E3Ks=" - }, - "model": { - "$ref": "AAAAAAFq+mmzBg1BtNk=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 338, - "top": 1000, - "height": 13, - "alpha": 0.7853981633974483, - "distance": 40, - "hostEdge": { - "$ref": "AAAAAAFq+mmzBg1E3Ks=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+mmzBg1K7ko=", - "_parent": { - "$ref": "AAAAAAFq+mmzBg1E3Ks=" - }, - "model": { - "$ref": "AAAAAAFq+mmzBg1BtNk=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 345, - "top": 959, - "height": 13, - "alpha": -0.5235987755982988, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFq+mmzBg1E3Ks=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+mmzBg1LJA4=", - "_parent": { - "$ref": "AAAAAAFq+mmzBg1E3Ks=" - }, - "model": { - "$ref": "AAAAAAFq+mmzBg1CyU8=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 258, - "top": 986, - "height": 13, - "alpha": -0.5235987755982988, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+mmzBg1E3Ks=" - } - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+mmzBg1MMiY=", - "_parent": { - "$ref": "AAAAAAFq+mmzBg1E3Ks=" - }, - "model": { - "$ref": "AAAAAAFq+mmzBg1CyU8=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 261, - "top": 999, - "height": 13, - "alpha": -0.7853981633974483, - "distance": 40, - "hostEdge": { - "$ref": "AAAAAAFq+mmzBg1E3Ks=" - } - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+mmzBg1NIfY=", - "_parent": { - "$ref": "AAAAAAFq+mmzBg1E3Ks=" - }, - "model": { - "$ref": "AAAAAAFq+mmzBg1CyU8=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 254, - "top": 958, - "height": 13, - "alpha": 0.5235987755982988, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFq+mmzBg1E3Ks=" - } - }, - { - "_type": "UMLQualifierCompartmentView", - "_id": "AAAAAAFq+mmzBg1O1WA=", - "_parent": { - "$ref": "AAAAAAFq+mmzBg1E3Ks=" - }, - "model": { - "$ref": "AAAAAAFq+mmzBg1BtNk=" - }, - "visible": false, - "font": "Arial;13;0", - "width": 10, - "height": 10 - }, - { - "_type": "UMLQualifierCompartmentView", - "_id": "AAAAAAFq+mmzBg1P+tQ=", - "_parent": { - "$ref": "AAAAAAFq+mmzBg1E3Ks=" - }, - "model": { - "$ref": "AAAAAAFq+mmzBg1CyU8=" - }, - "visible": false, - "font": "Arial;13;0", - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+mbhvQvNubw=" - }, - "tail": { - "$ref": "AAAAAAFq+mbrsAwfkvU=" - }, - "lineStyle": 1, - "points": "367:978;233:977", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+mmzBg1FdaE=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+mmzBg1G888=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+mmzBg1HTno=" - }, - "tailRoleNameLabel": { - "$ref": "AAAAAAFq+mmzBg1IYIM=" - }, - "tailPropertyLabel": { - "$ref": "AAAAAAFq+mmzBg1J6wo=" - }, - "tailMultiplicityLabel": { - "$ref": "AAAAAAFq+mmzBg1K7ko=" - }, - "headRoleNameLabel": { - "$ref": "AAAAAAFq+mmzBg1LJA4=" - }, - "headPropertyLabel": { - "$ref": "AAAAAAFq+mmzBg1MMiY=" - }, - "headMultiplicityLabel": { - "$ref": "AAAAAAFq+mmzBg1NIfY=" - }, - "tailQualifiersCompartment": { - "$ref": "AAAAAAFq+mmzBg1O1WA=" - }, - "headQualifiersCompartment": { - "$ref": "AAAAAAFq+mmzBg1P+tQ=" - } - } - ] - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+mbXngt5jIw=", - "_parent": { - "$ref": "AAAAAAFq+macVAs29Xg=" - }, - "name": "Client", - "ownedElements": [ - { - "_type": "UMLDependency", - "_id": "AAAAAAFq+mlO2QzB3o4=", - "_parent": { - "$ref": "AAAAAAFq+mbXngt5jIw=" - }, - "source": { - "$ref": "AAAAAAFq+mbXngt5jIw=" - }, - "target": { - "$ref": "AAAAAAFq+mbc+wuiaG4=" - } - }, - { - "_type": "UMLDependency", - "_id": "AAAAAAFq+mlZvgzSjnU=", - "_parent": { - "$ref": "AAAAAAFq+mbXngt5jIw=" - }, - "source": { - "$ref": "AAAAAAFq+mbXngt5jIw=" - }, - "target": { - "$ref": "AAAAAAFq+mbhvQvL3v4=" - } - } - ] - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+mbc+wuiaG4=", - "_parent": { - "$ref": "AAAAAAFq+macVAs29Xg=" - }, - "name": "Invoker", - "ownedElements": [ - { - "_type": "UMLAssociation", - "_id": "AAAAAAFq+mmNBAzjXws=", - "_parent": { - "$ref": "AAAAAAFq+mbc+wuiaG4=" - }, - "end1": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFq+mmNBAzkKAo=", - "_parent": { - "$ref": "AAAAAAFq+mmNBAzjXws=" - }, - "reference": { - "$ref": "AAAAAAFq+mbc+wuiaG4=" - }, - "navigable": false, - "aggregation": "shared" - }, - "end2": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFq+mmNBAzl9ck=", - "_parent": { - "$ref": "AAAAAAFq+mmNBAzjXws=" - }, - "reference": { - "$ref": "AAAAAAFq+md4dAxrM1U=" - } - } - } - ] - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+mbhvQvL3v4=", - "_parent": { - "$ref": "AAAAAAFq+macVAs29Xg=" - }, - "name": "Receiver", - "operations": [ - { - "_type": "UMLOperation", - "_id": "AAAAAAFq+mkO9wy6QRw=", - "_parent": { - "$ref": "AAAAAAFq+mbhvQvL3v4=" - }, - "name": "Action" - } - ] - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+mbrsAwdnRI=", - "_parent": { - "$ref": "AAAAAAFq+macVAs29Xg=" - }, - "name": "ConcreteCommand", - "ownedElements": [ - { - "_type": "UMLGeneralization", - "_id": "AAAAAAFq+mmcLQ0gpvI=", - "_parent": { - "$ref": "AAAAAAFq+mbrsAwdnRI=" - }, - "source": { - "$ref": "AAAAAAFq+mbrsAwdnRI=" - }, - "target": { - "$ref": "AAAAAAFq+md4dAxrM1U=" - } - }, - { - "_type": "UMLAssociation", - "_id": "AAAAAAFq+mmzBg1AXLI=", - "_parent": { - "$ref": "AAAAAAFq+mbrsAwdnRI=" - }, - "end1": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFq+mmzBg1BtNk=", - "_parent": { - "$ref": "AAAAAAFq+mmzBg1AXLI=" - }, - "reference": { - "$ref": "AAAAAAFq+mbrsAwdnRI=" - }, - "navigable": false - }, - "end2": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFq+mmzBg1CyU8=", - "_parent": { - "$ref": "AAAAAAFq+mmzBg1AXLI=" - }, - "reference": { - "$ref": "AAAAAAFq+mbhvQvL3v4=" - } - } - } - ], - "attributes": [ - { - "_type": "UMLAttribute", - "_id": "AAAAAAFq+miy7gyy148=", - "_parent": { - "$ref": "AAAAAAFq+mbrsAwdnRI=" - }, - "name": "receiver", - "type": { - "$ref": "AAAAAAFq+mbhvQvL3v4=" - } - } - ], - "operations": [ - { - "_type": "UMLOperation", - "_id": "AAAAAAFq+moLUw4cvXA=", - "_parent": { - "$ref": "AAAAAAFq+mbrsAwdnRI=" - }, - "name": "Excute" - } - ] - }, - { - "_type": "UMLInterface", - "_id": "AAAAAAFq+md4dAxrM1U=", - "_parent": { - "$ref": "AAAAAAFq+macVAs29Xg=" - }, - "name": "Command", - "operations": [ - { - "_type": "UMLOperation", - "_id": "AAAAAAFq+mesBwyZY7w=", - "_parent": { - "$ref": "AAAAAAFq+md4dAxrM1U=" - }, - "name": "Excute", - "isAbstract": true - } - ] - } - ] - }, - { - "_type": "UMLModel", - "_id": "AAAAAAFq+m9eCBCFGNU=", - "_parent": { - "$ref": "AAAAAAFF+h6SjaM2Hec=" - }, - "name": "行为型模式——中介者模式", - "ownedElements": [ - { - "_type": "UMLClassDiagram", - "_id": "AAAAAAFq+m9eCBCGdjk=", - "_parent": { - "$ref": "AAAAAAFq+m9eCBCFGNU=" - }, - "name": "中介者模式", - "ownedViews": [ - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+m+b8xDTbH4=", - "_parent": { - "$ref": "AAAAAAFq+m9eCBCGdjk=" - }, - "model": { - "$ref": "AAAAAAFq+m+b8xDRBt0=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+m+b8xDUQ9c=", - "_parent": { - "$ref": "AAAAAAFq+m+b8xDTbH4=" - }, - "model": { - "$ref": "AAAAAAFq+m+b8xDRBt0=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+m+b8xDV0Cw=", - "_parent": { - "$ref": "AAAAAAFq+m+b8xDUQ9c=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -64, - "top": 16, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+m+b8xDW4sc=", - "_parent": { - "$ref": "AAAAAAFq+m+b8xDUQ9c=" - }, - "font": "Arial;13;3", - "left": 85, - "top": 791, - "width": 71, - "height": 13, - "text": "Mediator" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+m+b8xDXvdE=", - "_parent": { - "$ref": "AAAAAAFq+m+b8xDUQ9c=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -64, - "top": 16, - "width": 194.27001953125, - "height": 13, - "text": "(from 行为型模式——中介者模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+m+b8xDYYsg=", - "_parent": { - "$ref": "AAAAAAFq+m+b8xDUQ9c=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -64, - "top": 16, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 80, - "top": 784, - "width": 81, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+m+b8xDV0Cw=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+m+b8xDW4sc=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+m+b8xDXvdE=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+m+b8xDYYsg=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+m+b8xDZZEo=", - "_parent": { - "$ref": "AAAAAAFq+m+b8xDTbH4=" - }, - "model": { - "$ref": "AAAAAAFq+m+b8xDRBt0=" - }, - "font": "Arial;13;0", - "left": 80, - "top": 809, - "width": 81, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+m+b8xDaDig=", - "_parent": { - "$ref": "AAAAAAFq+m+b8xDTbH4=" - }, - "model": { - "$ref": "AAAAAAFq+m+b8xDRBt0=" - }, - "font": "Arial;13;0", - "left": 80, - "top": 819, - "width": 81, - "height": 10 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+m+b8xDb0mc=", - "_parent": { - "$ref": "AAAAAAFq+m+b8xDTbH4=" - }, - "model": { - "$ref": "AAAAAAFq+m+b8xDRBt0=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -32, - "top": 8, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+m+b8xDcLxc=", - "_parent": { - "$ref": "AAAAAAFq+m+b8xDTbH4=" - }, - "model": { - "$ref": "AAAAAAFq+m+b8xDRBt0=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -32, - "top": 8, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 80, - "top": 784, - "width": 81, - "height": 49, - "nameCompartment": { - "$ref": "AAAAAAFq+m+b8xDUQ9c=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+m+b8xDZZEo=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+m+b8xDaDig=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+m+b8xDb0mc=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+m+b8xDcLxc=" - } - }, - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+m+gbRD8pQo=", - "_parent": { - "$ref": "AAAAAAFq+m9eCBCGdjk=" - }, - "model": { - "$ref": "AAAAAAFq+m+gbRD6t9E=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+m+gbRD9uc8=", - "_parent": { - "$ref": "AAAAAAFq+m+gbRD8pQo=" - }, - "model": { - "$ref": "AAAAAAFq+m+gbRD6t9E=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+m+gbRD+W9Y=", - "_parent": { - "$ref": "AAAAAAFq+m+gbRD9uc8=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -96, - "top": -48, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+m+gbRD/+8s=", - "_parent": { - "$ref": "AAAAAAFq+m+gbRD9uc8=" - }, - "font": "Arial;13;3", - "left": 389, - "top": 791, - "width": 71, - "height": 13, - "text": "Colleague" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+m+gbREA0VQ=", - "_parent": { - "$ref": "AAAAAAFq+m+gbRD9uc8=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -96, - "top": -48, - "width": 194.27001953125, - "height": 13, - "text": "(from 行为型模式——中介者模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+m+gbREBMHE=", - "_parent": { - "$ref": "AAAAAAFq+m+gbRD9uc8=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -96, - "top": -48, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 384, - "top": 784, - "width": 81, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+m+gbRD+W9Y=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+m+gbRD/+8s=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+m+gbREA0VQ=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+m+gbREBMHE=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+m+gbRECdPI=", - "_parent": { - "$ref": "AAAAAAFq+m+gbRD8pQo=" - }, - "model": { - "$ref": "AAAAAAFq+m+gbRD6t9E=" - }, - "font": "Arial;13;0", - "left": 384, - "top": 809, - "width": 81, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+m+gbREDiSg=", - "_parent": { - "$ref": "AAAAAAFq+m+gbRD8pQo=" - }, - "model": { - "$ref": "AAAAAAFq+m+gbRD6t9E=" - }, - "font": "Arial;13;0", - "left": 384, - "top": 819, - "width": 81, - "height": 10 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+m+gbREEuO8=", - "_parent": { - "$ref": "AAAAAAFq+m+gbRD8pQo=" - }, - "model": { - "$ref": "AAAAAAFq+m+gbRD6t9E=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -48, - "top": -24, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+m+gbREFvyI=", - "_parent": { - "$ref": "AAAAAAFq+m+gbRD8pQo=" - }, - "model": { - "$ref": "AAAAAAFq+m+gbRD6t9E=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -48, - "top": -24, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 384, - "top": 784, - "width": 81, - "height": 49, - "nameCompartment": { - "$ref": "AAAAAAFq+m+gbRD9uc8=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+m+gbRECdPI=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+m+gbREDiSg=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+m+gbREEuO8=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+m+gbREFvyI=" - } - }, - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+m+kdhElU10=", - "_parent": { - "$ref": "AAAAAAFq+m9eCBCGdjk=" - }, - "model": { - "$ref": "AAAAAAFq+m+kdhEjL54=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+m+kdhEmiV8=", - "_parent": { - "$ref": "AAAAAAFq+m+kdhElU10=" - }, - "model": { - "$ref": "AAAAAAFq+m+kdhEjL54=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+m+kdhEnKYY=", - "_parent": { - "$ref": "AAAAAAFq+m+kdhEmiV8=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -256, - "top": -48, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+m+kdhEox3U=", - "_parent": { - "$ref": "AAAAAAFq+m+kdhEmiV8=" - }, - "font": "Arial;13;1", - "left": 61, - "top": 935, - "width": 119, - "height": 13, - "text": "ConcreteMediator" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+m+kdhEpyo4=", - "_parent": { - "$ref": "AAAAAAFq+m+kdhEmiV8=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -256, - "top": -48, - "width": 194.27001953125, - "height": 13, - "text": "(from 行为型模式——中介者模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+m+kdhEqPeE=", - "_parent": { - "$ref": "AAAAAAFq+m+kdhEmiV8=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -256, - "top": -48, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 56, - "top": 928, - "width": 129, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+m+kdhEnKYY=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+m+kdhEox3U=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+m+kdhEpyo4=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+m+kdhEqPeE=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+m+kdhErvG8=", - "_parent": { - "$ref": "AAAAAAFq+m+kdhElU10=" - }, - "model": { - "$ref": "AAAAAAFq+m+kdhEjL54=" - }, - "font": "Arial;13;0", - "left": 56, - "top": 953, - "width": 129, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+m+kdhEshEM=", - "_parent": { - "$ref": "AAAAAAFq+m+kdhElU10=" - }, - "model": { - "$ref": "AAAAAAFq+m+kdhEjL54=" - }, - "font": "Arial;13;0", - "left": 56, - "top": 963, - "width": 129, - "height": 10 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+m+kdhEtU2I=", - "_parent": { - "$ref": "AAAAAAFq+m+kdhElU10=" - }, - "model": { - "$ref": "AAAAAAFq+m+kdhEjL54=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -128, - "top": -24, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+m+kdhEuOyc=", - "_parent": { - "$ref": "AAAAAAFq+m+kdhElU10=" - }, - "model": { - "$ref": "AAAAAAFq+m+kdhEjL54=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -128, - "top": -24, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 56, - "top": 928, - "width": 129, - "height": 49, - "nameCompartment": { - "$ref": "AAAAAAFq+m+kdhEmiV8=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+m+kdhErvG8=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+m+kdhEshEM=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+m+kdhEtU2I=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+m+kdhEuOyc=" - } - }, - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+m+4HRF3/hk=", - "_parent": { - "$ref": "AAAAAAFq+m9eCBCGdjk=" - }, - "model": { - "$ref": "AAAAAAFq+m+4HRF18iE=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+m+4HRF4fK0=", - "_parent": { - "$ref": "AAAAAAFq+m+4HRF3/hk=" - }, - "model": { - "$ref": "AAAAAAFq+m+4HRF18iE=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+m+4HRF5EuE=", - "_parent": { - "$ref": "AAAAAAFq+m+4HRF4fK0=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -256, - "top": -256, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+m+4HRF6u/o=", - "_parent": { - "$ref": "AAAAAAFq+m+4HRF4fK0=" - }, - "font": "Arial;13;1", - "left": 261, - "top": 935, - "width": 127.86083984375, - "height": 13, - "text": "ConcreteColleagueA" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+m+4HRF7fGk=", - "_parent": { - "$ref": "AAAAAAFq+m+4HRF4fK0=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -256, - "top": -256, - "width": 194.27001953125, - "height": 13, - "text": "(from 行为型模式——中介者模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+m+4HRF8d34=", - "_parent": { - "$ref": "AAAAAAFq+m+4HRF4fK0=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -256, - "top": -256, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 256, - "top": 928, - "width": 137.86083984375, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+m+4HRF5EuE=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+m+4HRF6u/o=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+m+4HRF7fGk=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+m+4HRF8d34=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+m+4HRF91S8=", - "_parent": { - "$ref": "AAAAAAFq+m+4HRF3/hk=" - }, - "model": { - "$ref": "AAAAAAFq+m+4HRF18iE=" - }, - "font": "Arial;13;0", - "left": 256, - "top": 953, - "width": 137.86083984375, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+m+4HRF+YZw=", - "_parent": { - "$ref": "AAAAAAFq+m+4HRF3/hk=" - }, - "model": { - "$ref": "AAAAAAFq+m+4HRF18iE=" - }, - "font": "Arial;13;0", - "left": 256, - "top": 963, - "width": 137.86083984375, - "height": 10 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+m+4HRF/Mdo=", - "_parent": { - "$ref": "AAAAAAFq+m+4HRF3/hk=" - }, - "model": { - "$ref": "AAAAAAFq+m+4HRF18iE=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -128, - "top": -128, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+m+4HRGAvxY=", - "_parent": { - "$ref": "AAAAAAFq+m+4HRF3/hk=" - }, - "model": { - "$ref": "AAAAAAFq+m+4HRF18iE=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -128, - "top": -128, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 256, - "top": 928, - "width": 137.86083984375, - "height": 49, - "nameCompartment": { - "$ref": "AAAAAAFq+m+4HRF4fK0=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+m+4HRF91S8=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+m+4HRF+YZw=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+m+4HRF/Mdo=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+m+4HRGAvxY=" - } - }, - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+m/QYxG81LU=", - "_parent": { - "$ref": "AAAAAAFq+m9eCBCGdjk=" - }, - "model": { - "$ref": "AAAAAAFq+m/QYxG6tjo=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+m/QYxG9AiQ=", - "_parent": { - "$ref": "AAAAAAFq+m/QYxG81LU=" - }, - "model": { - "$ref": "AAAAAAFq+m/QYxG6tjo=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+m/QYxG+4AE=", - "_parent": { - "$ref": "AAAAAAFq+m/QYxG9AiQ=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 416, - "top": -112, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+m/QYxG/DnE=", - "_parent": { - "$ref": "AAAAAAFq+m/QYxG9AiQ=" - }, - "font": "Arial;13;1", - "left": 453, - "top": 935, - "width": 127.86083984375, - "height": 13, - "text": "ConcreteColleagueB" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+m/QYxHAQJQ=", - "_parent": { - "$ref": "AAAAAAFq+m/QYxG9AiQ=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 416, - "top": -112, - "width": 194.27001953125, - "height": 13, - "text": "(from 行为型模式——中介者模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+m/QYxHB+2Q=", - "_parent": { - "$ref": "AAAAAAFq+m/QYxG9AiQ=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 416, - "top": -112, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 448, - "top": 928, - "width": 137.86083984375, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+m/QYxG+4AE=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+m/QYxG/DnE=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+m/QYxHAQJQ=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+m/QYxHB+2Q=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+m/QYxHC4cQ=", - "_parent": { - "$ref": "AAAAAAFq+m/QYxG81LU=" - }, - "model": { - "$ref": "AAAAAAFq+m/QYxG6tjo=" - }, - "font": "Arial;13;0", - "left": 448, - "top": 953, - "width": 137.86083984375, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+m/QYxHDRjc=", - "_parent": { - "$ref": "AAAAAAFq+m/QYxG81LU=" - }, - "model": { - "$ref": "AAAAAAFq+m/QYxG6tjo=" - }, - "font": "Arial;13;0", - "left": 448, - "top": 963, - "width": 137.86083984375, - "height": 10 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+m/QYxHE/1c=", - "_parent": { - "$ref": "AAAAAAFq+m/QYxG81LU=" - }, - "model": { - "$ref": "AAAAAAFq+m/QYxG6tjo=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 208, - "top": -56, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+m/QYxHFcgU=", - "_parent": { - "$ref": "AAAAAAFq+m/QYxG81LU=" - }, - "model": { - "$ref": "AAAAAAFq+m/QYxG6tjo=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 208, - "top": -56, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 448, - "top": 928, - "width": 137.86083984375, - "height": 49, - "nameCompartment": { - "$ref": "AAAAAAFq+m/QYxG9AiQ=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+m/QYxHC4cQ=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+m/QYxHDRjc=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+m/QYxHE/1c=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+m/QYxHFcgU=" - } - }, - { - "_type": "UMLGeneralizationView", - "_id": "AAAAAAFq+nDShhH9PkY=", - "_parent": { - "$ref": "AAAAAAFq+m9eCBCGdjk=" - }, - "model": { - "$ref": "AAAAAAFq+nDShRH7b84=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+nDShhH+QTg=", - "_parent": { - "$ref": "AAAAAAFq+nDShhH9PkY=" - }, - "model": { - "$ref": "AAAAAAFq+nDShRH7b84=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 105, - "top": 873, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+nDShhH9PkY=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+nDShhH/CTM=", - "_parent": { - "$ref": "AAAAAAFq+nDShhH9PkY=" - }, - "model": { - "$ref": "AAAAAAFq+nDShRH7b84=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 90, - "top": 873, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+nDShhH9PkY=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+nDShhIAOlc=", - "_parent": { - "$ref": "AAAAAAFq+nDShhH9PkY=" - }, - "model": { - "$ref": "AAAAAAFq+nDShRH7b84=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 134, - "top": 874, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+nDShhH9PkY=" - }, - "edgePosition": 1 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+m+b8xDTbH4=" - }, - "tail": { - "$ref": "AAAAAAFq+m+kdhElU10=" - }, - "lineStyle": 1, - "points": "120:927;120:833", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+nDShhH+QTg=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+nDShhH/CTM=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+nDShhIAOlc=" - } - }, - { - "_type": "UMLAssociationView", - "_id": "AAAAAAFq+nFayhIS5jg=", - "_parent": { - "$ref": "AAAAAAFq+m9eCBCGdjk=" - }, - "model": { - "$ref": "AAAAAAFq+nFayhIOz9o=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+nFayhITq5A=", - "_parent": { - "$ref": "AAAAAAFq+nFayhIS5jg=" - }, - "model": { - "$ref": "AAAAAAFq+nFayhIOz9o=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 271, - "top": 817, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+nFayhIS5jg=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+nFayhIUwh4=", - "_parent": { - "$ref": "AAAAAAFq+nFayhIS5jg=" - }, - "model": { - "$ref": "AAAAAAFq+nFayhIOz9o=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 271, - "top": 832, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+nFayhIS5jg=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+nFayhIVCXE=", - "_parent": { - "$ref": "AAAAAAFq+nFayhIS5jg=" - }, - "model": { - "$ref": "AAAAAAFq+nFayhIOz9o=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 272, - "top": 787, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+nFayhIS5jg=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+nFayhIWnSk=", - "_parent": { - "$ref": "AAAAAAFq+nFayhIS5jg=" - }, - "model": { - "$ref": "AAAAAAFq+nFayhIPFUQ=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 357, - "top": 816, - "height": 13, - "alpha": 0.5235987755982988, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+nFayhIS5jg=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+nFayhIX788=", - "_parent": { - "$ref": "AAAAAAFq+nFayhIS5jg=" - }, - "model": { - "$ref": "AAAAAAFq+nFayhIPFUQ=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 354, - "top": 830, - "height": 13, - "alpha": 0.7853981633974483, - "distance": 40, - "hostEdge": { - "$ref": "AAAAAAFq+nFayhIS5jg=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+nFayhIYrWM=", - "_parent": { - "$ref": "AAAAAAFq+nFayhIS5jg=" - }, - "model": { - "$ref": "AAAAAAFq+nFayhIPFUQ=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 361, - "top": 789, - "height": 13, - "alpha": -0.5235987755982988, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFq+nFayhIS5jg=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+nFayhIZPuk=", - "_parent": { - "$ref": "AAAAAAFq+nFayhIS5jg=" - }, - "model": { - "$ref": "AAAAAAFq+nFayhIQJto=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 186, - "top": 816, - "height": 13, - "alpha": -0.5235987755982988, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+nFayhIS5jg=" - } - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+nFayhIaX+0=", - "_parent": { - "$ref": "AAAAAAFq+nFayhIS5jg=" - }, - "model": { - "$ref": "AAAAAAFq+nFayhIQJto=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 189, - "top": 830, - "height": 13, - "alpha": -0.7853981633974483, - "distance": 40, - "hostEdge": { - "$ref": "AAAAAAFq+nFayhIS5jg=" - } - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+nFayhIbMG4=", - "_parent": { - "$ref": "AAAAAAFq+nFayhIS5jg=" - }, - "model": { - "$ref": "AAAAAAFq+nFayhIQJto=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 182, - "top": 789, - "height": 13, - "alpha": 0.5235987755982988, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFq+nFayhIS5jg=" - } - }, - { - "_type": "UMLQualifierCompartmentView", - "_id": "AAAAAAFq+nFayhIceLk=", - "_parent": { - "$ref": "AAAAAAFq+nFayhIS5jg=" - }, - "model": { - "$ref": "AAAAAAFq+nFayhIPFUQ=" - }, - "visible": false, - "font": "Arial;13;0", - "width": 10, - "height": 10 - }, - { - "_type": "UMLQualifierCompartmentView", - "_id": "AAAAAAFq+nFayhIdn+w=", - "_parent": { - "$ref": "AAAAAAFq+nFayhIS5jg=" - }, - "model": { - "$ref": "AAAAAAFq+nFayhIQJto=" - }, - "visible": false, - "font": "Arial;13;0", - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+m+b8xDTbH4=" - }, - "tail": { - "$ref": "AAAAAAFq+m+gbRD8pQo=" - }, - "lineStyle": 1, - "points": "383:808;161:808", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+nFayhITq5A=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+nFayhIUwh4=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+nFayhIVCXE=" - }, - "tailRoleNameLabel": { - "$ref": "AAAAAAFq+nFayhIWnSk=" - }, - "tailPropertyLabel": { - "$ref": "AAAAAAFq+nFayhIX788=" - }, - "tailMultiplicityLabel": { - "$ref": "AAAAAAFq+nFayhIYrWM=" - }, - "headRoleNameLabel": { - "$ref": "AAAAAAFq+nFayhIZPuk=" - }, - "headPropertyLabel": { - "$ref": "AAAAAAFq+nFayhIaX+0=" - }, - "headMultiplicityLabel": { - "$ref": "AAAAAAFq+nFayhIbMG4=" - }, - "tailQualifiersCompartment": { - "$ref": "AAAAAAFq+nFayhIceLk=" - }, - "headQualifiersCompartment": { - "$ref": "AAAAAAFq+nFayhIdn+w=" - } - }, - { - "_type": "UMLAssociationView", - "_id": "AAAAAAFq+nF7TRJvuSk=", - "_parent": { - "$ref": "AAAAAAFq+m9eCBCGdjk=" - }, - "model": { - "$ref": "AAAAAAFq+nF7TRJrgnk=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+nF7ThJwgFg=", - "_parent": { - "$ref": "AAAAAAFq+nF7TRJvuSk=" - }, - "model": { - "$ref": "AAAAAAFq+nF7TRJrgnk=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 220, - "top": 931, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+nF7TRJvuSk=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+nF7ThJx5VY=", - "_parent": { - "$ref": "AAAAAAFq+nF7TRJvuSk=" - }, - "model": { - "$ref": "AAAAAAFq+nF7TRJrgnk=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 220, - "top": 916, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+nF7TRJvuSk=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+nF7ThJyHTM=", - "_parent": { - "$ref": "AAAAAAFq+nF7TRJvuSk=" - }, - "model": { - "$ref": "AAAAAAFq+nF7TRJrgnk=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 220, - "top": 961, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+nF7TRJvuSk=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+nF7ThJzY4A=", - "_parent": { - "$ref": "AAAAAAFq+nF7TRJvuSk=" - }, - "model": { - "$ref": "AAAAAAFq+nF7TRJsqFE=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 210, - "top": 931, - "height": 13, - "alpha": 0.5235987755982988, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+nF7TRJvuSk=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+nF7ThJ01Q4=", - "_parent": { - "$ref": "AAAAAAFq+nF7TRJvuSk=" - }, - "model": { - "$ref": "AAAAAAFq+nF7TRJsqFE=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 213, - "top": 917, - "height": 13, - "alpha": 0.7853981633974483, - "distance": 40, - "hostEdge": { - "$ref": "AAAAAAFq+nF7TRJvuSk=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+nF7ThJ1xUs=", - "_parent": { - "$ref": "AAAAAAFq+nF7TRJvuSk=" - }, - "model": { - "$ref": "AAAAAAFq+nF7TRJsqFE=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 206, - "top": 958, - "height": 13, - "alpha": -0.5235987755982988, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFq+nF7TRJvuSk=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+nF7ThJ2cwI=", - "_parent": { - "$ref": "AAAAAAFq+nF7TRJvuSk=" - }, - "model": { - "$ref": "AAAAAAFq+nF7TRJthL0=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 229, - "top": 931, - "height": 13, - "alpha": -0.5235987755982988, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+nF7TRJvuSk=" - } - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+nF7ThJ3rbQ=", - "_parent": { - "$ref": "AAAAAAFq+nF7TRJvuSk=" - }, - "model": { - "$ref": "AAAAAAFq+nF7TRJthL0=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 226, - "top": 917, - "height": 13, - "alpha": -0.7853981633974483, - "distance": 40, - "hostEdge": { - "$ref": "AAAAAAFq+nF7TRJvuSk=" - } - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+nF7ThJ46ug=", - "_parent": { - "$ref": "AAAAAAFq+nF7TRJvuSk=" - }, - "model": { - "$ref": "AAAAAAFq+nF7TRJthL0=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 233, - "top": 958, - "height": 13, - "alpha": 0.5235987755982988, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFq+nF7TRJvuSk=" - } - }, - { - "_type": "UMLQualifierCompartmentView", - "_id": "AAAAAAFq+nF7ThJ54Sk=", - "_parent": { - "$ref": "AAAAAAFq+nF7TRJvuSk=" - }, - "model": { - "$ref": "AAAAAAFq+nF7TRJsqFE=" - }, - "visible": false, - "font": "Arial;13;0", - "width": 10, - "height": 10 - }, - { - "_type": "UMLQualifierCompartmentView", - "_id": "AAAAAAFq+nF7ThJ6MSQ=", - "_parent": { - "$ref": "AAAAAAFq+nF7TRJvuSk=" - }, - "model": { - "$ref": "AAAAAAFq+nF7TRJthL0=" - }, - "visible": false, - "font": "Arial;13;0", - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+m+4HRF3/hk=" - }, - "tail": { - "$ref": "AAAAAAFq+m+kdhElU10=" - }, - "lineStyle": 1, - "points": "185:952;255:952", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+nF7ThJwgFg=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+nF7ThJx5VY=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+nF7ThJyHTM=" - }, - "tailRoleNameLabel": { - "$ref": "AAAAAAFq+nF7ThJzY4A=" - }, - "tailPropertyLabel": { - "$ref": "AAAAAAFq+nF7ThJ01Q4=" - }, - "tailMultiplicityLabel": { - "$ref": "AAAAAAFq+nF7ThJ1xUs=" - }, - "headRoleNameLabel": { - "$ref": "AAAAAAFq+nF7ThJ2cwI=" - }, - "headPropertyLabel": { - "$ref": "AAAAAAFq+nF7ThJ3rbQ=" - }, - "headMultiplicityLabel": { - "$ref": "AAAAAAFq+nF7ThJ46ug=" - }, - "tailQualifiersCompartment": { - "$ref": "AAAAAAFq+nF7ThJ54Sk=" - }, - "headQualifiersCompartment": { - "$ref": "AAAAAAFq+nF7ThJ6MSQ=" - } - }, - { - "_type": "UMLGeneralizationView", - "_id": "AAAAAAFq+nGgORLkQCE=", - "_parent": { - "$ref": "AAAAAAFq+m9eCBCGdjk=" - }, - "model": { - "$ref": "AAAAAAFq+nGgORLiKB8=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+nGgORLl7G0=", - "_parent": { - "$ref": "AAAAAAFq+nGgORLkQCE=" - }, - "model": { - "$ref": "AAAAAAFq+nGgORLiKB8=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 370, - "top": 875, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+nGgORLkQCE=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+nGgORLm4V4=", - "_parent": { - "$ref": "AAAAAAFq+nGgORLkQCE=" - }, - "model": { - "$ref": "AAAAAAFq+nGgORLiKB8=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 370, - "top": 860, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+nGgORLkQCE=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+nGgORLnBoc=", - "_parent": { - "$ref": "AAAAAAFq+nGgORLkQCE=" - }, - "model": { - "$ref": "AAAAAAFq+nGgORLiKB8=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 370, - "top": 905, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+nGgORLkQCE=" - }, - "edgePosition": 1 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+m+gbRD8pQo=" - }, - "tail": { - "$ref": "AAAAAAFq+m+4HRF3/hk=" - }, - "points": "324:928;324:896;416:896;416:832", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+nGgORLl7G0=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+nGgORLm4V4=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+nGgORLnBoc=" - } - }, - { - "_type": "UMLGeneralizationView", - "_id": "AAAAAAFq+nGndhMH2QY=", - "_parent": { - "$ref": "AAAAAAFq+m9eCBCGdjk=" - }, - "model": { - "$ref": "AAAAAAFq+nGndhMFpzM=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+nGndhMIx6w=", - "_parent": { - "$ref": "AAAAAAFq+nGndhMH2QY=" - }, - "model": { - "$ref": "AAAAAAFq+nGndhMFpzM=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 455, - "top": 905, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+nGndhMH2QY=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+nGndhMJTwI=", - "_parent": { - "$ref": "AAAAAAFq+nGndhMH2QY=" - }, - "model": { - "$ref": "AAAAAAFq+nGndhMFpzM=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 455, - "top": 920, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+nGndhMH2QY=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+nGndhMK5nA=", - "_parent": { - "$ref": "AAAAAAFq+nGndhMH2QY=" - }, - "model": { - "$ref": "AAAAAAFq+nGndhMFpzM=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 456, - "top": 875, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+nGndhMH2QY=" - }, - "edgePosition": 1 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+m+gbRD8pQo=" - }, - "tail": { - "$ref": "AAAAAAFq+m/QYxG81LU=" - }, - "points": "496:928;496:896;416:896;416:832", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+nGndhMIx6w=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+nGndhMJTwI=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+nGndhMK5nA=" - } - } - ] - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+m+b8xDRBt0=", - "_parent": { - "$ref": "AAAAAAFq+m9eCBCFGNU=" - }, - "name": "Mediator", - "isAbstract": true - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+m+gbRD6t9E=", - "_parent": { - "$ref": "AAAAAAFq+m9eCBCFGNU=" - }, - "name": "Colleague", - "ownedElements": [ - { - "_type": "UMLAssociation", - "_id": "AAAAAAFq+nFayhIOz9o=", - "_parent": { - "$ref": "AAAAAAFq+m+gbRD6t9E=" - }, - "end1": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFq+nFayhIPFUQ=", - "_parent": { - "$ref": "AAAAAAFq+nFayhIOz9o=" - }, - "reference": { - "$ref": "AAAAAAFq+m+gbRD6t9E=" - }, - "navigable": false - }, - "end2": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFq+nFayhIQJto=", - "_parent": { - "$ref": "AAAAAAFq+nFayhIOz9o=" - }, - "reference": { - "$ref": "AAAAAAFq+m+b8xDRBt0=" - } - } - } - ], - "isAbstract": true - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+m+kdhEjL54=", - "_parent": { - "$ref": "AAAAAAFq+m9eCBCFGNU=" - }, - "name": "ConcreteMediator", - "ownedElements": [ - { - "_type": "UMLGeneralization", - "_id": "AAAAAAFq+nDShRH7b84=", - "_parent": { - "$ref": "AAAAAAFq+m+kdhEjL54=" - }, - "source": { - "$ref": "AAAAAAFq+m+kdhEjL54=" - }, - "target": { - "$ref": "AAAAAAFq+m+b8xDRBt0=" - } - }, - { - "_type": "UMLAssociation", - "_id": "AAAAAAFq+nF7TRJrgnk=", - "_parent": { - "$ref": "AAAAAAFq+m+kdhEjL54=" - }, - "end1": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFq+nF7TRJsqFE=", - "_parent": { - "$ref": "AAAAAAFq+nF7TRJrgnk=" - }, - "reference": { - "$ref": "AAAAAAFq+m+kdhEjL54=" - }, - "navigable": false - }, - "end2": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFq+nF7TRJthL0=", - "_parent": { - "$ref": "AAAAAAFq+nF7TRJrgnk=" - }, - "reference": { - "$ref": "AAAAAAFq+m+4HRF18iE=" - } - } - } - ] - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+m+4HRF18iE=", - "_parent": { - "$ref": "AAAAAAFq+m9eCBCFGNU=" - }, - "name": "ConcreteColleagueA", - "ownedElements": [ - { - "_type": "UMLGeneralization", - "_id": "AAAAAAFq+nGgORLiKB8=", - "_parent": { - "$ref": "AAAAAAFq+m+4HRF18iE=" - }, - "source": { - "$ref": "AAAAAAFq+m+4HRF18iE=" - }, - "target": { - "$ref": "AAAAAAFq+m+gbRD6t9E=" - } - } - ] - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+m/QYxG6tjo=", - "_parent": { - "$ref": "AAAAAAFq+m9eCBCFGNU=" - }, - "name": "ConcreteColleagueB", - "ownedElements": [ - { - "_type": "UMLGeneralization", - "_id": "AAAAAAFq+nGndhMFpzM=", - "_parent": { - "$ref": "AAAAAAFq+m/QYxG6tjo=" - }, - "source": { - "$ref": "AAAAAAFq+m/QYxG6tjo=" - }, - "target": { - "$ref": "AAAAAAFq+m+gbRD6t9E=" - } - } - ] - } - ] - }, - { - "_type": "UMLModel", - "_id": "AAAAAAFq+nQGtBRIDS4=", - "_parent": { - "$ref": "AAAAAAFF+h6SjaM2Hec=" - }, - "name": "行为型模式——访问者模式", - "ownedElements": [ - { - "_type": "UMLClassDiagram", - "_id": "AAAAAAFq+nQGtBRJvyc=", - "_parent": { - "$ref": "AAAAAAFq+nQGtBRIDS4=" - }, - "name": "访问者模式", - "ownedViews": [ - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+nSCrhScr+k=", - "_parent": { - "$ref": "AAAAAAFq+nQGtBRJvyc=" - }, - "model": { - "$ref": "AAAAAAFq+nSCrRSaL2c=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+nSCrhSdLdE=", - "_parent": { - "$ref": "AAAAAAFq+nSCrhScr+k=" - }, - "model": { - "$ref": "AAAAAAFq+nSCrRSaL2c=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+nSCrhSeiVI=", - "_parent": { - "$ref": "AAAAAAFq+nSCrhSdLdE=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 48, - "top": 96, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+nSCrhSfL4g=", - "_parent": { - "$ref": "AAAAAAFq+nSCrhSdLdE=" - }, - "font": "Arial;13;1", - "left": 53, - "top": 879, - "width": 71, - "height": 13, - "text": "Client" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+nSCrhSgDOo=", - "_parent": { - "$ref": "AAAAAAFq+nSCrhSdLdE=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 48, - "top": 96, - "width": 194.27001953125, - "height": 13, - "text": "(from 行为型模式——访问者模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+nSCrhSh3kc=", - "_parent": { - "$ref": "AAAAAAFq+nSCrhSdLdE=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 48, - "top": 96, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 48, - "top": 872, - "width": 81, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+nSCrhSeiVI=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+nSCrhSfL4g=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+nSCrhSgDOo=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+nSCrhSh3kc=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+nSCrhSi9Vg=", - "_parent": { - "$ref": "AAAAAAFq+nSCrhScr+k=" - }, - "model": { - "$ref": "AAAAAAFq+nSCrRSaL2c=" - }, - "font": "Arial;13;0", - "left": 48, - "top": 897, - "width": 81, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+nSCrhSjwnE=", - "_parent": { - "$ref": "AAAAAAFq+nSCrhScr+k=" - }, - "model": { - "$ref": "AAAAAAFq+nSCrRSaL2c=" - }, - "font": "Arial;13;0", - "left": 48, - "top": 907, - "width": 81, - "height": 10 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+nSCrhSkQ/E=", - "_parent": { - "$ref": "AAAAAAFq+nSCrhScr+k=" - }, - "model": { - "$ref": "AAAAAAFq+nSCrRSaL2c=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 24, - "top": 48, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+nSCrhSl8V8=", - "_parent": { - "$ref": "AAAAAAFq+nSCrhScr+k=" - }, - "model": { - "$ref": "AAAAAAFq+nSCrRSaL2c=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 24, - "top": 48, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 48, - "top": 872, - "width": 81, - "height": 65, - "nameCompartment": { - "$ref": "AAAAAAFq+nSCrhSdLdE=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+nSCrhSi9Vg=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+nSCrhSjwnE=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+nSCrhSkQ/E=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+nSCrhSl8V8=" - } - }, - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+nSHZxTFhgI=", - "_parent": { - "$ref": "AAAAAAFq+nQGtBRJvyc=" - }, - "model": { - "$ref": "AAAAAAFq+nSHZxTD6H0=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+nSHZxTGl4I=", - "_parent": { - "$ref": "AAAAAAFq+nSHZxTFhgI=" - }, - "model": { - "$ref": "AAAAAAFq+nSHZxTD6H0=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+nSHZxTHIzA=", - "_parent": { - "$ref": "AAAAAAFq+nSHZxTGl4I=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -32, - "top": 160, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+nSHZxTIS2o=", - "_parent": { - "$ref": "AAAAAAFq+nSHZxTGl4I=" - }, - "font": "Arial;13;1", - "left": 37, - "top": 1031, - "width": 98.24267578125, - "height": 13, - "text": "ObjectStructure" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+nSHZxTJwqw=", - "_parent": { - "$ref": "AAAAAAFq+nSHZxTGl4I=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -32, - "top": 160, - "width": 194.27001953125, - "height": 13, - "text": "(from 行为型模式——访问者模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+nSHZxTKP0M=", - "_parent": { - "$ref": "AAAAAAFq+nSHZxTGl4I=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -32, - "top": 160, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 32, - "top": 1024, - "width": 108.24267578125, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+nSHZxTHIzA=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+nSHZxTIS2o=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+nSHZxTJwqw=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+nSHZxTKP0M=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+nSHZxTLino=", - "_parent": { - "$ref": "AAAAAAFq+nSHZxTFhgI=" - }, - "model": { - "$ref": "AAAAAAFq+nSHZxTD6H0=" - }, - "font": "Arial;13;0", - "left": 32, - "top": 1049, - "width": 108.24267578125, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+nSHZxTM6cU=", - "_parent": { - "$ref": "AAAAAAFq+nSHZxTFhgI=" - }, - "model": { - "$ref": "AAAAAAFq+nSHZxTD6H0=" - }, - "font": "Arial;13;0", - "left": 32, - "top": 1059, - "width": 108.24267578125, - "height": 10 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+nSHZxTNMcc=", - "_parent": { - "$ref": "AAAAAAFq+nSHZxTFhgI=" - }, - "model": { - "$ref": "AAAAAAFq+nSHZxTD6H0=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -16, - "top": 80, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+nSHZxTOgNM=", - "_parent": { - "$ref": "AAAAAAFq+nSHZxTFhgI=" - }, - "model": { - "$ref": "AAAAAAFq+nSHZxTD6H0=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -16, - "top": 80, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 32, - "top": 1024, - "width": 108.24267578125, - "height": 45, - "nameCompartment": { - "$ref": "AAAAAAFq+nSHZxTGl4I=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+nSHZxTLino=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+nSHZxTM6cU=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+nSHZxTNMcc=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+nSHZxTOgNM=" - } - }, - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+nSM1hTukHA=", - "_parent": { - "$ref": "AAAAAAFq+nQGtBRJvyc=" - }, - "model": { - "$ref": "AAAAAAFq+nSM1hTs+Co=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+nSM1hTv1HI=", - "_parent": { - "$ref": "AAAAAAFq+nSM1hTukHA=" - }, - "model": { - "$ref": "AAAAAAFq+nSM1hTs+Co=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+nSM1hTw0BM=", - "_parent": { - "$ref": "AAAAAAFq+nSM1hTv1HI=" - }, - "visible": false, - "font": "Arial;13;0", - "top": 96, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+nSM1hTxMwU=", - "_parent": { - "$ref": "AAAAAAFq+nSM1hTv1HI=" - }, - "font": "Arial;13;1", - "left": 181, - "top": 887, - "width": 327, - "height": 13, - "text": "ConcreteVisitorA" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+nSM1hTy5CU=", - "_parent": { - "$ref": "AAAAAAFq+nSM1hTv1HI=" - }, - "visible": false, - "font": "Arial;13;0", - "top": 96, - "width": 194.27001953125, - "height": 13, - "text": "(from 行为型模式——访问者模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+nSM1hTzyDg=", - "_parent": { - "$ref": "AAAAAAFq+nSM1hTv1HI=" - }, - "visible": false, - "font": "Arial;13;0", - "top": 96, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 176, - "top": 880, - "width": 337, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+nSM1hTw0BM=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+nSM1hTxMwU=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+nSM1hTy5CU=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+nSM1hTzyDg=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+nSM1hT0GNE=", - "_parent": { - "$ref": "AAAAAAFq+nSM1hTukHA=" - }, - "model": { - "$ref": "AAAAAAFq+nSM1hTs+Co=" - }, - "font": "Arial;13;0", - "left": 176, - "top": 905, - "width": 337, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+nSM1hT19cc=", - "_parent": { - "$ref": "AAAAAAFq+nSM1hTukHA=" - }, - "model": { - "$ref": "AAAAAAFq+nSM1hTs+Co=" - }, - "subViews": [ - { - "_type": "UMLOperationView", - "_id": "AAAAAAFq+ni+qhYovFM=", - "_parent": { - "$ref": "AAAAAAFq+nSM1hT19cc=" - }, - "model": { - "$ref": "AAAAAAFq+ni+hBYlP8o=" - }, - "font": "Arial;13;0", - "left": 181, - "top": 920, - "width": 327, - "height": 13, - "text": "+visitConcreteElementA(ConcreteElementA elementA)", - "horizontalAlignment": 0 - }, - { - "_type": "UMLOperationView", - "_id": "AAAAAAFq+njMHhYuXXM=", - "_parent": { - "$ref": "AAAAAAFq+nSM1hT19cc=" - }, - "model": { - "$ref": "AAAAAAFq+njL+RYrbWs=" - }, - "font": "Arial;13;0", - "left": 181, - "top": 935, - "width": 327, - "height": 13, - "text": "+visitConcreteElementB(ConcreteElementB elementB)", - "horizontalAlignment": 0 - } - ], - "font": "Arial;13;0", - "left": 176, - "top": 915, - "width": 337, - "height": 38 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+nSM1hT2hXU=", - "_parent": { - "$ref": "AAAAAAFq+nSM1hTukHA=" - }, - "model": { - "$ref": "AAAAAAFq+nSM1hTs+Co=" - }, - "visible": false, - "font": "Arial;13;0", - "top": 48, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+nSM1hT3u4Q=", - "_parent": { - "$ref": "AAAAAAFq+nSM1hTukHA=" - }, - "model": { - "$ref": "AAAAAAFq+nSM1hTs+Co=" - }, - "visible": false, - "font": "Arial;13;0", - "top": 48, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 176, - "top": 880, - "width": 337, - "height": 81, - "nameCompartment": { - "$ref": "AAAAAAFq+nSM1hTv1HI=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+nSM1hT0GNE=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+nSM1hT19cc=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+nSM1hT2hXU=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+nSM1hT3u4Q=" - } - }, - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+nSSUhUXaFg=", - "_parent": { - "$ref": "AAAAAAFq+nQGtBRJvyc=" - }, - "model": { - "$ref": "AAAAAAFq+nSSUhUVMn4=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+nSSUhUYypo=", - "_parent": { - "$ref": "AAAAAAFq+nSSUhUXaFg=" - }, - "model": { - "$ref": "AAAAAAFq+nSSUhUVMn4=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+nSSUhUZf1U=", - "_parent": { - "$ref": "AAAAAAFq+nSSUhUYypo=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 176, - "top": 64, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+nSSUhUa+7I=", - "_parent": { - "$ref": "AAAAAAFq+nSSUhUYypo=" - }, - "font": "Arial;13;1", - "left": 549, - "top": 887, - "width": 327, - "height": 13, - "text": "ConcreteVisitorB" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+nSSUhUbJY4=", - "_parent": { - "$ref": "AAAAAAFq+nSSUhUYypo=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 176, - "top": 64, - "width": 194.27001953125, - "height": 13, - "text": "(from 行为型模式——访问者模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+nSSUhUcLo4=", - "_parent": { - "$ref": "AAAAAAFq+nSSUhUYypo=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 176, - "top": 64, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 544, - "top": 880, - "width": 337, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+nSSUhUZf1U=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+nSSUhUa+7I=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+nSSUhUbJY4=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+nSSUhUcLo4=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+nSSUhUdjWY=", - "_parent": { - "$ref": "AAAAAAFq+nSSUhUXaFg=" - }, - "model": { - "$ref": "AAAAAAFq+nSSUhUVMn4=" - }, - "font": "Arial;13;0", - "left": 544, - "top": 905, - "width": 337, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+nSSUhUeleU=", - "_parent": { - "$ref": "AAAAAAFq+nSSUhUXaFg=" - }, - "model": { - "$ref": "AAAAAAFq+nSSUhUVMn4=" - }, - "subViews": [ - { - "_type": "UMLOperationView", - "_id": "AAAAAAFq+njTkxY0FtY=", - "_parent": { - "$ref": "AAAAAAFq+nSSUhUeleU=" - }, - "model": { - "$ref": "AAAAAAFq+njTbhYx1Ks=" - }, - "font": "Arial;13;0", - "left": 549, - "top": 920, - "width": 327, - "height": 13, - "text": "+visitConcreteElementA(ConcreteElementA elementA)", - "horizontalAlignment": 0 - }, - { - "_type": "UMLOperationView", - "_id": "AAAAAAFq+njd6BY6X7Y=", - "_parent": { - "$ref": "AAAAAAFq+nSSUhUeleU=" - }, - "model": { - "$ref": "AAAAAAFq+njdwhY3qjs=" - }, - "font": "Arial;13;0", - "left": 549, - "top": 935, - "width": 327, - "height": 13, - "text": "+visitConcreteElementB(ConcreteElementB elementB)", - "horizontalAlignment": 0 - } - ], - "font": "Arial;13;0", - "left": 544, - "top": 915, - "width": 337, - "height": 38 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+nSSUhUfsLo=", - "_parent": { - "$ref": "AAAAAAFq+nSSUhUXaFg=" - }, - "model": { - "$ref": "AAAAAAFq+nSSUhUVMn4=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 88, - "top": 32, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+nSSUhUgmHA=", - "_parent": { - "$ref": "AAAAAAFq+nSSUhUXaFg=" - }, - "model": { - "$ref": "AAAAAAFq+nSSUhUVMn4=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 88, - "top": 32, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 544, - "top": 880, - "width": 337, - "height": 81, - "nameCompartment": { - "$ref": "AAAAAAFq+nSSUhUYypo=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+nSSUhUdjWY=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+nSSUhUeleU=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+nSSUhUfsLo=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+nSSUhUgmHA=" - } - }, - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+nSYThVApw0=", - "_parent": { - "$ref": "AAAAAAFq+nQGtBRJvyc=" - }, - "model": { - "$ref": "AAAAAAFq+nSYThU+TJY=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+nSYThVBWqY=", - "_parent": { - "$ref": "AAAAAAFq+nSYThVApw0=" - }, - "model": { - "$ref": "AAAAAAFq+nSYThU+TJY=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+nSYThVCQMA=", - "_parent": { - "$ref": "AAAAAAFq+nSYThVBWqY=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 128, - "top": 144, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+nSYThVDW4E=", - "_parent": { - "$ref": "AAAAAAFq+nSYThVBWqY=" - }, - "font": "Arial;13;1", - "left": 269, - "top": 1159, - "width": 127.994140625, - "height": 13, - "text": "ConcreteElementA" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+nSYThVEYS4=", - "_parent": { - "$ref": "AAAAAAFq+nSYThVBWqY=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 128, - "top": 144, - "width": 194.27001953125, - "height": 13, - "text": "(from 行为型模式——访问者模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+nSYThVFGQs=", - "_parent": { - "$ref": "AAAAAAFq+nSYThVBWqY=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 128, - "top": 144, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 264, - "top": 1152, - "width": 137.994140625, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+nSYThVCQMA=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+nSYThVDW4E=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+nSYThVEYS4=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+nSYThVFGQs=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+nSYThVGAmo=", - "_parent": { - "$ref": "AAAAAAFq+nSYThVApw0=" - }, - "model": { - "$ref": "AAAAAAFq+nSYThU+TJY=" - }, - "font": "Arial;13;0", - "left": 264, - "top": 1177, - "width": 137.994140625, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+nSYThVHmKk=", - "_parent": { - "$ref": "AAAAAAFq+nSYThVApw0=" - }, - "model": { - "$ref": "AAAAAAFq+nSYThU+TJY=" - }, - "subViews": [ - { - "_type": "UMLOperationView", - "_id": "AAAAAAFq+nkN5RZMvD4=", - "_parent": { - "$ref": "AAAAAAFq+nSYThVHmKk=" - }, - "model": { - "$ref": "AAAAAAFq+nkNvBZJXyk=" - }, - "font": "Arial;13;0", - "left": 269, - "top": 1192, - "width": 127.994140625, - "height": 13, - "text": "+accept(Visitor visitor)", - "horizontalAlignment": 0 - }, - { - "_type": "UMLOperationView", - "_id": "AAAAAAFq+nkWThZSff8=", - "_parent": { - "$ref": "AAAAAAFq+nSYThVHmKk=" - }, - "model": { - "$ref": "AAAAAAFq+nkWJxZPGGQ=" - }, - "font": "Arial;13;0", - "left": 269, - "top": 1207, - "width": 127.994140625, - "height": 13, - "text": "+OperationA()", - "horizontalAlignment": 0 - } - ], - "font": "Arial;13;0", - "left": 264, - "top": 1187, - "width": 137.994140625, - "height": 38 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+nSYThVIfs4=", - "_parent": { - "$ref": "AAAAAAFq+nSYThVApw0=" - }, - "model": { - "$ref": "AAAAAAFq+nSYThU+TJY=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 64, - "top": 72, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+nSYThVJn0w=", - "_parent": { - "$ref": "AAAAAAFq+nSYThVApw0=" - }, - "model": { - "$ref": "AAAAAAFq+nSYThU+TJY=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 64, - "top": 72, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 264, - "top": 1152, - "width": 137.994140625, - "height": 73, - "nameCompartment": { - "$ref": "AAAAAAFq+nSYThVBWqY=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+nSYThVGAmo=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+nSYThVHmKk=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+nSYThVIfs4=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+nSYThVJn0w=" - } - }, - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+nSfeRVpxrc=", - "_parent": { - "$ref": "AAAAAAFq+nQGtBRJvyc=" - }, - "model": { - "$ref": "AAAAAAFq+nSfeRVneu0=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+nSfeRVqOH4=", - "_parent": { - "$ref": "AAAAAAFq+nSfeRVpxrc=" - }, - "model": { - "$ref": "AAAAAAFq+nSfeRVneu0=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+nSfehVrgLo=", - "_parent": { - "$ref": "AAAAAAFq+nSfeRVqOH4=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -48, - "top": 80, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+nSfehVsilg=", - "_parent": { - "$ref": "AAAAAAFq+nSfeRVqOH4=" - }, - "font": "Arial;13;1", - "left": 469, - "top": 1159, - "width": 127.994140625, - "height": 13, - "text": "ConcreteElementB" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+nSfehVtIOo=", - "_parent": { - "$ref": "AAAAAAFq+nSfeRVqOH4=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -48, - "top": 80, - "width": 194.27001953125, - "height": 13, - "text": "(from 行为型模式——访问者模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+nSfehVua8Y=", - "_parent": { - "$ref": "AAAAAAFq+nSfeRVqOH4=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -48, - "top": 80, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 464, - "top": 1152, - "width": 137.994140625, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+nSfehVrgLo=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+nSfehVsilg=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+nSfehVtIOo=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+nSfehVua8Y=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+nSfehVvANA=", - "_parent": { - "$ref": "AAAAAAFq+nSfeRVpxrc=" - }, - "model": { - "$ref": "AAAAAAFq+nSfeRVneu0=" - }, - "font": "Arial;13;0", - "left": 464, - "top": 1177, - "width": 137.994140625, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+nSfehVwj/Q=", - "_parent": { - "$ref": "AAAAAAFq+nSfeRVpxrc=" - }, - "model": { - "$ref": "AAAAAAFq+nSfeRVneu0=" - }, - "subViews": [ - { - "_type": "UMLOperationView", - "_id": "AAAAAAFq+nkfxBZYLUk=", - "_parent": { - "$ref": "AAAAAAFq+nSfehVwj/Q=" - }, - "model": { - "$ref": "AAAAAAFq+nkfnRZVXgI=" - }, - "font": "Arial;13;0", - "left": 469, - "top": 1192, - "width": 127.994140625, - "height": 13, - "text": "+accept(Visitor visitor)", - "horizontalAlignment": 0 - }, - { - "_type": "UMLOperationView", - "_id": "AAAAAAFq+nkpkRZek2A=", - "_parent": { - "$ref": "AAAAAAFq+nSfehVwj/Q=" - }, - "model": { - "$ref": "AAAAAAFq+nkpahZbit4=" - }, - "font": "Arial;13;0", - "left": 469, - "top": 1207, - "width": 127.994140625, - "height": 13, - "text": "+OperationB()", - "horizontalAlignment": 0 - } - ], - "font": "Arial;13;0", - "left": 464, - "top": 1187, - "width": 137.994140625, - "height": 38 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+nSfehVxKO4=", - "_parent": { - "$ref": "AAAAAAFq+nSfeRVpxrc=" - }, - "model": { - "$ref": "AAAAAAFq+nSfeRVneu0=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -24, - "top": 40, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+nSfehVy9M8=", - "_parent": { - "$ref": "AAAAAAFq+nSfeRVpxrc=" - }, - "model": { - "$ref": "AAAAAAFq+nSfeRVneu0=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -24, - "top": 40, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 464, - "top": 1152, - "width": 137.994140625, - "height": 73, - "nameCompartment": { - "$ref": "AAAAAAFq+nSfeRVqOH4=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+nSfehVvANA=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+nSfehVwj/Q=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+nSfehVxKO4=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+nSfehVy9M8=" - } - }, - { - "_type": "UMLInterfaceView", - "_id": "AAAAAAFq+nSl+hWSL7c=", - "_parent": { - "$ref": "AAAAAAFq+nQGtBRJvyc=" - }, - "model": { - "$ref": "AAAAAAFq+nSl+hWQon0=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+nSl+hWTm8s=", - "_parent": { - "$ref": "AAAAAAFq+nSl+hWSL7c=" - }, - "model": { - "$ref": "AAAAAAFq+nSl+hWQon0=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+nSl+hWUKwg=", - "_parent": { - "$ref": "AAAAAAFq+nSl+hWTm8s=" - }, - "font": "Arial;13;0", - "left": 373, - "top": 1013, - "width": 127.994140625, - "height": 13, - "text": "«interface»" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+nSl+hWVnow=", - "_parent": { - "$ref": "AAAAAAFq+nSl+hWTm8s=" - }, - "font": "Arial;13;1", - "left": 373, - "top": 1028, - "width": 127.994140625, - "height": 13, - "text": "Element" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+nSl+hWWrAc=", - "_parent": { - "$ref": "AAAAAAFq+nSl+hWTm8s=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 80, - "top": 64, - "width": 194.27001953125, - "height": 13, - "text": "(from 行为型模式——访问者模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+nSl+hWXdmU=", - "_parent": { - "$ref": "AAAAAAFq+nSl+hWTm8s=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 80, - "top": 64, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 368, - "top": 1008, - "width": 137.994140625, - "height": 38, - "stereotypeLabel": { - "$ref": "AAAAAAFq+nSl+hWUKwg=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+nSl+hWVnow=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+nSl+hWWrAc=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+nSl+hWXdmU=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+nSl+hWYkjM=", - "_parent": { - "$ref": "AAAAAAFq+nSl+hWSL7c=" - }, - "model": { - "$ref": "AAAAAAFq+nSl+hWQon0=" - }, - "font": "Arial;13;0", - "left": 368, - "top": 1046, - "width": 137.994140625, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+nSl+hWZFiM=", - "_parent": { - "$ref": "AAAAAAFq+nSl+hWSL7c=" - }, - "model": { - "$ref": "AAAAAAFq+nSl+hWQon0=" - }, - "subViews": [ - { - "_type": "UMLOperationView", - "_id": "AAAAAAFq+nkCsRZGOUs=", - "_parent": { - "$ref": "AAAAAAFq+nSl+hWZFiM=" - }, - "model": { - "$ref": "AAAAAAFq+nkCiRZDN6k=" - }, - "font": "Arial;13;0", - "left": 373, - "top": 1061, - "width": 127.994140625, - "height": 13, - "text": "+accept(Visitor visitor)", - "horizontalAlignment": 0 - } - ], - "font": "Arial;13;0", - "left": 368, - "top": 1056, - "width": 137.994140625, - "height": 23 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+nSl+hWasQQ=", - "_parent": { - "$ref": "AAAAAAFq+nSl+hWSL7c=" - }, - "model": { - "$ref": "AAAAAAFq+nSl+hWQon0=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 40, - "top": 32, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+nSl+hWb69g=", - "_parent": { - "$ref": "AAAAAAFq+nSl+hWSL7c=" - }, - "model": { - "$ref": "AAAAAAFq+nSl+hWQon0=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 40, - "top": 32, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 368, - "top": 1008, - "width": 137.994140625, - "height": 71, - "nameCompartment": { - "$ref": "AAAAAAFq+nSl+hWTm8s=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+nSl+hWYkjM=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+nSl+hWZFiM=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+nSl+hWasQQ=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+nSl+hWb69g=" - } - }, - { - "_type": "UMLInterfaceView", - "_id": "AAAAAAFq+nS0KhW7Pz8=", - "_parent": { - "$ref": "AAAAAAFq+nQGtBRJvyc=" - }, - "model": { - "$ref": "AAAAAAFq+nS0KhW5/70=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+nS0KhW8l5Q=", - "_parent": { - "$ref": "AAAAAAFq+nS0KhW7Pz8=" - }, - "model": { - "$ref": "AAAAAAFq+nS0KhW5/70=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+nS0KhW9CZ8=", - "_parent": { - "$ref": "AAAAAAFq+nS0KhW8l5Q=" - }, - "font": "Arial;13;0", - "left": 325, - "top": 725, - "width": 327, - "height": 13, - "text": "«interface»" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+nS0KhW+ug8=", - "_parent": { - "$ref": "AAAAAAFq+nS0KhW8l5Q=" - }, - "font": "Arial;13;1", - "left": 325, - "top": 740, - "width": 327, - "height": 13, - "text": "Visitor" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+nS0KhW/nO8=", - "_parent": { - "$ref": "AAAAAAFq+nS0KhW8l5Q=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -16, - "top": -48, - "width": 194.27001953125, - "height": 13, - "text": "(from 行为型模式——访问者模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+nS0KhXAiBg=", - "_parent": { - "$ref": "AAAAAAFq+nS0KhW8l5Q=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -16, - "top": -48, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 320, - "top": 720, - "width": 337, - "height": 38, - "stereotypeLabel": { - "$ref": "AAAAAAFq+nS0KhW9CZ8=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+nS0KhW+ug8=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+nS0KhW/nO8=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+nS0KhXAiBg=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+nS0KhXB8DY=", - "_parent": { - "$ref": "AAAAAAFq+nS0KhW7Pz8=" - }, - "model": { - "$ref": "AAAAAAFq+nS0KhW5/70=" - }, - "font": "Arial;13;0", - "left": 320, - "top": 758, - "width": 337, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+nS0KhXCAJY=", - "_parent": { - "$ref": "AAAAAAFq+nS0KhW7Pz8=" - }, - "model": { - "$ref": "AAAAAAFq+nS0KhW5/70=" - }, - "subViews": [ - { - "_type": "UMLOperationView", - "_id": "AAAAAAFq+ncfDxYRjIY=", - "_parent": { - "$ref": "AAAAAAFq+nS0KhXCAJY=" - }, - "model": { - "$ref": "AAAAAAFq+nce5hYORq4=" - }, - "font": "Arial;13;0", - "left": 325, - "top": 773, - "width": 327, - "height": 13, - "text": "+visitConcreteElementA(ConcreteElementA elementA)", - "horizontalAlignment": 0 - }, - { - "_type": "UMLOperationView", - "_id": "AAAAAAFq+nctNxYXQf8=", - "_parent": { - "$ref": "AAAAAAFq+nS0KhXCAJY=" - }, - "model": { - "$ref": "AAAAAAFq+nctERYUyq4=" - }, - "font": "Arial;13;0", - "left": 325, - "top": 788, - "width": 327, - "height": 13, - "text": "+visitConcreteElementB(ConcreteElementB elementB)", - "horizontalAlignment": 0 - } - ], - "font": "Arial;13;0", - "left": 320, - "top": 768, - "width": 337, - "height": 38 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+nS0KhXDpIs=", - "_parent": { - "$ref": "AAAAAAFq+nS0KhW7Pz8=" - }, - "model": { - "$ref": "AAAAAAFq+nS0KhW5/70=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -8, - "top": -24, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+nS0KhXEjP0=", - "_parent": { - "$ref": "AAAAAAFq+nS0KhW7Pz8=" - }, - "model": { - "$ref": "AAAAAAFq+nS0KhW5/70=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -8, - "top": -24, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 320, - "top": 720, - "width": 337, - "height": 97, - "nameCompartment": { - "$ref": "AAAAAAFq+nS0KhW8l5Q=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+nS0KhXB8DY=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+nS0KhXCAJY=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+nS0KhXDpIs=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+nS0KhXEjP0=" - } - }, - { - "_type": "UMLInterfaceRealizationView", - "_id": "AAAAAAFq+nxwxhabVO0=", - "_parent": { - "$ref": "AAAAAAFq+nQGtBRJvyc=" - }, - "model": { - "$ref": "AAAAAAFq+nxwxhaa/is=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+nxwxhack2U=", - "_parent": { - "$ref": "AAAAAAFq+nxwxhabVO0=" - }, - "model": { - "$ref": "AAAAAAFq+nxwxhaa/is=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 427, - "top": 841, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+nxwxhabVO0=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+nxwxxadXU4=", - "_parent": { - "$ref": "AAAAAAFq+nxwxhabVO0=" - }, - "model": { - "$ref": "AAAAAAFq+nxwxhaa/is=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 412, - "top": 841, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+nxwxhabVO0=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+nxwxxaejJA=", - "_parent": { - "$ref": "AAAAAAFq+nxwxhabVO0=" - }, - "model": { - "$ref": "AAAAAAFq+nxwxhaa/is=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 456, - "top": 842, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+nxwxhabVO0=" - }, - "edgePosition": 1 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+nS0KhW7Pz8=" - }, - "tail": { - "$ref": "AAAAAAFq+nSM1hTukHA=" - }, - "points": "442:880;442:816", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+nxwxhack2U=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+nxwxxadXU4=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+nxwxxaejJA=" - } - }, - { - "_type": "UMLInterfaceRealizationView", - "_id": "AAAAAAFq+nx+NRasOIM=", - "_parent": { - "$ref": "AAAAAAFq+nQGtBRJvyc=" - }, - "model": { - "$ref": "AAAAAAFq+nx+NBarB1E=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+nx+NRatnRc=", - "_parent": { - "$ref": "AAAAAAFq+nx+NRasOIM=" - }, - "model": { - "$ref": "AAAAAAFq+nx+NBarB1E=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 561, - "top": 841, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+nx+NRasOIM=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+nx+NRaupHg=", - "_parent": { - "$ref": "AAAAAAFq+nx+NRasOIM=" - }, - "model": { - "$ref": "AAAAAAFq+nx+NBarB1E=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 546, - "top": 841, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+nx+NRasOIM=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+nx+NRavvIQ=", - "_parent": { - "$ref": "AAAAAAFq+nx+NRasOIM=" - }, - "model": { - "$ref": "AAAAAAFq+nx+NBarB1E=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 590, - "top": 842, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+nx+NRasOIM=" - }, - "edgePosition": 1 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+nS0KhW7Pz8=" - }, - "tail": { - "$ref": "AAAAAAFq+nSSUhUXaFg=" - }, - "points": "576:880;576:816", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+nx+NRatnRc=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+nx+NRaupHg=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+nx+NRavvIQ=" - } - }, - { - "_type": "UMLAssociationView", - "_id": "AAAAAAFq+nymLRbElFw=", - "_parent": { - "$ref": "AAAAAAFq+nQGtBRJvyc=" - }, - "model": { - "$ref": "AAAAAAFq+nymLBbADmA=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+nymLRbFLdg=", - "_parent": { - "$ref": "AAAAAAFq+nymLRbElFw=" - }, - "model": { - "$ref": "AAAAAAFq+nymLBbADmA=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 80, - "top": 747, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+nymLRbElFw=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+nymLRbGc1k=", - "_parent": { - "$ref": "AAAAAAFq+nymLRbElFw=" - }, - "model": { - "$ref": "AAAAAAFq+nymLBbADmA=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 80, - "top": 732, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+nymLRbElFw=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+nymLRbHwvk=", - "_parent": { - "$ref": "AAAAAAFq+nymLRbElFw=" - }, - "model": { - "$ref": "AAAAAAFq+nymLBbADmA=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 80, - "top": 777, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+nymLRbElFw=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+nymLRbIPBI=", - "_parent": { - "$ref": "AAAAAAFq+nymLRbElFw=" - }, - "model": { - "$ref": "AAAAAAFq+nymLRbBEp4=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 65, - "top": 840, - "height": 13, - "alpha": 0.5235987755982988, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+nymLRbElFw=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+nymLRbJriU=", - "_parent": { - "$ref": "AAAAAAFq+nymLRbElFw=" - }, - "model": { - "$ref": "AAAAAAFq+nymLRbBEp4=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 51, - "top": 837, - "height": 13, - "alpha": 0.7853981633974483, - "distance": 40, - "hostEdge": { - "$ref": "AAAAAAFq+nymLRbElFw=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+nymLRbKW7I=", - "_parent": { - "$ref": "AAAAAAFq+nymLRbElFw=" - }, - "model": { - "$ref": "AAAAAAFq+nymLRbBEp4=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 92, - "top": 844, - "height": 13, - "alpha": -0.5235987755982988, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFq+nymLRbElFw=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+nymLRbLgAY=", - "_parent": { - "$ref": "AAAAAAFq+nymLRbElFw=" - }, - "model": { - "$ref": "AAAAAAFq+nymLRbCZq4=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 294, - "top": 747, - "height": 13, - "alpha": -0.5235987755982988, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+nymLRbElFw=" - } - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+nymLRbM4MU=", - "_parent": { - "$ref": "AAAAAAFq+nymLRbElFw=" - }, - "model": { - "$ref": "AAAAAAFq+nymLRbCZq4=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 291, - "top": 733, - "height": 13, - "alpha": -0.7853981633974483, - "distance": 40, - "hostEdge": { - "$ref": "AAAAAAFq+nymLRbElFw=" - } - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+nymLRbN7ao=", - "_parent": { - "$ref": "AAAAAAFq+nymLRbElFw=" - }, - "model": { - "$ref": "AAAAAAFq+nymLRbCZq4=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 298, - "top": 774, - "height": 13, - "alpha": 0.5235987755982988, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFq+nymLRbElFw=" - } - }, - { - "_type": "UMLQualifierCompartmentView", - "_id": "AAAAAAFq+nymLRbO7+o=", - "_parent": { - "$ref": "AAAAAAFq+nymLRbElFw=" - }, - "model": { - "$ref": "AAAAAAFq+nymLRbBEp4=" - }, - "visible": false, - "font": "Arial;13;0", - "width": 10, - "height": 10 - }, - { - "_type": "UMLQualifierCompartmentView", - "_id": "AAAAAAFq+nymLRbP+TA=", - "_parent": { - "$ref": "AAAAAAFq+nymLRbElFw=" - }, - "model": { - "$ref": "AAAAAAFq+nymLRbCZq4=" - }, - "visible": false, - "font": "Arial;13;0", - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+nS0KhW7Pz8=" - }, - "tail": { - "$ref": "AAAAAAFq+nSCrhScr+k=" - }, - "points": "80:872;80:768;320:768", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+nymLRbFLdg=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+nymLRbGc1k=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+nymLRbHwvk=" - }, - "tailRoleNameLabel": { - "$ref": "AAAAAAFq+nymLRbIPBI=" - }, - "tailPropertyLabel": { - "$ref": "AAAAAAFq+nymLRbJriU=" - }, - "tailMultiplicityLabel": { - "$ref": "AAAAAAFq+nymLRbKW7I=" - }, - "headRoleNameLabel": { - "$ref": "AAAAAAFq+nymLRbLgAY=" - }, - "headPropertyLabel": { - "$ref": "AAAAAAFq+nymLRbM4MU=" - }, - "headMultiplicityLabel": { - "$ref": "AAAAAAFq+nymLRbN7ao=" - }, - "tailQualifiersCompartment": { - "$ref": "AAAAAAFq+nymLRbO7+o=" - }, - "headQualifiersCompartment": { - "$ref": "AAAAAAFq+nymLRbP+TA=" - } - }, - { - "_type": "UMLAssociationView", - "_id": "AAAAAAFq+nyz+BcHLDk=", - "_parent": { - "$ref": "AAAAAAFq+nQGtBRJvyc=" - }, - "model": { - "$ref": "AAAAAAFq+nyz+BcD/6o=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+nyz+BcIGg4=", - "_parent": { - "$ref": "AAAAAAFq+nyz+BcHLDk=" - }, - "model": { - "$ref": "AAAAAAFq+nyz+BcD/6o=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 105, - "top": 973, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+nyz+BcHLDk=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+nyz+RcJvK0=", - "_parent": { - "$ref": "AAAAAAFq+nyz+BcHLDk=" - }, - "model": { - "$ref": "AAAAAAFq+nyz+BcD/6o=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 120, - "top": 973, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+nyz+BcHLDk=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+nyz+RcKh3U=", - "_parent": { - "$ref": "AAAAAAFq+nyz+BcHLDk=" - }, - "model": { - "$ref": "AAAAAAFq+nyz+BcD/6o=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 76, - "top": 974, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+nyz+BcHLDk=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+nyz+RcLBis=", - "_parent": { - "$ref": "AAAAAAFq+nyz+BcHLDk=" - }, - "model": { - "$ref": "AAAAAAFq+nyz+BcE+gk=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 106, - "top": 955, - "height": 13, - "alpha": 0.5235987755982988, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+nyz+BcHLDk=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+nyz+RcMLbY=", - "_parent": { - "$ref": "AAAAAAFq+nyz+BcHLDk=" - }, - "model": { - "$ref": "AAAAAAFq+nyz+BcE+gk=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 119, - "top": 958, - "height": 13, - "alpha": 0.7853981633974483, - "distance": 40, - "hostEdge": { - "$ref": "AAAAAAFq+nyz+BcHLDk=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+nyz+RcNRz4=", - "_parent": { - "$ref": "AAAAAAFq+nyz+BcHLDk=" - }, - "model": { - "$ref": "AAAAAAFq+nyz+BcE+gk=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 78, - "top": 951, - "height": 13, - "alpha": -0.5235987755982988, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFq+nyz+BcHLDk=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+nyz+RcOk78=", - "_parent": { - "$ref": "AAAAAAFq+nyz+BcHLDk=" - }, - "model": { - "$ref": "AAAAAAFq+nyz+BcFXgg=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 106, - "top": 992, - "height": 13, - "alpha": -0.5235987755982988, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+nyz+BcHLDk=" - } - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+nyz+RcPbAw=", - "_parent": { - "$ref": "AAAAAAFq+nyz+BcHLDk=" - }, - "model": { - "$ref": "AAAAAAFq+nyz+BcFXgg=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 119, - "top": 989, - "height": 13, - "alpha": -0.7853981633974483, - "distance": 40, - "hostEdge": { - "$ref": "AAAAAAFq+nyz+BcHLDk=" - } - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+nyz+RcQfhc=", - "_parent": { - "$ref": "AAAAAAFq+nyz+BcHLDk=" - }, - "model": { - "$ref": "AAAAAAFq+nyz+BcFXgg=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 78, - "top": 996, - "height": 13, - "alpha": 0.5235987755982988, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFq+nyz+BcHLDk=" - } - }, - { - "_type": "UMLQualifierCompartmentView", - "_id": "AAAAAAFq+nyz+RcRkag=", - "_parent": { - "$ref": "AAAAAAFq+nyz+BcHLDk=" - }, - "model": { - "$ref": "AAAAAAFq+nyz+BcE+gk=" - }, - "visible": false, - "font": "Arial;13;0", - "width": 10, - "height": 10 - }, - { - "_type": "UMLQualifierCompartmentView", - "_id": "AAAAAAFq+nyz+RcSrk0=", - "_parent": { - "$ref": "AAAAAAFq+nyz+BcHLDk=" - }, - "model": { - "$ref": "AAAAAAFq+nyz+BcFXgg=" - }, - "visible": false, - "font": "Arial;13;0", - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+nSHZxTFhgI=" - }, - "tail": { - "$ref": "AAAAAAFq+nSCrhScr+k=" - }, - "points": "91:936;91:1024", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+nyz+BcIGg4=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+nyz+RcJvK0=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+nyz+RcKh3U=" - }, - "tailRoleNameLabel": { - "$ref": "AAAAAAFq+nyz+RcLBis=" - }, - "tailPropertyLabel": { - "$ref": "AAAAAAFq+nyz+RcMLbY=" - }, - "tailMultiplicityLabel": { - "$ref": "AAAAAAFq+nyz+RcNRz4=" - }, - "headRoleNameLabel": { - "$ref": "AAAAAAFq+nyz+RcOk78=" - }, - "headPropertyLabel": { - "$ref": "AAAAAAFq+nyz+RcPbAw=" - }, - "headMultiplicityLabel": { - "$ref": "AAAAAAFq+nyz+RcQfhc=" - }, - "tailQualifiersCompartment": { - "$ref": "AAAAAAFq+nyz+RcRkag=" - }, - "headQualifiersCompartment": { - "$ref": "AAAAAAFq+nyz+RcSrk0=" - } - }, - { - "_type": "UMLAssociationView", - "_id": "AAAAAAFq+nzNMRdyBSw=", - "_parent": { - "$ref": "AAAAAAFq+nQGtBRJvyc=" - }, - "model": { - "$ref": "AAAAAAFq+nzNMRdujs8=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+nzNMRdzogs=", - "_parent": { - "$ref": "AAAAAAFq+nzNMRdyBSw=" - }, - "model": { - "$ref": "AAAAAAFq+nzNMRdujs8=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 252, - "top": 1024, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+nzNMRdyBSw=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+nzNMRd0DJE=", - "_parent": { - "$ref": "AAAAAAFq+nzNMRdyBSw=" - }, - "model": { - "$ref": "AAAAAAFq+nzNMRdujs8=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 252, - "top": 1009, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+nzNMRdyBSw=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+nzNMhd1sEs=", - "_parent": { - "$ref": "AAAAAAFq+nzNMRdyBSw=" - }, - "model": { - "$ref": "AAAAAAFq+nzNMRdujs8=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 253, - "top": 1053, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+nzNMRdyBSw=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+nzNMhd2Uwc=", - "_parent": { - "$ref": "AAAAAAFq+nzNMRdyBSw=" - }, - "model": { - "$ref": "AAAAAAFq+nzNMRdvQPo=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 165, - "top": 1024, - "height": 13, - "alpha": 0.5235987755982988, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+nzNMRdyBSw=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+nzNMhd3sS8=", - "_parent": { - "$ref": "AAAAAAFq+nzNMRdyBSw=" - }, - "model": { - "$ref": "AAAAAAFq+nzNMRdvQPo=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 168, - "top": 1011, - "height": 13, - "alpha": 0.7853981633974483, - "distance": 40, - "hostEdge": { - "$ref": "AAAAAAFq+nzNMRdyBSw=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+nzNMhd4FpQ=", - "_parent": { - "$ref": "AAAAAAFq+nzNMRdyBSw=" - }, - "model": { - "$ref": "AAAAAAFq+nzNMRdvQPo=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 161, - "top": 1052, - "height": 13, - "alpha": -0.5235987755982988, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFq+nzNMRdyBSw=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+nzNMhd5/pQ=", - "_parent": { - "$ref": "AAAAAAFq+nzNMRdyBSw=" - }, - "model": { - "$ref": "AAAAAAFq+nzNMRdweDA=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 340, - "top": 1023, - "height": 13, - "alpha": -0.5235987755982988, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+nzNMRdyBSw=" - } - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+nzNMhd6Z1w=", - "_parent": { - "$ref": "AAAAAAFq+nzNMRdyBSw=" - }, - "model": { - "$ref": "AAAAAAFq+nzNMRdweDA=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 338, - "top": 1009, - "height": 13, - "alpha": -0.7853981633974483, - "distance": 40, - "hostEdge": { - "$ref": "AAAAAAFq+nzNMRdyBSw=" - } - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+nzNMhd7iTE=", - "_parent": { - "$ref": "AAAAAAFq+nzNMRdyBSw=" - }, - "model": { - "$ref": "AAAAAAFq+nzNMRdweDA=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 345, - "top": 1050, - "height": 13, - "alpha": 0.5235987755982988, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFq+nzNMRdyBSw=" - } - }, - { - "_type": "UMLQualifierCompartmentView", - "_id": "AAAAAAFq+nzNMhd8SDk=", - "_parent": { - "$ref": "AAAAAAFq+nzNMRdyBSw=" - }, - "model": { - "$ref": "AAAAAAFq+nzNMRdvQPo=" - }, - "visible": false, - "font": "Arial;13;0", - "width": 10, - "height": 10 - }, - { - "_type": "UMLQualifierCompartmentView", - "_id": "AAAAAAFq+nzNMhd9X7s=", - "_parent": { - "$ref": "AAAAAAFq+nzNMRdyBSw=" - }, - "model": { - "$ref": "AAAAAAFq+nzNMRdweDA=" - }, - "visible": false, - "font": "Arial;13;0", - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+nSl+hWSL7c=" - }, - "tail": { - "$ref": "AAAAAAFq+nSHZxTFhgI=" - }, - "lineStyle": 1, - "points": "140:1046;367:1044", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+nzNMRdzogs=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+nzNMRd0DJE=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+nzNMhd1sEs=" - }, - "tailRoleNameLabel": { - "$ref": "AAAAAAFq+nzNMhd2Uwc=" - }, - "tailPropertyLabel": { - "$ref": "AAAAAAFq+nzNMhd3sS8=" - }, - "tailMultiplicityLabel": { - "$ref": "AAAAAAFq+nzNMhd4FpQ=" - }, - "headRoleNameLabel": { - "$ref": "AAAAAAFq+nzNMhd5/pQ=" - }, - "headPropertyLabel": { - "$ref": "AAAAAAFq+nzNMhd6Z1w=" - }, - "headMultiplicityLabel": { - "$ref": "AAAAAAFq+nzNMhd7iTE=" - }, - "tailQualifiersCompartment": { - "$ref": "AAAAAAFq+nzNMhd8SDk=" - }, - "headQualifiersCompartment": { - "$ref": "AAAAAAFq+nzNMhd9X7s=" - } - }, - { - "_type": "UMLInterfaceRealizationView", - "_id": "AAAAAAFq+nzbBRfQkpo=", - "_parent": { - "$ref": "AAAAAAFq+nQGtBRJvyc=" - }, - "model": { - "$ref": "AAAAAAFq+nzbBRfP/ZI=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+nzbBRfR+B0=", - "_parent": { - "$ref": "AAAAAAFq+nzbBRfQkpo=" - }, - "model": { - "$ref": "AAAAAAFq+nzbBRfP/ZI=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 372, - "top": 1099, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+nzbBRfQkpo=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+nzbBRfSHBM=", - "_parent": { - "$ref": "AAAAAAFq+nzbBRfQkpo=" - }, - "model": { - "$ref": "AAAAAAFq+nzbBRfP/ZI=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 372, - "top": 1084, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+nzbBRfQkpo=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+nzbBRfT0Gg=", - "_parent": { - "$ref": "AAAAAAFq+nzbBRfQkpo=" - }, - "model": { - "$ref": "AAAAAAFq+nzbBRfP/ZI=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 372, - "top": 1129, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+nzbBRfQkpo=" - }, - "edgePosition": 1 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+nSl+hWSL7c=" - }, - "tail": { - "$ref": "AAAAAAFq+nSYThVApw0=" - }, - "points": "320:1152;320:1120;424:1120;424:1078", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+nzbBRfR+B0=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+nzbBRfSHBM=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+nzbBRfT0Gg=" - } - }, - { - "_type": "UMLInterfaceRealizationView", - "_id": "AAAAAAFq+nzg3Bf8pt8=", - "_parent": { - "$ref": "AAAAAAFq+nQGtBRJvyc=" - }, - "model": { - "$ref": "AAAAAAFq+nzg3Bf7mr4=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+nzg3Bf9CkQ=", - "_parent": { - "$ref": "AAAAAAFq+nzg3Bf8pt8=" - }, - "model": { - "$ref": "AAAAAAFq+nzg3Bf7mr4=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 475, - "top": 1129, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+nzg3Bf8pt8=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+nzg3Bf+57Y=", - "_parent": { - "$ref": "AAAAAAFq+nzg3Bf8pt8=" - }, - "model": { - "$ref": "AAAAAAFq+nzg3Bf7mr4=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 475, - "top": 1144, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+nzg3Bf8pt8=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+nzg3Bf/ZzE=", - "_parent": { - "$ref": "AAAAAAFq+nzg3Bf8pt8=" - }, - "model": { - "$ref": "AAAAAAFq+nzg3Bf7mr4=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 476, - "top": 1099, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+nzg3Bf8pt8=" - }, - "edgePosition": 1 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+nSl+hWSL7c=" - }, - "tail": { - "$ref": "AAAAAAFq+nSfeRVpxrc=" - }, - "points": "528:1152;528:1120;424:1120;424:1078", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+nzg3Bf9CkQ=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+nzg3Bf+57Y=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+nzg3Bf/ZzE=" - } - } - ] - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+nSCrRSaL2c=", - "_parent": { - "$ref": "AAAAAAFq+nQGtBRIDS4=" - }, - "name": "Client", - "ownedElements": [ - { - "_type": "UMLAssociation", - "_id": "AAAAAAFq+nymLBbADmA=", - "_parent": { - "$ref": "AAAAAAFq+nSCrRSaL2c=" - }, - "end1": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFq+nymLRbBEp4=", - "_parent": { - "$ref": "AAAAAAFq+nymLBbADmA=" - }, - "reference": { - "$ref": "AAAAAAFq+nSCrRSaL2c=" - }, - "navigable": false - }, - "end2": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFq+nymLRbCZq4=", - "_parent": { - "$ref": "AAAAAAFq+nymLBbADmA=" - }, - "reference": { - "$ref": "AAAAAAFq+nS0KhW5/70=" - } - } - }, - { - "_type": "UMLAssociation", - "_id": "AAAAAAFq+nyz+BcD/6o=", - "_parent": { - "$ref": "AAAAAAFq+nSCrRSaL2c=" - }, - "end1": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFq+nyz+BcE+gk=", - "_parent": { - "$ref": "AAAAAAFq+nyz+BcD/6o=" - }, - "reference": { - "$ref": "AAAAAAFq+nSCrRSaL2c=" - }, - "navigable": false - }, - "end2": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFq+nyz+BcFXgg=", - "_parent": { - "$ref": "AAAAAAFq+nyz+BcD/6o=" - }, - "reference": { - "$ref": "AAAAAAFq+nSHZxTD6H0=" - } - } - } - ] - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+nSHZxTD6H0=", - "_parent": { - "$ref": "AAAAAAFq+nQGtBRIDS4=" - }, - "name": "ObjectStructure", - "ownedElements": [ - { - "_type": "UMLAssociation", - "_id": "AAAAAAFq+nzNMRdujs8=", - "_parent": { - "$ref": "AAAAAAFq+nSHZxTD6H0=" - }, - "end1": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFq+nzNMRdvQPo=", - "_parent": { - "$ref": "AAAAAAFq+nzNMRdujs8=" - }, - "reference": { - "$ref": "AAAAAAFq+nSHZxTD6H0=" - }, - "navigable": false - }, - "end2": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFq+nzNMRdweDA=", - "_parent": { - "$ref": "AAAAAAFq+nzNMRdujs8=" - }, - "reference": { - "$ref": "AAAAAAFq+nSl+hWQon0=" - } - } - } - ] - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+nSM1hTs+Co=", - "_parent": { - "$ref": "AAAAAAFq+nQGtBRIDS4=" - }, - "name": "ConcreteVisitorA", - "ownedElements": [ - { - "_type": "UMLInterfaceRealization", - "_id": "AAAAAAFq+nxwxhaa/is=", - "_parent": { - "$ref": "AAAAAAFq+nSM1hTs+Co=" - }, - "source": { - "$ref": "AAAAAAFq+nSM1hTs+Co=" - }, - "target": { - "$ref": "AAAAAAFq+nS0KhW5/70=" - } - } - ], - "operations": [ - { - "_type": "UMLOperation", - "_id": "AAAAAAFq+ni+hBYlP8o=", - "_parent": { - "$ref": "AAAAAAFq+nSM1hTs+Co=" - }, - "name": "visitConcreteElementA", - "parameters": [ - { - "_type": "UMLParameter", - "_id": "AAAAAAFq+nnHWxZlzvo=", - "_parent": { - "$ref": "AAAAAAFq+ni+hBYlP8o=" - }, - "name": "ConcreteElementA elementA" - } - ] - }, - { - "_type": "UMLOperation", - "_id": "AAAAAAFq+njL+RYrbWs=", - "_parent": { - "$ref": "AAAAAAFq+nSM1hTs+Co=" - }, - "name": "visitConcreteElementB", - "parameters": [ - { - "_type": "UMLParameter", - "_id": "AAAAAAFq+nnOqxZos8c=", - "_parent": { - "$ref": "AAAAAAFq+njL+RYrbWs=" - }, - "name": "ConcreteElementB elementB" - } - ] - } - ] - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+nSSUhUVMn4=", - "_parent": { - "$ref": "AAAAAAFq+nQGtBRIDS4=" - }, - "name": "ConcreteVisitorB", - "ownedElements": [ - { - "_type": "UMLInterfaceRealization", - "_id": "AAAAAAFq+nx+NBarB1E=", - "_parent": { - "$ref": "AAAAAAFq+nSSUhUVMn4=" - }, - "source": { - "$ref": "AAAAAAFq+nSSUhUVMn4=" - }, - "target": { - "$ref": "AAAAAAFq+nS0KhW5/70=" - } - } - ], - "operations": [ - { - "_type": "UMLOperation", - "_id": "AAAAAAFq+njTbhYx1Ks=", - "_parent": { - "$ref": "AAAAAAFq+nSSUhUVMn4=" - }, - "name": "visitConcreteElementA", - "parameters": [ - { - "_type": "UMLParameter", - "_id": "AAAAAAFq+nnVbhZrqr0=", - "_parent": { - "$ref": "AAAAAAFq+njTbhYx1Ks=" - }, - "name": "ConcreteElementA elementA" - } - ] - }, - { - "_type": "UMLOperation", - "_id": "AAAAAAFq+njdwhY3qjs=", - "_parent": { - "$ref": "AAAAAAFq+nSSUhUVMn4=" - }, - "name": "visitConcreteElementB", - "parameters": [ - { - "_type": "UMLParameter", - "_id": "AAAAAAFq+nnc0BZu3uE=", - "_parent": { - "$ref": "AAAAAAFq+njdwhY3qjs=" - }, - "name": "ConcreteElementB elementB" - } - ] - } - ] - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+nSYThU+TJY=", - "_parent": { - "$ref": "AAAAAAFq+nQGtBRIDS4=" - }, - "name": "ConcreteElementA", - "ownedElements": [ - { - "_type": "UMLInterfaceRealization", - "_id": "AAAAAAFq+nzbBRfP/ZI=", - "_parent": { - "$ref": "AAAAAAFq+nSYThU+TJY=" - }, - "source": { - "$ref": "AAAAAAFq+nSYThU+TJY=" - }, - "target": { - "$ref": "AAAAAAFq+nSl+hWQon0=" - } - } - ], - "operations": [ - { - "_type": "UMLOperation", - "_id": "AAAAAAFq+nkNvBZJXyk=", - "_parent": { - "$ref": "AAAAAAFq+nSYThU+TJY=" - }, - "name": "accept", - "parameters": [ - { - "_type": "UMLParameter", - "_id": "AAAAAAFq+ns/ghaE1ho=", - "_parent": { - "$ref": "AAAAAAFq+nkNvBZJXyk=" - }, - "name": "Visitor visitor" - } - ] - }, - { - "_type": "UMLOperation", - "_id": "AAAAAAFq+nkWJxZPGGQ=", - "_parent": { - "$ref": "AAAAAAFq+nSYThU+TJY=" - }, - "name": "OperationA" - } - ] - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+nSfeRVneu0=", - "_parent": { - "$ref": "AAAAAAFq+nQGtBRIDS4=" - }, - "name": "ConcreteElementB", - "ownedElements": [ - { - "_type": "UMLInterfaceRealization", - "_id": "AAAAAAFq+nzg3Bf7mr4=", - "_parent": { - "$ref": "AAAAAAFq+nSfeRVneu0=" - }, - "source": { - "$ref": "AAAAAAFq+nSfeRVneu0=" - }, - "target": { - "$ref": "AAAAAAFq+nSl+hWQon0=" - } - } - ], - "operations": [ - { - "_type": "UMLOperation", - "_id": "AAAAAAFq+nkfnRZVXgI=", - "_parent": { - "$ref": "AAAAAAFq+nSfeRVneu0=" - }, - "name": "accept", - "parameters": [ - { - "_type": "UMLParameter", - "_id": "AAAAAAFq+nt0ERaIXGQ=", - "_parent": { - "$ref": "AAAAAAFq+nkfnRZVXgI=" - }, - "name": "Visitor visitor" - } - ] - }, - { - "_type": "UMLOperation", - "_id": "AAAAAAFq+nkpahZbit4=", - "_parent": { - "$ref": "AAAAAAFq+nSfeRVneu0=" - }, - "name": "OperationB" - } - ] - }, - { - "_type": "UMLInterface", - "_id": "AAAAAAFq+nSl+hWQon0=", - "_parent": { - "$ref": "AAAAAAFq+nQGtBRIDS4=" - }, - "name": "Element", - "operations": [ - { - "_type": "UMLOperation", - "_id": "AAAAAAFq+nkCiRZDN6k=", - "_parent": { - "$ref": "AAAAAAFq+nSl+hWQon0=" - }, - "name": "accept", - "parameters": [ - { - "_type": "UMLParameter", - "_id": "AAAAAAFq+nqmARZ8KWs=", - "_parent": { - "$ref": "AAAAAAFq+nkCiRZDN6k=" - }, - "name": "Visitor visitor" - } - ] - } - ] - }, - { - "_type": "UMLInterface", - "_id": "AAAAAAFq+nS0KhW5/70=", - "_parent": { - "$ref": "AAAAAAFq+nQGtBRIDS4=" - }, - "name": "Visitor", - "operations": [ - { - "_type": "UMLOperation", - "_id": "AAAAAAFq+nce5hYORq4=", - "_parent": { - "$ref": "AAAAAAFq+nS0KhW5/70=" - }, - "name": "visitConcreteElementA", - "parameters": [ - { - "_type": "UMLParameter", - "_id": "AAAAAAFq+nejdhYc8GM=", - "_parent": { - "$ref": "AAAAAAFq+nce5hYORq4=" - }, - "name": "ConcreteElementA elementA" - } - ] - }, - { - "_type": "UMLOperation", - "_id": "AAAAAAFq+nctERYUyq4=", - "_parent": { - "$ref": "AAAAAAFq+nS0KhW5/70=" - }, - "name": "visitConcreteElementB", - "parameters": [ - { - "_type": "UMLParameter", - "_id": "AAAAAAFq+nhlQRYgWHE=", - "_parent": { - "$ref": "AAAAAAFq+nctERYUyq4=" - }, - "name": "ConcreteElementB elementB" - } - ] - } - ] - } - ] - }, - { - "_type": "UMLModel", - "_id": "AAAAAAFq+oAmUx5vvB8=", - "_parent": { - "$ref": "AAAAAAFF+h6SjaM2Hec=" - }, - "name": "行为型模式——状态模式", - "ownedElements": [ - { - "_type": "UMLClassDiagram", - "_id": "AAAAAAFq+oAmUx5w7f4=", - "_parent": { - "$ref": "AAAAAAFq+oAmUx5vvB8=" - }, - "name": "状态模式", - "ownedViews": [ - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+oBjKB7P8FQ=", - "_parent": { - "$ref": "AAAAAAFq+oAmUx5w7f4=" - }, - "model": { - "$ref": "AAAAAAFq+oBjKB7Ne4Q=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+oBjKB7QCZM=", - "_parent": { - "$ref": "AAAAAAFq+oBjKB7P8FQ=" - }, - "model": { - "$ref": "AAAAAAFq+oBjKB7Ne4Q=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+oBjKB7Rl0k=", - "_parent": { - "$ref": "AAAAAAFq+oBjKB7QCZM=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 64, - "top": 48, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+oBjKB7StuU=", - "_parent": { - "$ref": "AAAAAAFq+oBjKB7QCZM=" - }, - "font": "Arial;13;1", - "left": 149, - "top": 871, - "width": 87, - "height": 13, - "text": "Context" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+oBjKB7T8pQ=", - "_parent": { - "$ref": "AAAAAAFq+oBjKB7QCZM=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 64, - "top": 48, - "width": 181.27001953125, - "height": 13, - "text": "(from 行为型模式——状态模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+oBjKB7U51U=", - "_parent": { - "$ref": "AAAAAAFq+oBjKB7QCZM=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 64, - "top": 48, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 144, - "top": 864, - "width": 97, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+oBjKB7Rl0k=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+oBjKB7StuU=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+oBjKB7T8pQ=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+oBjKB7U51U=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+oBjKB7VBaE=", - "_parent": { - "$ref": "AAAAAAFq+oBjKB7P8FQ=" - }, - "model": { - "$ref": "AAAAAAFq+oBjKB7Ne4Q=" - }, - "font": "Arial;13;0", - "left": 144, - "top": 889, - "width": 97, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+oBjKB7W63w=", - "_parent": { - "$ref": "AAAAAAFq+oBjKB7P8FQ=" - }, - "model": { - "$ref": "AAAAAAFq+oBjKB7Ne4Q=" - }, - "subViews": [ - { - "_type": "UMLOperationView", - "_id": "AAAAAAFq+oELnx+l7Pg=", - "_parent": { - "$ref": "AAAAAAFq+oBjKB7W63w=" - }, - "model": { - "$ref": "AAAAAAFq+oELex+iNak=" - }, - "font": "Arial;13;0", - "left": 149, - "top": 904, - "width": 87, - "height": 13, - "text": "+request()", - "horizontalAlignment": 0 - } - ], - "font": "Arial;13;0", - "left": 144, - "top": 899, - "width": 97, - "height": 23 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+oBjKB7XxQ8=", - "_parent": { - "$ref": "AAAAAAFq+oBjKB7P8FQ=" - }, - "model": { - "$ref": "AAAAAAFq+oBjKB7Ne4Q=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 32, - "top": 24, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+oBjKB7YwzM=", - "_parent": { - "$ref": "AAAAAAFq+oBjKB7P8FQ=" - }, - "model": { - "$ref": "AAAAAAFq+oBjKB7Ne4Q=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 32, - "top": 24, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 144, - "top": 864, - "width": 97, - "height": 65, - "nameCompartment": { - "$ref": "AAAAAAFq+oBjKB7QCZM=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+oBjKB7VBaE=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+oBjKB7W63w=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+oBjKB7XxQ8=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+oBjKB7YwzM=" - } - }, - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+oBx4B7483o=", - "_parent": { - "$ref": "AAAAAAFq+oAmUx5w7f4=" - }, - "model": { - "$ref": "AAAAAAFq+oBx4B72xto=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+oBx4B75HDE=", - "_parent": { - "$ref": "AAAAAAFq+oBx4B7483o=" - }, - "model": { - "$ref": "AAAAAAFq+oBx4B72xto=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+oBx4B76jIU=", - "_parent": { - "$ref": "AAAAAAFq+oBx4B75HDE=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 64, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+oBx4B77JPE=", - "_parent": { - "$ref": "AAAAAAFq+oBx4B75HDE=" - }, - "font": "Arial;13;3", - "left": 421, - "top": 871, - "width": 119, - "height": 13, - "text": "State" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+oBx4B78sC0=", - "_parent": { - "$ref": "AAAAAAFq+oBx4B75HDE=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 64, - "width": 181.27001953125, - "height": 13, - "text": "(from 行为型模式——状态模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+oBx4B79nn4=", - "_parent": { - "$ref": "AAAAAAFq+oBx4B75HDE=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 64, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 416, - "top": 864, - "width": 129, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+oBx4B76jIU=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+oBx4B77JPE=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+oBx4B78sC0=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+oBx4B79nn4=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+oBx4B7+va4=", - "_parent": { - "$ref": "AAAAAAFq+oBx4B7483o=" - }, - "model": { - "$ref": "AAAAAAFq+oBx4B72xto=" - }, - "font": "Arial;13;0", - "left": 416, - "top": 889, - "width": 129, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+oBx4B7/Apw=", - "_parent": { - "$ref": "AAAAAAFq+oBx4B7483o=" - }, - "model": { - "$ref": "AAAAAAFq+oBx4B72xto=" - }, - "subViews": [ - { - "_type": "UMLOperationView", - "_id": "AAAAAAFq+oFYRx+sjBQ=", - "_parent": { - "$ref": "AAAAAAFq+oBx4B7/Apw=" - }, - "model": { - "$ref": "AAAAAAFq+oFYIB+pFj8=" - }, - "font": "Arial;13;0", - "left": 421, - "top": 904, - "width": 119, - "height": 13, - "text": "+handle()", - "horizontalAlignment": 0 - } - ], - "font": "Arial;13;0", - "left": 416, - "top": 899, - "width": 129, - "height": 23 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+oBx4B8AFXM=", - "_parent": { - "$ref": "AAAAAAFq+oBx4B7483o=" - }, - "model": { - "$ref": "AAAAAAFq+oBx4B72xto=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 32, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+oBx4B8B7io=", - "_parent": { - "$ref": "AAAAAAFq+oBx4B7483o=" - }, - "model": { - "$ref": "AAAAAAFq+oBx4B72xto=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 32, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 416, - "top": 864, - "width": 129, - "height": 65, - "nameCompartment": { - "$ref": "AAAAAAFq+oBx4B75HDE=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+oBx4B7+va4=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+oBx4B7/Apw=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+oBx4B8AFXM=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+oBx4B8B7io=" - } - }, - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+oB2Tx8hbGI=", - "_parent": { - "$ref": "AAAAAAFq+oAmUx5w7f4=" - }, - "model": { - "$ref": "AAAAAAFq+oB2Th8fSHE=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+oB2Tx8iPDM=", - "_parent": { - "$ref": "AAAAAAFq+oB2Tx8hbGI=" - }, - "model": { - "$ref": "AAAAAAFq+oB2Th8fSHE=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+oB2Tx8jmiE=", - "_parent": { - "$ref": "AAAAAAFq+oB2Tx8iPDM=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -48, - "top": 48, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+oB2Tx8k2fY=", - "_parent": { - "$ref": "AAAAAAFq+oB2Tx8iPDM=" - }, - "font": "Arial;13;1", - "left": 261, - "top": 1031, - "width": 103, - "height": 13, - "text": "ConcreteStateA" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+oB2Tx8lC7k=", - "_parent": { - "$ref": "AAAAAAFq+oB2Tx8iPDM=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -48, - "top": 48, - "width": 181.27001953125, - "height": 13, - "text": "(from 行为型模式——状态模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+oB2Tx8mVpg=", - "_parent": { - "$ref": "AAAAAAFq+oB2Tx8iPDM=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -48, - "top": 48, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 256, - "top": 1024, - "width": 113, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+oB2Tx8jmiE=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+oB2Tx8k2fY=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+oB2Tx8lC7k=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+oB2Tx8mVpg=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+oB2Tx8nIVU=", - "_parent": { - "$ref": "AAAAAAFq+oB2Tx8hbGI=" - }, - "model": { - "$ref": "AAAAAAFq+oB2Th8fSHE=" - }, - "font": "Arial;13;0", - "left": 256, - "top": 1049, - "width": 113, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+oB2Tx8oGSg=", - "_parent": { - "$ref": "AAAAAAFq+oB2Tx8hbGI=" - }, - "model": { - "$ref": "AAAAAAFq+oB2Th8fSHE=" - }, - "subViews": [ - { - "_type": "UMLOperationView", - "_id": "AAAAAAFq+oF88B+zwUk=", - "_parent": { - "$ref": "AAAAAAFq+oB2Tx8oGSg=" - }, - "model": { - "$ref": "AAAAAAFq+oF8yh+wOR0=" - }, - "font": "Arial;13;0", - "left": 261, - "top": 1064, - "width": 103, - "height": 13, - "text": "+handle()", - "horizontalAlignment": 0 - } - ], - "font": "Arial;13;0", - "left": 256, - "top": 1059, - "width": 113, - "height": 23 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+oB2Tx8peAg=", - "_parent": { - "$ref": "AAAAAAFq+oB2Tx8hbGI=" - }, - "model": { - "$ref": "AAAAAAFq+oB2Th8fSHE=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -24, - "top": 24, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+oB2Tx8qrRY=", - "_parent": { - "$ref": "AAAAAAFq+oB2Tx8hbGI=" - }, - "model": { - "$ref": "AAAAAAFq+oB2Th8fSHE=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -24, - "top": 24, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 256, - "top": 1024, - "width": 113, - "height": 65, - "nameCompartment": { - "$ref": "AAAAAAFq+oB2Tx8iPDM=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+oB2Tx8nIVU=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+oB2Tx8oGSg=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+oB2Tx8peAg=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+oB2Tx8qrRY=" - } - }, - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+oB7Kh9Knx8=", - "_parent": { - "$ref": "AAAAAAFq+oAmUx5w7f4=" - }, - "model": { - "$ref": "AAAAAAFq+oB7Kh9Ii4U=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+oB7Kh9LHrs=", - "_parent": { - "$ref": "AAAAAAFq+oB7Kh9Knx8=" - }, - "model": { - "$ref": "AAAAAAFq+oB7Kh9Ii4U=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+oB7Kh9MG3o=", - "_parent": { - "$ref": "AAAAAAFq+oB7Kh9LHrs=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -80, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+oB7Kh9N1Pc=", - "_parent": { - "$ref": "AAAAAAFq+oB7Kh9LHrs=" - }, - "font": "Arial;13;1", - "left": 421, - "top": 1031, - "width": 111, - "height": 13, - "text": "ConcreteStateB" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+oB7Kh9OjkM=", - "_parent": { - "$ref": "AAAAAAFq+oB7Kh9LHrs=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -80, - "width": 181.27001953125, - "height": 13, - "text": "(from 行为型模式——状态模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+oB7Kh9P9ag=", - "_parent": { - "$ref": "AAAAAAFq+oB7Kh9LHrs=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -80, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 416, - "top": 1024, - "width": 121, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+oB7Kh9MG3o=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+oB7Kh9N1Pc=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+oB7Kh9OjkM=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+oB7Kh9P9ag=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+oB7Kh9QMHY=", - "_parent": { - "$ref": "AAAAAAFq+oB7Kh9Knx8=" - }, - "model": { - "$ref": "AAAAAAFq+oB7Kh9Ii4U=" - }, - "font": "Arial;13;0", - "left": 416, - "top": 1049, - "width": 121, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+oB7Kh9RsW4=", - "_parent": { - "$ref": "AAAAAAFq+oB7Kh9Knx8=" - }, - "model": { - "$ref": "AAAAAAFq+oB7Kh9Ii4U=" - }, - "subViews": [ - { - "_type": "UMLOperationView", - "_id": "AAAAAAFq+oGTnB+6fZo=", - "_parent": { - "$ref": "AAAAAAFq+oB7Kh9RsW4=" - }, - "model": { - "$ref": "AAAAAAFq+oGTdR+33fc=" - }, - "font": "Arial;13;0", - "left": 421, - "top": 1064, - "width": 111, - "height": 13, - "text": "+handle()", - "horizontalAlignment": 0 - } - ], - "font": "Arial;13;0", - "left": 416, - "top": 1059, - "width": 121, - "height": 23 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+oB7Kh9SbNE=", - "_parent": { - "$ref": "AAAAAAFq+oB7Kh9Knx8=" - }, - "model": { - "$ref": "AAAAAAFq+oB7Kh9Ii4U=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -40, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+oB7Kh9To0k=", - "_parent": { - "$ref": "AAAAAAFq+oB7Kh9Knx8=" - }, - "model": { - "$ref": "AAAAAAFq+oB7Kh9Ii4U=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -40, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 416, - "top": 1024, - "width": 121, - "height": 65, - "nameCompartment": { - "$ref": "AAAAAAFq+oB7Kh9LHrs=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+oB7Kh9QMHY=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+oB7Kh9RsW4=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+oB7Kh9SbNE=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+oB7Kh9To0k=" - } - }, - { - "_type": "UMLClassView", - "_id": "AAAAAAFq+oCBUB9zs2w=", - "_parent": { - "$ref": "AAAAAAFq+oAmUx5w7f4=" - }, - "model": { - "$ref": "AAAAAAFq+oCBUB9xjU8=" - }, - "subViews": [ - { - "_type": "UMLNameCompartmentView", - "_id": "AAAAAAFq+oCBUB90fAM=", - "_parent": { - "$ref": "AAAAAAFq+oCBUB9zs2w=" - }, - "model": { - "$ref": "AAAAAAFq+oCBUB9xjU8=" - }, - "subViews": [ - { - "_type": "LabelView", - "_id": "AAAAAAFq+oCBUB91BZs=", - "_parent": { - "$ref": "AAAAAAFq+oCBUB90fAM=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -128, - "height": 13 - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+oCBUR92LNw=", - "_parent": { - "$ref": "AAAAAAFq+oCBUB90fAM=" - }, - "font": "Arial;13;1", - "left": 581, - "top": 1031, - "width": 111, - "height": 13, - "text": "ConcreteStateC" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+oCBUR93r+s=", - "_parent": { - "$ref": "AAAAAAFq+oCBUB90fAM=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -128, - "width": 181.27001953125, - "height": 13, - "text": "(from 行为型模式——状态模式)" - }, - { - "_type": "LabelView", - "_id": "AAAAAAFq+oCBUR94GKw=", - "_parent": { - "$ref": "AAAAAAFq+oCBUB90fAM=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -128, - "height": 13, - "horizontalAlignment": 1 - } - ], - "font": "Arial;13;0", - "left": 576, - "top": 1024, - "width": 121, - "height": 25, - "stereotypeLabel": { - "$ref": "AAAAAAFq+oCBUB91BZs=" - }, - "nameLabel": { - "$ref": "AAAAAAFq+oCBUR92LNw=" - }, - "namespaceLabel": { - "$ref": "AAAAAAFq+oCBUR93r+s=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+oCBUR94GKw=" - } - }, - { - "_type": "UMLAttributeCompartmentView", - "_id": "AAAAAAFq+oCBUR95x3A=", - "_parent": { - "$ref": "AAAAAAFq+oCBUB9zs2w=" - }, - "model": { - "$ref": "AAAAAAFq+oCBUB9xjU8=" - }, - "font": "Arial;13;0", - "left": 576, - "top": 1049, - "width": 121, - "height": 10 - }, - { - "_type": "UMLOperationCompartmentView", - "_id": "AAAAAAFq+oCBUR96+5Q=", - "_parent": { - "$ref": "AAAAAAFq+oCBUB9zs2w=" - }, - "model": { - "$ref": "AAAAAAFq+oCBUB9xjU8=" - }, - "subViews": [ - { - "_type": "UMLOperationView", - "_id": "AAAAAAFq+oGb4x/Afgc=", - "_parent": { - "$ref": "AAAAAAFq+oCBUR96+5Q=" - }, - "model": { - "$ref": "AAAAAAFq+oGbux+9oYo=" - }, - "font": "Arial;13;0", - "left": 581, - "top": 1064, - "width": 111, - "height": 13, - "text": "+handle()", - "horizontalAlignment": 0 - } - ], - "font": "Arial;13;0", - "left": 576, - "top": 1059, - "width": 121, - "height": 23 - }, - { - "_type": "UMLReceptionCompartmentView", - "_id": "AAAAAAFq+oCBUR97dB0=", - "_parent": { - "$ref": "AAAAAAFq+oCBUB9zs2w=" - }, - "model": { - "$ref": "AAAAAAFq+oCBUB9xjU8=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -64, - "width": 10, - "height": 10 - }, - { - "_type": "UMLTemplateParameterCompartmentView", - "_id": "AAAAAAFq+oCBUR98Wrk=", - "_parent": { - "$ref": "AAAAAAFq+oCBUB9zs2w=" - }, - "model": { - "$ref": "AAAAAAFq+oCBUB9xjU8=" - }, - "visible": false, - "font": "Arial;13;0", - "left": -64, - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "containerChangeable": true, - "left": 576, - "top": 1024, - "width": 121, - "height": 65, - "nameCompartment": { - "$ref": "AAAAAAFq+oCBUB90fAM=" - }, - "attributeCompartment": { - "$ref": "AAAAAAFq+oCBUR95x3A=" - }, - "operationCompartment": { - "$ref": "AAAAAAFq+oCBUR96+5Q=" - }, - "receptionCompartment": { - "$ref": "AAAAAAFq+oCBUR97dB0=" - }, - "templateParameterCompartment": { - "$ref": "AAAAAAFq+oCBUR98Wrk=" - } - }, - { - "_type": "UMLAssociationView", - "_id": "AAAAAAFq+oHMZh/JTeU=", - "_parent": { - "$ref": "AAAAAAFq+oAmUx5w7f4=" - }, - "model": { - "$ref": "AAAAAAFq+oHMZh/Fl8c=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+oHMZx/KOM0=", - "_parent": { - "$ref": "AAAAAAFq+oHMZh/JTeU=" - }, - "model": { - "$ref": "AAAAAAFq+oHMZh/Fl8c=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 328, - "top": 875, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+oHMZh/JTeU=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+oHMZx/L7as=", - "_parent": { - "$ref": "AAAAAAFq+oHMZh/JTeU=" - }, - "model": { - "$ref": "AAAAAAFq+oHMZh/Fl8c=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 328, - "top": 860, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+oHMZh/JTeU=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+oHMZx/M/qI=", - "_parent": { - "$ref": "AAAAAAFq+oHMZh/JTeU=" - }, - "model": { - "$ref": "AAAAAAFq+oHMZh/Fl8c=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 328, - "top": 905, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+oHMZh/JTeU=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+oHMZx/NQa8=", - "_parent": { - "$ref": "AAAAAAFq+oHMZh/JTeU=" - }, - "model": { - "$ref": "AAAAAAFq+oHMZh/Gymw=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 266, - "top": 875, - "height": 13, - "alpha": 0.5235987755982988, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+oHMZh/JTeU=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+oHMZx/OUgI=", - "_parent": { - "$ref": "AAAAAAFq+oHMZh/JTeU=" - }, - "model": { - "$ref": "AAAAAAFq+oHMZh/Gymw=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 269, - "top": 861, - "height": 13, - "alpha": 0.7853981633974483, - "distance": 40, - "hostEdge": { - "$ref": "AAAAAAFq+oHMZh/JTeU=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+oHMZx/PuW0=", - "_parent": { - "$ref": "AAAAAAFq+oHMZh/JTeU=" - }, - "model": { - "$ref": "AAAAAAFq+oHMZh/Gymw=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 262, - "top": 902, - "height": 13, - "alpha": -0.5235987755982988, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFq+oHMZh/JTeU=" - }, - "edgePosition": 2 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+oHMZx/Q1Dc=", - "_parent": { - "$ref": "AAAAAAFq+oHMZh/JTeU=" - }, - "model": { - "$ref": "AAAAAAFq+oHMZh/HlN8=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 389, - "top": 875, - "height": 13, - "alpha": -0.5235987755982988, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+oHMZh/JTeU=" - } - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+oHMZx/RW30=", - "_parent": { - "$ref": "AAAAAAFq+oHMZh/JTeU=" - }, - "model": { - "$ref": "AAAAAAFq+oHMZh/HlN8=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 386, - "top": 861, - "height": 13, - "alpha": -0.7853981633974483, - "distance": 40, - "hostEdge": { - "$ref": "AAAAAAFq+oHMZh/JTeU=" - } - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+oHMZx/SYYg=", - "_parent": { - "$ref": "AAAAAAFq+oHMZh/JTeU=" - }, - "model": { - "$ref": "AAAAAAFq+oHMZh/HlN8=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 393, - "top": 902, - "height": 13, - "alpha": 0.5235987755982988, - "distance": 25, - "hostEdge": { - "$ref": "AAAAAAFq+oHMZh/JTeU=" - } - }, - { - "_type": "UMLQualifierCompartmentView", - "_id": "AAAAAAFq+oHMZx/T4bI=", - "_parent": { - "$ref": "AAAAAAFq+oHMZh/JTeU=" - }, - "model": { - "$ref": "AAAAAAFq+oHMZh/Gymw=" - }, - "visible": false, - "font": "Arial;13;0", - "width": 10, - "height": 10 - }, - { - "_type": "UMLQualifierCompartmentView", - "_id": "AAAAAAFq+oHMZx/UTWc=", - "_parent": { - "$ref": "AAAAAAFq+oHMZh/JTeU=" - }, - "model": { - "$ref": "AAAAAAFq+oHMZh/HlN8=" - }, - "visible": false, - "font": "Arial;13;0", - "width": 10, - "height": 10 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+oBx4B7483o=" - }, - "tail": { - "$ref": "AAAAAAFq+oBjKB7P8FQ=" - }, - "lineStyle": 1, - "points": "241:896;415:896", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+oHMZx/KOM0=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+oHMZx/L7as=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+oHMZx/M/qI=" - }, - "tailRoleNameLabel": { - "$ref": "AAAAAAFq+oHMZx/NQa8=" - }, - "tailPropertyLabel": { - "$ref": "AAAAAAFq+oHMZx/OUgI=" - }, - "tailMultiplicityLabel": { - "$ref": "AAAAAAFq+oHMZx/PuW0=" - }, - "headRoleNameLabel": { - "$ref": "AAAAAAFq+oHMZx/Q1Dc=" - }, - "headPropertyLabel": { - "$ref": "AAAAAAFq+oHMZx/RW30=" - }, - "headMultiplicityLabel": { - "$ref": "AAAAAAFq+oHMZx/SYYg=" - }, - "tailQualifiersCompartment": { - "$ref": "AAAAAAFq+oHMZx/T4bI=" - }, - "headQualifiersCompartment": { - "$ref": "AAAAAAFq+oHMZx/UTWc=" - } - }, - { - "_type": "UMLGeneralizationView", - "_id": "AAAAAAFq+oH+oCAlC1k=", - "_parent": { - "$ref": "AAAAAAFq+oAmUx5w7f4=" - }, - "model": { - "$ref": "AAAAAAFq+oH+oCAjqHI=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+oH+oCAmriE=", - "_parent": { - "$ref": "AAAAAAFq+oH+oCAlC1k=" - }, - "model": { - "$ref": "AAAAAAFq+oH+oCAjqHI=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 392, - "top": 955, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+oH+oCAlC1k=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+oH+oCAnhOw=", - "_parent": { - "$ref": "AAAAAAFq+oH+oCAlC1k=" - }, - "model": { - "$ref": "AAAAAAFq+oH+oCAjqHI=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 392, - "top": 940, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+oH+oCAlC1k=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+oH+oCAo53A=", - "_parent": { - "$ref": "AAAAAAFq+oH+oCAlC1k=" - }, - "model": { - "$ref": "AAAAAAFq+oH+oCAjqHI=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 392, - "top": 985, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+oH+oCAlC1k=" - }, - "edgePosition": 1 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+oBx4B7483o=" - }, - "tail": { - "$ref": "AAAAAAFq+oB2Tx8hbGI=" - }, - "points": "304:1024;304:976;480:976;480:928", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+oH+oCAmriE=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+oH+oCAnhOw=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+oH+oCAo53A=" - } - }, - { - "_type": "UMLGeneralizationView", - "_id": "AAAAAAFq+oIFgCA/6Ws=", - "_parent": { - "$ref": "AAAAAAFq+oAmUx5w7f4=" - }, - "model": { - "$ref": "AAAAAAFq+oIFfyA95kk=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+oIFgCBAKRs=", - "_parent": { - "$ref": "AAAAAAFq+oIFgCA/6Ws=" - }, - "model": { - "$ref": "AAAAAAFq+oIFfyA95kk=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 465, - "top": 969, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+oIFgCA/6Ws=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+oIFgCBBay4=", - "_parent": { - "$ref": "AAAAAAFq+oIFgCA/6Ws=" - }, - "model": { - "$ref": "AAAAAAFq+oIFfyA95kk=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 450, - "top": 969, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+oIFgCA/6Ws=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+oIFgCBCLsQ=", - "_parent": { - "$ref": "AAAAAAFq+oIFgCA/6Ws=" - }, - "model": { - "$ref": "AAAAAAFq+oIFfyA95kk=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 494, - "top": 970, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+oIFgCA/6Ws=" - }, - "edgePosition": 1 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+oBx4B7483o=" - }, - "tail": { - "$ref": "AAAAAAFq+oB7Kh9Knx8=" - }, - "points": "480:1024;480:928", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+oIFgCBAKRs=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+oIFgCBBay4=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+oIFgCBCLsQ=" - } - }, - { - "_type": "UMLGeneralizationView", - "_id": "AAAAAAFq+oIMkCBZLG0=", - "_parent": { - "$ref": "AAAAAAFq+oAmUx5w7f4=" - }, - "model": { - "$ref": "AAAAAAFq+oIMjyBXRiQ=" - }, - "subViews": [ - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+oIMkCBaMzU=", - "_parent": { - "$ref": "AAAAAAFq+oIMkCBZLG0=" - }, - "model": { - "$ref": "AAAAAAFq+oIMjyBXRiQ=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 559, - "top": 985, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+oIMkCBZLG0=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+oIMkCBbtLs=", - "_parent": { - "$ref": "AAAAAAFq+oIMkCBZLG0=" - }, - "model": { - "$ref": "AAAAAAFq+oIMjyBXRiQ=" - }, - "visible": null, - "font": "Arial;13;0", - "left": 559, - "top": 1000, - "height": 13, - "alpha": 1.5707963267948966, - "distance": 30, - "hostEdge": { - "$ref": "AAAAAAFq+oIMkCBZLG0=" - }, - "edgePosition": 1 - }, - { - "_type": "EdgeLabelView", - "_id": "AAAAAAFq+oIMkCBcKmo=", - "_parent": { - "$ref": "AAAAAAFq+oIMkCBZLG0=" - }, - "model": { - "$ref": "AAAAAAFq+oIMjyBXRiQ=" - }, - "visible": false, - "font": "Arial;13;0", - "left": 560, - "top": 955, - "height": 13, - "alpha": -1.5707963267948966, - "distance": 15, - "hostEdge": { - "$ref": "AAAAAAFq+oIMkCBZLG0=" - }, - "edgePosition": 1 - } - ], - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+oBx4B7483o=" - }, - "tail": { - "$ref": "AAAAAAFq+oCBUB9zs2w=" - }, - "points": "640:1024;640:976;480:976;480:928", - "showVisibility": true, - "nameLabel": { - "$ref": "AAAAAAFq+oIMkCBaMzU=" - }, - "stereotypeLabel": { - "$ref": "AAAAAAFq+oIMkCBbtLs=" - }, - "propertyLabel": { - "$ref": "AAAAAAFq+oIMkCBcKmo=" - } - }, - { - "_type": "UMLNoteView", - "_id": "AAAAAAFq+oQCFiJHdnw=", - "_parent": { - "$ref": "AAAAAAFq+oAmUx5w7f4=" - }, - "font": "Arial;13;0", - "left": 272, - "top": 1160, - "width": 389.8017578125, - "height": 25, - "autoResize": true, - "text": "具体状态,每一个子类实现一个与Context的一个状态相关的行为" - }, - { - "_type": "UMLNoteView", - "_id": "AAAAAAFq+oQIXCJNz0c=", - "_parent": { - "$ref": "AAAAAAFq+oAmUx5w7f4=" - }, - "font": "Arial;13;0", - "left": 56, - "top": 776, - "width": 323.3544921875, - "height": 25, - "text": "维护一个State子类的实例,这个实例定义当前的状态", - "wordWrap": false - }, - { - "_type": "UMLNoteLinkView", - "_id": "AAAAAAFq+oQ5KiKtFbA=", - "_parent": { - "$ref": "AAAAAAFq+oAmUx5w7f4=" - }, - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+oQCFiJHdnw=" - }, - "tail": { - "$ref": "AAAAAAFq+oB2Tx8hbGI=" - }, - "lineStyle": 1, - "points": "356:1089;449:1159" - }, - { - "_type": "UMLNoteLinkView", - "_id": "AAAAAAFq+oQ/pSKzDBc=", - "_parent": { - "$ref": "AAAAAAFq+oAmUx5w7f4=" - }, - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+oQCFiJHdnw=" - }, - "tail": { - "$ref": "AAAAAAFq+oB7Kh9Knx8=" - }, - "lineStyle": 1, - "points": "473:1089;467:1159" - }, - { - "_type": "UMLNoteLinkView", - "_id": "AAAAAAFq+oRGtCK5vAc=", - "_parent": { - "$ref": "AAAAAAFq+oAmUx5w7f4=" - }, - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+oQCFiJHdnw=" - }, - "tail": { - "$ref": "AAAAAAFq+oCBUB9zs2w=" - }, - "lineStyle": 1, - "points": "588:1089;485:1159" - }, - { - "_type": "UMLNoteLinkView", - "_id": "AAAAAAFq+oRORyK/+eE=", - "_parent": { - "$ref": "AAAAAAFq+oAmUx5w7f4=" - }, - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+oQIXCJNz0c=" - }, - "tail": { - "$ref": "AAAAAAFq+oBjKB7P8FQ=" - }, - "lineStyle": 1, - "points": "200:863;214:801" - }, - { - "_type": "UMLNoteLinkView", - "_id": "AAAAAAFq+oReASLG3Q8=", - "_parent": { - "$ref": "AAAAAAFq+oAmUx5w7f4=" - }, - "font": "Arial;13;0", - "head": { - "$ref": "AAAAAAFq+oQN3yJTYnk=" - }, - "tail": { - "$ref": "AAAAAAFq+oBx4B7483o=" - }, - "lineStyle": 1, - "points": "521:863;597:801" - }, - { - "_type": "UMLNoteView", - "_id": "AAAAAAFq+oQN3yJTYnk=", - "_parent": { - "$ref": "AAAAAAFq+oAmUx5w7f4=" - }, - "font": "Arial;13;0", - "left": 400, - "top": 776, - "width": 428.8017578125, - "height": 25, - "autoResize": true, - "text": "抽象状态类,顶一个一个接口封装与Context的一个特定状态相关的行为", - "wordWrap": false - } - ] - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+oBjKB7Ne4Q=", - "_parent": { - "$ref": "AAAAAAFq+oAmUx5vvB8=" - }, - "name": "Context", - "ownedElements": [ - { - "_type": "UMLAssociation", - "_id": "AAAAAAFq+oHMZh/Fl8c=", - "_parent": { - "$ref": "AAAAAAFq+oBjKB7Ne4Q=" - }, - "end1": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFq+oHMZh/Gymw=", - "_parent": { - "$ref": "AAAAAAFq+oHMZh/Fl8c=" - }, - "reference": { - "$ref": "AAAAAAFq+oBjKB7Ne4Q=" - }, - "navigable": false, - "aggregation": "shared" - }, - "end2": { - "_type": "UMLAssociationEnd", - "_id": "AAAAAAFq+oHMZh/HlN8=", - "_parent": { - "$ref": "AAAAAAFq+oHMZh/Fl8c=" - }, - "reference": { - "$ref": "AAAAAAFq+oBx4B72xto=" - } - } - } - ], - "operations": [ - { - "_type": "UMLOperation", - "_id": "AAAAAAFq+oELex+iNak=", - "_parent": { - "$ref": "AAAAAAFq+oBjKB7Ne4Q=" - }, - "name": "request" - } - ] - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+oBx4B72xto=", - "_parent": { - "$ref": "AAAAAAFq+oAmUx5vvB8=" - }, - "name": "State", - "operations": [ - { - "_type": "UMLOperation", - "_id": "AAAAAAFq+oFYIB+pFj8=", - "_parent": { - "$ref": "AAAAAAFq+oBx4B72xto=" - }, - "name": "handle" - } - ], - "isAbstract": true - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+oB2Th8fSHE=", - "_parent": { - "$ref": "AAAAAAFq+oAmUx5vvB8=" - }, - "name": "ConcreteStateA", - "ownedElements": [ - { - "_type": "UMLGeneralization", - "_id": "AAAAAAFq+oH+oCAjqHI=", - "_parent": { - "$ref": "AAAAAAFq+oB2Th8fSHE=" - }, - "source": { - "$ref": "AAAAAAFq+oB2Th8fSHE=" - }, - "target": { - "$ref": "AAAAAAFq+oBx4B72xto=" - } - } - ], - "operations": [ - { - "_type": "UMLOperation", - "_id": "AAAAAAFq+oF8yh+wOR0=", - "_parent": { - "$ref": "AAAAAAFq+oB2Th8fSHE=" - }, - "name": "handle" - } - ] - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+oB7Kh9Ii4U=", - "_parent": { - "$ref": "AAAAAAFq+oAmUx5vvB8=" - }, - "name": "ConcreteStateB", - "ownedElements": [ - { - "_type": "UMLGeneralization", - "_id": "AAAAAAFq+oIFfyA95kk=", - "_parent": { - "$ref": "AAAAAAFq+oB7Kh9Ii4U=" - }, - "source": { - "$ref": "AAAAAAFq+oB7Kh9Ii4U=" - }, - "target": { - "$ref": "AAAAAAFq+oBx4B72xto=" - } - } - ], - "operations": [ - { - "_type": "UMLOperation", - "_id": "AAAAAAFq+oGTdR+33fc=", - "_parent": { - "$ref": "AAAAAAFq+oB7Kh9Ii4U=" - }, - "name": "handle" - } - ] - }, - { - "_type": "UMLClass", - "_id": "AAAAAAFq+oCBUB9xjU8=", - "_parent": { - "$ref": "AAAAAAFq+oAmUx5vvB8=" - }, - "name": "ConcreteStateC", - "ownedElements": [ - { - "_type": "UMLGeneralization", - "_id": "AAAAAAFq+oIMjyBXRiQ=", - "_parent": { - "$ref": "AAAAAAFq+oCBUB9xjU8=" - }, - "source": { - "$ref": "AAAAAAFq+oCBUB9xjU8=" - }, - "target": { - "$ref": "AAAAAAFq+oBx4B72xto=" - } - } - ], - "operations": [ - { - "_type": "UMLOperation", - "_id": "AAAAAAFq+oGbux+9oYo=", - "_parent": { - "$ref": "AAAAAAFq+oCBUB9xjU8=" - }, - "name": "handle" - } - ] - } - ] - } - ] -} \ No newline at end of file diff --git a/distributed/READEME.MD b/distributed/READEME.MD new file mode 100644 index 00000000..ee5fa058 --- /dev/null +++ b/distributed/READEME.MD @@ -0,0 +1,9 @@ +hystrix 如何进行降级、限流、熔断 + +mq 各种mq的使用 + +registration-center 各种注册中心 + +springcloud-netflix netflix组件使用 + +sso 单点登录 \ No newline at end of file diff --git a/distributed/gateway/README.md b/distributed/gateway/README.md new file mode 100644 index 00000000..1c55bcb3 --- /dev/null +++ b/distributed/gateway/README.md @@ -0,0 +1,14 @@ +gateway单独使用 +https://blog.csdn.net/jiongyan6966/article/details/84633632 + +service-product 8081 +http://localhost:8081/method + +service-order-load1 8082 +service-order-load2 8083 +http://localhost:8082/method +http://localhost:8083/method + +zuul-gateway 9000 +http://localhost:9000/shop-api/product/method +http://localhost:9000/shop-api/order/method \ No newline at end of file diff --git a/distributed/gateway/service-order-load1/pom.xml b/distributed/gateway/service-order-load1/pom.xml new file mode 100644 index 00000000..15367fc2 --- /dev/null +++ b/distributed/gateway/service-order-load1/pom.xml @@ -0,0 +1,49 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.2.6.RELEASE + + + cn.lastwhisper + service-order-load1 + 0.0.1-SNAPSHOT + service-a + Demo project for Spring Boot + + + 1.8 + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.junit.vintage + junit-vintage-engine + + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/distributed/gateway/service-order-load1/src/main/java/cn/lastwhisper/service/ServiceB1Application.java b/distributed/gateway/service-order-load1/src/main/java/cn/lastwhisper/service/ServiceB1Application.java new file mode 100644 index 00000000..f896ce24 --- /dev/null +++ b/distributed/gateway/service-order-load1/src/main/java/cn/lastwhisper/service/ServiceB1Application.java @@ -0,0 +1,25 @@ +package cn.lastwhisper.service; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.HashMap; +import java.util.Map; + +@RestController +@SpringBootApplication +public class ServiceB1Application { + + public static void main(String[] args) { + SpringApplication.run(ServiceB1Application.class, args); + } + + @RequestMapping("/method") + public Map methodA(){ + HashMap hashMap = new HashMap<>(); + hashMap.put("service","order 1"); + return hashMap; + } +} diff --git a/distributed/gateway/service-order-load1/src/main/resources/application.yml b/distributed/gateway/service-order-load1/src/main/resources/application.yml new file mode 100644 index 00000000..08841319 --- /dev/null +++ b/distributed/gateway/service-order-load1/src/main/resources/application.yml @@ -0,0 +1,2 @@ +server: + port: 8082 \ No newline at end of file diff --git a/distributed/gateway/service-order-load1/src/test/java/cn/lastwhisper/servicea/ServiceAApplicationTests.java b/distributed/gateway/service-order-load1/src/test/java/cn/lastwhisper/servicea/ServiceAApplicationTests.java new file mode 100644 index 00000000..e1c1731c --- /dev/null +++ b/distributed/gateway/service-order-load1/src/test/java/cn/lastwhisper/servicea/ServiceAApplicationTests.java @@ -0,0 +1,13 @@ +package cn.lastwhisper.service; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class ServiceAApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/distributed/gateway/service-order-load2/pom.xml b/distributed/gateway/service-order-load2/pom.xml new file mode 100644 index 00000000..8a53509f --- /dev/null +++ b/distributed/gateway/service-order-load2/pom.xml @@ -0,0 +1,49 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.2.6.RELEASE + + + cn.lastwhisper + service-order-load2 + 0.0.1-SNAPSHOT + service-a + Demo project for Spring Boot + + + 1.8 + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.junit.vintage + junit-vintage-engine + + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/distributed/gateway/service-order-load2/src/main/java/cn/lastwhisper/service/ServiceB2Application.java b/distributed/gateway/service-order-load2/src/main/java/cn/lastwhisper/service/ServiceB2Application.java new file mode 100644 index 00000000..62c2618f --- /dev/null +++ b/distributed/gateway/service-order-load2/src/main/java/cn/lastwhisper/service/ServiceB2Application.java @@ -0,0 +1,25 @@ +package cn.lastwhisper.service; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.HashMap; +import java.util.Map; + +@RestController +@SpringBootApplication +public class ServiceB2Application { + + public static void main(String[] args) { + SpringApplication.run(ServiceB2Application.class, args); + } + + @RequestMapping("/method") + public Map methodA(){ + HashMap hashMap = new HashMap<>(); + hashMap.put("service","order 2"); + return hashMap; + } +} diff --git a/distributed/gateway/service-order-load2/src/main/resources/application.yml b/distributed/gateway/service-order-load2/src/main/resources/application.yml new file mode 100644 index 00000000..9899989d --- /dev/null +++ b/distributed/gateway/service-order-load2/src/main/resources/application.yml @@ -0,0 +1,2 @@ +server: + port: 8083 \ No newline at end of file diff --git a/distributed/gateway/service-order-load2/src/test/java/cn/lastwhisper/servicea/ServiceAApplicationTests.java b/distributed/gateway/service-order-load2/src/test/java/cn/lastwhisper/servicea/ServiceAApplicationTests.java new file mode 100644 index 00000000..e1c1731c --- /dev/null +++ b/distributed/gateway/service-order-load2/src/test/java/cn/lastwhisper/servicea/ServiceAApplicationTests.java @@ -0,0 +1,13 @@ +package cn.lastwhisper.service; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class ServiceAApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/distributed/gateway/service-product/pom.xml b/distributed/gateway/service-product/pom.xml new file mode 100644 index 00000000..f1d0b245 --- /dev/null +++ b/distributed/gateway/service-product/pom.xml @@ -0,0 +1,49 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.2.6.RELEASE + + + cn.lastwhisper + service-product + 0.0.1-SNAPSHOT + service-a + Demo project for Spring Boot + + + 1.8 + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.junit.vintage + junit-vintage-engine + + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/distributed/gateway/service-product/src/main/java/cn/lastwhisper/service/ServiceAApplication.java b/distributed/gateway/service-product/src/main/java/cn/lastwhisper/service/ServiceAApplication.java new file mode 100644 index 00000000..9af2565f --- /dev/null +++ b/distributed/gateway/service-product/src/main/java/cn/lastwhisper/service/ServiceAApplication.java @@ -0,0 +1,26 @@ +package cn.lastwhisper.service; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.HashMap; +import java.util.Map; + +@RestController +@SpringBootApplication +public class ServiceAApplication { + + public static void main(String[] args) { + SpringApplication.run(ServiceAApplication.class, args); + } + + @RequestMapping("/method") + public Map methodA(){ + HashMap hashMap = new HashMap<>(); + hashMap.put("service","product"); + return hashMap; + } + +} diff --git a/distributed/gateway/service-product/src/main/resources/application.yml b/distributed/gateway/service-product/src/main/resources/application.yml new file mode 100644 index 00000000..54b155ff --- /dev/null +++ b/distributed/gateway/service-product/src/main/resources/application.yml @@ -0,0 +1,2 @@ +server: + port: 8081 \ No newline at end of file diff --git a/distributed/gateway/service-product/src/test/java/cn/lastwhisper/service/ServiceAApplicationTests.java b/distributed/gateway/service-product/src/test/java/cn/lastwhisper/service/ServiceAApplicationTests.java new file mode 100644 index 00000000..e1c1731c --- /dev/null +++ b/distributed/gateway/service-product/src/test/java/cn/lastwhisper/service/ServiceAApplicationTests.java @@ -0,0 +1,13 @@ +package cn.lastwhisper.service; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class ServiceAApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/distributed/gateway/zuul-gateway/pom.xml b/distributed/gateway/zuul-gateway/pom.xml new file mode 100644 index 00000000..900c1c21 --- /dev/null +++ b/distributed/gateway/zuul-gateway/pom.xml @@ -0,0 +1,62 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.2.6.RELEASE + + + cn.lastwhisper + zuul-gateway + 0.0.1-SNAPSHOT + zuul-gateway + gateway + + + 1.8 + Hoxton.SR3 + + + + + org.springframework.cloud + spring-cloud-starter-netflix-zuul + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.junit.vintage + junit-vintage-engine + + + + + + + + + org.springframework.cloud + spring-cloud-dependencies + ${spring-cloud.version} + pom + import + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/distributed/gateway/zuul-gateway/src/main/java/cn/lastwhisper/zuul/ZuulGatewayApplication.java b/distributed/gateway/zuul-gateway/src/main/java/cn/lastwhisper/zuul/ZuulGatewayApplication.java new file mode 100644 index 00000000..7998f028 --- /dev/null +++ b/distributed/gateway/zuul-gateway/src/main/java/cn/lastwhisper/zuul/ZuulGatewayApplication.java @@ -0,0 +1,15 @@ +package cn.lastwhisper.zuul; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.netflix.zuul.EnableZuulProxy; + +@EnableZuulProxy +@SpringBootApplication +public class ZuulGatewayApplication { + + public static void main(String[] args) { + SpringApplication.run(ZuulGatewayApplication.class, args); + } + +} diff --git a/distributed/gateway/zuul-gateway/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/distributed/gateway/zuul-gateway/src/main/resources/META-INF/additional-spring-configuration-metadata.json new file mode 100644 index 00000000..31cf7253 --- /dev/null +++ b/distributed/gateway/zuul-gateway/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -0,0 +1,8 @@ +{ + "properties": [ + { + "name": "api-2.ribbon.listOfServers", + "type": "java.lang.String", + "description": "Description for api-2.ribbon.listOfServers." + } +] } \ No newline at end of file diff --git a/distributed/gateway/zuul-gateway/src/main/resources/application.yml b/distributed/gateway/zuul-gateway/src/main/resources/application.yml new file mode 100644 index 00000000..ccb268ee --- /dev/null +++ b/distributed/gateway/zuul-gateway/src/main/resources/application.yml @@ -0,0 +1,16 @@ +server: + port: 9000 +zuul: + routes: + product: + path: /shop-api/product/** + url: http://localhost:8081/ + order: + path: /shop-api/order/** +# url: http://localhost:8083/ +order: + ribbon: + listOfServers: http://localhost:8082,http://localhost:8083 +ribbon: + eureka: + enabled: false diff --git a/distributed/gateway/zuul-gateway/src/test/java/cn/lastwhisper/zuul/ZuulGatewayApplicationTests.java b/distributed/gateway/zuul-gateway/src/test/java/cn/lastwhisper/zuul/ZuulGatewayApplicationTests.java new file mode 100644 index 00000000..511fa9a9 --- /dev/null +++ b/distributed/gateway/zuul-gateway/src/test/java/cn/lastwhisper/zuul/ZuulGatewayApplicationTests.java @@ -0,0 +1,13 @@ +package cn.lastwhisper.zuul; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class ZuulGatewayApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/java-basic/spring/src/main/resources/application.properties b/distributed/gray/README.md similarity index 100% rename from java-basic/spring/src/main/resources/application.properties rename to distributed/gray/README.md diff --git a/distributed/gray/pom.xml b/distributed/gray/pom.xml new file mode 100644 index 00000000..f25dbc3e --- /dev/null +++ b/distributed/gray/pom.xml @@ -0,0 +1,59 @@ + + + 4.0.0 + + cn.cunchang + gray + 1.0-SNAPSHOT + + + 8 + 8 + + + + + org.springframework.boot + spring-boot-starter-web + 2.2.4.RELEASE + + + + org.redisson + redisson-spring-boot-starter + 3.12.3 + + + + org.projectlombok + lombok + 1.18.22 + + + + com.alibaba + fastjson + 1.2.80 + + + + com.google.guava + guava + 30.1.1-jre + + + + org.apache.commons + commons-lang3 + 3.10 + + + + org.apache.commons + commons-collections4 + 4.2 + + + \ No newline at end of file diff --git a/distributed/gray/src/main/java/cn/cunchang/Application.java b/distributed/gray/src/main/java/cn/cunchang/Application.java new file mode 100644 index 00000000..69748ef6 --- /dev/null +++ b/distributed/gray/src/main/java/cn/cunchang/Application.java @@ -0,0 +1,14 @@ +package cn.cunchang; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.context.properties.EnableConfigurationProperties; + +@SpringBootApplication() +@EnableConfigurationProperties +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } +} diff --git a/distributed/gray/src/main/java/cn/cunchang/v1/Constant.java b/distributed/gray/src/main/java/cn/cunchang/v1/Constant.java new file mode 100644 index 00000000..375343dd --- /dev/null +++ b/distributed/gray/src/main/java/cn/cunchang/v1/Constant.java @@ -0,0 +1,30 @@ +package cn.cunchang.v1; + +/** + * + */ +public interface Constant { + + + /** + * 灰度 + */ + String GRAY = "gray"; + + + /** + * 正常 + */ + String NORMAL = "normal"; + + /** + * 灰度数量 + */ + String GRAY_NUMBER = "grayNumber"; + + + /** + * 正常请求数量 + */ + String NORMAL_NUMBER = "normalNumber"; +} diff --git a/distributed/gray/src/main/java/cn/cunchang/v1/GrayHelper.java b/distributed/gray/src/main/java/cn/cunchang/v1/GrayHelper.java new file mode 100644 index 00000000..b71ebf68 --- /dev/null +++ b/distributed/gray/src/main/java/cn/cunchang/v1/GrayHelper.java @@ -0,0 +1,155 @@ +package cn.cunchang.v1; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.util.CollectionUtils; + +import java.util.HashMap; +import java.util.Map; + +/** + * + */ +@Slf4j(topic = "gray") +public class GrayHelper { + + /** + * 灰度权重规则key + */ + public final static String GRAY_RULE_STR_KEY = "gray_rule_str_key"; + + /** + * 灰度权重map + */ + private static Map groupMap = new HashMap(); + + + private Map grayRuleCache; + + + /** + * 灰度是否开启 + */ + private static boolean grayOpen = false; + + + /** + * 灰度开启的情况下是否全部走灰度 + */ + private static boolean allRequestGray = false; + + + /** + * 加载灰度权重规则 + * 配置格式: + * {"requestConfig":[{"id":1,"grayNumber":100,"normarlNumber":9900},{"id":2,"grayNumber":1000,"normarlNumber":9000}],"allRequestGray":true,"grayOpen":true} + */ + public void loadRule(){ + + try { + String grayRule = grayRuleCache.get(GRAY_RULE_STR_KEY); + + if(StringUtils.isBlank(grayRule)){ + log.error("gray_rule_str is null"); + return; + } + JSONObject jsonObject = JSONObject.parseObject(grayRule); + //是否开启灰度 + boolean go = jsonObject.getBoolean("grayOpen"); + + grayOpen = go; + + //灰度开启后是否全部走灰度 + boolean arg = jsonObject.getBoolean("allRequestGray"); + + allRequestGray = arg; + + JSONArray jsonArray = jsonObject.getJSONArray("requestConfig"); + if(CollectionUtils.isEmpty(jsonArray)){ + log.warn("requestConfig is empty"); + return; + } + for (Object o : jsonArray) { + JSONObject j = (JSONObject)o; + Integer id = j.getInteger("id"); + WeightCategory grayWeightCategory = new WeightCategory(Constant.GRAY,j.getInteger("grayNumber")); + WeightCategory normalWeightCategory = new WeightCategory(Constant.NORMAL,j.getInteger("normarlNumber")); + InterfaceWeightGroup interfaceWeightGroup = new InterfaceWeightGroup(id,grayWeightCategory,normalWeightCategory); + groupMap.put(id,interfaceWeightGroup); + } + log.info("loadRule finish,groupMap:{}",JSONObject.toJSONString(groupMap)); + + + }catch (Exception e){ + log.error("load loadRule error",e); + } + + } + + /** + * 是否命中灰度 + * @param requestConfigId + * @return + */ + public boolean isGray(Integer requestConfigId){ + try { + if(!grayOpen){ + log.info("grayOpen is false"); + return false; + } + if(requestConfigId == null){ + return false; + } + + InterfaceWeightGroup interfaceWeightGroup = groupMap.get(requestConfigId); + //找不到配置,则返回false + if(interfaceWeightGroup == null){ + return false; + } + return interfaceWeightGroup.accessGray(); + }catch (Exception e){ + log.error("error to isGray",e); + return false; + } + + } + + public static void main(String[] args) { + + JSONArray jsonArray = new JSONArray(); + for (int i =0; i < 3 ;i ++) { + JSONObject requestConfig1 = new JSONObject(); + requestConfig1.put("id",i +1); + requestConfig1.put("grayNumber",100); + requestConfig1.put("normalNumber",9900); + jsonArray.add(requestConfig1); + } + + JSONObject jsonObject = new JSONObject(); + jsonObject.put("requestConfigList",jsonArray); + + System.out.println(jsonArray); + + + + //JSONArray jsonArray = JSONObject.parseArray(rBucket.get()); + if(CollectionUtils.isEmpty(jsonArray)){ + log.warn("requestConfig is empty"); + return; + } + for (Object o : jsonArray) { + JSONObject j = (JSONObject)o; + Integer id = j.getInteger("id"); + WeightCategory grayWeightCategory = new WeightCategory(Constant.GRAY,j.getInteger(Constant.GRAY_NUMBER)); + WeightCategory normalWeightCategory = new WeightCategory(Constant.NORMAL,j.getInteger(Constant.NORMAL_NUMBER)); + InterfaceWeightGroup interfaceWeightGroup = new InterfaceWeightGroup(id,grayWeightCategory,normalWeightCategory); + groupMap.put(id,interfaceWeightGroup); + } + log.info("loadRule finish,groupMap={}",JSONObject.toJSONString(groupMap)); + } + + + +} diff --git a/distributed/gray/src/main/java/cn/cunchang/v1/InterfaceWeightGroup.java b/distributed/gray/src/main/java/cn/cunchang/v1/InterfaceWeightGroup.java new file mode 100644 index 00000000..e8734362 --- /dev/null +++ b/distributed/gray/src/main/java/cn/cunchang/v1/InterfaceWeightGroup.java @@ -0,0 +1,153 @@ +package cn.cunchang.v1; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.util.CollectionUtils; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +/** + * + */ +@Slf4j(topic = "gray") +public class InterfaceWeightGroup { + + + /** + * 权重配置ID + */ + private Integer id; + + + /** + * 灰度权重对象 + */ + private WeightCategory grayWeightCategory = null; + + /** + * 正常请求权重对象 + */ + private WeightCategory normalWeightCategory = null; + + /** + * 灰度请求进来次数 + */ + private int grayRequestAccessNumber = 0; + + + /** + * 权重请求列表 + */ + private List categoryList=new ArrayList<>(); + + /** + * 初始化 + */ + private void init(){ + + categoryList.add(grayWeightCategory); + categoryList.add(normalWeightCategory); + + } + + + + public InterfaceWeightGroup(Integer id,WeightCategory grayWeightCategory,WeightCategory normalWeightCategory){ + this.id = id; + this.grayWeightCategory = grayWeightCategory; + this.normalWeightCategory = normalWeightCategory; + //添加权重到list + init(); + } + + /** + * 此次是否是灰度 + * @return + */ + public boolean accessGray(){ + + String categoryName = getWeight(categoryList); + + if(Constant.GRAY.equals(categoryName)){ + grayRequestAccessNumber ++; + log.info("id={},grayRequestAccessNumber={}",id,grayRequestAccessNumber); + return true; + } + + return false; + + } + + /** + * 权重获取方法 + * @param categorys + * @return + */ + public String getWeight(List categorys) { + + if(CollectionUtils.isEmpty(categorys)){ + return Constant.NORMAL; + } + + Integer weightSum = 0; + String result=null; + for (WeightCategory wc : categorys) { + weightSum += wc.getWeight(); + } + + if (weightSum <= 0) { + log.error("Error: weightSum=" + weightSum.toString()); + return result; + } + Random random = new Random(); + Integer n = random.nextInt(weightSum); // n in [0, weightSum) + Integer m = 0; + for (WeightCategory wc : categorys) { + if (m <= n && n < m + wc.getWeight()) { + result=wc.getCategory(); + break; + } + m += wc.getWeight(); + } + + return result; + } + + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public WeightCategory getGrayWeightCategory() { + return grayWeightCategory; + } + + public void setGrayWeightCategory(WeightCategory grayWeightCategory) { + this.grayWeightCategory = grayWeightCategory; + } + + public WeightCategory getNormalWeightCategory() { + return normalWeightCategory; + } + + public void setNormalWeightCategory(WeightCategory normalWeightCategory) { + this.normalWeightCategory = normalWeightCategory; + } + + public int getGrayRequestAccessNumber() { + return grayRequestAccessNumber; + } + + public void setGrayRequestAccessNumber(int grayRequestAccessNumber) { + this.grayRequestAccessNumber = grayRequestAccessNumber; + } + + + + +} diff --git a/distributed/gray/src/main/java/cn/cunchang/v1/WeightCategory.java b/distributed/gray/src/main/java/cn/cunchang/v1/WeightCategory.java new file mode 100644 index 00000000..bb0c0a4b --- /dev/null +++ b/distributed/gray/src/main/java/cn/cunchang/v1/WeightCategory.java @@ -0,0 +1,36 @@ +package cn.cunchang.v1; + +/** + * 权重分类 + * + */ +public class WeightCategory { + + //类别 + private String category; + //权重值 + private int weight; + + public WeightCategory(String category, int weight) { + this.category = category; + this.weight = weight; + } + + public String getCategory() { + return category; + } + + public void setCategory(String category) { + this.category = category; + } + + public int getWeight() { + return weight; + } + + public void setWeight(int weight) { + this.weight = weight; + + } + +} diff --git a/distributed/gray/src/main/java/cn/cunchang/v1/WeightRandom.java b/distributed/gray/src/main/java/cn/cunchang/v1/WeightRandom.java new file mode 100644 index 00000000..02f1ba8c --- /dev/null +++ b/distributed/gray/src/main/java/cn/cunchang/v1/WeightRandom.java @@ -0,0 +1,103 @@ +package cn.cunchang.v1; + +import com.google.common.base.Preconditions; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import javafx.util.Pair; +import lombok.extern.slf4j.Slf4j; + +import java.util.*; + +@Slf4j +public class WeightRandom { + + /** + * 以权重为key + */ + private TreeMap weightMap = new TreeMap<>(); + + public WeightRandom(List> list) { + Preconditions.checkNotNull(list, "list can NOT be null!"); + for (Pair pair : list) { + // 权重值需大于0 + Preconditions.checkArgument(pair.getValue().doubleValue() > 0, String.format("非法权重值:pair=%s", pair)); + + double lastWeight = this.weightMap.size() == 0 ? 0 : this.weightMap.lastKey(); + + //权重累加值作为map的key + this.weightMap.put(pair.getValue().doubleValue() + lastWeight, pair.getKey()); + } + } + + public K random() { + // 在权重累加值范围内生成随机值 + double randomWeight = this.weightMap.lastKey() * Math.random(); + // 取key权重值大于随机值的节点 + SortedMap tailMap = this.weightMap.tailMap(randomWeight, false); + // 再取第一个节点 + return this.weightMap.get(tailMap.firstKey()); + } + + public static void main(String[] args) { + + List> list; + + WeightRandom random; + + list = Lists.newArrayList(); + list.add(new Pair<>("Gray", 1)); + list.add(new Pair<>("Normal", 9)); + + random = new WeightRandom<>(list); + + Map countMap = Maps.newHashMap(); + for (int i = 0; i < 10000; i++) { + String randomKey = random.random(); + countMap.put(randomKey, countMap.getOrDefault(randomKey, 0) + 1); + } + + for (Pair pair : list) { + log.debug("{}:{}", pair.getKey(), countMap.get(pair.getKey())); + } + } + + +// public static void main(String[] args) { +// List> pairs = new ArrayList<>(); +// pairs.add(new Pair<>("a", 1D)); +// pairs.add(new Pair<>("b", 1D)); +// pairs.add(new Pair<>("c", 1D)); +// pairs.add(new Pair<>("d", 1D)); +// pairs.add(new Pair<>("e", 1D)); +// pairs.add(new Pair<>("f", 6D)); +// WeightRandom weightRandom = new WeightRandom<>(pairs); +// int a = 0, b = 0, c = 0, d = 0, e = 0, f = 0; +// for (int i = 0; i < 110000; i++) { +// String key = weightRandom.random(); +// if ("a".equals(key)) { +// a++; +// } +// if ("b".equals(key)) { +// b++; +// } +// if ("c".equals(key)) { +// c++; +// } +// if ("d".equals(key)) { +// d++; +// } +// if ("e".equals(key)) { +// e++; +// } +// if ("f".equals(key)) { +// f++; +// } +// } +// System.out.println(a);// 9994 +// System.out.println(b);// 10035 +// System.out.println(c);// 10119 +// System.out.println(d);// 9950 +// System.out.println(e);// 10088 +// System.out.println(f);// 59814 +// } +} \ No newline at end of file diff --git a/distributed/gray/src/main/java/cn/cunchang/v1/WeightTest.java b/distributed/gray/src/main/java/cn/cunchang/v1/WeightTest.java new file mode 100644 index 00000000..716dea1d --- /dev/null +++ b/distributed/gray/src/main/java/cn/cunchang/v1/WeightTest.java @@ -0,0 +1,74 @@ +package cn.cunchang.v1; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +/** + * + */ +public class WeightTest { + + public static void main(String[] args) throws Exception{ + + //测试数据 + List categoryList=new ArrayList<>(); + WeightCategory weightCategory1=new WeightCategory("一等奖",100); + WeightCategory weightCategory2=new WeightCategory("二等奖",900); + categoryList.add(weightCategory1); + categoryList.add(weightCategory2); + + String result= ""; + int a1=0,a2=0; + for (int i=0;i<1000;i++){ + if(i%50 ==0){ + System.out.println("sleep "); + Thread.currentThread().sleep(5000L); + } + result = getWeight(categoryList); + System.out.println(i+" 开奖结果: "+result); + if(result.equals("一等奖")){ + a1++; + } + else if(result.equals("二等奖")){ + a2++; + } + } + + System.out.println("一等奖共出现 "+a1); + System.out.println("二等奖共出现 "+a2); + + + } + + /** + * 权重获取方法 + * @param categorys + * @return + */ + public static String getWeight(List categorys) { + Integer weightSum = 0; + String result=null; + for (WeightCategory wc : categorys) { + weightSum += wc.getWeight(); + } + + if (weightSum <= 0) { + System.err.println("Error: weightSum=" + weightSum.toString()); + return result; + } + Random random = new Random(); + Integer n = random.nextInt(weightSum); // n in [0, weightSum) + Integer m = 0; + for (WeightCategory wc : categorys) { + if (m <= n && n < m + wc.getWeight()) { + result=wc.getCategory(); + break; + } + m += wc.getWeight(); + } + return result; + } + + +} diff --git a/distributed/gray/src/main/java/cn/cunchang/v2/Constant.java b/distributed/gray/src/main/java/cn/cunchang/v2/Constant.java new file mode 100644 index 00000000..a325b9d2 --- /dev/null +++ b/distributed/gray/src/main/java/cn/cunchang/v2/Constant.java @@ -0,0 +1,31 @@ +package cn.cunchang.v2; + +/** + * Created by qiumu on 2020/10/10. + */ +public interface Constant { + + + /** + * 灰度 + */ + String GRAY = "gray"; + + + /** + * 正常 + */ + String NORMAL = "normal"; + + + /** + * 灰度数量 + */ + String GRAY_NUMBER = "grayNumber"; + + + /** + * 正常请求数量 + */ + String NORMAL_NUMBER = "normalNumber"; +} diff --git a/distributed/gray/src/main/java/cn/cunchang/v2/GrayHelper.java b/distributed/gray/src/main/java/cn/cunchang/v2/GrayHelper.java new file mode 100644 index 00000000..68ff11eb --- /dev/null +++ b/distributed/gray/src/main/java/cn/cunchang/v2/GrayHelper.java @@ -0,0 +1,310 @@ +package cn.cunchang.v2; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.MapUtils; +import org.apache.commons.lang3.StringUtils; +import org.redisson.api.RBucket; +import org.redisson.api.RedissonClient; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +import javax.annotation.PostConstruct; +import javax.annotation.Resource; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Created by qiumu on 2020/10/10. + */ +@Slf4j(topic = "grayLog") +@Service("grayHelper") +public class GrayHelper { + + /** + * 灰度权重规则key + */ + public final static String GRAY_RULE_STR_KEY = "gray_rule_str_key"; + + + /** + * 灰度开关key + */ + public final static String GRAY_OPEN_KEY = "gray_open"; + + + /** + * 灰度权重规则key + */ + public final static String ALL_REQUEST_GRAY_KEY = "all_request_gray"; + + + /** + * 灰度用户ID列表 + */ + public final static String GRAY_USER_ID_LIST = "grayUserIdList"; + + /** + * 请求配置列表 + */ + public final static String REQUEST_CONFIG_LIST = "requestConfigList"; + + /** + * 灰度权重map + */ + private static Map groupMap = new HashMap(); + + + /** + * 白名单用户ID列表 + */ + private static List userIdList = new ArrayList(); + + @Resource + private RedissonClient redissonClient; + + /** + * 设置灰度是否开启 + * @param grayOpen + */ + public void setGrayOpen(String grayOpen){ + + try { + RBucket rBucket = redissonClient.getBucket(GRAY_OPEN_KEY); + rBucket.set(Boolean.valueOf(grayOpen)); + }catch (Exception e){ + log.error("error to setGrayOpen",e); + } + } + + /** + * 设置灰度是否开启 + * @param allRequestGray + */ + public void setAllRequestGray(String allRequestGray){ + + try { + RBucket rBucket = redissonClient.getBucket(ALL_REQUEST_GRAY_KEY); + rBucket.set(Boolean.valueOf(allRequestGray)); + }catch (Exception e){ + log.error("error to setAllRequestGray",e); + } + } + + /** + * 获取是否开启灰度 + * @return + */ + public Boolean getGrayOpen(){ + + try { + RBucket rBucket = redissonClient.getBucket(GRAY_OPEN_KEY); + if(rBucket == null || rBucket.get()==null){ + return false; + } + return rBucket.get(); + }catch (Exception e){ + log.error("error to getGrayOpen",e); + } + return false; + } + + + /** + * 获取是否全部请求走灰度 + * @return + */ + public Boolean getAllRequestGray(){ + + try { + RBucket rBucket = redissonClient.getBucket(ALL_REQUEST_GRAY_KEY); + if(rBucket == null || rBucket.get()==null){ + return false; + } + return rBucket.get(); + }catch (Exception e){ + log.error("error to getAllRequestGray",e); + } + return false; + } + + + + + /** + * 加载灰度权重规则,grayUserIdList为白名单,白名单不为空,则优先走白名单策略,否则走接口权重策略。requestConfigList为接口灰度权重访问策略。 + * 配置格式: + * {"grayUserIdList":[12323,12323,2323,23244],"requestConfigList":[{"normalNumber":80,"id":1,"grayNumber":20},{"normalNumber":80,"id":2,"grayNumber":20},{"normalNumber":80,"id":3,"grayNumber":20}]} + */ + /** + * 启动后自动加载 + * @return + */ + @PostConstruct + public synchronized boolean loadRule(){ + + try { + RBucket rBucket = redissonClient.getBucket(GRAY_RULE_STR_KEY); + + if(rBucket == null || StringUtils.isBlank(rBucket.get())){ + log.error("gray_rule_str is null"); + return false; + } + //灰度策略json字符串 + String config = rBucket.get(); + log.info("config={}",config); + JSONObject jsonObject = JSONObject.parseObject(config); + + //设置白名单 + JSONArray grayUserArrayList = jsonObject.getJSONArray(GRAY_USER_ID_LIST); + + //先清空在重新添加 + userIdList.clear(); + //不为空则重新添加 + if(!CollectionUtils.isEmpty(grayUserArrayList)){ + + for (Object userId : grayUserArrayList){ + userIdList.add((Integer)userId); + } + } + + + //设置groupMap + JSONArray jsonArray = jsonObject.getJSONArray(REQUEST_CONFIG_LIST); + if(CollectionUtils.isEmpty(jsonArray)){ + log.warn("requestConfig is empty"); + return false; + } + for (Object o : jsonArray) { + JSONObject j = (JSONObject)o; + Integer id = j.getInteger("id"); + WeightCategory grayWeightCategory = new WeightCategory(Constant.GRAY,j.getInteger(Constant.GRAY_NUMBER)); + WeightCategory normalWeightCategory = new WeightCategory(Constant.NORMAL,j.getInteger(Constant.NORMAL_NUMBER)); + InterfaceWeightGroup interfaceWeightGroup = new InterfaceWeightGroup(id,grayWeightCategory,normalWeightCategory); + groupMap.put(id,interfaceWeightGroup); + } + log.info("loadRule finish,userIdList={}",JSONObject.toJSONString(userIdList)); + log.info("loadRule finish,groupMap={}",JSONObject.toJSONString(groupMap)); + + + }catch (Exception e){ + log.error("load loadRule error",e); + return false; + } + + return true; + } + + /** + * 是否命中灰度 + * @param requestConfigId + * @return + */ + public boolean isGray(Integer requestConfigId){ + try { + //如果灰度关闭则返回false + if(!getGrayOpen()){ + log.info("grayOpen is false"); + return false; + } + //如果灰度打开,并且所有请求都走灰度则返回true + if(getAllRequestGray()){ + log.info("access gray interface,requestConfigId={}",requestConfigId); + return true; + } + if(requestConfigId == null){ + return false; + } + + if(MapUtils.isEmpty(groupMap)){ + loadRule(); + } + + InterfaceWeightGroup interfaceWeightGroup = groupMap.get(requestConfigId); + //找不到配置,则返回false + if(interfaceWeightGroup == null){ + return false; + } + return interfaceWeightGroup.accessGray(); + }catch (Exception e){ + log.error("error to isGray",e); + return false; + } + + } + + /** + * 是否命中灰度 + * @param requestConfigId 接口配置ID + * @param userId 用户ID + * @return + */ + public boolean isGray(Integer requestConfigId,Integer userId){ + try { + //如果灰度关闭则返回false + if(!getGrayOpen()){ + log.info("grayOpen is false"); + return false; + } + //如果灰度打开,并且所有请求都走灰度则返回true + if(getAllRequestGray()){ + log.info("access gray interface,requestConfigId={}",requestConfigId); + return true; + } + + if(requestConfigId == null){ + return false; + } + + //如果用户白名单策略不为空,则优先走白名单判断 + if(!CollectionUtils.isEmpty(userIdList)){ + if(userIdList.contains(userId)){ + log.info("access gray interface,requestConfigId={},userId={}",requestConfigId,userId); + return true; + } + return false; + } + + if(MapUtils.isEmpty(groupMap)){ + loadRule(); + } + + InterfaceWeightGroup interfaceWeightGroup = groupMap.get(requestConfigId); + //找不到配置,则返回false + if(interfaceWeightGroup == null){ + return false; + } + return interfaceWeightGroup.accessGray(); + }catch (Exception e){ + log.error("error to isGray",e); + return false; + } + + } + + public static void main(String[] args){ + JSONArray jsonArray = new JSONArray(); + + JSONObject requestConfig1 = new JSONObject(); + requestConfig1.put("id",1); + requestConfig1.put("grayNumber",100); + requestConfig1.put("normalNumber",9900); + + JSONObject requestConfig2 = new JSONObject(); + requestConfig2.put("id",2); + requestConfig2.put("grayNumber",1000); + requestConfig2.put("normalNumber",9000); + + jsonArray.add(requestConfig1); + jsonArray.add(requestConfig2); + + + System.out.println(jsonArray); + } + + + +} diff --git a/distributed/gray/src/main/java/cn/cunchang/v2/InterfaceWeightGroup.java b/distributed/gray/src/main/java/cn/cunchang/v2/InterfaceWeightGroup.java new file mode 100644 index 00000000..a630ba51 --- /dev/null +++ b/distributed/gray/src/main/java/cn/cunchang/v2/InterfaceWeightGroup.java @@ -0,0 +1,152 @@ +package cn.cunchang.v2; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.util.CollectionUtils; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * Created by qiumu on 2020/10/10. + */ +@Slf4j(topic = "grayLog") +public class InterfaceWeightGroup { + + + + /** + * 权重配置ID + */ + private Integer id; + + + /** + * 灰度权重对象 + */ + private WeightCategory grayWeightCategory = null; + + /** + * 正常请求权重对象 + */ + private WeightCategory normalWeightCategory = null; + + /** + * 灰度请求进来次数 + */ + private AtomicInteger grayRequestAccessNumber = new AtomicInteger(0); + + /** + * 灰度请求进来次数 + */ + private AtomicInteger normalRequestAccessNumber = new AtomicInteger(0);; + + + /** + * 权重请求列表 + */ + private List categoryList=new ArrayList<>(); + + /** + * 初始化 + */ + private void init(){ + + categoryList.add(grayWeightCategory); + categoryList.add(normalWeightCategory); + + } + + + + public InterfaceWeightGroup(Integer id,WeightCategory grayWeightCategory,WeightCategory normalWeightCategory){ + this.id = id; + this.grayWeightCategory = grayWeightCategory; + this.normalWeightCategory = normalWeightCategory; + //添加权重到list + init(); + } + + /** + * 此次是否是灰度 + * @return + */ + public boolean accessGray(){ + + String categoryName = getWeight(categoryList); + + if(Constant.GRAY.equals(categoryName)){ + int grayNumber = grayRequestAccessNumber.incrementAndGet(); + log.info("id={},grayRequestAccessNumber={}",id,grayNumber); + return true; + } + + int normalNumber = normalRequestAccessNumber.incrementAndGet(); + log.info("id={},normalRequestAccessNumber={}",id,normalNumber); + + return false; + + } + + /** + * 权重获取方法 + * @param categorys + * @return + */ + public String getWeight(List categorys) { + + if(CollectionUtils.isEmpty(categorys)){ + return Constant.NORMAL; + } + + Integer weightSum = 0; + String result=null; + for (WeightCategory wc : categorys) { + weightSum += wc.getWeight(); + } + + if (weightSum <= 0) { + log.error("Error: weightSum=" + weightSum.toString()); + return result; + } + Random random = new Random(); + Integer n = random.nextInt(weightSum); // n in [0, weightSum) + Integer m = 0; + for (WeightCategory wc : categorys) { + if (m <= n && n < m + wc.getWeight()) { + result=wc.getCategory(); + break; + } + m += wc.getWeight(); + } + + return result; + } + + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public WeightCategory getGrayWeightCategory() { + return grayWeightCategory; + } + + public void setGrayWeightCategory(WeightCategory grayWeightCategory) { + this.grayWeightCategory = grayWeightCategory; + } + + public WeightCategory getNormalWeightCategory() { + return normalWeightCategory; + } + + public void setNormalWeightCategory(WeightCategory normalWeightCategory) { + this.normalWeightCategory = normalWeightCategory; + } + +} diff --git a/distributed/gray/src/main/java/cn/cunchang/v2/UrlListEnum.java b/distributed/gray/src/main/java/cn/cunchang/v2/UrlListEnum.java new file mode 100644 index 00000000..b82fc015 --- /dev/null +++ b/distributed/gray/src/main/java/cn/cunchang/v2/UrlListEnum.java @@ -0,0 +1,150 @@ +package cn.cunchang.v2; + +/** + * 付款计划、付款申请单、提现申请单leo迁移的接口列表 + * Created by qiumu on 2020/10/28. + */ +public enum UrlListEnum { + + PC进场费管理_付款计划_1(1,"leo/1.0/payPlan/list"), + + PC合同详情_付款计划_2(2,"leo/1.0/payPlan/detail"), + + PC合同详情_付款计划_新增付款计划_3(3,"leo/1.0/payPlan/add"), + + PC合同详情_付款计划_新增其他费用付款计划_4(4,"leo/1.0/other/fee/payPlan/add"), + + PC合同详情_付款计划_新增押金付款计划_5(5,"leo/1.0/deposit/plan/create"), + + PC合同详情_付款计划_删除_6(6,"leo/1.0/payPlan/delete"), + + PC合同详情_付款计划_发起请款_查询付款计划_7(7,"leo/1.0/payPlanLine/detail"), + + 瓯柑那边调用_根据付款申请单号获取付款计划税前金额_8(8,"leo/1.0/payPlan/getByApplyNo"), + + 付款成功后lvy回调leo更新付款计划为付款成功_9(9,"leo/1.0/payApply/pay/callback"), + + 移动端付款申请单列表_10(10,"leo/search/payApply"), + + PC合同_付款计划_发起请款_提交_check_11(11,"leo/1.0/payPlan/check"), + + PC合同_付款计划_发起请款_提交_12(12,"leo/1.0/payPlan/edit"), + + 付款申请单列表_查询条件subjectTypeList_13(13,"leo/1.0/scm/invoice/subjectType/list"), + + 付款申请单列表List_14(14,"leo/1.0/payApply/list"), + + 付款申请单列表sum_15(15,"leo/1.0/payApply/sumAmount"), + + 直营付款申请单获取审批人_16(16,"leo/1.0/approval/task/checker/payment/apply"), + + KA付款申请单获取审批人_17(17,"leo/1.0/approval/task/checker/ka/payment/apply"), + + KA付款申请单获取审批人2_18(18,"leo/1.0/approval/task/checker/payment/apply/ka"), + + 付款申请单回调_19(19,"leo/1.0/payApply/check/result"), + + 付款申请单撤回_20(20,"leo/1.0/payPlan/recall"), + + PC付款申请单_发票核销_21(21,"leo/1.0/payApply/invoice/use"), + + PC付款申请单_切换票款顺序_22(22,"leo/1.0/payApply/invoice/updateMethod"), + + PC付款申请单_审批详情1_23(23,"leo/1.0/approval/purchasePlan/getProcessDetail"), + + PC付款申请单_审批详情2_24(24,"leo/1.0/payApply/check/detail"), + + PC付款申请单_申请详情_25(25,"leo/1.0/payApply/detail"), + + 提现申请回调_26(26,"leo/1.0/approval/callback/merchant/withDraw/add"), + + 商户提现流程审批流程获取任务节点的审批人接口_27(27,"leo/1.0/approval/task/checker/merchant/withDraw/add"), + + 移动端提现申请列表_28(28,"/leo/search/withdrawals"), + + PC端_财务管理_提现申请_提现申请列表List_29(29,"leo/1.0/merchant/withDraw/queryWithdrawList"), + + PC端_财务管理_提现申请_提现申请列表Sum_30(30,"leo/1.0/merchant/withDraw/sumAmount"), + + PC端_财务管理_提现申请_提现申请列表查询条件1_31(31,"leo/1.0/h5/merchant/withDraw/clientStatusList"), + + PC端_财务管理_提现申请_提现申请列表查询条件2_32(32,"leo/1.0/h5/merchant/withDraw/statusList"), + + PC端_财务管理_提现申请_提现申请列表_审核_通过_拒绝_冻结_33(33,"leo/1.0/merchant/withDraw/financialOperationCheck"), + + PC端_财务管理_提现申请_提现申请列表_审批详情_34(34,"leo/1.0/approval/purchasePlan/getProcessDetail"), + + PC端_财务管理_提现申请_提现申请列表_审核_35(35,"leo/1.0/merchant/withDraw/getWithdrawalDetail"), + + PC端_财务管理_提现申请_提现申请列表_发票核对_查询发票_36(36,"leo/1.0/merchant/withDraw/getInvoiceInfo"), + + PC端_财务管理_提现申请_提现申请列表_发票核对_通过_不通过_37(37,"leo/1.0/merchant/withDraw/invoiceCheck"), + + 移动端_审批中心_提现修改发票_38(38,"leo/1.0/merchant/withDraw/modifyInvoiceInfo"), + + PC端_财务管理_提现申请_先款后票白名单维护_39(39,"leo/1.0/withdrawals/whitelist/list"), + + PC端_财务管理_提现申请_先款后票白名单维护_新增_40(40,"leo/1.0/withdrawals/whitelist/batch"), + + PC端_财务管理_提现申请_先款后票白名单维护_作废_41(41,"leo/1.0/withdrawals/whitelist/{mainBizId}"), + + PC端_财务管理_提现申请_先款后票白名单维护_生效_作废_42(42,"leo/1.0/withdrawals/whitelist/enable/{mainBizId}"), + + PC端_财务管理_提现申请_先款后票白名单维护_导出_43(43,"leo/1.0/withdrawals/whitelist/export"), + + 提现申请_导出_44(44,"leo/1.0/h5/merchant/withDraw/export"), + + lvy账单任务创建AccountFreezeTask_45(45,"leo/1.0/merchant/withDraw/recall/byLvy"), + + 提现批量审核_查询_46(46,"leo/1.0/h5/merchant/withDraw/batch/getTaskInfo"), + + 提现批量审核_下一步47(47,"leo/1.0/h5/merchant/withDraw/batch/getAuditDetailList"), + + 批量处理审批任务48(48,"leo/1.0/h5/merchant/withDraw/batchHandleApprovalTask"), + + BD审核任务_49(49,"/leo/1.0/merchant/withDraw/addBdCheckOperatorRecord"), + + 获取提现发票信息_50(50,"/leo/1.0/merchant/withdrawal/invoice"), + + 获取批量审批提现单列表_51(51,"/leo/1.0/merchant/withDraw/batch/getList"), + + 获取批量审批提现单列表总金额_52(52,"/leo/1.0/merchant/withDraw/batch/sumAmount"), + + 批量审核提交_53(53,"/leo/1.0/merchant/withDraw/batch/submit"), + + 提现先款后票_发票核销_54(54,"/leo/1.0/withdrawals/invoice/deduct"), + + ; + + + + + /** + * 接口ID + */ + private Integer id ; + + + /** + * + */ + private String url; + + + UrlListEnum(Integer id,String url){ + this.id = id; + this.url = url; + } + + + public Integer getId() { + return id; + } + + public String getUrl() { + return url; + } + + + +} diff --git a/distributed/gray/src/main/java/cn/cunchang/v2/WeightCategory.java b/distributed/gray/src/main/java/cn/cunchang/v2/WeightCategory.java new file mode 100644 index 00000000..4c730a23 --- /dev/null +++ b/distributed/gray/src/main/java/cn/cunchang/v2/WeightCategory.java @@ -0,0 +1,36 @@ +package cn.cunchang.v2; + +/** + * 权重分类 + * Created by qiumu on 2020/10/10. + */ +public class WeightCategory { + + //类别 + private String category; + //权重值 + private int weight; + + public WeightCategory(String category, int weight) { + this.category = category; + this.weight = weight; + } + + public String getCategory() { + return category; + } + + public void setCategory(String category) { + this.category = category; + } + + public int getWeight() { + return weight; + } + + public void setWeight(int weight) { + this.weight = weight; + + } + +} diff --git a/distributed/gray/src/main/java/cn/cunchang/v2/WeightTest.java b/distributed/gray/src/main/java/cn/cunchang/v2/WeightTest.java new file mode 100644 index 00000000..6213f151 --- /dev/null +++ b/distributed/gray/src/main/java/cn/cunchang/v2/WeightTest.java @@ -0,0 +1,70 @@ +package cn.cunchang.v2; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +/** + * Created by qiumu on 2020/10/10. + */ +public class WeightTest { + + public static void main(String[] args){ + + //测试数据 + List categoryList=new ArrayList<>(); + WeightCategory weightCategory1=new WeightCategory("一等奖",1000); + WeightCategory weightCategory2=new WeightCategory("二等奖",9000); + categoryList.add(weightCategory1); + categoryList.add(weightCategory2); + + String result= ""; + int a1=0,a2=0; + for (int i=0;i<10000;i++){ + result = getWeight(categoryList); + System.out.println(i+" 开奖结果: "+result); + if(result.equals("一等奖")){ + a1++; + } + else if(result.equals("二等奖")){ + a2++; + } + } + + System.out.println("一等奖共出现 "+a1); + System.out.println("二等奖共出现 "+a2); + + + } + + /** + * 权重获取方法 + * @param categorys + * @return + */ + public static String getWeight(List categorys) { + Integer weightSum = 0; + String result=null; + for (WeightCategory wc : categorys) { + weightSum += wc.getWeight(); + } + + if (weightSum <= 0) { + System.err.println("Error: weightSum=" + weightSum.toString()); + return result; + } + Random random = new Random(); + Integer n = random.nextInt(weightSum); // n in [0, weightSum) + Integer m = 0; + for (WeightCategory wc : categorys) { + if (m <= n && n < m + wc.getWeight()) { + result=wc.getCategory(); + break; + } + m += wc.getWeight(); + } + return result; + } + + +} diff --git a/distributed/gray/src/main/java/cn/cunchang/v2/web/GrayConfigController.java b/distributed/gray/src/main/java/cn/cunchang/v2/web/GrayConfigController.java new file mode 100644 index 00000000..18a2ab3d --- /dev/null +++ b/distributed/gray/src/main/java/cn/cunchang/v2/web/GrayConfigController.java @@ -0,0 +1,148 @@ +package cn.cunchang.v2.web; + +import cn.cunchang.v2.GrayHelper; +import cn.cunchang.v2.web.req.RequestConfigParam; +import com.alibaba.fastjson.JSON; +import lombok.extern.slf4j.Slf4j; +import org.redisson.api.RBucket; +import org.redisson.api.RedissonClient; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.concurrent.TimeUnit; + +/** + * Created by qiumu on 2020/10/11. + */ + +@Controller +@Slf4j(topic = "grayLog") +public class GrayConfigController { + + @Resource + private GrayHelper grayHelper; + + @Resource + private RedissonClient redissonClient; + + /** + * 第一步:每台机器都进行设置灰度策略配置并加载 + * @param config + * @return + */ + @RequestMapping(value = {"/gray/loadRequestConfig"},method = RequestMethod.POST) + @ResponseBody + public String loadRequestConfig(@RequestBody RequestConfigParam config){ + + boolean ok = false; + try { + String json = JSON.toJSONString(config); + RBucket rBucket = redissonClient.getBucket(GrayHelper.GRAY_RULE_STR_KEY); + //保存60天 + rBucket.set(json,60 * 24 * 60 * 60, TimeUnit.SECONDS); + + ok = grayHelper.loadRule(); + }catch (Exception e){ + log.error(e.getMessage(),e); + return "fail"; + } + if(ok){ + return "ok"; + } + return "fail"; + + } + + /** + * 第一步:设置灰度策略配置并加载 + * @param grayOpen + * @return + */ + @RequestMapping(value = {"/gray/setGrayOpen"}) + @ResponseBody + public String setGrayOpen(@RequestParam("grayOpen") String grayOpen){ + + try { + grayHelper.setGrayOpen(grayOpen); + }catch (Exception e){ + log.error(e.getMessage(),e); + return "fail"; + } + return "ok"; + } + + /** + * 第二步:设置是否都走灰度请求 + * @param allRequestGray + * @return + */ + @RequestMapping(value = {"/gray/setAllRequestGray"}) + @ResponseBody + public String setAllRequestGray(@RequestParam("allRequestGray") String allRequestGray){ + + try { + grayHelper.setAllRequestGray(allRequestGray); + }catch (Exception e){ + log.error(e.getMessage(),e); + return "fail"; + } + return "ok"; + } + + /** + * 获取请求配置 + * @return + */ + @RequestMapping(value = {"/gray/getRequestConfig"}) + @ResponseBody + public String getRequestConfig(){ + + try { + RBucket rBucket = redissonClient.getBucket(GrayHelper.GRAY_RULE_STR_KEY); + if(rBucket == null || rBucket.get() == null){ + return "empty"; + } + return rBucket.get(); + }catch (Exception e){ + log.error(e.getMessage(),e); + return "fail"; + } + + } + + /** + * 查询灰度开关 + * @return + */ + @RequestMapping(value = {"/gray/getGrayOpen"}) + @ResponseBody + public Boolean getGrayOpen(){ + + try { + return grayHelper.getGrayOpen(); + }catch (Exception e){ + log.error(e.getMessage(),e); + return false; + } + } + + /** + * + * @return + */ + @RequestMapping(value = {"/gray/getAllRequestGray"}) + @ResponseBody + public Boolean getAllRequestGray(){ + + try { + return grayHelper.getAllRequestGray(); + }catch (Exception e){ + log.error(e.getMessage(),e); + return false; + } + } + + + +} diff --git a/distributed/gray/src/main/java/cn/cunchang/v2/web/req/RequestConfig.java b/distributed/gray/src/main/java/cn/cunchang/v2/web/req/RequestConfig.java new file mode 100644 index 00000000..b2a5b92b --- /dev/null +++ b/distributed/gray/src/main/java/cn/cunchang/v2/web/req/RequestConfig.java @@ -0,0 +1,22 @@ +package cn.cunchang.v2.web.req; + +import lombok.Data; + +/** + * Created by qiumu on 2020/10/11. + */ +@Data +public class RequestConfig { + + + /** + * 接口ID + */ + private Integer id; + + private Integer grayNumber; + + private Integer normalNumber; + + +} diff --git a/distributed/gray/src/main/java/cn/cunchang/v2/web/req/RequestConfigParam.java b/distributed/gray/src/main/java/cn/cunchang/v2/web/req/RequestConfigParam.java new file mode 100644 index 00000000..5006f22f --- /dev/null +++ b/distributed/gray/src/main/java/cn/cunchang/v2/web/req/RequestConfigParam.java @@ -0,0 +1,25 @@ +package cn.cunchang.v2.web.req; + +import lombok.Data; + +import java.util.List; + +/** + * Created by qiumu on 2020/10/11. + */ +@Data +public class RequestConfigParam { + + + /** + * 白名单userID + */ + private List grayUserIdList; + + + /** + * 配置列表 + */ + private List requestConfigList; + +} diff --git a/distributed/gray/src/main/resources/application.yml b/distributed/gray/src/main/resources/application.yml new file mode 100644 index 00000000..1cb00593 --- /dev/null +++ b/distributed/gray/src/main/resources/application.yml @@ -0,0 +1,12 @@ +# common spring boot settings + +spring.redis.database= +spring.redis.host=127.0.0.1 +spring.redis.port=6397 +spring.redis.password= +spring.redis.ssl= +spring.redis.timeout= +spring.redis.cluster.nodes= +spring.redis.sentinel.master= +spring.redis.sentinel.nodes= + diff --git a/distributed/hystrix/README.MD b/distributed/hystrix/README.MD new file mode 100644 index 00000000..a1fbe45d --- /dev/null +++ b/distributed/hystrix/README.MD @@ -0,0 +1,51 @@ +# 1. hystrixcommand使用 + +1. HystrixCommand 单值 同步 异步 +2. HystrixObservableCommand 多行值 同步 异步 + +rxjava 异步响应式编程 + +# 2. 资源隔离策略 + +**线程池** + +​ 有超时时间限制(适合网络请求) + +​ 线程池执行command,将结果tomcat线程。通过线程池的核心线程数、等待队列、拒绝策略,以及fallback方法,保护tomcat线程。 + +**信号量** + +​ 无超时时间限制(适合执行本地复杂的算法,本地算法不能死循环,不然无法释放当前tomcat线程,其他tomcat线程也无法进入) + +​ 通过信号量放行tomcat线程执行command,其他线程走fallback。 + +ThreadPoolKey==GroupKey 某服务 + CommandKey 某服务下的接口 + +# 3. request cache + +一次请求内的缓存,id=1,3,5,3,只有最后一个3是从request cache中拿的,下次再请求id=1,3,5,都是重新获取的。 + +允许在一次请求中清空缓存 + +# 4. fallback + +fallback可以使用信号量进行保护,超过信号量和队列直接reject + +# 5. circuit breaker + +requestVolumeThreshold(30) //10秒内的请求滑动窗口 +errorThresholdPercentage(40) //异常请求比例(默认50) +sleepWindowInMilliseconds(3000) //断路器开启后的睡眠窗口 + +断路器状态:close、half-open、open + +# 6. 总结 + +1、hystrix内部工作原理:8大执行步骤和流程 +2、资源隔离:你如果有很多个依赖服务,高可用性,先做资源隔离,任何一个依赖服务的故障不会导致你的服务的资源耗尽,不会崩溃 +3、请求缓存:对于一个request context内的多个相同command,使用request cache,提升性能 +4、熔断:基于短路器,采集各种异常事件,报错,超时,reject,短路,熔断,一定时间范围内就不允许访问了,直接降级,自动恢复的机制 +5、降级:报错,超时,reject,熔断,降级,服务提供容错的机制 +6、限流:在你的服务里面,通过线程池,或者信号量,限制对某个后端的服务或资源的访问量,避免从你的服务这里过去太多的流量,打死某个资源 +7、超时:避免某个依赖服务性能过差,导致大量的线程hang住去调用那个服务,会导致你的服务本身性能也比较差 \ No newline at end of file diff --git a/distributed/hystrix/eshop-cache-ha/pom.xml b/distributed/hystrix/eshop-cache-ha/pom.xml new file mode 100644 index 00000000..dceb82cf --- /dev/null +++ b/distributed/hystrix/eshop-cache-ha/pom.xml @@ -0,0 +1,109 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.2.2.RELEASE + + + cn.lastwhisper + eshop-cache-ha + 0.0.1-SNAPSHOT + eshop-cache-ha + eshop-cache-ha + + + UTF-8 + 1.8 + + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-thymeleaf + + + + org.springframework.boot + spring-boot-starter-jdbc + + + + org.springframework.boot + spring-boot-starter-actuator + + + com.alibaba + fastjson + 1.2.62 + + + + org.mybatis + mybatis-spring + 1.2.2 + + + + org.mybatis + mybatis + 3.2.8 + + + + org.apache.tomcat + tomcat-jdbc + + + + mysql + mysql-connector-java + + + + org.apache.httpcomponents + httpclient + + + + org.projectlombok + lombok + + + + com.netflix.hystrix + hystrix-core + 1.5.12 + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.junit.vintage + junit-vintage-engine + + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/distributed/hystrix/eshop-cache-ha/src/main/java/cn/lastwhisper/cache/ha/CacheApplication.java b/distributed/hystrix/eshop-cache-ha/src/main/java/cn/lastwhisper/cache/ha/CacheApplication.java new file mode 100644 index 00000000..a31ec889 --- /dev/null +++ b/distributed/hystrix/eshop-cache-ha/src/main/java/cn/lastwhisper/cache/ha/CacheApplication.java @@ -0,0 +1,73 @@ +package cn.lastwhisper.cache.ha; + +import cn.lastwhisper.cache.ha.filter.HystrixRequestContextFilter; +import lombok.extern.slf4j.Slf4j; +import org.apache.ibatis.session.SqlSessionFactory; +import org.mybatis.spring.SqlSessionFactoryBean; +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.core.env.Environment; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; +import org.springframework.jdbc.datasource.DataSourceTransactionManager; +import org.springframework.transaction.PlatformTransactionManager; + +import javax.sql.DataSource; +import java.net.InetAddress; +import java.net.UnknownHostException; + +/** + * @author Administrator + */ +@Slf4j +@SpringBootApplication +@MapperScan("cn.lastwhisper.cache.ha.mapper.UserMapper") +public class CacheApplication { + + @Bean + @ConfigurationProperties(prefix = "spring.datasource") + public DataSource dataSource() { + return new org.apache.tomcat.jdbc.pool.DataSource(); + } + + @Bean + public SqlSessionFactory sqlSessionFactoryBean() throws Exception { + SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean(); + sqlSessionFactoryBean.setDataSource(dataSource()); + PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); + sqlSessionFactoryBean.setMapperLocations(resolver.getResources("classpath:/mybatis/*.xml")); + return sqlSessionFactoryBean.getObject(); + } + + @Bean + public PlatformTransactionManager transactionManager() { + return new DataSourceTransactionManager(dataSource()); + } + + // 注册filter 测试request cache开启 + //@Bean + //public FilterRegistrationBean filterRegistrationBean() { + // FilterRegistrationBean filterRegistrationBean + // = new FilterRegistrationBean<>(new HystrixRequestContextFilter()); + // filterRegistrationBean.addUrlPatterns("/*"); + // return filterRegistrationBean; + //} + + public static void main(String[] args) throws UnknownHostException { + ConfigurableApplicationContext application = SpringApplication.run(CacheApplication.class, args); + Environment env = application.getEnvironment(); + String ip = InetAddress.getLocalHost().getHostAddress(); + String port = env.getProperty("server.port") == null ? "" : env.getProperty("server.port"); + String path = env.getProperty("server.servlet.context-path") == null ? "" : env.getProperty("server.servlet.context-path"); + log.info("\n----------------------------------------------------------\n\t" + + "Application hotel-query-service is running! Access URLs:\n\t" + + "Local: \t\thttp://localhost:" + port + path + "/\n\t" + + "External: \thttp://" + ip + ":" + port + path + "/\n\t" + + "swagger-ui: \thttp://" + ip + ":" + port + path + "/swagger-ui.html\n\t" + + "----------------------------------------------------------"); + } +} diff --git a/distributed/hystrix/eshop-cache-ha/src/main/java/cn/lastwhisper/cache/ha/controller/CacheController.java b/distributed/hystrix/eshop-cache-ha/src/main/java/cn/lastwhisper/cache/ha/controller/CacheController.java new file mode 100644 index 00000000..dd1d0ba3 --- /dev/null +++ b/distributed/hystrix/eshop-cache-ha/src/main/java/cn/lastwhisper/cache/ha/controller/CacheController.java @@ -0,0 +1,140 @@ +package cn.lastwhisper.cache.ha.controller; + +import cn.lastwhisper.cache.ha.http.HttpClientUtils; +import cn.lastwhisper.cache.ha.hystrix.command.GetBrandNameCommand; +import cn.lastwhisper.cache.ha.hystrix.command.GetCityNameCommand; +import cn.lastwhisper.cache.ha.hystrix.command.GetProductInfoCommand; +import cn.lastwhisper.cache.ha.hystrix.command.GetProductInfosCommand; +import cn.lastwhisper.cache.ha.model.ProductInfo; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; +import rx.Observable; +import rx.Observer; + +import java.util.Objects; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; + +/** + * 缓存服务的接口 + * @author Administrator + * + */ +@Controller +public class CacheController { + /** + * Mq异步查询原生db,并将数据更新到各级缓存 + * + * @param productId + * @return java.lang.String + */ + @RequestMapping("/change/product") + @ResponseBody + public Object changeProduct(Long productId) { + // 拿到一个商品id + // 调用商品服务的接口,获取商品id对应的商品的最新数据 + // 用HttpClient去调用商品服务的http接口 + String url = "http://127.0.0.1:8082/getProductInfo?productId=" + productId; + String response = HttpClientUtils.sendGetRequest(url); + System.out.println(response); + + return "success"; + } + + /** + * nginx之后的各级缓存都失效了,此时直接访问到最原生的db层了 + */ + @RequestMapping("/getProductInfo") + @ResponseBody + public Object getProductInfo(Long productId) { + + GetProductInfoCommand getProductInfoCommand = new GetProductInfoCommand(productId); + ProductInfo productInfo = null; + + // 同步执行 + productInfo = getProductInfoCommand.execute(); + + // 异步执行 + //try { + // Future queue = getProductInfoCommand.queue(); + // // 中间可以干别的事情 + // productInfo = queue.get(); + //} catch (InterruptedException | ExecutionException e) { + // e.printStackTrace(); + //} + + // 通过semaphore隔离,从本地地区缓存中获取数据 + Long cityId = Objects.requireNonNull(productInfo).getCityId(); + GetCityNameCommand getCityNameCommand = new GetCityNameCommand(cityId); + String cityName = getCityNameCommand.execute(); + productInfo.setCityName(cityName); + + // 通过threadPool隔离以及fallback,从本地品牌缓存中获取数据 + Long brandId = productInfo.getBrandId(); + GetBrandNameCommand getBrandNameCommand = new GetBrandNameCommand(brandId); + String brandName = getBrandNameCommand.execute(); + productInfo.setBrandName(brandName); + + System.out.println(productInfo); + return productInfo; + //return "success"; + } + + /** + * 通过一个HystrixObservableCommand批量获取多条商品信息 + */ + @RequestMapping("/getProductInfos") + @ResponseBody + public Object getProductInfos(String productIds) { + + GetProductInfosCommand getProductInfosCommand = new GetProductInfosCommand(productIds.split(",")); + Observable observable = null; + + // 同步执行,subscribe只是取值而已 + observable = getProductInfosCommand.observe(); + + // 延迟执行,等到subscribe时才开始执行construct + //observable = getProductInfosCommand.toObservable(); + + //Action1 忽略completed和error信号 + observable.subscribe(new Observer() { + + @Override + public void onCompleted() { + System.out.println("获取完了所有的商品数据"); + } + + @Override + public void onError(Throwable e) { + e.printStackTrace(); + } + + @Override + public void onNext(ProductInfo productInfo) { + System.out.println(productInfo); + } + }); + + return "success"; + } + + /** + * 通过多个HystrixCommand批量获取多条商品信息 + */ + @RequestMapping("/getProductInfos2") + @ResponseBody + public String getProductInfos2(String productIds) { + + for (String productId : productIds.split(",")) { + GetProductInfoCommand getProductInfoCommand = new GetProductInfoCommand( + Long.valueOf(productId)); + ProductInfo productInfo = getProductInfoCommand.execute(); + System.out.println(productInfo); + System.out.println("是否来自缓存 " + getProductInfoCommand.isResponseFromCache()); + } + return "success"; + } + + +} diff --git a/distributed/hystrix/eshop-cache-ha/src/main/java/cn/lastwhisper/cache/ha/controller/HelloController.java b/distributed/hystrix/eshop-cache-ha/src/main/java/cn/lastwhisper/cache/ha/controller/HelloController.java new file mode 100644 index 00000000..4bdff623 --- /dev/null +++ b/distributed/hystrix/eshop-cache-ha/src/main/java/cn/lastwhisper/cache/ha/controller/HelloController.java @@ -0,0 +1,16 @@ +package cn.lastwhisper.cache.ha.controller; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +@Controller +public class HelloController { + + @RequestMapping("/hello") + @ResponseBody + public String hello(String name) { + return "hello, " + name; + } + +} diff --git a/distributed/hystrix/eshop-cache-ha/src/main/java/cn/lastwhisper/cache/ha/filter/HystrixRequestContextFilter.java b/distributed/hystrix/eshop-cache-ha/src/main/java/cn/lastwhisper/cache/ha/filter/HystrixRequestContextFilter.java new file mode 100644 index 00000000..6a30287d --- /dev/null +++ b/distributed/hystrix/eshop-cache-ha/src/main/java/cn/lastwhisper/cache/ha/filter/HystrixRequestContextFilter.java @@ -0,0 +1,36 @@ +package cn.lastwhisper.cache.ha.filter; + +import com.netflix.hystrix.strategy.concurrency.HystrixRequestContext; + +import javax.servlet.*; +import java.io.IOException; + +/** + * hystrix request context过滤器 + * @author lastwhisper + * @date 2019/12/19 + */ +public class HystrixRequestContextFilter implements Filter { + + @Override + public void init(FilterConfig filterConfig) throws ServletException { + + } + + @Override + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { + HystrixRequestContext context = HystrixRequestContext.initializeContext(); + try { + filterChain.doFilter(servletRequest, servletResponse); + } catch (Exception e) { + e.printStackTrace(); + } finally { + context.shutdown(); + } + } + + @Override + public void destroy() { + + } +} diff --git a/distributed/hystrix/eshop-cache-ha/src/main/java/cn/lastwhisper/cache/ha/http/HttpClientUtils.java b/distributed/hystrix/eshop-cache-ha/src/main/java/cn/lastwhisper/cache/ha/http/HttpClientUtils.java new file mode 100644 index 00000000..75f55608 --- /dev/null +++ b/distributed/hystrix/eshop-cache-ha/src/main/java/cn/lastwhisper/cache/ha/http/HttpClientUtils.java @@ -0,0 +1,121 @@ +package cn.lastwhisper.cache.ha.http; + +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.NameValuePair; +import org.apache.http.client.HttpClient; +import org.apache.http.client.entity.UrlEncodedFormEntity; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.message.BasicNameValuePair; +import org.apache.http.util.EntityUtils; + +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +/** + * HttpClient工具类 + * @author lixuerui + * + */ +@SuppressWarnings("deprecation") +public class HttpClientUtils { + + /** + * 发送GET请求 + * @param url 请求URL + * @return 响应结果 + */ + @SuppressWarnings("resource") + public static String sendGetRequest(String url) { + String httpResponse = null; + + HttpClient httpClient; + InputStream is = null; + BufferedReader br = null; + + try { + // 发送GET请求 + httpClient = HttpClientBuilder.create().build(); + HttpGet httpget = new HttpGet(url); + HttpResponse response = httpClient.execute(httpget); + + // 处理响应 + HttpEntity entity = response.getEntity(); + if (entity != null) { + is = entity.getContent(); + br = new BufferedReader(new InputStreamReader(is)); + + StringBuilder buffer = new StringBuilder(""); + String line; + + while ((line = br.readLine()) != null) { + buffer.append(line).append("\n"); + } + + httpResponse = buffer.toString(); + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + if (br != null) { + br.close(); + } + if (is != null) { + is.close(); + } + } catch (Exception e2) { + e2.printStackTrace(); + } + } + + return httpResponse; + } + + /** + * 发送post请求 + * @param url URL + * @param map 参数Map + */ + @SuppressWarnings({"rawtypes", "resource"}) + public static String sendPostRequest(String url, Map map) { + HttpClient httpClient; + HttpPost httpPost; + String result = null; + + try { + httpClient = HttpClientBuilder.create().build(); + httpPost = new HttpPost(url); + + //设置参数 + List list = new ArrayList<>(); + for (Entry elem : map.entrySet()) { + list.add(new BasicNameValuePair(elem.getKey(), elem.getValue())); + } + if (list.size() > 0) { + UrlEncodedFormEntity entity = new UrlEncodedFormEntity(list, "utf-8"); + httpPost.setEntity(entity); + } + + HttpResponse response = httpClient.execute(httpPost); + if (response != null) { + HttpEntity resEntity = response.getEntity(); + if (resEntity != null) { + result = EntityUtils.toString(resEntity, "utf-8"); + } + } + } catch (Exception ex) { + ex.printStackTrace(); + } + + return result; + } + +} \ No newline at end of file diff --git a/distributed/hystrix/eshop-cache-ha/src/main/java/cn/lastwhisper/cache/ha/hystrix/command/GetBrandNameCommand.java b/distributed/hystrix/eshop-cache-ha/src/main/java/cn/lastwhisper/cache/ha/hystrix/command/GetBrandNameCommand.java new file mode 100644 index 00000000..716bf07e --- /dev/null +++ b/distributed/hystrix/eshop-cache-ha/src/main/java/cn/lastwhisper/cache/ha/hystrix/command/GetBrandNameCommand.java @@ -0,0 +1,44 @@ +package cn.lastwhisper.cache.ha.hystrix.command; + +import cn.lastwhisper.cache.ha.local.BrandCache; +import com.netflix.hystrix.*; + +/** + * 获取品牌名称的command + * @author lastwhisper + * @date 2019/12/20 + */ +public class GetBrandNameCommand extends HystrixCommand { + + private Long brandId; + + public GetBrandNameCommand(Long brandId) { + super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("GetBrandNameGroup")) + .andCommandKey(HystrixCommandKey.Factory.asKey("GetBrandNameCommand")) + .andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("GetBrandNamePool")) + .andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter() + .withCoreSize(15) + .withQueueSizeRejectionThreshold(10)) + // 设置HystrixCommand.getFallback()最大允许的并发请求数量,默认值是10, + // 也是通过semaphore信号量的机制去限流,如果超出了这个最大值,那么直接被reject + .andCommandPropertiesDefaults(HystrixCommandProperties.Setter() + .withFallbackIsolationSemaphoreMaxConcurrentRequests(15)) + ); + this.brandId = brandId; + } + + + @Override + protected String run() throws Exception { + // 调用一个品牌服务的接口 + // 如果调用失败了,报错了,那么就会去调用fallback降级机制 + throw new Exception(); + } + + // 降级方法 + @Override + protected String getFallback() { + System.out.println("从本地缓存获取过期的品牌数据,brandId=" + brandId); + return BrandCache.getBrandName(brandId); + } +} diff --git a/distributed/hystrix/eshop-cache-ha/src/main/java/cn/lastwhisper/cache/ha/hystrix/command/GetCityNameCommand.java b/distributed/hystrix/eshop-cache-ha/src/main/java/cn/lastwhisper/cache/ha/hystrix/command/GetCityNameCommand.java new file mode 100644 index 00000000..7384e824 --- /dev/null +++ b/distributed/hystrix/eshop-cache-ha/src/main/java/cn/lastwhisper/cache/ha/hystrix/command/GetCityNameCommand.java @@ -0,0 +1,39 @@ +package cn.lastwhisper.cache.ha.hystrix.command; + +import cn.lastwhisper.cache.ha.local.LocationCache; +import com.netflix.hystrix.*; + +/** + * 获取城市名称的command + * @author lastwhisper + * @date 2019/12/19 + */ +public class GetCityNameCommand extends HystrixCommand { + + private Long cityId; + + /** + * to use thread isolation + * HystrixCommandProperties.Setter() + * .withExecutionIsolationStrategy(ExecutionIsolationStrategy.THREAD) + * to use semaphore isolation + * HystrixCommandProperties.Setter() + * .withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE) + * 通过信号量隔离进行限流 + */ + public GetCityNameCommand(Long cityId){ + super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("GetCityNameGroup")) + .andCommandKey(HystrixCommandKey.Factory.asKey("GetCityNameCommand")) + .andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("GetCityNamePool")) + .andCommandPropertiesDefaults(HystrixCommandProperties.Setter() + .withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.SEMAPHORE) + .withExecutionIsolationSemaphoreMaxConcurrentRequests(15))); + this.cityId = cityId; + } + + @Override + protected String run() throws Exception { + return LocationCache.getCityName(cityId); + } + +} diff --git a/distributed/hystrix/eshop-cache-ha/src/main/java/cn/lastwhisper/cache/ha/hystrix/command/GetProductInfoCommand.java b/distributed/hystrix/eshop-cache-ha/src/main/java/cn/lastwhisper/cache/ha/hystrix/command/GetProductInfoCommand.java new file mode 100644 index 00000000..cb12cc32 --- /dev/null +++ b/distributed/hystrix/eshop-cache-ha/src/main/java/cn/lastwhisper/cache/ha/hystrix/command/GetProductInfoCommand.java @@ -0,0 +1,116 @@ +package cn.lastwhisper.cache.ha.hystrix.command; + +import cn.lastwhisper.cache.ha.http.HttpClientUtils; +import cn.lastwhisper.cache.ha.model.ProductInfo; +import com.alibaba.fastjson.JSONObject; +import com.netflix.hystrix.*; +import com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategyDefault; + +/** + * 获取单条商品信息的command + * @author lastwhisper + * @date 2019/12/19 + */ +public class GetProductInfoCommand extends HystrixCommand { + + private static final HystrixCommandKey GETTER_KEY = HystrixCommandKey.Factory.asKey("GetProductInfoCommand"); + private Long productId; + /* + * @HystrixCommand( + fallbackMethod = "fallback", + commandProperties = { + @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1000"),//超时降级 + @HystrixProperty(name = "circuitBreaker.enabled", value = "true"),//同意使用断路器来熔断请求 + //timeInMilliseconds/numBuckets内,最小请求数 + @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"), + //断路器打开后的休眠时间窗口,休眠结束后,断路器进入"半打开"状态 + + @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "10000"), + //断路器打开的错误比条件(在timeInMilliseconds内,请求超过requestVolumeThreshold前提下,错误比超60,开启断路器) + @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "60") + }, + threadPoolProperties = { + // 线程池参数 + @HystrixProperty(name = "coreSize", value = "20"), + @HystrixProperty(name = "maxQueueSize", value = "10"), + @HystrixProperty(name = "keepAliveTimeMinutes", value = "1000"), + @HystrixProperty(name = "queueSizeRejectionThreshold", value = "8"), + //滚动时间窗口长度,被分成多个numBuckets,该参数需要被numBuckets整除 + @HystrixProperty(name = "metrics.rollingStats.timeInMilliseconds", value = "1500"), + @HystrixProperty(name = "metrics.rollingStats.numBuckets", value = "12") + }) + * + */ + + /** + * 首先线程池10-20不代表并发能力10-20,如果一个接口的tp99为50ms,1个线程1s可以处理20请求, + * 10个线程就可以处理200请求每秒。10个实例就是tps为2000。 + * 所以具体配置如何取决于接口性能和设置的超时时间等因素。 + */ + public GetProductInfoCommand(Long productId) { + /* + * ThreadPoolKey==GroupKey 某服务 + * CommandKey 某服务下的接口 + */ + super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("GetProductInfoGroup")) + .andCommandKey(GETTER_KEY) + .andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("GetProductInfoPool")) + .andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter() + .withCoreSize(10) //核心线程数 + .withMaxQueueSize(8) //最大等待队列 + //.withQueueSizeRejectionThreshold(15)//等待队列大小, + ) + // 如果withMaxQueueSize { + + private String[] productIds; + + public GetProductInfosCommand(String[] productIds) { + super(HystrixCommandGroupKey.Factory.asKey("GetProductInfoGroup")); + this.productIds = productIds; + } + + @Override + protected Observable construct() { + return Observable.create(new Observable.OnSubscribe() { + @Override + public void call(Subscriber subscriber) { + try { + for (String productId : productIds) { + String url = "http://127.0.0.1:8082/getProductInfo?productId=" + productId; + String response = HttpClientUtils.sendGetRequest(url); + ProductInfo productInfo = JSONObject.parseObject(response, ProductInfo.class); + subscriber.onNext(productInfo); + } + subscriber.onCompleted(); + } catch (Exception e) { + subscriber.onError(e); + } + } + }).subscribeOn(Schedulers.io()); + } + +} diff --git a/distributed/hystrix/eshop-cache-ha/src/main/java/cn/lastwhisper/cache/ha/hystrix/command/UpdateProductInfoCommand.java b/distributed/hystrix/eshop-cache-ha/src/main/java/cn/lastwhisper/cache/ha/hystrix/command/UpdateProductInfoCommand.java new file mode 100644 index 00000000..923decee --- /dev/null +++ b/distributed/hystrix/eshop-cache-ha/src/main/java/cn/lastwhisper/cache/ha/hystrix/command/UpdateProductInfoCommand.java @@ -0,0 +1,27 @@ +package cn.lastwhisper.cache.ha.hystrix.command; + +import com.netflix.hystrix.HystrixCommand; +import com.netflix.hystrix.HystrixCommandGroupKey; + +/** + * 清空hystrix的request cache + * @author lastwhisper + * @date 2019/12/20 + */ +public class UpdateProductInfoCommand extends HystrixCommand { + + private Long productId; + + public UpdateProductInfoCommand(Long productId) { + super(HystrixCommandGroupKey.Factory.asKey("GetProductInfoGroup")); + this.productId=productId; + } + + @Override + protected Boolean run() throws Exception { + GetProductInfoCommand.flushCache(productId); + return true; + } + + +} diff --git a/distributed/hystrix/eshop-cache-ha/src/main/java/cn/lastwhisper/cache/ha/local/BrandCache.java b/distributed/hystrix/eshop-cache-ha/src/main/java/cn/lastwhisper/cache/ha/local/BrandCache.java new file mode 100644 index 00000000..b47cf27e --- /dev/null +++ b/distributed/hystrix/eshop-cache-ha/src/main/java/cn/lastwhisper/cache/ha/local/BrandCache.java @@ -0,0 +1,23 @@ +package cn.lastwhisper.cache.ha.local; + +import java.util.HashMap; +import java.util.Map; + +/** + * 品牌缓存 + * @author Administrator + * + */ +public class BrandCache { + + private static Map brandMap = new HashMap(); + + static { + brandMap.put(1L, "iphone"); + } + + public static String getBrandName(Long brandId) { + return brandMap.get(brandId); + } + +} diff --git a/distributed/hystrix/eshop-cache-ha/src/main/java/cn/lastwhisper/cache/ha/local/LocationCache.java b/distributed/hystrix/eshop-cache-ha/src/main/java/cn/lastwhisper/cache/ha/local/LocationCache.java new file mode 100644 index 00000000..50f2989c --- /dev/null +++ b/distributed/hystrix/eshop-cache-ha/src/main/java/cn/lastwhisper/cache/ha/local/LocationCache.java @@ -0,0 +1,20 @@ +package cn.lastwhisper.cache.ha.local; + +import java.util.HashMap; +import java.util.Map; +/** + * 本地缓存 + */ +public class LocationCache { + + private static Map cityMap = new HashMap<>(); + + static { + cityMap.put(1L, "北京"); + } + + public static String getCityName(Long cityId) { + return cityMap.get(cityId); + } + +} diff --git a/distributed/hystrix/eshop-cache-ha/src/main/java/cn/lastwhisper/cache/ha/mapper/UserMapper.java b/distributed/hystrix/eshop-cache-ha/src/main/java/cn/lastwhisper/cache/ha/mapper/UserMapper.java new file mode 100644 index 00000000..10b3254e --- /dev/null +++ b/distributed/hystrix/eshop-cache-ha/src/main/java/cn/lastwhisper/cache/ha/mapper/UserMapper.java @@ -0,0 +1,5 @@ +package cn.lastwhisper.cache.ha.mapper; + +public interface UserMapper { + +} diff --git a/distributed/hystrix/eshop-cache-ha/src/main/java/cn/lastwhisper/cache/ha/model/ProductInfo.java b/distributed/hystrix/eshop-cache-ha/src/main/java/cn/lastwhisper/cache/ha/model/ProductInfo.java new file mode 100644 index 00000000..54841fa5 --- /dev/null +++ b/distributed/hystrix/eshop-cache-ha/src/main/java/cn/lastwhisper/cache/ha/model/ProductInfo.java @@ -0,0 +1,38 @@ +package cn.lastwhisper.cache.ha.model; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.ToString; + +/** + * 商品信息 + * @author Administrator + * + */ +@Data +@ToString +@AllArgsConstructor +@NoArgsConstructor +public class ProductInfo { + + private Long id; + private String name; + private Double price; + private String pictureList; + private String specification; + private String service; + private String color; + private String size; + private Long shopId; + private String modifiedTime; + + // semaphore + private Long cityId; + private String cityName; + + // fallback + private Long brandId; + private String brandName; + +} diff --git a/distributed/hystrix/eshop-cache-ha/src/main/resources/application.properties b/distributed/hystrix/eshop-cache-ha/src/main/resources/application.properties new file mode 100644 index 00000000..5d55d56a --- /dev/null +++ b/distributed/hystrix/eshop-cache-ha/src/main/resources/application.properties @@ -0,0 +1,5 @@ +server.port=8081 +spring.datasource.url=jdbc:mysql://localhost:3306/eshop?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8 +spring.datasource.username=root +spring.datasource.password=root +spring.datasource.driver-class-name=com.mysql.jdbc.Driver \ No newline at end of file diff --git a/distributed/hystrix/eshop-cache-ha/src/main/resources/mybatis/UserMapper.xml b/distributed/hystrix/eshop-cache-ha/src/main/resources/mybatis/UserMapper.xml new file mode 100644 index 00000000..5eba84ae --- /dev/null +++ b/distributed/hystrix/eshop-cache-ha/src/main/resources/mybatis/UserMapper.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/distributed/hystrix/eshop-cache-ha/src/main/resources/templates/hello.html b/distributed/hystrix/eshop-cache-ha/src/main/resources/templates/hello.html new file mode 100644 index 00000000..e69de29b diff --git a/distributed/hystrix/eshop-cache-ha/src/test/java/cn/lastwhisper/cache/ha/CircuitBreakerTest.java b/distributed/hystrix/eshop-cache-ha/src/test/java/cn/lastwhisper/cache/ha/CircuitBreakerTest.java new file mode 100644 index 00000000..d59ee0f6 --- /dev/null +++ b/distributed/hystrix/eshop-cache-ha/src/test/java/cn/lastwhisper/cache/ha/CircuitBreakerTest.java @@ -0,0 +1,55 @@ +package cn.lastwhisper.cache.ha; + + +import cn.lastwhisper.cache.ha.http.HttpClientUtils; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +public class CircuitBreakerTest { + + @Test + public void testCircuitBreaker() throws InterruptedException { + for (int i = 0; i < 15; i++) { + String response = HttpClientUtils.sendGetRequest("http://localhost:8081/getProductInfo?productId=1"); + System.out.println("第" + (i + 1) + "次正常请求,断路器状态:close,结果为:" + response); + } + for (int i = 15; i < 40; i++) { + String response = HttpClientUtils.sendGetRequest("http://localhost:8081/getProductInfo?productId=-1"); + System.out.println("第" + (i + 1) + "次异常请求,断路器状态:close,结果为:" + response); + } + System.out.println("等待5秒钟,requestVolumeThreshold和errorThresholdPercentage都满足断路器状态置为open"); + Thread.sleep(5000); + /* + * 等待了5s后, + * 请求滑动窗口满足 request num=40>requestVolumeThreshold=30 + * 异常请求比例 errorThresholdPercentage = 25/40=62.5%>40% + * requestVolumeThreshold和errorThresholdPercentage都满足断路器状态置为open + */ + for (int i = 40; i < 50; i++) { + if (i % 2 == 0) { + String response = HttpClientUtils.sendGetRequest("http://localhost:8081/getProductInfo?productId=1"); + System.out.println("第" + (i + 1) + "次短路正常请求,断路器状态:open,结果为:" + response); + } else { + String response = HttpClientUtils.sendGetRequest("http://localhost:8081/getProductInfo?productId=-1"); + System.out.println("第" + (i + 1) + "次短路异常请求,断路器状态:open,结果为:" + response); + } + + } + // 统计单位,有一个时间窗口的,我们必须要等到那个时间窗口过了以后,才会说,hystrix看一下最近的这个时间窗口 + // 比如说,最近的10秒内,有多少条数据,其中异常的数据有没有到一定的比例 + // 如果到了一定的比例,那么才会去短路 + System.out.println("等待5秒钟,断路器状态:holf-open,尝试正常请求"); + Thread.sleep(3001); + for (int i = 50; i < 60; i++) { + String response = HttpClientUtils.sendGetRequest("http://localhost:8081/getProductInfo?productId=1"); + if(i==50){ + System.out.println("第" + (i + 1) + "次正常请求,断路器状态:holf-open,结果为:" + response); + }else { + System.out.println("第" + (i + 1) + "次正常请求,断路器状态:open,结果为:" + response); + } + + } + } + +} diff --git a/distributed/hystrix/eshop-cache-ha/src/test/java/cn/lastwhisper/cache/ha/RejectTest.java b/distributed/hystrix/eshop-cache-ha/src/test/java/cn/lastwhisper/cache/ha/RejectTest.java new file mode 100644 index 00000000..0590fc69 --- /dev/null +++ b/distributed/hystrix/eshop-cache-ha/src/test/java/cn/lastwhisper/cache/ha/RejectTest.java @@ -0,0 +1,34 @@ +package cn.lastwhisper.cache.ha; + + +import cn.lastwhisper.cache.ha.http.HttpClientUtils; + +public class RejectTest { + + private static class TestThread extends Thread { + + private int index; + + public TestThread(int index) { + this.index = index; + } + + @Override + public void run() { + String response = HttpClientUtils.sendGetRequest("http://localhost:8081/getProductInfo?productId=-2"); + System.out.println("第" + (index + 1) + "次请求,结果为:" + response); + } + + } + + /** + * 测试hystrix线程池的maxCoreSize和QueueSize + */ + public static void main(String[] args) throws Exception { + for (int i = 0; i < 25; i++) { + new TestThread(i).start(); + } + + } + +} diff --git a/distributed/hystrix/eshop-product-ha/pom.xml b/distributed/hystrix/eshop-product-ha/pom.xml new file mode 100644 index 00000000..08284bee --- /dev/null +++ b/distributed/hystrix/eshop-product-ha/pom.xml @@ -0,0 +1,103 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.2.2.RELEASE + + + cn.lastwhisper + eshop-product-ha + 0.0.1-SNAPSHOT + eshop-product-ha + eshop-product-ha + + + UTF-8 + 1.8 + + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-thymeleaf + + + + org.springframework.boot + spring-boot-starter-jdbc + + + + org.springframework.boot + spring-boot-starter-actuator + + + org.mybatis + mybatis-spring + 1.2.2 + + + + org.mybatis + mybatis + 3.2.8 + + + + org.apache.tomcat + tomcat-jdbc + + + + org.projectlombok + lombok + + + + org.apache.httpcomponents + httpclient + + + + mysql + mysql-connector-java + + + + com.alibaba + fastjson + 1.2.62 + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.junit.vintage + junit-vintage-engine + + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/distributed/hystrix/eshop-product-ha/src/main/java/cn/lastwhisper/product/ha/ProductApplication.java b/distributed/hystrix/eshop-product-ha/src/main/java/cn/lastwhisper/product/ha/ProductApplication.java new file mode 100644 index 00000000..18ef1ffb --- /dev/null +++ b/distributed/hystrix/eshop-product-ha/src/main/java/cn/lastwhisper/product/ha/ProductApplication.java @@ -0,0 +1,59 @@ +package cn.lastwhisper.product.ha; + +import lombok.extern.slf4j.Slf4j; +import org.apache.ibatis.session.SqlSessionFactory; +import org.mybatis.spring.SqlSessionFactoryBean; +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.core.env.Environment; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; +import org.springframework.jdbc.datasource.DataSourceTransactionManager; +import org.springframework.transaction.PlatformTransactionManager; + +import javax.sql.DataSource; +import java.net.InetAddress; +import java.net.UnknownHostException; + +@Slf4j +@SpringBootApplication +@MapperScan("cn.lastwhisper.product.ha.mapper.UserMapper") +public class ProductApplication { + @Bean + @ConfigurationProperties(prefix = "spring.datasource") + public DataSource dataSource() { + return new org.apache.tomcat.jdbc.pool.DataSource(); + } + + @Bean + public SqlSessionFactory sqlSessionFactoryBean() throws Exception { + SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean(); + sqlSessionFactoryBean.setDataSource(dataSource()); + PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); + sqlSessionFactoryBean.setMapperLocations(resolver.getResources("classpath:/mybatis/*.xml")); + return sqlSessionFactoryBean.getObject(); + } + + @Bean + public PlatformTransactionManager transactionManager() { + return new DataSourceTransactionManager(dataSource()); + } + + public static void main(String[] args) throws UnknownHostException { + ConfigurableApplicationContext application = SpringApplication.run(ProductApplication.class, args); + Environment env = application.getEnvironment(); + String ip = InetAddress.getLocalHost().getHostAddress(); + String port = env.getProperty("server.port")==null?"":env.getProperty("server.port"); + String path = env.getProperty("server.servlet.context-path")==null?"":env.getProperty("server.servlet.context-path"); + log.info("\n----------------------------------------------------------\n\t" + + "Application hotel-query-service is running! Access URLs:\n\t" + + "Local: \t\thttp://localhost:" + port + path + "/\n\t" + + "External: \thttp://" + ip + ":" + port + path + "/\n\t" + + "swagger-ui: \thttp://" + ip + ":" + port + path + "/swagger-ui.html\n\t" + + "----------------------------------------------------------"); + } + +} diff --git a/distributed/hystrix/eshop-product-ha/src/main/java/cn/lastwhisper/product/ha/controller/HelloController.java b/distributed/hystrix/eshop-product-ha/src/main/java/cn/lastwhisper/product/ha/controller/HelloController.java new file mode 100644 index 00000000..b9772fc9 --- /dev/null +++ b/distributed/hystrix/eshop-product-ha/src/main/java/cn/lastwhisper/product/ha/controller/HelloController.java @@ -0,0 +1,16 @@ +package cn.lastwhisper.product.ha.controller; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +@Controller +public class HelloController { + + @RequestMapping("/hello") + @ResponseBody + public String hello(String name) { + return "hello, " + name; + } + +} diff --git a/distributed/hystrix/eshop-product-ha/src/main/java/cn/lastwhisper/product/ha/controller/ProductController.java b/distributed/hystrix/eshop-product-ha/src/main/java/cn/lastwhisper/product/ha/controller/ProductController.java new file mode 100644 index 00000000..53dc36a4 --- /dev/null +++ b/distributed/hystrix/eshop-product-ha/src/main/java/cn/lastwhisper/product/ha/controller/ProductController.java @@ -0,0 +1,25 @@ +package cn.lastwhisper.product.ha.controller; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +/** + * 商品服务的接口 + * @author Administrator + * + */ +@Controller +public class ProductController { + + @RequestMapping("/getProductInfo") + @ResponseBody + public String getProductInfo(Long productId) { + return "{\"id\": " + productId + ", \"name\": \"iphone7手机\", \"price\": 5599, " + + "\"pictureList\":\"a.jpg,b.jpg\", \"specification\": \"iphone7的规格\", " + + "\"service\": \"iphone7的售后服务\", \"color\": \"红色,白色,黑色\", " + + "\"size\": \"5.5\", \"shopId\": 1, \"modifiedTime\": \"2017-01-01 12:00:00\"," + + " \"cityId\": 1, \"brandId\": 1}"; + } + +} diff --git a/distributed/hystrix/eshop-product-ha/src/main/java/cn/lastwhisper/product/ha/mapper/UserMapper.java b/distributed/hystrix/eshop-product-ha/src/main/java/cn/lastwhisper/product/ha/mapper/UserMapper.java new file mode 100644 index 00000000..410e08da --- /dev/null +++ b/distributed/hystrix/eshop-product-ha/src/main/java/cn/lastwhisper/product/ha/mapper/UserMapper.java @@ -0,0 +1,8 @@ +package cn.lastwhisper.product.ha.mapper; + +/** + * @author Administrator + */ +public interface UserMapper { + +} diff --git a/distributed/hystrix/eshop-product-ha/src/main/resources/application.properties b/distributed/hystrix/eshop-product-ha/src/main/resources/application.properties new file mode 100644 index 00000000..09fb0276 --- /dev/null +++ b/distributed/hystrix/eshop-product-ha/src/main/resources/application.properties @@ -0,0 +1,6 @@ +server.port=8082 +spring.datasource.url=jdbc:mysql://localhost:3306/eshop?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8 +spring.datasource.username=root +spring.datasource.password=root +spring.datasource.driver-class-name=com.mysql.jdbc.Driver +logging.level.org.apache.http.impl=info \ No newline at end of file diff --git a/distributed/hystrix/eshop-product-ha/src/main/resources/mybatis/UserMapper.xml b/distributed/hystrix/eshop-product-ha/src/main/resources/mybatis/UserMapper.xml new file mode 100644 index 00000000..e4a16e95 --- /dev/null +++ b/distributed/hystrix/eshop-product-ha/src/main/resources/mybatis/UserMapper.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/distributed/hystrix/eshop-product-ha/src/main/resources/templates/hello.html b/distributed/hystrix/eshop-product-ha/src/main/resources/templates/hello.html new file mode 100644 index 00000000..e69de29b diff --git a/distributed/hystrix/eshop-product-ha/src/test/java/cn/lastwhisper/product/ha/ProductHaApplicationTests.java b/distributed/hystrix/eshop-product-ha/src/test/java/cn/lastwhisper/product/ha/ProductHaApplicationTests.java new file mode 100644 index 00000000..9759c6d9 --- /dev/null +++ b/distributed/hystrix/eshop-product-ha/src/test/java/cn/lastwhisper/product/ha/ProductHaApplicationTests.java @@ -0,0 +1,13 @@ +package cn.lastwhisper.product.ha; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class ProductHaApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/distributed/hystrix/pom.xml b/distributed/hystrix/pom.xml new file mode 100644 index 00000000..d81c256f --- /dev/null +++ b/distributed/hystrix/pom.xml @@ -0,0 +1,12 @@ + + + 4.0.0 + + cn.lastwhisper + hystrix + 1.0-SNAPSHOT + + + \ No newline at end of file diff --git a/distributed/lock/flow1/Thread Group100.jmx b/distributed/lock/flow1/Thread Group100.jmx new file mode 100644 index 00000000..1ebff925 --- /dev/null +++ b/distributed/lock/flow1/Thread Group100.jmx @@ -0,0 +1,51 @@ + + + + + + false + true + false + + + + + + + + continue + + false + 1 + + 100 + 1 + false + + + true + + + + + + + http://localhost/ + + + + http://localhost/buy_goods + GET + true + false + true + false + + + + + + + + + diff --git a/distributed/lock/flow1/pom.xml b/distributed/lock/flow1/pom.xml new file mode 100644 index 00000000..f1340bcb --- /dev/null +++ b/distributed/lock/flow1/pom.xml @@ -0,0 +1,97 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.4.0 + + + cn.cunchang + flow1 + 0.0.1-SNAPSHOT + flow1 + Demo project for redis distributed lock + + + 1.8 + + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-data-redis + + + + org.springframework.boot + spring-boot-starter-actuator + + + + org.springframework.boot + spring-boot-devtools + runtime + true + + + + org.springframework.boot + spring-boot-starter-test + test + + + + org.apache.commons + commons-pool2 + + + + redis.clients + jedis + 3.1.0 + + + + + org.springframework.boot + spring-boot-starter-aop + + + + org.redisson + redisson + 3.13.6 + + + + org.projectlombok + lombok + true + + + + junit + junit + 4.12 + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/distributed/lock/flow1/src/main/java/cn/cunchang/Application1.java b/distributed/lock/flow1/src/main/java/cn/cunchang/Application1.java new file mode 100644 index 00000000..4b963062 --- /dev/null +++ b/distributed/lock/flow1/src/main/java/cn/cunchang/Application1.java @@ -0,0 +1,14 @@ +package cn.cunchang; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; + +@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class}) +public class Application1 { + + public static void main(String[] args) { + SpringApplication.run(Application1.class, args); + } + +} diff --git a/distributed/lock/flow1/src/main/java/cn/cunchang/config/RedisConfig.java b/distributed/lock/flow1/src/main/java/cn/cunchang/config/RedisConfig.java new file mode 100644 index 00000000..2225fde2 --- /dev/null +++ b/distributed/lock/flow1/src/main/java/cn/cunchang/config/RedisConfig.java @@ -0,0 +1,42 @@ + +package cn.cunchang.config; + +import org.redisson.Redisson; +import org.redisson.api.RedissonClient; +import org.redisson.client.codec.Codec; +import org.redisson.config.Config; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; +import org.springframework.data.redis.serializer.StringRedisSerializer; + +import java.io.Serializable; + +@Configuration +public class RedisConfig { + + /*** 保证不是序列化后的乱码配置 */ + @Bean + public RedisTemplate redisTemplate(LettuceConnectionFactory connectionFactory) { + RedisTemplate redisTemplate = new RedisTemplate<>(); + redisTemplate.setKeySerializer(new StringRedisSerializer()); + redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer()); + redisTemplate.setConnectionFactory(connectionFactory); + return redisTemplate; + } + + @Bean + public RedissonClient redisson() { + Config config = new Config(); + config.useSingleServer().setAddress("redis://127.0.0.1:6379").setDatabase(0); + try { + config.setCodec((Codec) Class.forName("org.redisson.codec.JsonJacksonCodec").newInstance()); + } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) { + e.printStackTrace(); + } + return Redisson.create(config); + } +} + diff --git a/distributed/lock/flow1/src/main/java/cn/cunchang/controller/GoodController1.java b/distributed/lock/flow1/src/main/java/cn/cunchang/controller/GoodController1.java new file mode 100644 index 00000000..e26a1669 --- /dev/null +++ b/distributed/lock/flow1/src/main/java/cn/cunchang/controller/GoodController1.java @@ -0,0 +1,37 @@ +package cn.cunchang.controller; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + + +//@RestController +public class GoodController1 { + @Autowired + private StringRedisTemplate stringRedisTemplate; + @Value("${server.port}") + private String serverPort; + + /** + * + * 产生的问题:单机无锁,非原子操作 + * @return + */ + @GetMapping("/buy_goods") + public String buyGoods() { + String result = stringRedisTemplate.opsForValue().get("goods:001"); + int goodsNumber = result == null ? 0 : Integer.parseInt(result); + if (goodsNumber > 0) { + int realNumber = goodsNumber - 1; + stringRedisTemplate.opsForValue().set("goods:001", realNumber + ""); + System.out.println(" 你已经成功秒杀商品,此时还剩余: " + realNumber + " 件 " + " \t 服务器端口 : " + serverPort); + return " 你已经成功秒杀商品,此时还剩余: " + realNumber + " 件 " + " \t 服务器端口 : " + serverPort; + } else { + System.out.println(" 商品已经售罄 / 活动结束 / 调用超时,欢迎下次光临 " + " \t 服务器端口 : " + serverPort); + } + return " 商品已经售罄 / 活动结束 / 调用超时,欢迎下次光临 " + " \t 服务器端口 : " + serverPort; + } +} + diff --git a/distributed/lock/flow1/src/main/java/cn/cunchang/controller/GoodController2.java b/distributed/lock/flow1/src/main/java/cn/cunchang/controller/GoodController2.java new file mode 100644 index 00000000..70fb08d5 --- /dev/null +++ b/distributed/lock/flow1/src/main/java/cn/cunchang/controller/GoodController2.java @@ -0,0 +1,39 @@ +package cn.cunchang.controller; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + + +//@RestController +public class GoodController2 { + @Autowired + private StringRedisTemplate stringRedisTemplate; + @Value("${server.port}") + private String serverPort; + + /** + * 解决了1的问题 + * 产生的问题:集群有锁,非原子操作 + * @return + */ + @GetMapping("/buy_goods") + public String buyGoods() { + synchronized (this) { + String result = stringRedisTemplate.opsForValue().get("goods:001"); + int goodsNumber = result == null ? 0 : Integer.parseInt(result); + if (goodsNumber > 0) { + int realNumber = goodsNumber - 1; + stringRedisTemplate.opsForValue().set("goods:001", realNumber + ""); + System.out.println(" 你已经成功秒杀商品,此时还剩余: " + realNumber + " 件 " + " \t 服务器端口 : " + serverPort); + return " 你已经成功秒杀商品,此时还剩余: " + realNumber + " 件 " + " \t 服务器端口 : " + serverPort; + } else { + System.out.println(" 商品已经售罄 / 活动结束 / 调用超时,欢迎下次光临 " + " \t 服务器端口 : " + serverPort); + } + return " 商品已经售罄 / 活动结束 / 调用超时,欢迎下次光临 " + " \t 服务器端口 : " + serverPort; + } + } +} + diff --git a/distributed/lock/flow1/src/main/java/cn/cunchang/controller/GoodController3.java b/distributed/lock/flow1/src/main/java/cn/cunchang/controller/GoodController3.java new file mode 100644 index 00000000..702e55f1 --- /dev/null +++ b/distributed/lock/flow1/src/main/java/cn/cunchang/controller/GoodController3.java @@ -0,0 +1,52 @@ +package cn.cunchang.controller; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.UUID; + + +//@RestController +public class GoodController3 { + @Autowired + private StringRedisTemplate stringRedisTemplate; + @Value("${server.port}") + private String serverPort; + + private String LOCK_KEY = "seckillLock"; + + /** + * 解决了2的问题 + * 产生的问题:集群有分布式锁,设置锁后宕机,死锁 + * @return + */ + @GetMapping("/buy_goods") + public String buyGoods() { + + try { + String lockValue = UUID.randomUUID().toString(); + //NX + Boolean flag = stringRedisTemplate.opsForValue().setIfAbsent(LOCK_KEY, lockValue); + if (!flag) { + return "抢锁失败!!!请再次尝试"; + } + String result = stringRedisTemplate.opsForValue().get("goods:001"); + int goodsNumber = result == null ? 0 : Integer.parseInt(result); + if (goodsNumber > 0) { + int realNumber = goodsNumber - 1; + stringRedisTemplate.opsForValue().set("goods:001", realNumber + ""); + System.out.println(" 你已经成功秒杀商品,此时还剩余: " + realNumber + " 件 " + " \t 服务器端口 : " + serverPort); + return " 你已经成功秒杀商品,此时还剩余: " + realNumber + " 件 " + " \t 服务器端口 : " + serverPort; + } else { + System.out.println(" 商品已经售罄 / 活动结束 / 调用超时,欢迎下次光临 " + " \t 服务器端口 : " + serverPort); + } + return " 商品已经售罄 / 活动结束 / 调用超时,欢迎下次光临 " + " \t 服务器端口 : " + serverPort; + } finally { + stringRedisTemplate.delete(LOCK_KEY); + } + } +} + diff --git a/distributed/lock/flow1/src/main/java/cn/cunchang/controller/GoodController4.java b/distributed/lock/flow1/src/main/java/cn/cunchang/controller/GoodController4.java new file mode 100644 index 00000000..d5e3de10 --- /dev/null +++ b/distributed/lock/flow1/src/main/java/cn/cunchang/controller/GoodController4.java @@ -0,0 +1,54 @@ +package cn.cunchang.controller; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.UUID; +import java.util.concurrent.TimeUnit; + + +//@RestController +public class GoodController4 { + @Autowired + private StringRedisTemplate stringRedisTemplate; + @Value("${server.port}") + private String serverPort; + + private String LOCK_KEY = "seckillLock"; + + /** + * 解决了3的问题 + * 产生的问题:加锁+过期,非原子操作 + * @return + */ + @GetMapping("/buy_goods") + public String buyGoods() { + + try { + String lockValue = UUID.randomUUID().toString(); + //NX + Boolean flag = stringRedisTemplate.opsForValue().setIfAbsent(LOCK_KEY, lockValue); + stringRedisTemplate.expire(LOCK_KEY,10L, TimeUnit.SECONDS); + if (!flag) { + return "抢锁失败!!!请再次尝试"; + } + String result = stringRedisTemplate.opsForValue().get("goods:001"); + int goodsNumber = result == null ? 0 : Integer.parseInt(result); + if (goodsNumber > 0) { + int realNumber = goodsNumber - 1; + stringRedisTemplate.opsForValue().set("goods:001", realNumber + ""); + System.out.println(" 你已经成功秒杀商品,此时还剩余: " + realNumber + " 件 " + " \t 服务器端口 : " + serverPort); + return " 你已经成功秒杀商品,此时还剩余: " + realNumber + " 件 " + " \t 服务器端口 : " + serverPort; + } else { + System.out.println(" 商品已经售罄 / 活动结束 / 调用超时,欢迎下次光临 " + " \t 服务器端口 : " + serverPort); + } + return " 商品已经售罄 / 活动结束 / 调用超时,欢迎下次光临 " + " \t 服务器端口 : " + serverPort; + } finally { + stringRedisTemplate.delete(LOCK_KEY); + } + } +} + diff --git a/distributed/lock/flow1/src/main/java/cn/cunchang/controller/GoodController5.java b/distributed/lock/flow1/src/main/java/cn/cunchang/controller/GoodController5.java new file mode 100644 index 00000000..79a9f19f --- /dev/null +++ b/distributed/lock/flow1/src/main/java/cn/cunchang/controller/GoodController5.java @@ -0,0 +1,56 @@ +package cn.cunchang.controller; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.UUID; +import java.util.concurrent.TimeUnit; + + +//@RestController +public class GoodController5 { + @Autowired + private StringRedisTemplate stringRedisTemplate; + @Value("${server.port}") + private String serverPort; + + private String LOCK_KEY = "seckillLock"; + + /** + * 解决了4的问题

+ * 产生的问题:加锁解锁可能不是一个客户端 + * A抢到锁后锁10秒过期,A业务执行了11秒(正常5~8秒突发情况),锁在第10秒过期后, + * B抢到锁,B业务执行了1秒,A释放锁,此时其实是把B拿到的锁释放了,B还在执行业务代码 + * C抢到锁,B与C分布式锁的代码其实是在并行执行 + * @return + */ + @GetMapping("/buy_goods") + public String buyGoods() { + + try { + String lockValue = UUID.randomUUID().toString(); + //NX+time + Boolean flag = stringRedisTemplate.opsForValue().setIfAbsent(LOCK_KEY, lockValue, 10L, TimeUnit.SECONDS); + if (!flag) { + return "抢锁失败!!!请再次尝试"; + } + String result = stringRedisTemplate.opsForValue().get("goods:001"); + int goodsNumber = result == null ? 0 : Integer.parseInt(result); + if (goodsNumber > 0) { + int realNumber = goodsNumber - 1; + stringRedisTemplate.opsForValue().set("goods:001", realNumber + ""); + System.out.println(" 你已经成功秒杀商品,此时还剩余: " + realNumber + " 件 " + " \t 服务器端口 : " + serverPort); + return " 你已经成功秒杀商品,此时还剩余: " + realNumber + " 件 " + " \t 服务器端口 : " + serverPort; + } else { + System.out.println(" 商品已经售罄 / 活动结束 / 调用超时,欢迎下次光临 " + " \t 服务器端口 : " + serverPort); + } + return " 商品已经售罄 / 活动结束 / 调用超时,欢迎下次光临 " + " \t 服务器端口 : " + serverPort; + } finally { + stringRedisTemplate.delete(LOCK_KEY); + } + } +} + diff --git a/distributed/lock/flow1/src/main/java/cn/cunchang/controller/GoodController6.java b/distributed/lock/flow1/src/main/java/cn/cunchang/controller/GoodController6.java new file mode 100644 index 00000000..68ca8cd0 --- /dev/null +++ b/distributed/lock/flow1/src/main/java/cn/cunchang/controller/GoodController6.java @@ -0,0 +1,56 @@ +package cn.cunchang.controller; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.web.bind.annotation.GetMapping; + +import java.util.UUID; +import java.util.concurrent.TimeUnit; + + +//@RestController +public class GoodController6 { + @Autowired + private StringRedisTemplate stringRedisTemplate; + @Value("${server.port}") + private String serverPort; + + private String LOCK_KEY = "seckillLock"; + + /** + * 解决了5的问题

+ * + * 产生的问题:判断是不是同一个客户端,不是原子操作,会导致死锁 + * + * @return + */ + @GetMapping("/buy_goods") + public String buyGoods() { + String lockValue = UUID.randomUUID().toString(); + try { + //NX+time + Boolean flag = stringRedisTemplate.opsForValue().setIfAbsent(LOCK_KEY, lockValue, 10L, TimeUnit.SECONDS); + if (!flag) { + return "抢锁失败!!!请再次尝试"; + } + String result = stringRedisTemplate.opsForValue().get("goods:001"); + int goodsNumber = result == null ? 0 : Integer.parseInt(result); + if (goodsNumber > 0) { + int realNumber = goodsNumber - 1; + stringRedisTemplate.opsForValue().set("goods:001", realNumber + ""); + System.out.println(" 你已经成功秒杀商品,此时还剩余: " + realNumber + " 件 " + " \t 服务器端口 : " + serverPort); + return " 你已经成功秒杀商品,此时还剩余: " + realNumber + " 件 " + " \t 服务器端口 : " + serverPort; + } else { + System.out.println(" 商品已经售罄 / 活动结束 / 调用超时,欢迎下次光临 " + " \t 服务器端口 : " + serverPort); + } + return " 商品已经售罄 / 活动结束 / 调用超时,欢迎下次光临 " + " \t 服务器端口 : " + serverPort; + } finally { + String nowLockValue = stringRedisTemplate.opsForValue().get(LOCK_KEY); + if (nowLockValue != null && nowLockValue.equals(lockValue)) { + stringRedisTemplate.delete(LOCK_KEY); + } + } + } +} + diff --git a/distributed/lock/flow1/src/main/java/cn/cunchang/controller/GoodController7_1.java b/distributed/lock/flow1/src/main/java/cn/cunchang/controller/GoodController7_1.java new file mode 100644 index 00000000..a9b15388 --- /dev/null +++ b/distributed/lock/flow1/src/main/java/cn/cunchang/controller/GoodController7_1.java @@ -0,0 +1,82 @@ +package cn.cunchang.controller; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.data.redis.core.script.DefaultRedisScript; +import org.springframework.web.bind.annotation.GetMapping; + +import javax.annotation.PostConstruct; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.TimeUnit; + + +//@RestController +public class GoodController7_1 { + @Autowired + private StringRedisTemplate stringRedisTemplate; + @Value("${server.port}") + private String serverPort; + + private String LOCK_KEY = "seckillLock"; + + private String DEL_SCRIPT = "if redis.call(\"get\",KEYS[1]) == ARGV[1]\n" + + "then\n" + + " return redis.call(\"del\",KEYS[1])\n" + + "else\n" + + " return 0\n" + + "end"; + + private DefaultRedisScript getRedisScript; + + @PostConstruct + public void init() { + getRedisScript = new DefaultRedisScript<>(); + getRedisScript.setResultType(List.class); + // 加载lua文本 + getRedisScript.setScriptText(DEL_SCRIPT); + // 加载lua文件 +// getRedisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("lua/DelLockScript.lua"))); + } + + /** + * 解决了6的问题

+ * - lua

+ * - 事务 + *

+ * 产生的问题:续租 + * + * @return + */ + @GetMapping("/buy_goods") + public String buyGoods() { + String lockValue = UUID.randomUUID().toString(); + try { + //NX+time + Boolean flag = stringRedisTemplate.opsForValue().setIfAbsent(LOCK_KEY, lockValue, 10L, TimeUnit.SECONDS); + if (!flag) { + return "抢锁失败!!!请再次尝试"; + } + String result = stringRedisTemplate.opsForValue().get("goods:001"); + int goodsNumber = result == null ? 0 : Integer.parseInt(result); + if (goodsNumber > 0) { + int realNumber = goodsNumber - 1; + stringRedisTemplate.opsForValue().set("goods:001", realNumber + ""); + System.out.println(" 你已经成功秒杀商品,此时还剩余: " + realNumber + " 件 " + " \t 服务器端口 : " + serverPort); + return " 你已经成功秒杀商品,此时还剩余: " + realNumber + " 件 " + " \t 服务器端口 : " + serverPort; + } else { + System.out.println(" 商品已经售罄 / 活动结束 / 调用超时,欢迎下次光临 " + " \t 服务器端口 : " + serverPort); + } + return " 商品已经售罄 / 活动结束 / 调用超时,欢迎下次光临 " + " \t 服务器端口 : " + serverPort; + } finally { + List keys = new ArrayList<>(); + keys.add(LOCK_KEY); + List args = new ArrayList<>(); + args.add(lockValue); + stringRedisTemplate.execute(getRedisScript, keys, args); + } + } +} + diff --git a/distributed/lock/flow1/src/main/java/cn/cunchang/controller/GoodController7_2.java b/distributed/lock/flow1/src/main/java/cn/cunchang/controller/GoodController7_2.java new file mode 100644 index 00000000..5af00008 --- /dev/null +++ b/distributed/lock/flow1/src/main/java/cn/cunchang/controller/GoodController7_2.java @@ -0,0 +1,72 @@ +package cn.cunchang.controller; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.web.bind.annotation.GetMapping; + +import java.util.List; +import java.util.UUID; +import java.util.concurrent.TimeUnit; + + +//@RestController +public class GoodController7_2 { + @Autowired + private StringRedisTemplate stringRedisTemplate; + @Value("${server.port}") + private String serverPort; + + private String LOCK_KEY = "seckillLock"; + + /** + * 解决了6的问题

+ * - lua

+ * - 事务 + *

+ * 产生的问题:续租 + * + * @return + */ + @GetMapping("/buy_goods") + public String buyGoods() { + String lockValue = UUID.randomUUID().toString(); + try { + //NX+time + Boolean flag = stringRedisTemplate.opsForValue().setIfAbsent(LOCK_KEY, lockValue, 10L, TimeUnit.SECONDS); + if (!flag) { + return "抢锁失败!!!请再次尝试"; + } + String result = stringRedisTemplate.opsForValue().get("goods:001"); + int goodsNumber = result == null ? 0 : Integer.parseInt(result); + if (goodsNumber > 0) { + int realNumber = goodsNumber - 1; + stringRedisTemplate.opsForValue().set("goods:001", realNumber + ""); + System.out.println(" 你已经成功秒杀商品,此时还剩余: " + realNumber + " 件 " + " \t 服务器端口 : " + serverPort); + return " 你已经成功秒杀商品,此时还剩余: " + realNumber + " 件 " + " \t 服务器端口 : " + serverPort; + } else { + System.out.println(" 商品已经售罄 / 活动结束 / 调用超时,欢迎下次光临 " + " \t 服务器端口 : " + serverPort); + } + return " 商品已经售罄 / 活动结束 / 调用超时,欢迎下次光临 " + " \t 服务器端口 : " + serverPort; + } finally { + while (true) { + stringRedisTemplate.watch(LOCK_KEY); // 加事务,乐观锁 + if (lockValue.equalsIgnoreCase(stringRedisTemplate.opsForValue().get(LOCK_KEY))) { + stringRedisTemplate.setEnableTransactionSupport(true); + stringRedisTemplate.multi(); + // 开始事务 + stringRedisTemplate.delete(LOCK_KEY); + List list = stringRedisTemplate.exec(); + if (list == null) { + // 如果等于 null ,就是没有删掉,删除失败,再回去 while 循环那再重新执行删除 + continue; + } + } + // 如果删除成功,释放监控器,并且 breank 跳出当前循环 + stringRedisTemplate.unwatch(); + break; + } + } + } +} + diff --git a/distributed/lock/flow1/src/main/java/cn/cunchang/controller/GoodController8.java b/distributed/lock/flow1/src/main/java/cn/cunchang/controller/GoodController8.java new file mode 100644 index 00000000..424d16f0 --- /dev/null +++ b/distributed/lock/flow1/src/main/java/cn/cunchang/controller/GoodController8.java @@ -0,0 +1,57 @@ +package cn.cunchang.controller; + +import org.redisson.api.RBucket; +import org.redisson.api.RLock; +import org.redisson.api.RedissonClient; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + + +@RestController +public class GoodController8 { + @Value("${server.port}") + private String serverPort; + + private String LOCK_KEY = "seckillLock"; + + @Autowired + private RedissonClient redisson; + + /** + * 解决了7的问题

+ * - watch dog + *

+ * 产生的问题: + * + * @return + */ + @GetMapping("/buy_goods") + public String buyGoods() { + RLock rLock = redisson.getLock(LOCK_KEY); + try { + rLock.lock(); + + RBucket bucket = redisson.getBucket("goods:001"); + Integer result = bucket.get(); + + int goodsNumber = result == null ? 0 : result; + if (goodsNumber > 0) { + int realNumber = goodsNumber - 1; + bucket.set(realNumber); + System.out.println(" 你已经成功秒杀商品,此时还剩余: " + realNumber + " 件 " + " \t 服务器端口 : " + serverPort); + return " 你已经成功秒杀商品,此时还剩余: " + realNumber + " 件 " + " \t 服务器端口 : " + serverPort; + } else { + System.out.println(" 商品已经售罄 / 活动结束 / 调用超时,欢迎下次光临 " + " \t 服务器端口 : " + serverPort); + } + return " 商品已经售罄 / 活动结束 / 调用超时,欢迎下次光临 " + " \t 服务器端口 : " + serverPort; + } finally { + // 极端情况下会出现问题 + if (rLock.isLocked() && rLock.isHeldByCurrentThread()) { + rLock.unlock(); + } + } + } +} + diff --git a/distributed/lock/flow1/src/main/resources/application.properties b/distributed/lock/flow1/src/main/resources/application.properties new file mode 100644 index 00000000..f9964fd0 --- /dev/null +++ b/distributed/lock/flow1/src/main/resources/application.properties @@ -0,0 +1,12 @@ +server.port=1111 +spring.redis.database=0 +spring.redis.host=localhost +#连接池最大连接数(使用负值表示没有限制)默认8 +spring.redis.port=6379 +#连接池最大阻塞等待时间(使用负值表示没有限制)默认-1 +spring.redis.lettuce.pool.max-active=8 +#连接池中的最大空闲连接默认8 +spring.redis.lettuce.pool.max-wait=-1 +#连接池中的最小空闲连接默认0 +spring.redis.lettuce.pool.max-idle=8 +spring.redis.lettuce.pool.min-idle=0 \ No newline at end of file diff --git a/distributed/lock/flow1/src/main/resources/lua/DelLockScript.lua b/distributed/lock/flow1/src/main/resources/lua/DelLockScript.lua new file mode 100644 index 00000000..7b3fdb1e --- /dev/null +++ b/distributed/lock/flow1/src/main/resources/lua/DelLockScript.lua @@ -0,0 +1,6 @@ +if redis.call("get",KEYS[1]) == ARGV[1] +then + return redis.call("del",KEYS[1]) +else + return 0 +end \ No newline at end of file diff --git a/distributed/lock/flow1/src/test/java/cn/cunchang/Application1Tests.java b/distributed/lock/flow1/src/test/java/cn/cunchang/Application1Tests.java new file mode 100644 index 00000000..992218a4 --- /dev/null +++ b/distributed/lock/flow1/src/test/java/cn/cunchang/Application1Tests.java @@ -0,0 +1,13 @@ +package cn.cunchang; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class Application1Tests { + + @Test + void contextLoads() { + } + +} diff --git a/distributed/lock/flow2/pom.xml b/distributed/lock/flow2/pom.xml new file mode 100644 index 00000000..5ebdfc0f --- /dev/null +++ b/distributed/lock/flow2/pom.xml @@ -0,0 +1,98 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.4.0 + + + cn.cunchang + flow2 + 0.0.1-SNAPSHOT + flow2 + Demo project for redis distributed lock + + + 1.8 + + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-data-redis + + + + org.springframework.boot + spring-boot-starter-actuator + + + + org.springframework.boot + spring-boot-devtools + runtime + true + + + + org.springframework.boot + spring-boot-starter-test + test + + + + org.apache.commons + commons-pool2 + + + + + redis.clients + jedis + 3.1.0 + + + + + org.springframework.boot + spring-boot-starter-aop + + + + org.redisson + redisson + 3.13.6 + + + + org.projectlombok + lombok + true + + + + junit + junit + 4.12 + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/distributed/lock/flow2/src/main/java/cn/cunchang/Application2.java b/distributed/lock/flow2/src/main/java/cn/cunchang/Application2.java new file mode 100644 index 00000000..40274927 --- /dev/null +++ b/distributed/lock/flow2/src/main/java/cn/cunchang/Application2.java @@ -0,0 +1,14 @@ +package cn.cunchang; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; + +@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class}) +public class Application2 { + + public static void main(String[] args) { + SpringApplication.run(Application2.class, args); + } + +} diff --git a/distributed/lock/flow2/src/main/java/cn/cunchang/config/RedisConfig.java b/distributed/lock/flow2/src/main/java/cn/cunchang/config/RedisConfig.java new file mode 100644 index 00000000..2eeefe5e --- /dev/null +++ b/distributed/lock/flow2/src/main/java/cn/cunchang/config/RedisConfig.java @@ -0,0 +1,42 @@ + +package cn.cunchang.config; + +import org.redisson.Redisson; +import org.redisson.api.RedissonClient; +import org.redisson.client.codec.Codec; +import org.redisson.config.Config; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; +import org.springframework.data.redis.serializer.StringRedisSerializer; + +import java.io.Serializable; + +@Configuration +public class RedisConfig { + + /*** 保证不是序列化后的乱码配置 */ + @Bean + public RedisTemplate redisTemplate(LettuceConnectionFactory connectionFactory) { + RedisTemplate redisTemplate = new RedisTemplate<>(); + redisTemplate.setKeySerializer(new StringRedisSerializer()); + redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer()); + redisTemplate.setConnectionFactory(connectionFactory); + return redisTemplate; + } + + @Bean + public RedissonClient redisson() { + Config config = new Config(); + config.useSingleServer().setAddress("redis://127.0.0.1:6379").setDatabase(0);; + try { + config.setCodec((Codec) Class.forName("org.redisson.codec.JsonJacksonCodec").newInstance()); + } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) { + e.printStackTrace(); + } + return Redisson.create(config); + } +} + diff --git a/distributed/lock/flow2/src/main/java/cn/cunchang/controller/GoodController.java b/distributed/lock/flow2/src/main/java/cn/cunchang/controller/GoodController.java new file mode 100644 index 00000000..28b586da --- /dev/null +++ b/distributed/lock/flow2/src/main/java/cn/cunchang/controller/GoodController.java @@ -0,0 +1,34 @@ +package cn.cunchang.controller; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + + +//@RestController +public class GoodController { + @Autowired + private StringRedisTemplate stringRedisTemplate; + @Value("${server.port}") + private String serverPort; + + @GetMapping("/buy_goods") + public String buyGoods() { + synchronized (this) { + String result = stringRedisTemplate.opsForValue().get("goods:001"); + int goodsNumber = result == null ? 0 : Integer.parseInt(result); + if (goodsNumber > 0) { + int realNumber = goodsNumber - 1; + stringRedisTemplate.opsForValue().set("goods:001", realNumber + ""); + System.out.println(" 你已经成功秒杀商品,此时还剩余: " + realNumber + " 件 " + " \t 服务器端口 : " + serverPort); + return " 你已经成功秒杀商品,此时还剩余: " + realNumber + " 件 " + " \t 服务器端口 : " + serverPort; + } else { + System.out.println(" 商品已经售罄 / 活动结束 / 调用超时,欢迎下次光临 " + " \t 服务器端口 : " + serverPort); + } + return " 商品已经售罄 / 活动结束 / 调用超时,欢迎下次光临 " + " \t 服务器端口 : " + serverPort; + } + } +} + diff --git a/distributed/lock/flow2/src/main/java/cn/cunchang/controller/GoodController8.java b/distributed/lock/flow2/src/main/java/cn/cunchang/controller/GoodController8.java new file mode 100644 index 00000000..424d16f0 --- /dev/null +++ b/distributed/lock/flow2/src/main/java/cn/cunchang/controller/GoodController8.java @@ -0,0 +1,57 @@ +package cn.cunchang.controller; + +import org.redisson.api.RBucket; +import org.redisson.api.RLock; +import org.redisson.api.RedissonClient; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + + +@RestController +public class GoodController8 { + @Value("${server.port}") + private String serverPort; + + private String LOCK_KEY = "seckillLock"; + + @Autowired + private RedissonClient redisson; + + /** + * 解决了7的问题

+ * - watch dog + *

+ * 产生的问题: + * + * @return + */ + @GetMapping("/buy_goods") + public String buyGoods() { + RLock rLock = redisson.getLock(LOCK_KEY); + try { + rLock.lock(); + + RBucket bucket = redisson.getBucket("goods:001"); + Integer result = bucket.get(); + + int goodsNumber = result == null ? 0 : result; + if (goodsNumber > 0) { + int realNumber = goodsNumber - 1; + bucket.set(realNumber); + System.out.println(" 你已经成功秒杀商品,此时还剩余: " + realNumber + " 件 " + " \t 服务器端口 : " + serverPort); + return " 你已经成功秒杀商品,此时还剩余: " + realNumber + " 件 " + " \t 服务器端口 : " + serverPort; + } else { + System.out.println(" 商品已经售罄 / 活动结束 / 调用超时,欢迎下次光临 " + " \t 服务器端口 : " + serverPort); + } + return " 商品已经售罄 / 活动结束 / 调用超时,欢迎下次光临 " + " \t 服务器端口 : " + serverPort; + } finally { + // 极端情况下会出现问题 + if (rLock.isLocked() && rLock.isHeldByCurrentThread()) { + rLock.unlock(); + } + } + } +} + diff --git a/distributed/lock/flow2/src/main/resources/application.properties b/distributed/lock/flow2/src/main/resources/application.properties new file mode 100644 index 00000000..03d037e6 --- /dev/null +++ b/distributed/lock/flow2/src/main/resources/application.properties @@ -0,0 +1,12 @@ +server.port=2222 +spring.redis.database=0 +spring.redis.host=localhost +#连接池最大连接数(使用负值表示没有限制)默认8 +spring.redis.port=6379 +#连接池最大阻塞等待时间(使用负值表示没有限制)默认-1 +spring.redis.lettuce.pool.max-active=8 +#连接池中的最大空闲连接默认8 +spring.redis.lettuce.pool.max-wait=-1 +#连接池中的最小空闲连接默认0 +spring.redis.lettuce.pool.max-idle=8 +spring.redis.lettuce.pool.min-idle=0 \ No newline at end of file diff --git a/distributed/lock/flow2/src/test/java/cn/cunchang/Application2Tests.java b/distributed/lock/flow2/src/test/java/cn/cunchang/Application2Tests.java new file mode 100644 index 00000000..59265d64 --- /dev/null +++ b/distributed/lock/flow2/src/test/java/cn/cunchang/Application2Tests.java @@ -0,0 +1,13 @@ +package cn.cunchang; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class Application2Tests { + + @Test + void contextLoads() { + } + +} diff --git a/distributed/lock/jedis/README.md b/distributed/lock/jedis/README.md new file mode 100644 index 00000000..156c1efe --- /dev/null +++ b/distributed/lock/jedis/README.md @@ -0,0 +1,30 @@ + +# redis学习时的代码笔记 + +## asynqueue 异步队列 + +## basic 基础数据结构操作 + +## cluster Java集群操作 + +## dlock redis分布式锁 + +## hyperloglog 统计 + +## bloomfilter 布隆过滤器 + +## partition hash节点迁移率 + +## pipeline 流水线指令 + +## publishersubscriber 发布订阅 + +## sentinel 哨兵 + +## transaction 事务 + + + + + + diff --git a/distributed/lock/jedis/pom.xml b/distributed/lock/jedis/pom.xml new file mode 100644 index 00000000..a97af966 --- /dev/null +++ b/distributed/lock/jedis/pom.xml @@ -0,0 +1,61 @@ + + + 4.0.0 + + cn.lastwhisper + jedis + 1.0-SNAPSHOT + jedis + + + + + + com.redislabs + jrebloom + 1.0.1 + + + + com.alibaba + fastjson + 1.2.56 + + + + com.google.guava + guava + 27.0.1-jre + + + + + redis.clients + jedis + 2.9.0 + + + + junit + junit + 4.12 + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.7.0 + + 1.8 + 1.8 + + + + + \ No newline at end of file diff --git a/distributed/lock/jedis/src/main/java/cn/cunchang/JedisUtil.java b/distributed/lock/jedis/src/main/java/cn/cunchang/JedisUtil.java new file mode 100644 index 00000000..216ed3f2 --- /dev/null +++ b/distributed/lock/jedis/src/main/java/cn/cunchang/JedisUtil.java @@ -0,0 +1,15 @@ +package cn.cunchang; + +import cn.cunchang.common.Const; +import redis.clients.jedis.Jedis; + +public class JedisUtil { + + public static Jedis getJedis() { + // 默认db0,可以设置 + Jedis jedis = new Jedis(Const.IP, Const.PORT); +// jedis.select(1); + return jedis; + } + +} diff --git a/database/redis/src/main/java/cn/lastwhisper/redis/asynqueue/RedisDelayingQueue.java b/distributed/lock/jedis/src/main/java/cn/cunchang/asynqueue/RedisDelayingQueue.java similarity index 96% rename from database/redis/src/main/java/cn/lastwhisper/redis/asynqueue/RedisDelayingQueue.java rename to distributed/lock/jedis/src/main/java/cn/cunchang/asynqueue/RedisDelayingQueue.java index 3ac51dfa..e9ca8024 100644 --- a/database/redis/src/main/java/cn/lastwhisper/redis/asynqueue/RedisDelayingQueue.java +++ b/distributed/lock/jedis/src/main/java/cn/cunchang/asynqueue/RedisDelayingQueue.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.redis.asynqueue; +package cn.cunchang.asynqueue; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.TypeReference; @@ -10,7 +10,7 @@ /** * 延时队列的实现 - * @author lastwhisper + * @author cunchang */ public class RedisDelayingQueue { @@ -68,6 +68,7 @@ public static void main(String[] args) { RedisDelayingQueue queue = new RedisDelayingQueue(jedis, "q-demo"); Thread producer = new Thread() { + @Override public void run() { for (int i = 0; i < 10; i++) { queue.delay("codehole" + i); @@ -77,6 +78,7 @@ public void run() { }; Thread consumer = new Thread() { + @Override public void run() { queue.loop(); } diff --git a/distributed/lock/jedis/src/main/java/cn/cunchang/basic/BasicOperation.java b/distributed/lock/jedis/src/main/java/cn/cunchang/basic/BasicOperation.java new file mode 100644 index 00000000..d207c9fd --- /dev/null +++ b/distributed/lock/jedis/src/main/java/cn/cunchang/basic/BasicOperation.java @@ -0,0 +1,12 @@ +package cn.cunchang.basic; + +/** + * Redis基础数据结构的操作 + * @author cunchang + * @date 2019/11/23 + */ +public class BasicOperation { + + + +} diff --git a/database/redis/src/main/java/cn/lastwhisper/redis/basic/StringOper.java b/distributed/lock/jedis/src/main/java/cn/cunchang/basic/StringOper.java similarity index 84% rename from database/redis/src/main/java/cn/lastwhisper/redis/basic/StringOper.java rename to distributed/lock/jedis/src/main/java/cn/cunchang/basic/StringOper.java index 5ff185ce..3beefdbd 100644 --- a/database/redis/src/main/java/cn/lastwhisper/redis/basic/StringOper.java +++ b/distributed/lock/jedis/src/main/java/cn/cunchang/basic/StringOper.java @@ -1,10 +1,10 @@ -package cn.lastwhisper.redis.basic; +package cn.cunchang.basic; import redis.clients.jedis.Jedis; /** * string数据结构的操作 - * @author lastwhisper + * @author cunchang * @date 2019/11/24 */ public class StringOper { diff --git a/database/redis/src/main/java/cn/lastwhisper/redis/bloomfilter/BloomTest.java b/distributed/lock/jedis/src/main/java/cn/cunchang/bloomfilter/BloomTest.java similarity index 94% rename from database/redis/src/main/java/cn/lastwhisper/redis/bloomfilter/BloomTest.java rename to distributed/lock/jedis/src/main/java/cn/cunchang/bloomfilter/BloomTest.java index 6692b993..442a9b29 100644 --- a/database/redis/src/main/java/cn/lastwhisper/redis/bloomfilter/BloomTest.java +++ b/distributed/lock/jedis/src/main/java/cn/cunchang/bloomfilter/BloomTest.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.redis.bloomfilter; +package cn.cunchang.bloomfilter; import io.rebloom.client.Client; import org.junit.Test; @@ -7,7 +7,7 @@ /** * 布隆过滤器测试 - * @author lastwhisper + * @author cunchang */ public class BloomTest { diff --git a/database/redis/src/main/java/cn/lastwhisper/redis/bloomfilter/BloomTest2.java b/distributed/lock/jedis/src/main/java/cn/cunchang/bloomfilter/BloomTest2.java similarity index 96% rename from database/redis/src/main/java/cn/lastwhisper/redis/bloomfilter/BloomTest2.java rename to distributed/lock/jedis/src/main/java/cn/cunchang/bloomfilter/BloomTest2.java index b40954eb..813dcae2 100644 --- a/database/redis/src/main/java/cn/lastwhisper/redis/bloomfilter/BloomTest2.java +++ b/distributed/lock/jedis/src/main/java/cn/cunchang/bloomfilter/BloomTest2.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.redis.bloomfilter; +package cn.cunchang.bloomfilter; import io.rebloom.client.Client; @@ -8,7 +8,7 @@ /** * 测试bloomfilter的误判率 - * @author lastwhisper + * @author cunchang */ public class BloomTest2 { diff --git a/database/redis/src/main/java/cn/lastwhisper/redis/bloomfilter/BloomTest3.java b/distributed/lock/jedis/src/main/java/cn/cunchang/bloomfilter/BloomTest3.java similarity index 96% rename from database/redis/src/main/java/cn/lastwhisper/redis/bloomfilter/BloomTest3.java rename to distributed/lock/jedis/src/main/java/cn/cunchang/bloomfilter/BloomTest3.java index cb69ca2b..3b3f78b3 100644 --- a/database/redis/src/main/java/cn/lastwhisper/redis/bloomfilter/BloomTest3.java +++ b/distributed/lock/jedis/src/main/java/cn/cunchang/bloomfilter/BloomTest3.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.redis.bloomfilter; +package cn.cunchang.bloomfilter; import io.rebloom.client.Client; @@ -7,7 +7,7 @@ import java.util.concurrent.ThreadLocalRandom; /** - * @author lastwhisper + * @author cunchang */ public class BloomTest3 { private String chars; diff --git a/database/redis/src/main/java/cn/lastwhisper/redis/bloomfilter/GuavaBloom.java b/distributed/lock/jedis/src/main/java/cn/cunchang/bloomfilter/GuavaBloom.java similarity index 91% rename from database/redis/src/main/java/cn/lastwhisper/redis/bloomfilter/GuavaBloom.java rename to distributed/lock/jedis/src/main/java/cn/cunchang/bloomfilter/GuavaBloom.java index 8eb2ac28..e663a39f 100644 --- a/database/redis/src/main/java/cn/lastwhisper/redis/bloomfilter/GuavaBloom.java +++ b/distributed/lock/jedis/src/main/java/cn/cunchang/bloomfilter/GuavaBloom.java @@ -1,11 +1,11 @@ -package cn.lastwhisper.redis.bloomfilter; +package cn.cunchang.bloomfilter; import com.google.common.hash.BloomFilter; import com.google.common.hash.Funnel; import com.google.common.hash.Funnels; /** - * @author lastwhisper + * @author cunchang */ public class GuavaBloom { public static void main(String[] args) { diff --git a/database/redis/src/main/java/cn/lastwhisper/redis/cluster/ClusterTest.java b/distributed/lock/jedis/src/main/java/cn/cunchang/cluster/ClusterTest.java similarity index 95% rename from database/redis/src/main/java/cn/lastwhisper/redis/cluster/ClusterTest.java rename to distributed/lock/jedis/src/main/java/cn/cunchang/cluster/ClusterTest.java index 8db76db0..0b12060d 100644 --- a/database/redis/src/main/java/cn/lastwhisper/redis/cluster/ClusterTest.java +++ b/distributed/lock/jedis/src/main/java/cn/cunchang/cluster/ClusterTest.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.redis.cluster; +package cn.cunchang.cluster; import redis.clients.jedis.HostAndPort; import redis.clients.jedis.JedisCluster; @@ -12,7 +12,7 @@ /** * 集群测试 - * @author lastwhisper + * @author cunchang */ public class ClusterTest { diff --git a/database/redis/src/main/java/cn/lastwhisper/redis/cluster/JedisClusterFactory.java b/distributed/lock/jedis/src/main/java/cn/cunchang/cluster/JedisClusterFactory.java similarity index 96% rename from database/redis/src/main/java/cn/lastwhisper/redis/cluster/JedisClusterFactory.java rename to distributed/lock/jedis/src/main/java/cn/cunchang/cluster/JedisClusterFactory.java index 681410ea..f85de56a 100644 --- a/database/redis/src/main/java/cn/lastwhisper/redis/cluster/JedisClusterFactory.java +++ b/distributed/lock/jedis/src/main/java/cn/cunchang/cluster/JedisClusterFactory.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.redis.cluster; +package cn.cunchang.cluster; import redis.clients.jedis.HostAndPort; import redis.clients.jedis.JedisCluster; @@ -38,7 +38,7 @@ public void init() { } - public void destory() { + public void destroy() { if (jedisCluster != null) { try { jedisCluster.close(); diff --git a/distributed/lock/jedis/src/main/java/cn/cunchang/common/Const.java b/distributed/lock/jedis/src/main/java/cn/cunchang/common/Const.java new file mode 100644 index 00000000..4cfa486d --- /dev/null +++ b/distributed/lock/jedis/src/main/java/cn/cunchang/common/Const.java @@ -0,0 +1,13 @@ +package cn.cunchang.common; + +/** + * + * @author cunchang + * @date 2020/4/20 + */ +public interface Const { + + String IP = "127.0.0.1"; + Integer PORT = 6379; + +} diff --git a/database/redis/src/main/java/cn/lastwhisper/redis/hyperloglog/PfTest.java b/distributed/lock/jedis/src/main/java/cn/cunchang/hyperloglog/PfTest.java similarity index 81% rename from database/redis/src/main/java/cn/lastwhisper/redis/hyperloglog/PfTest.java rename to distributed/lock/jedis/src/main/java/cn/cunchang/hyperloglog/PfTest.java index 87e66c52..ece304a0 100644 --- a/database/redis/src/main/java/cn/lastwhisper/redis/hyperloglog/PfTest.java +++ b/distributed/lock/jedis/src/main/java/cn/cunchang/hyperloglog/PfTest.java @@ -1,10 +1,11 @@ -package cn.lastwhisper.redis.hyperloglog; +package cn.cunchang.hyperloglog; +import cn.cunchang.common.Const; import org.junit.Test; import redis.clients.jedis.Jedis; /** - * @author lastwhisper + * @author cunchang */ public class PfTest { @@ -13,7 +14,7 @@ public class PfTest { */ @Test public void test1() { - Jedis jedis = new Jedis("192.168.108.129", 6379); + Jedis jedis = new Jedis(Const.IP, Const.PORT); for (int i = 0; i < 1000; i++) { jedis.pfadd("uv", "user" + i); // 出现误差 @@ -31,7 +32,7 @@ public void test1() { */ @Test public void test2() { - Jedis jedis = new Jedis("192.168.108.129", 6379); + Jedis jedis = new Jedis(Const.IP, Const.PORT); for (int i = 0; i < 10000; i++) { jedis.pfadd("uv", "user" + i); } diff --git a/distributed/lock/jedis/src/main/java/cn/cunchang/lock/LockDome.java b/distributed/lock/jedis/src/main/java/cn/cunchang/lock/LockDome.java new file mode 100644 index 00000000..970127be --- /dev/null +++ b/distributed/lock/jedis/src/main/java/cn/cunchang/lock/LockDome.java @@ -0,0 +1,238 @@ +package cn.cunchang.lock; + + +import redis.clients.jedis.Jedis; +import redis.clients.jedis.Transaction; + +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.UUID; + +/** + * 分布式锁 + * + * @author cunchang + */ +public class LockDome { + + + /** + * 问题:死锁 + * 解决:需要设置过期时间,自动释放锁 + * + * @param jedis Redis客户端 + * @param lockKey set指令的key + */ + public static void wrongLock1(Jedis jedis, String lockKey) { + Long result = jedis.setnx(lockKey, "lockValue"); + // 1 0 + if (result == 0L) { + throw new RuntimeException("操作太频繁,等一分钟在操作"); + } + try { + // wrong: 若在程序死循环,无法释放锁,将发生死锁 + // do something + } finally { + jedis.del(lockKey); + jedis.close(); + } + } + + /** + * 处理wrongLock1的问题 + *

+ * 问题:非原子操作,死锁 + * 解决: + * - 原生set + * - lua + * - 事务 + * + * @param jedis Redis客户端 + * @param lockKey set指令的key + * @param expireTime 超期时间 + */ + public static void wrongLock2(Jedis jedis, String lockKey, int expireTime) { + Long result = jedis.setnx(lockKey, "lockValue"); + // 1 0 + if (result == 0L) { + throw new RuntimeException("操作太频繁,等一分钟在操作"); + } + try { + // wrong: setnx+expire非原子操作(若程序在这里突然所属进程崩溃、机器宕机等,无法释放锁,将发生死锁) + jedis.expire(lockKey, expireTime); + // do something + } finally { + jedis.del(lockKey); + jedis.close(); + } + } + + //设置锁的lua脚本 + static String SETNX_EXPIRE_SCRIPT = "if redis.call('setnx', KEYS[1], KEYS[2]) == 1 then\n" + + "return redis.call('expire', KEYS[1], KEYS[3]);\n" + + "end\n" + + "return nil;"; + + static String RELEASE_SCRIPT = "if redis.call('get', KEYS[1]) == ARGV[1] then\n" + + " return redis.call('del', KEYS[1]);\n" + + " else return 0 end"; + + static String SETNX_EXPIRE_SCRIPT2 = + "if redis.call('setnx', KEYS[1], KEYS[2]) == 1 then return redis.call('expire', KEYS[1], KEYS[3]); end return nil;"; + + static String RELEASE_SCRIPT2 = + "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]); else return 0 end"; + + + /** + * 问题:锁错误释放 + * 解决:value设置随机数,获取lockkey对应的value,判断一下value是否相等 + * + * @param jedis Redis客户端 + * @param lockKey set指令的key + * @param expireTime 超期时间 + */ + public static void wrongLock3_1(Jedis jedis, String lockKey, int expireTime) { + Object result = jedis.set(lockKey, "lockValue", "NX", "EX", expireTime); + // OK null + if (Objects.isNull(result)) { + throw new RuntimeException("操作太频繁,等一分钟在操作"); + } + try { + // do something + // wrong : + // do something 执行超过锁过期时间,锁过期释放 + // do something 执行完毕后,del key,导致锁错误释放 + } finally { + jedis.del(lockKey); + jedis.close(); + } + } + + /** + * 问题:锁错误释放 + * 解决:value设置随机数,获取lockkey对应的value,判断一下value是否相等 + * + * @param jedis Redis客户端 + * @param lockKey set指令的key + * @param expireTime 超期时间 + */ + public static void wrongLock3_2(Jedis jedis, String lockKey, int expireTime) { + String SETNX_EXPIRE_SCRIPT = "if redis.call('setnx', KEYS[1], KEYS[2]) == 1 then\n" + + "return redis.call('expire', KEYS[1], KEYS[3]);\n" + + "end\n" + + "return nil;"; + + Object result = jedis.eval(SETNX_EXPIRE_SCRIPT, 3, lockKey, "lockValue", Integer.toString(expireTime)); + // 1 null + if (Objects.isNull(result)) { + throw new RuntimeException("操作太频繁,等一分钟在操作"); + } + try { + // do something + // wrong : + // do something 执行超过锁过期时间,锁过期释放 + // do something 执行完毕后,del key,导致锁错误释放 + } finally { + jedis.del(lockKey); + jedis.close(); + } + } + + /** + * 问题:client1超时后锁过期释放,client2获取锁后,client1执行完成,将client2的锁释放,导致锁错误释放 + * 解决:value设置随机数 + * + * @param jedis Redis客户端 + * @param lockKey set指令的key + * @param expireTime 超期时间 + */ + public static void wrongLock4(Jedis jedis, String lockKey, int expireTime) { + String randomId = UUID.randomUUID().toString(); + Object result = jedis.set(lockKey, randomId, "NX", "EX", expireTime); + // OK null + if (Objects.isNull(result)) { + throw new RuntimeException("操作太频繁,等一分钟在操作"); + } + try { + // do something + } finally { + // 判断加锁与解锁是不是同一个客户端,防止误解锁 + if (randomId.equals(jedis.get(lockKey))) { + // wrong :无法保证原子性 + jedis.del(lockKey); + } + jedis.close(); + } + } + + /** + * 问题:equals和del不是原子操作 + * 解决: + * - lua + * - 事务 + * + * @param jedis Redis客户端 + * @param lockKey set指令的key + * @param expireTime 超期时间 + */ + public static void lock5_1(Jedis jedis, String lockKey, int expireTime) { + String randomId = UUID.randomUUID().toString(); + Object result = jedis.set(lockKey, randomId, "NX", "EX", expireTime); + // OK null + if (Objects.isNull(result)) { + throw new RuntimeException("操作太频繁,等一分钟在操作"); + } + try { + // do something + } finally { + // 判断加锁与解锁是不是同一个客户端,防止误解锁 + jedis.eval(RELEASE_SCRIPT, Collections.singletonList(lockKey), Collections.singletonList(randomId)); + jedis.close(); + } + } + + /** + * 问题:equals和del不是原子操作 + * 解决: + * - lua + * - 事务 + * + * @param jedis Redis客户端 + * @param lockKey set指令的key + * @param expireTime 超期时间 + */ + public static void lock5_2(Jedis jedis, String lockKey, int expireTime) { + String randomId = UUID.randomUUID().toString(); + Object result = jedis.set(lockKey, randomId, "NX", "EX", expireTime); + // OK null + if (Objects.isNull(result)) { + throw new RuntimeException("操作太频繁,等一分钟在操作"); + } + try { + // do something + } finally { + // 判断加锁与解锁是不是同一个客户端,防止误解锁 + // 通过watch+事务,实现乐观锁,尝试删除key;删除失败说明自己的锁已经过期 + while (true) { + // watch监控key + jedis.watch(lockKey); + String redisLockValue = jedis.get(lockKey); + if (randomId.equals(redisLockValue)) { + Transaction tx = jedis.multi(); + tx.del(lockKey); + // 事务发现watch的key对应value发生变化,del会执行失败,就不会释放别人的锁了 + List execResult = tx.exec(); + if (execResult == null) { + continue; + } + } + jedis.unwatch(); + break; + } + jedis.close(); + } + } + +} \ No newline at end of file diff --git a/distributed/lock/jedis/src/main/java/cn/cunchang/lock/RedisWithReentrantLock.java b/distributed/lock/jedis/src/main/java/cn/cunchang/lock/RedisWithReentrantLock.java new file mode 100644 index 00000000..619ef64a --- /dev/null +++ b/distributed/lock/jedis/src/main/java/cn/cunchang/lock/RedisWithReentrantLock.java @@ -0,0 +1,81 @@ +package cn.cunchang.lock; + +import cn.cunchang.JedisUtil; +import redis.clients.jedis.Jedis; +import java.util.HashMap; +import java.util.Map; + +//redis可重入锁,java实现 +public class RedisWithReentrantLock { + /* + *ThreadLocal是一个关于创建线程局部变量的类。 + *通常情况下,我们创建的变量是可以被任何一个线程访问并修改的。 + * 而使用ThreadLocal创建的变量只能被当前线程访问,其他线程则无法访问和修改。 + */ + private ThreadLocal> lockers = new ThreadLocal<>(); + + private Jedis jedis; + + public RedisWithReentrantLock(Jedis jedis) { + this.jedis = jedis; + } + + private boolean _lock(String key){ + //使用 set ket value ex number nx 指令上锁(“给萝卜占个坑”) + return jedis.set(key , "","nx" , "ex" ,5L) != null; + } + + private void _unlock(String key){ + jedis.del(key); + } + + private Map currentLockers(){ + Map refs = lockers.get(); + if (refs != null){ + return refs; + } + lockers.set(new HashMap<>()); + return lockers.get(); + } + + public boolean lock(String key ){ + Map refs = currentLockers(); + Integer refCnt = refs.get(key); + if (refCnt != null){ //如果加过锁 + refs.put(key , refCnt + 1); //那就在threadlocal再加一把锁 + return true; + } + boolean ok = this._lock(key); //这里是没加过锁,那就进行加锁 + if (!ok){ + return false; //加锁不成功,返回false + } + refs.put(key , 1 ); //加锁成功,则在threalocal里面加上加锁信息 + return true; + } + + public boolean unlock(String key){ + Map refs = currentLockers(); + Integer refCnt = refs.get(key); + if (refCnt == null){ //如果没有加锁的对象,那就不需要解锁 + return false; + } + refCnt -= 1; //如果有加锁的对象,那就去掉一层锁 + if (refCnt > 0 ){ + refs.put(key , refCnt); //更新threadlocal对象信息 + }else { //如果刚才减锁的对象只有一层锁,减一之后就没有锁了,那么就把threalocal里面的对象移除 + refs.remove(key); + this._unlock(key); + } + return true; + } + + public static void main(String[] args) { + Jedis jedis = JedisUtil.getJedis(); + RedisWithReentrantLock redis = new RedisWithReentrantLock(jedis); + System.out.println(redis.lock("codehole")); + System.out.println(redis.lock("codehole")); + System.out.println(redis.unlock("codehole")); + System.out.println(redis.unlock("codehole")); + } +} + diff --git a/distributed/lock/jedis/src/main/java/cn/cunchang/lock/real/Client.java b/distributed/lock/jedis/src/main/java/cn/cunchang/lock/real/Client.java new file mode 100644 index 00000000..9f5b324c --- /dev/null +++ b/distributed/lock/jedis/src/main/java/cn/cunchang/lock/real/Client.java @@ -0,0 +1,23 @@ +package cn.cunchang.lock.real; + +import cn.cunchang.JedisUtil; + +/** + * @author cunchang + */ +public class Client { + + public static void main(String[] args) { + // 校验参数或者干了什么 + LockUtil.wrongLock3_2(JedisUtil.getJedis(),"stock_lock_key",100, new CodeBlock() { + @Override + public void operatingSharedResource() { + // 查库存 + // 库存-1 + // 更新库存 + } + }); + // 封装结果或者干了什么 + } + +} diff --git a/distributed/lock/jedis/src/main/java/cn/cunchang/lock/real/CodeBlock.java b/distributed/lock/jedis/src/main/java/cn/cunchang/lock/real/CodeBlock.java new file mode 100644 index 00000000..0cd4a235 --- /dev/null +++ b/distributed/lock/jedis/src/main/java/cn/cunchang/lock/real/CodeBlock.java @@ -0,0 +1,15 @@ +package cn.cunchang.lock.real; + +/** + * 代码块 + * + * @author cunchang + */ +public interface CodeBlock { + + /** + * 操作共享资源 + */ + void operatingSharedResource(); + +} diff --git a/distributed/lock/jedis/src/main/java/cn/cunchang/lock/real/LockUtil.java b/distributed/lock/jedis/src/main/java/cn/cunchang/lock/real/LockUtil.java new file mode 100644 index 00000000..bdc3629d --- /dev/null +++ b/distributed/lock/jedis/src/main/java/cn/cunchang/lock/real/LockUtil.java @@ -0,0 +1,128 @@ +package cn.cunchang.lock.real; + +import redis.clients.jedis.Jedis; + +import java.util.Objects; + +public class LockUtil { + + + /** + * 问题:死锁 + * 解决:需要设置过期时间,自动释放锁 + * + * @param jedis Redis客户端 + * @param lockKey set指令的key + * @param codeBlock 代码块 + */ + public static void wrongLock1(Jedis jedis, String lockKey, CodeBlock codeBlock) { + Long result = jedis.setnx(lockKey, "lockValue"); + if (result == 0L) { + throw new RuntimeException("操作太频繁,等一分钟在操作"); + } + try { + codeBlock.operatingSharedResource(); + } finally { + jedis.del(lockKey); + jedis.close(); + } + } + + /** + * 处理wrongLock1的问题 + *

+ * 问题:非原子操作,死锁 + * 解决: + * - 原生set + * - lua + * - 事务 + * + * @param jedis Redis客户端 + * @param lockKey set指令的key + * @param expireTime 超期时间 + */ + public static void wrongLock2(Jedis jedis, String lockKey, int expireTime, CodeBlock codeBlock) { + Long result = jedis.setnx(lockKey, "lockValue"); + if (result == 0L) { + throw new RuntimeException("操作太频繁,等一分钟在操作"); + } + try { + // wrong: setnx+expire非原子操作(若程序在这里突然所属进程崩溃、机器宕机等,无法释放锁,将发生死锁) + jedis.expire(lockKey, expireTime); + codeBlock.operatingSharedResource(); + } finally { + jedis.del(lockKey); + jedis.close(); + } + } + + //设置锁的lua脚本 + static String SETNX_EXPIRE_SCRIPT = "if redis.call('setnx', KEYS[1], KEYS[2]) == 1 then\n" + + "return redis.call('expire', KEYS[1], KEYS[3]);\n" + + "end\n" + + "return nil;"; + + static String RELEASE_SCRIPT = "if redis.call('get', KEYS[1]) == ARGV[1] then\n" + + " return redis.call('del', KEYS[1]);\n" + + " else return 0 end"; + + static String SETNX_EXPIRE_SCRIPT2 = + "if redis.call('setnx', KEYS[1], KEYS[2]) == 1 then return redis.call('expire', KEYS[1], KEYS[3]); end return nil;"; + + static String RELEASE_SCRIPT2 = + "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]); else return 0 end"; + + + /** + * 问题:锁错误释放 + * 解决:value设置随机数,获取lockkey对应的value,判断一下value是否相等 + * + * @param jedis Redis客户端 + * @param lockKey set指令的key + * @param expireTime 超期时间 秒 + */ + public static void wrongLock3_1(Jedis jedis, String lockKey, int expireTime, CodeBlock codeBlock) { + Object result = jedis.set(lockKey, "lockValue", "NX", "EX", expireTime); + + if (Objects.isNull(result)) { + throw new RuntimeException("操作太频繁,等一分钟在操作"); + } + try { + // do something + // wrong : + // do something 执行超过锁过期时间,锁过期释放 + // do something 执行完毕后,del key,导致锁错误释放 + codeBlock.operatingSharedResource(); + } finally { + jedis.del(lockKey); + jedis.close(); + } + } + + /** + * 问题:锁错误释放 + * 解决:value设置随机数,获取lockkey对应的value,判断一下value是否相等 + * + * @param jedis Redis客户端 + * @param lockKey set指令的key + * @param expireTime 超期时间 + */ + public static void wrongLock3_2(Jedis jedis, String lockKey, int expireTime, CodeBlock codeBlock) { + Object result = jedis.eval(SETNX_EXPIRE_SCRIPT, 3, lockKey, "lockValue", Integer.toString(expireTime)); + + if (Objects.isNull(result)) { + throw new RuntimeException("操作太频繁,等一分钟在操作"); + } + try { + // do something + // wrong : + // do something 执行超过锁过期时间,锁过期释放 + // do something 执行完毕后,del key,导致锁错误释放 + codeBlock.operatingSharedResource(); + } finally { + jedis.del(lockKey); + jedis.close(); + } + } + +} diff --git a/database/redis/src/main/java/cn/lastwhisper/redis/partition/PartitionTest.java b/distributed/lock/jedis/src/main/java/cn/cunchang/partition/PartitionTest.java similarity index 98% rename from database/redis/src/main/java/cn/lastwhisper/redis/partition/PartitionTest.java rename to distributed/lock/jedis/src/main/java/cn/cunchang/partition/PartitionTest.java index cb80e748..e9e304f9 100644 --- a/database/redis/src/main/java/cn/lastwhisper/redis/partition/PartitionTest.java +++ b/distributed/lock/jedis/src/main/java/cn/cunchang/partition/PartitionTest.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.redis.partition; +package cn.cunchang.partition; import java.util.ArrayList; import java.util.LinkedHashMap; @@ -7,7 +7,7 @@ /** * hash分区 迁移率 - * @author lastwhisper + * @author cunchang */ public class PartitionTest { private final static Object value = new Object(); diff --git a/database/redis/src/main/java/cn/lastwhisper/redis/pipeline/PipelineTest.java b/distributed/lock/jedis/src/main/java/cn/cunchang/pipeline/PipelineTest.java similarity index 95% rename from database/redis/src/main/java/cn/lastwhisper/redis/pipeline/PipelineTest.java rename to distributed/lock/jedis/src/main/java/cn/cunchang/pipeline/PipelineTest.java index fd6cd57a..33515f51 100644 --- a/database/redis/src/main/java/cn/lastwhisper/redis/pipeline/PipelineTest.java +++ b/distributed/lock/jedis/src/main/java/cn/cunchang/pipeline/PipelineTest.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.redis.pipeline; +package cn.cunchang.pipeline; import org.junit.Test; import redis.clients.jedis.Jedis; @@ -6,7 +6,7 @@ /** * 流水线 - * @author lastwhisper + * @author cunchang */ public class PipelineTest { //没有使用pipieline的情况下 diff --git a/database/redis/src/main/java/cn/lastwhisper/redis/publishersubscriber/PublisherTest.java b/distributed/lock/jedis/src/main/java/cn/cunchang/publishersubscriber/PublisherTest.java similarity index 82% rename from database/redis/src/main/java/cn/lastwhisper/redis/publishersubscriber/PublisherTest.java rename to distributed/lock/jedis/src/main/java/cn/cunchang/publishersubscriber/PublisherTest.java index c25f9321..97812bfc 100644 --- a/database/redis/src/main/java/cn/lastwhisper/redis/publishersubscriber/PublisherTest.java +++ b/distributed/lock/jedis/src/main/java/cn/cunchang/publishersubscriber/PublisherTest.java @@ -1,10 +1,10 @@ -package cn.lastwhisper.redis.publishersubscriber; +package cn.cunchang.publishersubscriber; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPubSub; /** - * @author lastwhisper + * @author cunchang */ public class PublisherTest { //发布 diff --git a/database/redis/src/main/java/cn/lastwhisper/redis/publishersubscriber/SubscriberTest.java b/distributed/lock/jedis/src/main/java/cn/cunchang/publishersubscriber/SubscriberTest.java similarity index 87% rename from database/redis/src/main/java/cn/lastwhisper/redis/publishersubscriber/SubscriberTest.java rename to distributed/lock/jedis/src/main/java/cn/cunchang/publishersubscriber/SubscriberTest.java index b76632ab..41dc69ce 100644 --- a/database/redis/src/main/java/cn/lastwhisper/redis/publishersubscriber/SubscriberTest.java +++ b/distributed/lock/jedis/src/main/java/cn/cunchang/publishersubscriber/SubscriberTest.java @@ -1,10 +1,10 @@ -package cn.lastwhisper.redis.publishersubscriber; +package cn.cunchang.publishersubscriber; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPubSub; /** - * @author lastwhisper + * @author cunchang */ public class SubscriberTest { //订阅 diff --git a/database/redis/src/main/java/cn/lastwhisper/redis/sentinel/SentinelTest.java b/distributed/lock/jedis/src/main/java/cn/cunchang/sentinel/SentinelTest.java similarity index 96% rename from database/redis/src/main/java/cn/lastwhisper/redis/sentinel/SentinelTest.java rename to distributed/lock/jedis/src/main/java/cn/cunchang/sentinel/SentinelTest.java index f4dd2131..c0efbcb9 100644 --- a/database/redis/src/main/java/cn/lastwhisper/redis/sentinel/SentinelTest.java +++ b/distributed/lock/jedis/src/main/java/cn/cunchang/sentinel/SentinelTest.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.redis.sentinel; +package cn.cunchang.sentinel; import org.junit.Before; import org.junit.Test; @@ -12,7 +12,7 @@ import java.util.concurrent.TimeUnit; /** - * @author lastwhisper + * @author cunchang */ public class SentinelTest { private JedisSentinelPool sentinelPool; diff --git a/database/redis/src/main/java/cn/lastwhisper/redis/transaction/TransactionTest.java b/distributed/lock/jedis/src/main/java/cn/cunchang/transaction/TransactionTest.java similarity index 79% rename from database/redis/src/main/java/cn/lastwhisper/redis/transaction/TransactionTest.java rename to distributed/lock/jedis/src/main/java/cn/cunchang/transaction/TransactionTest.java index 8eb3fde8..f3a5f6ed 100644 --- a/database/redis/src/main/java/cn/lastwhisper/redis/transaction/TransactionTest.java +++ b/distributed/lock/jedis/src/main/java/cn/cunchang/transaction/TransactionTest.java @@ -1,5 +1,6 @@ -package cn.lastwhisper.redis.transaction; +package cn.cunchang.transaction; +import cn.cunchang.JedisUtil; import redis.clients.jedis.Jedis; import redis.clients.jedis.Transaction; @@ -7,13 +8,14 @@ /** * redis事务测试 - * @author lastwhisper + * @author cunchang */ public class TransactionTest { + public static void main(String[] args) { - Jedis jedis = new Jedis("192.168.108.131", 7000); + Jedis jedis = JedisUtil.getJedis(); String userId = "abc"; - String key = keyFor(userId); + String key = buildKey(userId); jedis.setnx(key, String.valueOf(5)); // setnx 做初始化 System.out.println(doubleAccount(jedis, userId)); jedis.close(); @@ -23,7 +25,7 @@ public static void main(String[] args) { * */ public static int doubleAccount(Jedis jedis, String userId) { - String key = keyFor(userId); + String key = buildKey(userId); while (true) { jedis.watch(key); int value = Integer.parseInt(jedis.get(key)); @@ -38,7 +40,7 @@ public static int doubleAccount(Jedis jedis, String userId) { return Integer.parseInt(jedis.get(key)); // 重新获取余额 } - public static String keyFor(String userId) { + public static String buildKey(String userId) { return String.format("account_{}", userId); } } diff --git a/distributed/lock/jedis/src/main/resources/Setnx_Expire_Srcipt.lua b/distributed/lock/jedis/src/main/resources/Setnx_Expire_Srcipt.lua new file mode 100644 index 00000000..d6dbab39 --- /dev/null +++ b/distributed/lock/jedis/src/main/resources/Setnx_Expire_Srcipt.lua @@ -0,0 +1,4 @@ +if redis.call('setnx', KEYS[1], KEYS[2]) == 1 + then return redis.call('expire', KEYS[1], KEYS[3]); +end + return nil; \ No newline at end of file diff --git a/distributed/lock/redisson/pom.xml b/distributed/lock/redisson/pom.xml new file mode 100644 index 00000000..19f53d6e --- /dev/null +++ b/distributed/lock/redisson/pom.xml @@ -0,0 +1,40 @@ + + + 4.0.0 + + cn.cunchang + redisson + 1.0-SNAPSHOT + redisson + + + + + + org.redisson + redisson + 3.13.0 + + + + org.slf4j + slf4j-simple + 1.7.25 + + + + com.alibaba + fastjson + 1.2.56 + + + + junit + junit + 4.12 + + + + \ No newline at end of file diff --git a/distributed/lock/redisson/src/main/java/cn/cunchang/RedissonUtil.java b/distributed/lock/redisson/src/main/java/cn/cunchang/RedissonUtil.java new file mode 100644 index 00000000..f8e66a8a --- /dev/null +++ b/distributed/lock/redisson/src/main/java/cn/cunchang/RedissonUtil.java @@ -0,0 +1,37 @@ +package cn.cunchang; + +import org.redisson.Redisson; +import org.redisson.api.RedissonClient; +import org.redisson.client.codec.Codec; +import org.redisson.config.Config; + +public class RedissonUtil { + + public static RedissonClient getRedissonClient() { + Config config = new Config(); + try { + config.setCodec((Codec) Class.forName("org.redisson.codec.JsonJacksonCodec").newInstance()); + } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) { + e.printStackTrace(); + } + config.useSingleServer().setAddress("redis://127.0.0.1:6379"); + + RedissonClient redisson = Redisson.create(config); + return redisson; + } + + public static RedissonClient getRedissonClient(long watchDogTime) { + Config config = new Config(); + config.setLockWatchdogTimeout(watchDogTime); +// try { +// config.setCodec((Codec) Class.forName("org.redisson.codec.JsonJacksonCodec").newInstance()); +// } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) { +// e.printStackTrace(); +// } + config.useSingleServer().setAddress("redis://127.0.0.1:6379"); + + RedissonClient redisson = Redisson.create(config); + return redisson; + } + +} diff --git a/distributed/lock/redisson/src/main/java/cn/cunchang/lock/DemoMain.java b/distributed/lock/redisson/src/main/java/cn/cunchang/lock/DemoMain.java new file mode 100644 index 00000000..6e1ff5b9 --- /dev/null +++ b/distributed/lock/redisson/src/main/java/cn/cunchang/lock/DemoMain.java @@ -0,0 +1,103 @@ +package cn.cunchang.lock; + +import cn.cunchang.RedissonUtil; +import org.redisson.api.RLock; +import org.redisson.api.RedissonClient; + +import java.util.concurrent.CountDownLatch; + +public class DemoMain { + + private volatile static boolean flag = false; + + public static void main(String[] args) throws Exception { + + RedissonClient redisson = RedissonUtil.getRedissonClient(); + + CountDownLatch countDownLatch = new CountDownLatch(3); + + Thread thread1 = new Thread(new Runnable() { + @Override + public void run() { + RLock lock = redisson.getLock("myLock"); + try { + lock.lock(); + System.out.println("t1 lock!!!+id:" + Thread.currentThread().getId()); + + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + while (flag) { + int i = 1; + } + System.out.println("t1 debug!!!+id:" + Thread.currentThread().getId()); + } finally { + lock.unlock(); + countDownLatch.countDown(); + } + } + }); + + Thread thread2 = new Thread(new Runnable() { + @Override + public void run() { + RLock lock = redisson.getLock("myLock"); + try { + lock.lock(); + System.out.println("t2 lock!!!+id:" + Thread.currentThread().getId()); + + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + while (flag) { + int i = 1; + } + System.out.println("t2 debug!!!+id:" + Thread.currentThread().getId()); + } finally { + lock.unlock(); + countDownLatch.countDown(); + } + } + }); + + Thread thread3 = new Thread(new Runnable() { + @Override + public void run() { + RLock lock = redisson.getLock("myLock"); + try { + lock.lock(); + System.out.println("t2 lock!!!+id:" + Thread.currentThread().getId()); + + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + while (flag) { + int i = 1; + } + System.out.println("t2 debug!!!+id:" + Thread.currentThread().getId()); + } finally { + lock.unlock(); + countDownLatch.countDown(); + } + } + }); + + + thread1.start(); + thread2.start(); + thread3.start(); + + countDownLatch.await(); + redisson.shutdown(); + } + +} \ No newline at end of file diff --git a/distributed/lock/redisson/src/main/java/cn/cunchang/lock/LockDemo.java b/distributed/lock/redisson/src/main/java/cn/cunchang/lock/LockDemo.java new file mode 100644 index 00000000..b15f969d --- /dev/null +++ b/distributed/lock/redisson/src/main/java/cn/cunchang/lock/LockDemo.java @@ -0,0 +1,46 @@ +package cn.cunchang.lock; + +import cn.cunchang.RedissonUtil; +import org.redisson.api.RBucket; +import org.redisson.api.RLock; +import org.redisson.api.RedissonClient; + +public class LockDemo { + + static long doSomethingTime = 20; + /** + * + * 每隔 leaseRenewalTime/3 就会进行续租,每次续租 leaseRenewalTime 毫秒 + */ + static long leaseRenewalTime = 9 * 1000; + + /** + * lock一直获取锁,直到能获取 + * + */ + public static void main(String[] args) { + RedissonClient redisson = RedissonUtil.getRedissonClient(leaseRenewalTime); + RLock lock = redisson.getLock("myLock"); + RBucket rBucket = redisson.getBucket("myLock"); + try { + lock.lock(); + long ttl = rBucket.remainTimeToLive(); + System.out.println("lock | lockkey:myLock,ttl:" + ttl); + for (int i = 1; i <= doSomethingTime; i++) { + Thread.sleep(995L); + ttl = rBucket.remainTimeToLive(); + System.out.println("do something " + i + " 秒 | lockkey:myLock,ttl:" + ttl); + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + if (lock.isHeldByCurrentThread() && lock.isLocked()) { + lock.unlock(); + long ttl = rBucket.remainTimeToLive(); + System.out.println("unlock lockkey:myLock,ttl:" + ttl); + } + redisson.shutdown(); + } + } + +} diff --git a/distributed/lock/redisson/src/main/java/cn/cunchang/lock/MultiLockDemo.java b/distributed/lock/redisson/src/main/java/cn/cunchang/lock/MultiLockDemo.java new file mode 100644 index 00000000..85ef4c83 --- /dev/null +++ b/distributed/lock/redisson/src/main/java/cn/cunchang/lock/MultiLockDemo.java @@ -0,0 +1,53 @@ +package cn.cunchang.lock; + +import cn.cunchang.RedissonUtil; +import org.redisson.RedissonMultiLock; +import org.redisson.api.RLock; +import org.redisson.api.RedissonClient; + +public class MultiLockDemo { + + static long doSomethingTime = 20; + + static long watchDogTime = 10 * 1000; + + /** + * 不设置过期时间有watch dog续租 + * + * @param args + */ + public static void main(String[] args) { + RedissonClient redissonInstance1 = RedissonUtil.getRedissonClient(watchDogTime); + RedissonClient redissonInstance2 = RedissonUtil.getRedissonClient(watchDogTime); + RedissonClient redissonInstance3 = RedissonUtil.getRedissonClient(watchDogTime); + + RLock lock1 = redissonInstance1.getLock("lock1"); + RLock lock2 = redissonInstance2.getLock("lock2"); + RLock lock3 = redissonInstance3.getLock("lock3"); + + RedissonMultiLock lock = new RedissonMultiLock(lock1, lock2, lock3); + try { + // 同时加锁:lock1 lock2 lock3 + // 所有的锁都上锁成功才算成功。 + lock.lock(); +// rLock.lock(10, TimeUnit.SECONDS); + System.out.println("lock -->lock1 lock2 lock3"); + for (int i = 1; i <= doSomethingTime; i++) { + Thread.sleep(1000L); + System.out.println("do something " + i + " 秒..."); + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + // lock.isHeldByCurrentThread() =》java.lang.UnsupportedOperationException + // lock.isLocked() =》java.lang.UnsupportedOperationException + System.out.println("unlock -->lock1 lock2 lock3"); + lock.unlock(); + redissonInstance1.shutdown(); + redissonInstance2.shutdown(); + redissonInstance3.shutdown(); + } + + } + +} diff --git a/distributed/lock/redisson/src/main/java/cn/cunchang/lock/RedLockDemo.java b/distributed/lock/redisson/src/main/java/cn/cunchang/lock/RedLockDemo.java new file mode 100644 index 00000000..57a592ca --- /dev/null +++ b/distributed/lock/redisson/src/main/java/cn/cunchang/lock/RedLockDemo.java @@ -0,0 +1,95 @@ +package cn.cunchang.lock; + +import cn.cunchang.RedissonUtil; +import org.redisson.RedissonRedLock; +import org.redisson.api.RBucket; +import org.redisson.api.RLock; +import org.redisson.api.RedissonClient; + +public class RedLockDemo { + + static long doSomethingTime = 10; + + static long watchDogTime = 9 * 1000; + + /** + * 不设置过期时间有watch dog续租 + * + * @param args + */ + public static void main(String[] args) { + // 5个完全互相独立,不存在主从复制或者其他集群协调机制的 Redis 实例 + RedissonClient redissonInstance1 = RedissonUtil.getRedissonClient(watchDogTime); + RedissonClient redissonInstance2 = RedissonUtil.getRedissonClient(watchDogTime); + RedissonClient redissonInstance3 = RedissonUtil.getRedissonClient(watchDogTime); + RedissonClient redissonInstance4 = RedissonUtil.getRedissonClient(watchDogTime); + RedissonClient redissonInstance5 = RedissonUtil.getRedissonClient(watchDogTime); + + RLock lock1 = redissonInstance1.getLock("lock1"); + RLock lock2 = redissonInstance2.getLock("lock2"); + RLock lock3 = redissonInstance3.getLock("lock3"); + RLock lock4 = redissonInstance4.getLock("lock4"); + RLock lock5 = redissonInstance5.getLock("lock5"); + + RBucket rBucket1 = redissonInstance1.getBucket("lock1"); + RBucket rBucket2 = redissonInstance1.getBucket("lock2"); + RBucket rBucket3 = redissonInstance1.getBucket("lock3"); + RBucket rBucket4 = redissonInstance1.getBucket("lock4"); + RBucket rBucket5 = redissonInstance1.getBucket("lock5"); + + RedissonRedLock lock = new RedissonRedLock(lock1, lock2, lock3, lock4, lock5); + try { + // 同时加锁:lock1, lock2, lock3, lock4, lock5 + // 红锁在(N/2 +1)个节点上加锁成功就算成功。 + System.out.println("pre lock -->" + + "\tlock1,ttl:" + rBucket1.remainTimeToLive() + + "\tlock2,ttl:" + rBucket2.remainTimeToLive() + + "\tlock3,ttl:" + rBucket3.remainTimeToLive() + + "\tlock4,ttl:" + rBucket4.remainTimeToLive() + + "\tlock5,ttl:" + rBucket5.remainTimeToLive() + ); + boolean falg = lock.tryLock(); + if (!falg) { + System.out.println("lock fail"); + return; + } + System.out.println("lock success -->" + + "\tlock1,ttl:" + rBucket1.remainTimeToLive() + + "\tlock2,ttl:" + rBucket2.remainTimeToLive() + + "\tlock3,ttl:" + rBucket3.remainTimeToLive() + + "\tlock4,ttl:" + rBucket4.remainTimeToLive() + + "\tlock5,ttl:" + rBucket5.remainTimeToLive() + ); + for (int i = 1; i <= doSomethingTime; i++) { + Thread.sleep(995L); + System.out.println("do something " + i + " 秒 | " + + "\tlock1,ttl:" + rBucket1.remainTimeToLive() + + "\tlock2,ttl:" + rBucket2.remainTimeToLive() + + "\tlock3,ttl:" + rBucket3.remainTimeToLive() + + "\tlock4,ttl:" + rBucket4.remainTimeToLive() + + "\tlock5,ttl:" + rBucket5.remainTimeToLive() + ); + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + // lock.isHeldByCurrentThread() =》java.lang.UnsupportedOperationException + // lock.isLocked() =》java.lang.UnsupportedOperationException + System.out.println("unlock -->" + + "\tlock1,ttl:" + rBucket1.remainTimeToLive() + + "\tlock2,ttl:" + rBucket2.remainTimeToLive() + + "\tlock3,ttl:" + rBucket3.remainTimeToLive() + + "\tlock4,ttl:" + rBucket4.remainTimeToLive() + + "\tlock5,ttl:" + rBucket5.remainTimeToLive() + ); + lock.unlock(); + redissonInstance1.shutdown(); + redissonInstance2.shutdown(); + redissonInstance3.shutdown(); + redissonInstance4.shutdown(); + redissonInstance5.shutdown(); + } + } + + +} diff --git a/distributed/lock/redisson/src/main/java/cn/cunchang/lock/TryLockDemo.java b/distributed/lock/redisson/src/main/java/cn/cunchang/lock/TryLockDemo.java new file mode 100644 index 00000000..a6a86fa7 --- /dev/null +++ b/distributed/lock/redisson/src/main/java/cn/cunchang/lock/TryLockDemo.java @@ -0,0 +1,56 @@ +package cn.cunchang.lock; + +import cn.cunchang.RedissonUtil; +import org.redisson.api.RBucket; +import org.redisson.api.RLock; +import org.redisson.api.RedissonClient; + +import java.util.concurrent.TimeUnit; + +public class TryLockDemo { + + static long doSomethingTime = 300L; + // 锁租约时间 + static long leaseTime = 10L; + + /** + * tryLock 尝试获取锁 + */ + public static void main(String[] args) { + RedissonClient redisson = RedissonUtil.getRedissonClient(); + RLock lock = redisson.getLock("myLock"); + RBucket rBucket = redisson.getBucket("myLock"); + try { + boolean lockFlag = false; + // 无租锁时间,锁会自动续租 + lockFlag = lock.tryLock(); + // 等待0秒,租10秒,锁不会自动续租 +// lockFlag = lock.tryLock(0L, leaseTime, TimeUnit.SECONDS); + if (lockFlag) { + long ttl = rBucket.remainTimeToLive(); + System.out.println("lock | lockkey:myLock,ttl:" + ttl); + for (int i = 1; i <= doSomethingTime; i++) { + Thread.sleep(995L); + ttl = rBucket.remainTimeToLive(); + System.out.println("do something " + i + " 秒 | lockkey:myLock,ttl:" + ttl); + } + } + + } catch (Exception e) { + e.printStackTrace(); + } finally { + if (lock.isHeldByCurrentThread() && lock.isLocked()) { + lock.unlock(); + long ttl = rBucket.remainTimeToLive(); + System.out.println("unlock lockkey:myLock,ttl:" + ttl); + } + redisson.shutdown(); + } +// try { +// Thread.sleep(10000000000L); +// } catch (InterruptedException e) { +// e.printStackTrace(); +// } + } + +} diff --git a/distributed/lock/redisson/src/main/java/cn/cunchang/lock/test/ThreadGcTest.java b/distributed/lock/redisson/src/main/java/cn/cunchang/lock/test/ThreadGcTest.java new file mode 100644 index 00000000..10973cd9 --- /dev/null +++ b/distributed/lock/redisson/src/main/java/cn/cunchang/lock/test/ThreadGcTest.java @@ -0,0 +1,60 @@ +package cn.cunchang.lock.test; + +import cn.cunchang.RedissonUtil; +import org.redisson.api.RBucket; +import org.redisson.api.RLock; +import org.redisson.api.RedissonClient; + +public class ThreadGcTest { + + /** + * 线程不释放锁,线程被回收后,看门狗不续约 + */ + public static void main(String[] args) { + stackSegement(); + + try { + // 等待stackSegement()执行完成 + Thread.sleep(5000L); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + // 回收 new Thread + System.gc(); + System.out.println("回收 new Thread!!!"); + + + try { + Thread.sleep(10000000000L); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + private static void stackSegement() { + Thread thread = new Thread(new Runnable() { + @Override + public void run() { + RedissonClient redisson = RedissonUtil.getRedissonClient(); + RLock lock = redisson.getLock("myLock"); + try { + boolean lockFlag; + // 无租锁时间,锁会自动续租 + lockFlag = lock.tryLock(); + if (lockFlag) { + System.out.println("拿到锁"); + } else { + System.out.println("没拿到锁"); + } + + } catch (Exception e) { + e.printStackTrace(); + } + System.out.println("new thread() run方法执行完毕!!!"); + } + }); + thread.start(); + } + +} diff --git a/distributed/mq/activemq/README.MD b/distributed/mq/activemq/README.MD new file mode 100644 index 00000000..23216b4a --- /dev/null +++ b/distributed/mq/activemq/README.MD @@ -0,0 +1,22 @@ +ActiveMQ是一种开源的基于JMS(Java Message Servie)规范的一种消息中间件的实现。 + +ActiveMQ的两种消息传递类型 + +![img](https://img2018.cnblogs.com/blog/1468250/201907/1468250-20190720132250768-792851447.png) + +(1)点对点传输,即一个生产者对应一个消费者,生产者向broke推送数据,数据存储在broke的一个队列中,当消费者接受该条队列里的数据。 + +(2)基于发布/订阅模式的传输,即根据订阅话题来接收相应数据,一个生产者可向多个消费者推送数据 + + + + + +参考: +https://blog.csdn.net/qq_16313365/article/details/78543166 +https://blog.csdn.net/qq_16313365/article/details/79850055 + +纯demo https://www.cnblogs.com/xiguadadage/p/11217604.html + + + diff --git a/distributed/mq/activemq/activemq-api/pom.xml b/distributed/mq/activemq/activemq-api/pom.xml new file mode 100644 index 00000000..19ea549d --- /dev/null +++ b/distributed/mq/activemq/activemq-api/pom.xml @@ -0,0 +1,23 @@ + + + + cn.lastwhisper + 1.0-SNAPSHOT + activemq-api + 4.0.0 + + + UTF-8 + + + + + org.apache.activemq + activemq-all + 5.11.1 + + + + \ No newline at end of file diff --git a/distributed/mq/activemq/activemq-api/src/main/java/cn/latwhisper/activemq/Constant.java b/distributed/mq/activemq/activemq-api/src/main/java/cn/latwhisper/activemq/Constant.java new file mode 100644 index 00000000..4250df33 --- /dev/null +++ b/distributed/mq/activemq/activemq-api/src/main/java/cn/latwhisper/activemq/Constant.java @@ -0,0 +1,16 @@ +package cn.latwhisper.activemq; + +/** + * + * @author lastwhisper + * @date 2020/2/10 + */ +public interface Constant { + // tcp://IP:61616 + String BROKER_URL = "tcp://192.168.217.101:61616"; + + String QUEUE_NAME="hello-queue"; + + String TOPIC_NAME="hello-topic"; + +} diff --git a/distributed/mq/activemq/activemq-api/src/main/java/cn/latwhisper/activemq/queue/QueueConsumer.java b/distributed/mq/activemq/activemq-api/src/main/java/cn/latwhisper/activemq/queue/QueueConsumer.java new file mode 100644 index 00000000..72560be6 --- /dev/null +++ b/distributed/mq/activemq/activemq-api/src/main/java/cn/latwhisper/activemq/queue/QueueConsumer.java @@ -0,0 +1,123 @@ +package cn.latwhisper.activemq.queue; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.Destination; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.Session; +import javax.jms.TextMessage; + +import cn.latwhisper.activemq.Constant; +import org.apache.activemq.ActiveMQConnectionFactory; + +/** + * 队列消息-接收(消费)者 + *

+ * ClassName: QueueConsumer + *

+ *

+ * Copyright: (c)2017 JASTAR·WANG,All rights reserved. + *

+ * + * @author Jastar·Wang + * @date 2017-11-15 + */ +public class QueueConsumer { + + private ConnectionFactory connectionFactory; + private Connection connection; + private Session session; + private Destination destination; + // 注意这里是消息接收(消费)者 + private MessageConsumer messageConsumer; + + public static void main(String[] args) { + QueueConsumer consumer = new QueueConsumer(); + consumer.doReceive(); + } + + public void doReceive() { + try { + connectionFactory = new ActiveMQConnectionFactory(Constant.BROKER_URL); + connection = connectionFactory.createConnection(); + connection.start(); + session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); + destination = session.createQueue(Constant.QUEUE_NAME); + + /** + * 注意:这里要创建一个消息消费,并指定目的地(即消息源队列) + */ + messageConsumer = session.createConsumer(destination); + + // 方式一:监听接收 + receiveByListener(); + + // 方式二:阻塞接收 + // receiveByManual(); + + /** + * 注意:这里不能再关闭对象了 + */ + // messageConsumer.close(); + } catch (Exception e) { + e.printStackTrace(); + } finally { + /** + * 注意:这里不能再关闭Connection了 + */ + // connection.close(); + } + + } + + /** + * 通过注册监听器的方式接收消息,属于被动监听 + */ + private void receiveByListener() { + try { + messageConsumer.setMessageListener(new MessageListener() { + + @Override + public void onMessage(Message message) { + if (message instanceof TextMessage) { + try { + TextMessage msg = (TextMessage) message; + System.out.println("Received:“" + msg.getText() + + "”"); + // 可以通过此方法反馈消息已收到 + msg.acknowledge(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + } + }); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 通过手动去接收消息的方式,属于主动获取 + */ + private void receiveByManual() { + while (true) { + try { + /** + * 通过receive()方法阻塞接收消息,参数为超时时间(单位:毫秒) + */ + TextMessage message = (TextMessage) messageConsumer + .receive(60000); + if (message != null) { + System.out.println("Received:“" + message.getText() + "”"); + } + } catch (Exception e) { + e.printStackTrace(); + } + + } + } +} diff --git a/distributed/mq/activemq/activemq-api/src/main/java/cn/latwhisper/activemq/queue/QueueProducer.java b/distributed/mq/activemq/activemq-api/src/main/java/cn/latwhisper/activemq/queue/QueueProducer.java new file mode 100644 index 00000000..f32ef229 --- /dev/null +++ b/distributed/mq/activemq/activemq-api/src/main/java/cn/latwhisper/activemq/queue/QueueProducer.java @@ -0,0 +1,143 @@ +package cn.latwhisper.activemq.queue; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; + +import cn.latwhisper.activemq.Constant; +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; + +/** + * 队列消息-发送(生产)者 + *

+ * ClassName: QueueProducer + *

+ *

+ * Copyright: (c)2017 JASTAR·WANG,All rights reserved. + *

+ * + * @author Jastar·Wang + * @date 2017-11-15 + */ +public class QueueProducer { + + // 连接工厂(在AMQ中由ActiveMQConnectionFactory实现) + private ConnectionFactory connectionFactory; + + // 连接对象 + private Connection connection; + + // 会话对象 + private Session session; + + // 消息目的地(对于点对点模型,是Queue对象;对于发布订阅模型,是Topic对象;它们都继承或实现了该接口) + private Destination destination; + + // 消息发送(生产)者 + private MessageProducer messageProducer; + + public static void main(String[] args) { + QueueProducer producer = new QueueProducer(); + producer.doSend(); + } + + public void doSend() { + try { + /** + * 1.创建连接工厂
+ * 构造函数有多个重载,默认连接本地MQ服务器,也可以手动设置用户名、密码、连接地址信息
+ * new ActiveMQConnectionFactory(userName, password, brokerURL) + */ + connectionFactory = new ActiveMQConnectionFactory(Constant.BROKER_URL); + + /** + * 2.创建连接 + */ + connection = connectionFactory.createConnection(); + + /** + * 3.启动连接 + */ + connection.start(); + + /** + * 4.创建会话
+ * param1:是否支持事务,若为true,则会忽略第二个参数,默认为SESSION_TRANSACTED
+ * param2:确认消息模式,若第一个参数为false时,该参数有以下几种状态
+ * -Session.AUTO_ACKNOWLEDGE:自动确认。客户端发送和接收消息不需要做额外的工作,即使接收端发生异常, + * 也会被当作正常发送成功
+ * -Session.CLIENT_ACKNOWLEDGE:客户端确认。客户端接收到消息后,必须调用message. + * acknowledge() 方法给予收到反馈,JMS服务器才会把该消息当做发送成功,并删除
+ * -Session.DUPS_OK_ACKNOWLEDGE:副本确认。一旦接收端应用程序的方法调用从处理消息处返回, + * 会话对象就会确认消息的接收,而且允许重复确认。 + */ + session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); + + /** + * 5.创建(发送)消息目的地,即队列,参数为队列名称 + */ + destination = session.createQueue(Constant.QUEUE_NAME); + + /** + * 6.创建一个消息生产者,并指定目的地 + */ + messageProducer = session.createProducer(destination); + /** + * 其他操作: 设置生产者的生产模式,默认为持久化
+ * 参数有以下两种状态:
+ * -DeliveryMode.NON_PERSISTENT:消息不持久化,消息被消费之后或者超时之后将从队列中删除 + * -DeliveryMode.PERSISTENT:消息会持久化,即使接收端消费消息之后仍然会保存 + */ + messageProducer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + + /** + * 其他操作:设置消息的存活时间(单位:毫秒) + */ + messageProducer.setTimeToLive(60000); + + for (int i = 0; i < 5; i++) { + /** + * 7.创建文本消息
+ * 此外,还有多种类型的消息如对象,字节……都可以通过session.createXXXMessage()方法创建 + */ + TextMessage message = session.createTextMessage("send content:" + + i); + + /** + * 8. 发送 + */ + messageProducer.send(message); + + } + System.out.println("消息发送完成!"); + /** + * 如果有事务操作也可以提交事务 + */ + session.commit(); + + /** + * 9.关闭生产者对象(即使关闭了程序也在运行) + */ + messageProducer.close(); + } catch (Exception e) { + e.printStackTrace(); + } finally { + if (connection != null) { + try { + /** + * 10.关闭连接(将会关闭程序) + */ + connection.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + } +} diff --git a/distributed/mq/activemq/activemq-api/src/main/java/cn/latwhisper/activemq/topic/TopicConsumer.java b/distributed/mq/activemq/activemq-api/src/main/java/cn/latwhisper/activemq/topic/TopicConsumer.java new file mode 100644 index 00000000..9cff46b9 --- /dev/null +++ b/distributed/mq/activemq/activemq-api/src/main/java/cn/latwhisper/activemq/topic/TopicConsumer.java @@ -0,0 +1,111 @@ +package cn.latwhisper.activemq.topic; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.Destination; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.Session; +import javax.jms.TextMessage; + +import cn.latwhisper.activemq.Constant; +import org.apache.activemq.ActiveMQConnectionFactory; + +/** + * 主题消息-接收(消费)者 + *

+ * ClassName: TopicConsumer + *

+ *

+ * Copyright: (c)2017 JASTAR·WANG,All rights reserved. + *

+ * + * @author Jastar·Wang + * @date 2017-11-15 + */ +public class TopicConsumer { + private ConnectionFactory connectionFactory; + private Connection connection; + private Session session; + private Destination destination; + private MessageConsumer messageConsumer; + + public static void main(String[] args) { + /** + * Pub/Sub模型中,消息可被多个对象接收,不同于P2P模型 + */ + TopicConsumer consumer1 = new TopicConsumer(); + consumer1.doReceive(); + TopicConsumer consumer2 = new TopicConsumer(); + consumer2.doReceive(); + } + + public void doReceive() { + try { + connectionFactory = new ActiveMQConnectionFactory(Constant.BROKER_URL); + connection = connectionFactory.createConnection(); + connection.start(); + session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); + destination = session.createTopic(Constant.TOPIC_NAME); + messageConsumer = session.createConsumer(destination); + + // 方式一:监听接收 + receiveByListener(); + + // 方式二:阻塞接收 + // receiveByManual(); + + } catch (Exception e) { + e.printStackTrace(); + } + + } + + /** + * 通过注册监听器的方式接收消息,属于被动监听 + */ + private void receiveByListener() { + try { + messageConsumer.setMessageListener(new MessageListener() { + + @Override + public void onMessage(Message message) { + if (message instanceof TextMessage) { + try { + TextMessage msg = (TextMessage) message; + System.out.println("Received:“" + msg.getText() + + "”"); + } catch (Exception e) { + e.printStackTrace(); + } + } + + } + }); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 通过手动去接收消息的方式,属于主动获取 + */ + private void receiveByManual() { + while (true) { + try { + /** + * 通过receive()方法阻塞接收消息,参数为超时时间(单位:毫秒) + */ + TextMessage message = (TextMessage) messageConsumer + .receive(60000); + if (message != null) { + System.out.println("Received:“" + message.getText() + "”"); + } + } catch (Exception e) { + e.printStackTrace(); + } + + } + } +} diff --git a/distributed/mq/activemq/activemq-api/src/main/java/cn/latwhisper/activemq/topic/TopicProducer.java b/distributed/mq/activemq/activemq-api/src/main/java/cn/latwhisper/activemq/topic/TopicProducer.java new file mode 100644 index 00000000..b054e6d2 --- /dev/null +++ b/distributed/mq/activemq/activemq-api/src/main/java/cn/latwhisper/activemq/topic/TopicProducer.java @@ -0,0 +1,141 @@ +package cn.latwhisper.activemq.topic; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; + +import cn.latwhisper.activemq.Constant; +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; + +/** + * 主题消息-发送(生产)者 + *

+ * ClassName: TopicProducer + *

+ *

+ * Copyright: (c)2017 JASTAR·WANG,All rights reserved. + *

+ * + * @author Jastar·Wang + * @date 2017-11-15 + */ +public class TopicProducer { + + // 连接工厂(在AMQ中由ActiveMQConnectionFactory实现) + private ConnectionFactory connectionFactory; + + // 连接对象 + private Connection connection; + + // 会话对象 + private Session session; + + // 消息目的地(对于点对点模型,是Queue对象;对于发布订阅模型,是Topic对象;它们都继承或实现了该接口) + private Destination destination; + + // 消息发送(生产)者 + private MessageProducer messageProducer; + + public static void main(String[] args) { + TopicProducer producer = new TopicProducer(); + producer.doSend(); + } + + public void doSend() { + try { + /** + * 1.创建连接工厂
+ * 构造函数有多个重载,默认连接本地MQ服务器,也可以手动设置用户名、密码、连接地址信息
+ * new ActiveMQConnectionFactory(userName, password, brokerURL) + */ + connectionFactory = new ActiveMQConnectionFactory(Constant.BROKER_URL); + + /** + * 2.创建连接 + */ + connection = connectionFactory.createConnection(); + + /** + * 3.启动连接 + */ + connection.start(); + + /** + * 4.创建会话
+ * param1:是否支持事务,若为true,则会忽略第二个参数,默认为SESSION_TRANSACTED
+ * param2:确认消息模式,若第一个参数为false时,该参数有以下几种状态
+ * -Session.AUTO_ACKNOWLEDGE:自动确认。客户端发送和接收消息不需要做额外的工作,即使接收端发生异常, + * 也会被当作正常发送成功
+ * -Session.CLIENT_ACKNOWLEDGE:客户端确认。客户端接收到消息后,必须调用message. + * acknowledge() 方法给予收到反馈,JMS服务器才会把该消息当做发送成功,并删除
+ * -Session.DUPS_OK_ACKNOWLEDGE:副本确认。一旦接收端应用程序的方法调用从处理消息处返回, + * 会话对象就会确认消息的接收,而且允许重复确认。 + */ + session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); + + /** + * 5.创建(发送)消息目的地,【点对点模型和发布订阅模型发送的唯一不同就是这里】 + */ + destination = session.createTopic(Constant.TOPIC_NAME); + + /** + * 6.创建一个消息生产者,并指定目的地 + */ + messageProducer = session.createProducer(destination); + /** + * 其他操作: 设置生产者的生产模式,默认为持久化
+ * 参数有以下两种状态:
+ * -DeliveryMode.NON_PERSISTENT:消息不持久化,消息被消费之后或者超时之后将从队列中删除 + * -DeliveryMode.PERSISTENT:消息会持久化,即使接收端消费消息之后仍然会保存 + */ + messageProducer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + + /** + * 其他操作:设置消息的存活时间(单位:毫秒) + */ + messageProducer.setTimeToLive(60000); + + /** + * 7.创建文本消息
+ * 此外,还有多种类型的消息如对象,字节……都可以通过session.createXXXMessage()方法创建 + */ + TextMessage message = session + .createTextMessage("send topic content"); + + /** + * 8. 发送 + */ + messageProducer.send(message); + + System.out.println("消息发送完成!"); + /** + * 如果有事务操作也可以提交事务 + */ + session.commit(); + + /** + * 9.关闭生产者对象(即使关闭了程序也在运行) + */ + messageProducer.close(); + } catch (Exception e) { + e.printStackTrace(); + } finally { + if (connection != null) { + try { + /** + * 10.关闭连接(将会关闭程序) + */ + connection.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + } +} diff --git "a/distributed/mq/activemq/activemq-api/src/main/resources/jms\350\247\204\350\214\203\346\216\245\345\217\243.jpg" "b/distributed/mq/activemq/activemq-api/src/main/resources/jms\350\247\204\350\214\203\346\216\245\345\217\243.jpg" new file mode 100644 index 00000000..65a3d5a8 Binary files /dev/null and "b/distributed/mq/activemq/activemq-api/src/main/resources/jms\350\247\204\350\214\203\346\216\245\345\217\243.jpg" differ diff --git a/distributed/mq/activemq/activemq-spring/pom.xml b/distributed/mq/activemq/activemq-spring/pom.xml new file mode 100644 index 00000000..eaf993b1 --- /dev/null +++ b/distributed/mq/activemq/activemq-spring/pom.xml @@ -0,0 +1,92 @@ + + + 4.0.0 + + activemq-spring + cn.lastwhisper + 1.0-SNAPSHOT + war + + + UTF-8 + 4.1.8.RELEASE + + + + + junit + junit + 4.10 + test + + + + jstl + jstl + 1.2 + + + + + org.springframework + spring-core + ${springframework} + + + org.springframework + spring-context + ${springframework} + + + org.springframework + spring-tx + ${springframework} + + + org.springframework + spring-webmvc + ${springframework} + + + org.springframework + spring-jms + ${springframework} + + + + + org.apache.activemq + activemq-spring + 5.14.5 + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + 8 + 8 + + + + + org.apache.tomcat.maven + tomcat7-maven-plugin + 2.2 + + + 8080 + + / + + + + + \ No newline at end of file diff --git a/distributed/mq/activemq/activemq-spring/src/main/java/cn/lastwhisper/activemq/amq/consumer/queue/QueueReceiver1.java b/distributed/mq/activemq/activemq-spring/src/main/java/cn/lastwhisper/activemq/amq/consumer/queue/QueueReceiver1.java new file mode 100644 index 00000000..e7de6b6d --- /dev/null +++ b/distributed/mq/activemq/activemq-spring/src/main/java/cn/lastwhisper/activemq/amq/consumer/queue/QueueReceiver1.java @@ -0,0 +1,32 @@ + +package cn.lastwhisper.activemq.amq.consumer.queue; + +import org.springframework.stereotype.Component; + +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageListener; +import javax.jms.TextMessage; + +/** + * 队列消息消费者1 + * + * @author Jastar·Wang + * @date 2018年4月4日 + * @since 1.0 + */ +@Component +public class QueueReceiver1 implements MessageListener { + + @Override + public void onMessage(Message message) { + try { + /* + * 实际项目中拿到String类型的message(通常是JSON字符串)之后,会进行反序列化成对象,做进一步的处理 + */ + System.out.println("QueueReceiver1接收到消息:" + ((TextMessage) message).getText()); + } catch (JMSException e) { + e.printStackTrace(); + } + } +} diff --git a/distributed/mq/activemq/activemq-spring/src/main/java/cn/lastwhisper/activemq/amq/consumer/queue/QueueReceiver2.java b/distributed/mq/activemq/activemq-spring/src/main/java/cn/lastwhisper/activemq/amq/consumer/queue/QueueReceiver2.java new file mode 100644 index 00000000..47f105a2 --- /dev/null +++ b/distributed/mq/activemq/activemq-spring/src/main/java/cn/lastwhisper/activemq/amq/consumer/queue/QueueReceiver2.java @@ -0,0 +1,30 @@ + +package cn.lastwhisper.activemq.amq.consumer.queue; + +import org.springframework.stereotype.Component; + +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageListener; +import javax.jms.TextMessage; + +/** + * 队列消息消费者2 + * + * @author Jastar·Wang + * @date 2018年4月4日 + * @since 1.0 + */ +@Component +public class QueueReceiver2 implements MessageListener { + + @Override + public void onMessage(Message message) { + try { + System.out.println("QueueReceiver2接收到消息:" + ((TextMessage) message).getText()); + } catch (JMSException e) { + e.printStackTrace(); + } + } + +} diff --git a/distributed/mq/activemq/activemq-spring/src/main/java/cn/lastwhisper/activemq/amq/consumer/topic/TopicReceiver1.java b/distributed/mq/activemq/activemq-spring/src/main/java/cn/lastwhisper/activemq/amq/consumer/topic/TopicReceiver1.java new file mode 100644 index 00000000..60ef5ff0 --- /dev/null +++ b/distributed/mq/activemq/activemq-spring/src/main/java/cn/lastwhisper/activemq/amq/consumer/topic/TopicReceiver1.java @@ -0,0 +1,29 @@ +package cn.lastwhisper.activemq.amq.consumer.topic; + +import org.springframework.stereotype.Component; + +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageListener; +import javax.jms.TextMessage; + +/** + * 主题消息消费者1 + * + * @author Jastar·Wang + * @date 2018年4月4日 + * @since 1.0 + */ +@Component +public class TopicReceiver1 implements MessageListener { + + @Override + public void onMessage(Message message) { + try { + System.out.println("TopicReceiver1接收到消息:" + ((TextMessage) message).getText()); + } catch (JMSException e) { + e.printStackTrace(); + } + } + +} diff --git a/distributed/mq/activemq/activemq-spring/src/main/java/cn/lastwhisper/activemq/amq/consumer/topic/TopicReceiver2.java b/distributed/mq/activemq/activemq-spring/src/main/java/cn/lastwhisper/activemq/amq/consumer/topic/TopicReceiver2.java new file mode 100644 index 00000000..936cd7ab --- /dev/null +++ b/distributed/mq/activemq/activemq-spring/src/main/java/cn/lastwhisper/activemq/amq/consumer/topic/TopicReceiver2.java @@ -0,0 +1,29 @@ +package cn.lastwhisper.activemq.amq.consumer.topic; + +import org.springframework.stereotype.Component; + +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageListener; +import javax.jms.TextMessage; + +/** + * 主题消息消费者2 + * + * @author Jastar·Wang + * @date 2018年4月4日 + * @since 1.0 + */ +@Component +public class TopicReceiver2 implements MessageListener { + + @Override + public void onMessage(Message message) { + try { + System.out.println("TopicReceiver2接收到消息:" + ((TextMessage) message).getText()); + } catch (JMSException e) { + e.printStackTrace(); + } + } + +} diff --git a/distributed/mq/activemq/activemq-spring/src/main/java/cn/lastwhisper/activemq/amq/producer/QueueSender.java b/distributed/mq/activemq/activemq-spring/src/main/java/cn/lastwhisper/activemq/amq/producer/QueueSender.java new file mode 100644 index 00000000..403066b5 --- /dev/null +++ b/distributed/mq/activemq/activemq-spring/src/main/java/cn/lastwhisper/activemq/amq/producer/QueueSender.java @@ -0,0 +1,45 @@ +package cn.lastwhisper.activemq.amq.producer; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.jms.core.JmsTemplate; +import org.springframework.jms.core.MessageCreator; +import org.springframework.stereotype.Component; + +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.Session; + +/** + * 队列消息生产者 + * + * @author Jastar·Wang + * @date 2018年4月4日 + * @since 1.0 + */ +@Component +public class QueueSender { + + @Autowired + @Qualifier("jmsQueueTemplate") + private JmsTemplate jmsTemplate; + + /** + * 发送一条消息到指定的队列(目标) + * + * @param queueName + * 队列名称 + * @param message + * 消息内容 + */ + public void send(String queueName, final String message) { + jmsTemplate.send(queueName, new MessageCreator() { + @Override + public Message createMessage(Session session) throws JMSException { + // 其他的还有createXXXMessage(...) + return session.createTextMessage(message); + } + }); + } + +} diff --git a/distributed/mq/activemq/activemq-spring/src/main/java/cn/lastwhisper/activemq/amq/producer/TopicSender.java b/distributed/mq/activemq/activemq-spring/src/main/java/cn/lastwhisper/activemq/amq/producer/TopicSender.java new file mode 100644 index 00000000..7f253ab2 --- /dev/null +++ b/distributed/mq/activemq/activemq-spring/src/main/java/cn/lastwhisper/activemq/amq/producer/TopicSender.java @@ -0,0 +1,45 @@ +package cn.lastwhisper.activemq.amq.producer; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.jms.core.JmsTemplate; +import org.springframework.jms.core.MessageCreator; +import org.springframework.stereotype.Component; + +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.Session; + +/** + * 主题消息生产者 + * + * @author Jastar·Wang + * @date 2018年4月4日 + * @since 1.0 + */ +@Component +public class TopicSender { + + @Autowired + @Qualifier("jmsTopicTemplate") + private JmsTemplate jmsTemplate; + + /** + * 发送一条消息到指定的队列(目标) + * + * @param topicName + * 队列名称 + * @param message + * 消息内容 + */ + public void send(String topicName, final String message) { + jmsTemplate.send(topicName, new MessageCreator() { + @Override + public Message createMessage(Session session) throws JMSException { + // 其他的还有createXXXMessage(...) + return session.createTextMessage(message); + } + }); + } + +} diff --git a/distributed/mq/activemq/activemq-spring/src/main/java/cn/lastwhisper/activemq/ctrl/DemoController.java b/distributed/mq/activemq/activemq-spring/src/main/java/cn/lastwhisper/activemq/ctrl/DemoController.java new file mode 100644 index 00000000..7497fdb8 --- /dev/null +++ b/distributed/mq/activemq/activemq-spring/src/main/java/cn/lastwhisper/activemq/ctrl/DemoController.java @@ -0,0 +1,69 @@ +package cn.lastwhisper.activemq.ctrl; + +import cn.lastwhisper.activemq.amq.producer.QueueSender; +import cn.lastwhisper.activemq.amq.producer.TopicSender; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +/** + * @author Jastar·Wang + * @date 2018年4月4日 + * @since 1.0 + */ +@Controller +@RequestMapping("/demo") +public class DemoController { + + /** 队列名称 */ + public static final String QUEUE_NAME = "my.queue"; + + /** 主题名称 */ + public static final String TOPIC_NAME = "my.topic"; + + @Autowired + private QueueSender queueSender; + + @Autowired + private TopicSender topicSender; + + /** + * 发送消息到队列,一条消息只会被一个消费者接收,接收完后会从队列中删除 + * + * @param message + * @return + */ + @ResponseBody + @RequestMapping("sendToQueue") + public String sendToQueue(String message) { + String result = ""; + try { + queueSender.send(QUEUE_NAME, message); + result = "suc"; + } catch (Exception e) { + result = e.getCause().toString(); + } + return result; + } + + /** + * 发送消息到主题 ,所有订阅者都可以收到消息 + * + * @param message + * @return String + */ + @ResponseBody + @RequestMapping("sendToTopic") + public String sendToTopic(String message) { + String result = ""; + try { + topicSender.send(TOPIC_NAME, message); + result = "suc"; + } catch (Exception e) { + result = e.getCause().toString(); + } + return result; + } + +} diff --git a/distributed/mq/activemq/activemq-spring/src/main/resources/spring-amq.xml b/distributed/mq/activemq/activemq-spring/src/main/resources/spring-amq.xml new file mode 100644 index 00000000..3fe8e1c6 --- /dev/null +++ b/distributed/mq/activemq/activemq-spring/src/main/resources/spring-amq.xml @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/distributed/mq/activemq/activemq-spring/src/main/resources/spring-main.xml b/distributed/mq/activemq/activemq-spring/src/main/resources/spring-main.xml new file mode 100644 index 00000000..17257d4e --- /dev/null +++ b/distributed/mq/activemq/activemq-spring/src/main/resources/spring-main.xml @@ -0,0 +1,18 @@ + + + + + + + \ No newline at end of file diff --git a/distributed/mq/activemq/activemq-spring/src/main/resources/spring-mvc.xml b/distributed/mq/activemq/activemq-spring/src/main/resources/spring-mvc.xml new file mode 100644 index 00000000..b3897afa --- /dev/null +++ b/distributed/mq/activemq/activemq-spring/src/main/resources/spring-mvc.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/distributed/mq/activemq/activemq-spring/src/main/webapp/WEB-INF/web.xml b/distributed/mq/activemq/activemq-spring/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 00000000..e962f813 --- /dev/null +++ b/distributed/mq/activemq/activemq-spring/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,57 @@ + + + + demo-spring-amq + + + + contextConfigLocation + classpath*:spring-*.xml + + + org.springframework.web.context.ContextLoaderListener + + + + + + + SpringMVC + org.springframework.web.servlet.DispatcherServlet + + + contextConfigLocation + classpath:spring-mvc.xml + + 1 + + + SpringMVC + + / + + + + + + characterEncoding + org.springframework.web.filter.CharacterEncodingFilter + + encoding + UTF-8 + + + forceEncoding + true + + + + characterEncoding + /* + + + + diff --git a/distributed/mq/activemq/activemq-spring/src/main/webapp/index.jsp b/distributed/mq/activemq/activemq-spring/src/main/webapp/index.jsp new file mode 100644 index 00000000..91e7161f --- /dev/null +++ b/distributed/mq/activemq/activemq-spring/src/main/webapp/index.jsp @@ -0,0 +1,97 @@ +<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> +<% + String path = request.getContextPath(); +%> + + + + +Spring集成ActiveMQ演示实例 + + + + + + + + + + +

Hello ActiveMQ

+
+

Producer

+ +
+ + +
+ +
+ + diff --git a/distributed/mq/activemq/pom.xml b/distributed/mq/activemq/pom.xml new file mode 100644 index 00000000..4afa1822 --- /dev/null +++ b/distributed/mq/activemq/pom.xml @@ -0,0 +1,86 @@ + + + 4.0.0 + + cn.lastwhisper + activemq + pom + 1.0-SNAPSHOT + + + + + org.apache.activemq + activemq-all + 5.11.1 + + + org.apache.activemq + activemq-pool + 5.12.1 + + + org.springframework + spring-jms + 4.3.8.RELEASE + + + org.springframework + spring-aop + 4.3.8.RELEASE + + + org.springframework + spring-beans + 4.3.8.RELEASE + + + org.springframework + spring-context + 4.3.8.RELEASE + + + org.springframework + spring-context-support + 4.3.8.RELEASE + + + org.springframework + spring-core + 4.3.8.RELEASE + + + org.springframework + spring-messaging + 4.3.8.RELEASE + + + org.springframework + spring-oxm + 4.3.8.RELEASE + + + org.springframework + spring-tx + 4.3.8.RELEASE + + + commons-pool + commons-pool + 1.6 + + + mysql + mysql-connector-java + 5.1.37 + + + com.alibaba + druid + 1.0.29 + + + + \ No newline at end of file diff --git a/distributed/mq/rabbitmq/README.md b/distributed/mq/rabbitmq/README.md new file mode 100644 index 00000000..bbc38fa8 --- /dev/null +++ b/distributed/mq/rabbitmq/README.md @@ -0,0 +1,5 @@ +rabbitmq-api 为基础api与高级特性源码 +rabbitmq-spring 为整合springamqp框架源码 +rabbitmq-springboot-producer & rabbitmq-springboot-consumer 为整合springboot框架源码 +rabbitmq-springboot-producer-reliable 为rabbitmq可靠消息投递方案 +rabbitmq-springcloudstream-producer & rabbitmq-springcloudstream-consumer 为整合spring cloud stream源码 \ No newline at end of file diff --git "a/distributed/mq/rabbitmq/RabbitMQ\345\256\211\350\243\205\346\226\207\346\241\243.txt" "b/distributed/mq/rabbitmq/RabbitMQ\345\256\211\350\243\205\346\226\207\346\241\243.txt" new file mode 100644 index 00000000..c401d74b --- /dev/null +++ "b/distributed/mq/rabbitmq/RabbitMQ\345\256\211\350\243\205\346\226\207\346\241\243.txt" @@ -0,0 +1,31 @@ +https://coding.imooc.com/class/262.html + +准备: +yum install build-essential openssl openssl-devel unixODBC unixODBC-devel +make gcc gcc-c++ kernel-devel m4 ncurses-devel tk tc xz + +下载: +wget www.rabbitmq.com/releases/erlang/erlang-18.3-1.el7.centos.x86_64.rpm +wget http://repo.iotti.biz/CentOS/7/x86_64/socat-1.7.3.2-5.el7.lux.x86_64.rpm +wget www.rabbitmq.com/releases/rabbitmq-server/v3.6.5/rabbitmq-server-3.6.5-1.noarch.rpm + +安装: +rpm -ivh + +配置文件: +vim /usr/lib/rabbitmq/lib/rabbitmq_server-3.6.5/ebin/rabbit.app +比如修改密码、配置等等,例如:loopback_users 中的 <<"guest">>,只保留guest + +命令: +rabbitmqctl rabbitmq-plugins rabbitmq-server +服务启动和停止: +启动 rabbitmq-server start & +停止 rabbitmqctl app_stop + +管理插件:rabbitmq-plugins enable rabbitmq_management +访问地址:http://192.168.217.101:15672/ + + + + + diff --git a/distributed/mq/rabbitmq/pom.xml b/distributed/mq/rabbitmq/pom.xml new file mode 100644 index 00000000..edd5dccd --- /dev/null +++ b/distributed/mq/rabbitmq/pom.xml @@ -0,0 +1,21 @@ + + + 4.0.0 + + cn.lastwhisper + rabbitmq + pom + 1.0-SNAPSHOT + + + + + org.springframework.amqp + spring-rabbit + 2.2.2.RELEASE + + + + \ No newline at end of file diff --git a/distributed/mq/rabbitmq/rabbitmq-api/README.md b/distributed/mq/rabbitmq/rabbitmq-api/README.md new file mode 100644 index 00000000..0c7ba903 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-api/README.md @@ -0,0 +1,127 @@ +│ +├─quickstart 快速入门 +│ +├─api rabbitmq client api学习 +│ │ +│ ├─exchange 三种交换器 +│ │ +│ ├─message 消息 +│ │ +│ ├─confirm 生产者确认消息机制 +│ │ +│ ├─returnlistener 生产者消息不可达机制 +│ │ +│ ├─consumer 自定消费者 +│ │ +│ ├─limit 消费者限流 +│ │ +│ ├─ack 消费者ack、nack和重回队列机制 +│ │ +│ └─dlx 死信队列 +│ +└─ + +# 1. quickstart +快速入门项目 +# 2. 生产端confirm机制 +## 2.1 Confirm消息确认机制的概念 +指生产者投递消息后,如果Broker收到消息,则会给生产者一个应答。 +生产者进行接收应答,用来确认这条消息是否正常发送到Broker。 +是消息可靠性投递的核心保障。 + +## 2.2 确认机制的流程图 + +![在这里插入图片描述](https://img-blog.csdnimg.cn/20181231233125448.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTIyMTE2MDM=,size_16,color_FFFFFF,t_70) + +发送消息与监听应答的消息是异步操作。 + +## 2.3 开启confirm核心代码 + +在channel开启确认模式:`channel.confirmSelect();` +在channel添加监听:`channel.addConfirmListener(ConfirmListener listener);` 返回监听成功和失败的结果,对具体结果进行相应的处理(重新发送、记录日志等待后续处理等) + +# 3. 生产端Return机制 + +用于处理一些不可路由的消息。 + +## 3.1 return消息机制的流程图 + +![在这里插入图片描述](https://img-blog.csdnimg.cn/20190101002146316.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTIyMTE2MDM=,size_16,color_FFFFFF,t_70) + +消息的生产者通过制定Exchange和RoutingKey,把消息投递到某一个队列中,消费者监听队列,进行消费。 + +但在一些情况下,发送消息时,Exchange不存在或RoutingKey路由不到,Return Listener就会监听这种不可达的消息,然后进行处理。 + +## 3.2 开启return核心代码 + +关键配置项:`Mandatory`:true,监听器会接收到路由不可达的消息,然后进行处理;false,Broker会自动删除该消息。默认是false。 + +添加ReturnListener + +```java +channel.addReturnListener(new ReturnListener()); +``` + +# 4. 消费端限流 + +## 4.1 消费端限流的概念 + +当巨量消息瞬间全部推送时,单个客户端无法同时处理这些数据,服务器容易故障。因此要进行消费端限流 + +RabbitMQ提供了一种**Qos(服务质量保证)功能**,消费端在**非自动确认**前提下,如果一定数目的消息未被确认前(通过consume或者channel设置Qos值),不进行消费新消息。 + +## 4.2 开启限流核心代码 + +```java +DefaultConsumer defaultConsumer = new DefaultConsumer(channel) { + @Override + public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { + // 手动ack签收 + channel.basicAck(envelope.getDeliveryTag(), false); // 不批量签收 + } + }; +/* +* prefetchSize:消息限制大小,一般为0,不做限制。 +* prefetchCount:一次处理消息的个数,一般设置为1 +* global:一般为false。true,在channel级别做限制;false,在consumer级别做限制 +*/ +channel.basicQos(0, 1, false); +//限流:autoAck需设置为false, 关闭自动签收 +channel.basicConsume(QUEUE_NAME, false, defaultConsumer); +``` + +消费端必须手工签收,不然无法消费消息 + +# 5. 消费端ack与重回队列机制 + +消费端手工签收消息时,消费 成功后,进行ack确认。由于业务异常,会调用NACK拒绝确认,在进行NACK时可以将消息重回队列,进行重试。 + +一般在实际应用中,会关闭重回队列。 + +# 6. TTL队列 + +TTL:Time To Live,生存时间。 +可以指定消息的过期时间。 +可以指定队列的过期时间,从消息入队列开始计算,超过了队列的超时时间设置,那么消息会自动清除。 + +# 7. 死信队列 + +DLX:Dead-Letter-Exchange +当消息在队列中变成死信时,能被重新publish到另一个Exchange,该Exchange就是DLX。 + +死信队列产生的情况: + +1. 消息被拒绝(`basic.reject/ basic.nack`)并且`requeue=false`(没有重回队列) + +2. 消息TTL过期 + +3. 队列达到最大长度 + +死信队列的设置: + +1. 正常声明交换机,队列并绑定,需要在队列上设置一个参数:arguments.put("x-dead-letter-exchange", "dlx.exchange"); +2. 声明死信队列的Exchange和Queue,然后进行绑定: + Exchange: dlx.exchange + Queue: dlx.queue + RoutingKey: # +3. 在消息过期、requeue、队列达到最大长度时(即为死信),消息会发送到指定的dlx.exchange交换机上,消费者会监听该交换机所绑定的死信队列。 \ No newline at end of file diff --git a/distributed/mq/rabbitmq/rabbitmq-api/pom.xml b/distributed/mq/rabbitmq/rabbitmq-api/pom.xml new file mode 100644 index 00000000..2f23ea97 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-api/pom.xml @@ -0,0 +1,33 @@ + + + 4.0.0 + + rabbitmq-api + cn.lastwhisper + 1.0-SNAPSHOT + jar + + + + com.rabbitmq + amqp-client + 3.6.5 + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + 8 + 8 + + + + + \ No newline at end of file diff --git a/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/ack/Consumer.java b/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/ack/Consumer.java new file mode 100644 index 00000000..66166785 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/ack/Consumer.java @@ -0,0 +1,36 @@ +package cn.lastwhisper.rabbitmq.api.ack; + +import cn.lastwhisper.rabbitmq.common.Constant; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; + +public class Consumer { + + + public static void main(String[] args) throws Exception { + + + ConnectionFactory connectionFactory = new ConnectionFactory(); + connectionFactory.setHost(Constant.ip); + connectionFactory.setPort(Constant.port); + connectionFactory.setVirtualHost("/"); + + Connection connection = connectionFactory.newConnection(); + Channel channel = connection.createChannel(); + + + String exchangeName = "test_ack_exchange"; + String queueName = "test_ack_queue"; + String routingKey = "ack.#"; + + channel.exchangeDeclare(exchangeName, "topic", true, false, null); + channel.queueDeclare(queueName, true, false, false, null); + channel.queueBind(queueName, exchangeName, routingKey); + + // 手工签收 必须要关闭 autoAck = false + channel.basicConsume(queueName, false, new MyConsumer(channel)); + + + } +} diff --git a/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/ack/MyConsumer.java b/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/ack/MyConsumer.java new file mode 100644 index 00000000..f1f7eed2 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/ack/MyConsumer.java @@ -0,0 +1,39 @@ +package cn.lastwhisper.rabbitmq.api.ack; + +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.DefaultConsumer; +import com.rabbitmq.client.Envelope; + +import java.io.IOException; + +public class MyConsumer extends DefaultConsumer { + + + private Channel channel; + + public MyConsumer(Channel channel) { + super(channel); + this.channel = channel; + } + + @Override + public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { + System.err.println("-----------consume message----------"); + System.err.println("body: " + new String(body)); + try { + Thread.sleep(2000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + if ((Integer) properties.getHeaders().get("num") == 0) { + // noack 重回队列 + channel.basicNack(envelope.getDeliveryTag(), false, true); + } else { + channel.basicAck(envelope.getDeliveryTag(), false); + } + + } + + +} diff --git a/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/ack/Producer.java b/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/ack/Producer.java new file mode 100644 index 00000000..9f677a57 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/ack/Producer.java @@ -0,0 +1,43 @@ +package cn.lastwhisper.rabbitmq.api.ack; + +import cn.lastwhisper.rabbitmq.common.Constant; +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; + +import java.util.HashMap; +import java.util.Map; + +public class Producer { + + + public static void main(String[] args) throws Exception { + + ConnectionFactory connectionFactory = new ConnectionFactory(); + connectionFactory.setHost(Constant.ip); + connectionFactory.setPort(Constant.port); + connectionFactory.setVirtualHost("/"); + + Connection connection = connectionFactory.newConnection(); + Channel channel = connection.createChannel(); + + String exchange = "test_ack_exchange"; + String routingKey = "ack.save"; + + for(int i =0; i<5; i ++){ + + Map headers = new HashMap(); + headers.put("num", i); + + AMQP.BasicProperties properties = new AMQP.BasicProperties.Builder() + .deliveryMode(2) + .contentEncoding("UTF-8") + .headers(headers) + .build(); + String msg = "Hello RabbitMQ ACK Message " + i; + channel.basicPublish(exchange, routingKey, true, properties, msg.getBytes()); + } + + } +} diff --git a/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/confirm/Consumer.java b/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/confirm/Consumer.java new file mode 100644 index 00000000..45a327a4 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/confirm/Consumer.java @@ -0,0 +1,50 @@ +package cn.lastwhisper.rabbitmq.api.confirm; + +import cn.lastwhisper.rabbitmq.common.Constant; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; +import com.rabbitmq.client.QueueingConsumer; +import com.rabbitmq.client.QueueingConsumer.Delivery; + +public class Consumer { + + + public static void main(String[] args) throws Exception { + + + //1 创建ConnectionFactory + ConnectionFactory connectionFactory = new ConnectionFactory(); + connectionFactory.setHost(Constant.ip); + connectionFactory.setPort(Constant.port); + connectionFactory.setVirtualHost("/"); + + //2 获取C onnection + Connection connection = connectionFactory.newConnection(); + + //3 通过Connection创建一个新的Channel + Channel channel = connection.createChannel(); + + String exchangeName = "test_confirm_exchange"; + String routingKey = "confirm.#"; + String queueName = "test_confirm_queue"; + + //4 声明交换机和队列 然后进行绑定设置, 最后制定路由Key + channel.exchangeDeclare(exchangeName, "topic", true); + channel.queueDeclare(queueName, true, false, false, null); + channel.queueBind(queueName, exchangeName, routingKey); + + //5 创建消费者 + QueueingConsumer queueingConsumer = new QueueingConsumer(channel); + channel.basicConsume(queueName, true, queueingConsumer); + + while (true) { + Delivery delivery = queueingConsumer.nextDelivery(); + String msg = new String(delivery.getBody()); + + System.err.println("消费端: " + msg); + } + + + } +} diff --git a/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/confirm/Producer.java b/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/confirm/Producer.java new file mode 100644 index 00000000..837719fe --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/confirm/Producer.java @@ -0,0 +1,53 @@ +package cn.lastwhisper.rabbitmq.api.confirm; + +import cn.lastwhisper.rabbitmq.common.Constant; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.ConfirmListener; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; + +import java.io.IOException; + +public class Producer { + + + public static void main(String[] args) throws Exception { + //1 创建ConnectionFactory + ConnectionFactory connectionFactory = new ConnectionFactory(); + connectionFactory.setHost(Constant.ip); + connectionFactory.setPort(Constant.port); + connectionFactory.setVirtualHost("/"); + + //2 获取C onnection + Connection connection = connectionFactory.newConnection(); + + //3 通过Connection创建一个新的Channel + Channel channel = connection.createChannel(); + + + //4 指定我们的消息投递模式: 消息的确认模式 + channel.confirmSelect(); + + String exchangeName = "test_confirm_exchange"; + String routingKey = "confirm.save"; + + //5 发送一条消息 + String msg = "Hello RabbitMQ Send confirm message!"; + channel.basicPublish(exchangeName, routingKey, null, msg.getBytes()); + + //6 添加一个确认监听 + channel.addConfirmListener(new ConfirmListener() { + @Override + public void handleNack(long deliveryTag, boolean multiple) throws IOException { + System.err.println("-------no ack!-----------"); + } + + @Override + public void handleAck(long deliveryTag, boolean multiple) throws IOException { + System.err.println("-------ack!-----------"); + } + }); + + + } +} diff --git a/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/consumer/Consumer.java b/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/consumer/Consumer.java new file mode 100644 index 00000000..d15032f2 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/consumer/Consumer.java @@ -0,0 +1,46 @@ +package cn.lastwhisper.rabbitmq.api.consumer; + +import cn.lastwhisper.rabbitmq.common.Constant; +import com.rabbitmq.client.*; + +import java.io.IOException; + +public class Consumer { + + + public static void main(String[] args) throws Exception { + + + ConnectionFactory connectionFactory = new ConnectionFactory(); + connectionFactory.setHost(Constant.ip); + connectionFactory.setPort(Constant.port); + connectionFactory.setVirtualHost("/"); + + Connection connection = connectionFactory.newConnection(); + Channel channel = connection.createChannel(); + + + String exchangeName = "test_consumer_exchange"; + String routingKey = "consumer.#"; + String queueName = "test_consumer_queue"; + + channel.exchangeDeclare(exchangeName, "topic", true, false, null); + channel.queueDeclare(queueName, true, false, false, null); + channel.queueBind(queueName, exchangeName, routingKey); + + //channel.basicConsume(queueName, true, new MyConsumer(channel)); + channel.basicConsume(queueName, true, new DefaultConsumer(channel) { + @Override + public void handleDelivery(String consumerTag, Envelope envelope, + AMQP.BasicProperties properties, byte[] body) throws IOException { + System.err.println("-----------consume message----------"); + System.err.println("consumerTag: " + consumerTag); + System.err.println("envelope: " + envelope); + System.err.println("properties: " + properties); + System.err.println("body: " + new String(body)); + } + }); + + + } +} diff --git a/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/consumer/MyConsumer.java b/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/consumer/MyConsumer.java new file mode 100644 index 00000000..44e94470 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/consumer/MyConsumer.java @@ -0,0 +1,27 @@ +package cn.lastwhisper.rabbitmq.api.consumer; + +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.DefaultConsumer; +import com.rabbitmq.client.Envelope; + +import java.io.IOException; + +public class MyConsumer extends DefaultConsumer { + + + public MyConsumer(Channel channel) { + super(channel); + } + + @Override + public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { + System.err.println("-----------consume message----------"); + System.err.println("consumerTag: " + consumerTag); + System.err.println("envelope: " + envelope); + System.err.println("properties: " + properties); + System.err.println("body: " + new String(body)); + } + + +} diff --git a/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/consumer/Producer.java b/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/consumer/Producer.java new file mode 100644 index 00000000..b7a02a45 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/consumer/Producer.java @@ -0,0 +1,30 @@ +package cn.lastwhisper.rabbitmq.api.consumer; + +import cn.lastwhisper.rabbitmq.common.Constant; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; + +public class Producer { + + public static void main(String[] args) throws Exception { + + ConnectionFactory connectionFactory = new ConnectionFactory(); + connectionFactory.setHost(Constant.ip); + connectionFactory.setPort(Constant.port); + connectionFactory.setVirtualHost("/"); + + Connection connection = connectionFactory.newConnection(); + Channel channel = connection.createChannel(); + + String exchange = "test_consumer_exchange"; + String routingKey = "consumer.save"; + + String msg = "Hello RabbitMQ Consumer Message"; + + for (int i = 0; i < 5; i++) { + channel.basicPublish(exchange, routingKey, true, null, msg.getBytes()); + } + + } +} diff --git a/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/dlx/Consumer.java b/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/dlx/Consumer.java new file mode 100644 index 00000000..bb88ed68 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/dlx/Consumer.java @@ -0,0 +1,46 @@ +package cn.lastwhisper.rabbitmq.api.dlx; + +import cn.lastwhisper.rabbitmq.common.Constant; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; + +import java.util.HashMap; +import java.util.Map; + +public class Consumer { + + + public static void main(String[] args) throws Exception { + + ConnectionFactory connectionFactory = new ConnectionFactory(); + connectionFactory.setHost(Constant.ip); + connectionFactory.setPort(Constant.port); + connectionFactory.setVirtualHost("/"); + + Connection connection = connectionFactory.newConnection(); + Channel channel = connection.createChannel(); + + // 这就是一个普通的交换机 和 队列 以及路由 + String exchangeName = "test_dlx_exchange"; + String queueName = "test_dlx_queue"; + String routingKey = "dlx.#"; + + channel.exchangeDeclare(exchangeName, "topic", true, false, null); + + Map arguments = new HashMap<>(); + arguments.put("x-dead-letter-exchange", "dlx.exchange"); + //这个agruments属性,要设置到声明队列上 + channel.queueDeclare(queueName, true, false, false, arguments); + channel.queueBind(queueName, exchangeName, routingKey); + + //要进行死信队列的声明: + channel.exchangeDeclare("dlx.exchange", "topic", true, false, null); + channel.queueDeclare("dlx.queue", true, false, false, null); + channel.queueBind("dlx.queue", "dlx.exchange", "#"); + + channel.basicConsume(queueName, true, new MyConsumer(channel)); + + + } +} diff --git a/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/dlx/MyConsumer.java b/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/dlx/MyConsumer.java new file mode 100644 index 00000000..9f4b16f1 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/dlx/MyConsumer.java @@ -0,0 +1,27 @@ +package cn.lastwhisper.rabbitmq.api.dlx; + +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.DefaultConsumer; +import com.rabbitmq.client.Envelope; + +import java.io.IOException; + +public class MyConsumer extends DefaultConsumer { + + + public MyConsumer(Channel channel) { + super(channel); + } + + @Override + public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { + System.err.println("-----------consume message----------"); + System.err.println("consumerTag: " + consumerTag); + System.err.println("envelope: " + envelope); + System.err.println("properties: " + properties); + System.err.println("body: " + new String(body)); + } + + +} diff --git a/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/dlx/Producer.java b/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/dlx/Producer.java new file mode 100644 index 00000000..8750aa8e --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/dlx/Producer.java @@ -0,0 +1,42 @@ +package cn.lastwhisper.rabbitmq.api.dlx; + +import cn.lastwhisper.rabbitmq.common.Constant; +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; + +public class Producer { + + /** + * 1.消息被拒绝(basic.reject/ basic.nack)并且requeue=false(没有重回队列) + * 2.消息TTL过期 + * 3.队列达到最大长度 + */ + public static void main(String[] args) throws Exception { + + ConnectionFactory connectionFactory = new ConnectionFactory(); + connectionFactory.setHost(Constant.ip); + connectionFactory.setPort(Constant.port); + connectionFactory.setVirtualHost("/"); + + Connection connection = connectionFactory.newConnection(); + Channel channel = connection.createChannel(); + + String exchange = "test_dlx_exchange"; + String routingKey = "dlx.save"; + + String msg = "Hello RabbitMQ DLX Message"; + + for(int i =0; i<1; i ++){ + + AMQP.BasicProperties properties = new AMQP.BasicProperties.Builder() + .deliveryMode(2) + .contentEncoding("UTF-8") + .expiration("10000") + .build(); + channel.basicPublish(exchange, routingKey, true, properties, msg.getBytes()); + } + + } +} diff --git a/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/exchange/direct/Consumer4DirectExchange.java b/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/exchange/direct/Consumer4DirectExchange.java new file mode 100644 index 00000000..aa99b58d --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/exchange/direct/Consumer4DirectExchange.java @@ -0,0 +1,50 @@ +package cn.lastwhisper.rabbitmq.api.exchange.direct; + +import cn.lastwhisper.rabbitmq.common.Constant; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; +import com.rabbitmq.client.QueueingConsumer; +import com.rabbitmq.client.QueueingConsumer.Delivery; + +public class Consumer4DirectExchange { + + public static void main(String[] args) throws Exception { + + + ConnectionFactory connectionFactory = new ConnectionFactory(); + connectionFactory.setHost(Constant.ip); + connectionFactory.setPort(Constant.port); + connectionFactory.setVirtualHost("/"); + + connectionFactory.setAutomaticRecoveryEnabled(true); + connectionFactory.setNetworkRecoveryInterval(3000); + Connection connection = connectionFactory.newConnection(); + + Channel channel = connection.createChannel(); + //4 声明 + String exchangeName = "test_direct_exchange"; + String exchangeType = "direct"; + String queueName = "test_direct_queue"; + String routingKey = "test.direct"; + + //表示声明了一个交换机 + channel.exchangeDeclare(exchangeName, exchangeType, true, false, false, null); + //表示声明了一个队列 + channel.queueDeclare(queueName, false, false, false, null); + //建立一个绑定关系: + channel.queueBind(queueName, exchangeName, routingKey); + + //durable 是否持久化消息 + QueueingConsumer consumer = new QueueingConsumer(channel); + //参数:队列名称、是否自动ACK、Consumer + channel.basicConsume(queueName, true, consumer); + //循环获取消息 + while (true) { + //获取消息,如果没有消息,这一步将会一直阻塞 + Delivery delivery = consumer.nextDelivery(); + String msg = new String(delivery.getBody()); + System.out.println("收到消息:" + msg); + } + } +} diff --git a/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/exchange/direct/Producer4DirectExchange.java b/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/exchange/direct/Producer4DirectExchange.java new file mode 100644 index 00000000..c45d7dfc --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/exchange/direct/Producer4DirectExchange.java @@ -0,0 +1,37 @@ +package cn.lastwhisper.rabbitmq.api.exchange.direct; + +import cn.lastwhisper.rabbitmq.common.Constant; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; + +public class Producer4DirectExchange { + /** + * + */ + public static void main(String[] args) throws Exception { + + //1 创建ConnectionFactory + ConnectionFactory connectionFactory = new ConnectionFactory(); + connectionFactory.setHost(Constant.ip); + connectionFactory.setPort(Constant.port); + connectionFactory.setVirtualHost("/"); + + //2 创建Connection + Connection connection = connectionFactory.newConnection(); + //3 创建Channel + Channel channel = connection.createChannel(); + //4 声明 + String exchangeName = "test_direct_exchange"; + String routingKey = "test.direct111"; + //5 发送 + + String msg = "Hello World RabbitMQ 4 Direct Exchange Message 111 ... "; + channel.basicPublish(exchangeName, routingKey, null, msg.getBytes()); + + + //channel.close(); + //connection.close(); + } + +} diff --git a/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/exchange/fanout/Consumer4FanoutExchange.java b/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/exchange/fanout/Consumer4FanoutExchange.java new file mode 100644 index 00000000..2593ef56 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/exchange/fanout/Consumer4FanoutExchange.java @@ -0,0 +1,45 @@ +package cn.lastwhisper.rabbitmq.api.exchange.fanout; + +import cn.lastwhisper.rabbitmq.common.Constant; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; +import com.rabbitmq.client.QueueingConsumer; +import com.rabbitmq.client.QueueingConsumer.Delivery; + +public class Consumer4FanoutExchange { + + public static void main(String[] args) throws Exception { + + ConnectionFactory connectionFactory = new ConnectionFactory() ; + connectionFactory.setHost(Constant.ip); + connectionFactory.setPort(Constant.port); + connectionFactory.setVirtualHost("/"); + + connectionFactory.setAutomaticRecoveryEnabled(true); + connectionFactory.setNetworkRecoveryInterval(3000); + Connection connection = connectionFactory.newConnection(); + + Channel channel = connection.createChannel(); + //4 声明 + String exchangeName = "test_fanout_exchange"; + String exchangeType = "fanout"; + String queueName = "test_fanout_queue"; + String routingKey = ""; //不设置路由键 + channel.exchangeDeclare(exchangeName, exchangeType, true, false, false, null); + channel.queueDeclare(queueName, false, false, false, null); + channel.queueBind(queueName, exchangeName, routingKey); + + //durable 是否持久化消息 + QueueingConsumer consumer = new QueueingConsumer(channel); + //参数:队列名称、是否自动ACK、Consumer + channel.basicConsume(queueName, true, consumer); + //循环获取消息 + while(true){ + //获取消息,如果没有消息,这一步将会一直阻塞 + Delivery delivery = consumer.nextDelivery(); + String msg = new String(delivery.getBody()); + System.out.println("收到消息:" + msg); + } + } +} diff --git a/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/exchange/fanout/Producer4FanoutExchange.java b/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/exchange/fanout/Producer4FanoutExchange.java new file mode 100644 index 00000000..1ca61d4b --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/exchange/fanout/Producer4FanoutExchange.java @@ -0,0 +1,35 @@ +package cn.lastwhisper.rabbitmq.api.exchange.fanout; + +import cn.lastwhisper.rabbitmq.common.Constant; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; + +public class Producer4FanoutExchange { + + + public static void main(String[] args) throws Exception { + + //1 创建ConnectionFactory + ConnectionFactory connectionFactory = new ConnectionFactory(); + connectionFactory.setHost(Constant.ip); + connectionFactory.setPort(Constant.port); + connectionFactory.setVirtualHost("/"); + + //2 创建Connection + Connection connection = connectionFactory.newConnection(); + //3 创建Channel + Channel channel = connection.createChannel(); + //4 声明 + String exchangeName = "test_fanout_exchange"; + //5 发送 + for(int i = 0; i < 10; i ++) { + String msg = "Hello World RabbitMQ 4 FANOUT Exchange Message ..."; + // routingKey随便写 + channel.basicPublish(exchangeName, "", null , msg.getBytes()); + } + channel.close(); + connection.close(); + } + +} diff --git a/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/exchange/topic/Consumer4TopicExchange.java b/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/exchange/topic/Consumer4TopicExchange.java new file mode 100644 index 00000000..f818a203 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/exchange/topic/Consumer4TopicExchange.java @@ -0,0 +1,51 @@ +package cn.lastwhisper.rabbitmq.api.exchange.topic; + +import cn.lastwhisper.rabbitmq.common.Constant; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; +import com.rabbitmq.client.QueueingConsumer; +import com.rabbitmq.client.QueueingConsumer.Delivery; + +public class Consumer4TopicExchange { + + public static void main(String[] args) throws Exception { + + + ConnectionFactory connectionFactory = new ConnectionFactory() ; + + connectionFactory.setHost(Constant.ip); + connectionFactory.setPort(Constant.port); + connectionFactory.setVirtualHost("/"); + + connectionFactory.setAutomaticRecoveryEnabled(true); + connectionFactory.setNetworkRecoveryInterval(3000); + Connection connection = connectionFactory.newConnection(); + + Channel channel = connection.createChannel(); + //4 声明 + String exchangeName = "test_topic_exchange"; + String exchangeType = "topic"; + String queueName = "test_topic_queue"; + String routingKey = "user.#"; + //String routingKey = "user.*"; + // 1 声明交换机 + channel.exchangeDeclare(exchangeName, exchangeType, true, false, false, null); + // 2 声明队列 + channel.queueDeclare(queueName, false, false, false, null); + // 3 建立交换机和队列的绑定关系: + channel.queueBind(queueName, exchangeName, routingKey); + + //durable 是否持久化消息 + QueueingConsumer consumer = new QueueingConsumer(channel); + //参数:队列名称、是否自动ACK、Consumer + channel.basicConsume(queueName, true, consumer); + //循环获取消息 + while(true){ + //获取消息,如果没有消息,这一步将会一直阻塞 + Delivery delivery = consumer.nextDelivery(); + String msg = new String(delivery.getBody()); + System.out.println("收到消息:" + msg); + } + } +} diff --git a/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/exchange/topic/Producer4TopicExchange.java b/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/exchange/topic/Producer4TopicExchange.java new file mode 100644 index 00000000..dcb61e45 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/exchange/topic/Producer4TopicExchange.java @@ -0,0 +1,39 @@ +package cn.lastwhisper.rabbitmq.api.exchange.topic; + +import cn.lastwhisper.rabbitmq.common.Constant; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; + +public class Producer4TopicExchange { + + + public static void main(String[] args) throws Exception { + + //1 创建ConnectionFactory + ConnectionFactory connectionFactory = new ConnectionFactory(); + connectionFactory.setHost(Constant.ip); + connectionFactory.setPort(Constant.port); + connectionFactory.setVirtualHost("/"); + + //2 创建Connection + Connection connection = connectionFactory.newConnection(); + //3 创建Channel + Channel channel = connection.createChannel(); + //4 声明 + String exchangeName = "test_topic_exchange"; + String routingKey1 = "user.save"; + String routingKey2 = "user.update"; + String routingKey3 = "user.delete.abc"; + //5 发送 + + String msg = "Hello World RabbitMQ 4 Topic Exchange Message ..."; + channel.basicPublish(exchangeName, routingKey1 , null , msg.getBytes()); + channel.basicPublish(exchangeName, routingKey2 , null , msg.getBytes()); + channel.basicPublish(exchangeName, routingKey3 , null , msg.getBytes()); + + channel.close(); + connection.close(); + } + +} diff --git a/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/limit/Consumer.java b/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/limit/Consumer.java new file mode 100644 index 00000000..940efecb --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/limit/Consumer.java @@ -0,0 +1,43 @@ +package cn.lastwhisper.rabbitmq.api.limit; + +import cn.lastwhisper.rabbitmq.common.Constant; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; + +public class Consumer { + + + public static void main(String[] args) throws Exception { + + + ConnectionFactory connectionFactory = new ConnectionFactory(); + connectionFactory.setHost(Constant.ip); + connectionFactory.setPort(Constant.port); + connectionFactory.setVirtualHost("/"); + + Connection connection = connectionFactory.newConnection(); + Channel channel = connection.createChannel(); + + + String exchangeName = "test_qos_exchange"; + String queueName = "test_qos_queue"; + String routingKey = "qos.#"; + + channel.exchangeDeclare(exchangeName, "topic", true, false, null); + channel.queueDeclare(queueName, true, false, false, null); + channel.queueBind(queueName, exchangeName, routingKey); + + /* + * prefetchSize:消息限制大小,一般为0,不做限制。 + * prefetchCount:一次处理消息的个数,一般设置为1 + * global:一般为false。true,在channel级别做限制;false,在consumer级别做限制 + */ + channel.basicQos(0, 1, false); + + // 限流方式 第一件事就是 autoAck设置为 false + channel.basicConsume(queueName, false, new MyConsumer(channel)); + + + } +} diff --git a/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/limit/MyConsumer.java b/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/limit/MyConsumer.java new file mode 100644 index 00000000..911e2702 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/limit/MyConsumer.java @@ -0,0 +1,33 @@ +package cn.lastwhisper.rabbitmq.api.limit; + +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.DefaultConsumer; +import com.rabbitmq.client.Envelope; + +import java.io.IOException; + +public class MyConsumer extends DefaultConsumer { + + + private Channel channel; + + public MyConsumer(Channel channel) { + super(channel); + this.channel = channel; + } + + @Override + public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { + System.err.println("-----------consume message----------"); + System.err.println("consumerTag: " + consumerTag); + System.err.println("envelope: " + envelope); + System.err.println("properties: " + properties); + System.err.println("body: " + new String(body)); + + //channel.basicAck(envelope.getDeliveryTag(), false); + + } + + +} diff --git a/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/limit/Producer.java b/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/limit/Producer.java new file mode 100644 index 00000000..1d4d8591 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/limit/Producer.java @@ -0,0 +1,30 @@ +package cn.lastwhisper.rabbitmq.api.limit; + +import cn.lastwhisper.rabbitmq.common.Constant; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; + +public class Producer { + + public static void main(String[] args) throws Exception { + + ConnectionFactory connectionFactory = new ConnectionFactory(); + connectionFactory.setHost(Constant.ip); + connectionFactory.setPort(Constant.port); + connectionFactory.setVirtualHost("/"); + + Connection connection = connectionFactory.newConnection(); + Channel channel = connection.createChannel(); + + String exchange = "test_qos_exchange"; + String routingKey = "qos.save"; + + String msg = "Hello RabbitMQ QOS Message"; + + for(int i =0; i<5; i ++){ + channel.basicPublish(exchange, routingKey, true, null, msg.getBytes()); + } + + } +} diff --git a/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/message/Consumer.java b/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/message/Consumer.java new file mode 100644 index 00000000..5c75aa01 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/message/Consumer.java @@ -0,0 +1,50 @@ +package cn.lastwhisper.rabbitmq.api.message; + +import cn.lastwhisper.rabbitmq.common.Constant; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; +import com.rabbitmq.client.QueueingConsumer; +import com.rabbitmq.client.QueueingConsumer.Delivery; + +import java.util.Map; + +public class Consumer { + + public static void main(String[] args) throws Exception { + + //1 创建一个ConnectionFactory, 并进行配置 + ConnectionFactory connectionFactory = new ConnectionFactory(); + connectionFactory.setHost(Constant.ip); + connectionFactory.setPort(Constant.port); + connectionFactory.setVirtualHost("/"); + + //2 通过连接工厂创建连接 + Connection connection = connectionFactory.newConnection(); + + //3 通过connection创建一个Channel + Channel channel = connection.createChannel(); + + //4 声明(创建)一个队列 + String queueName = "test001"; + channel.queueDeclare(queueName, true, false, false, null); + + //5 创建消费者 + QueueingConsumer queueingConsumer = new QueueingConsumer(channel); + + //6 设置Channel + channel.basicConsume(queueName, true, queueingConsumer); + + while (true) { + //7 获取消息 + Delivery delivery = queueingConsumer.nextDelivery(); + String msg = new String(delivery.getBody()); + System.err.println("消费端: " + msg); + Map headers = delivery.getProperties().getHeaders(); + System.err.println("headers get my1 value: " + headers.get("my1") + "\tmy1 value:" + headers.get("my2")); + + //Envelope envelope = delivery.getEnvelope(); + } + + } +} diff --git a/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/message/Producer.java b/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/message/Producer.java new file mode 100644 index 00000000..1cb7e8d1 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/message/Producer.java @@ -0,0 +1,51 @@ +package cn.lastwhisper.rabbitmq.api.message; + +import cn.lastwhisper.rabbitmq.common.Constant; +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; + +import java.util.HashMap; +import java.util.Map; + +public class Producer { + + + public static void main(String[] args) throws Exception { + //1 创建一个ConnectionFactory, 并进行配置 + ConnectionFactory connectionFactory = new ConnectionFactory(); + connectionFactory.setHost(Constant.ip); + connectionFactory.setPort(Constant.port); + connectionFactory.setVirtualHost("/"); + + //2 通过连接工厂创建连接 + Connection connection = connectionFactory.newConnection(); + + //3 通过connection创建一个Channel + Channel channel = connection.createChannel(); + + // 自定义属性 + Map headers = new HashMap<>(); + headers.put("my1", "111"); + headers.put("my2", "222"); + + AMQP.BasicProperties properties = new AMQP.BasicProperties.Builder() + .deliveryMode(2) + .contentEncoding("UTF-8") + .expiration("10000") + .headers(headers) + .build(); + + //4 通过Channel发送数据 + for(int i=0; i < 5; i++){ + String msg = "Hello RabbitMQ!"; + //1 exchange 2 routingKey + channel.basicPublish("", "test001", properties, msg.getBytes()); + } + + //5 记得要关闭相关的连接 + channel.close(); + connection.close(); + } +} diff --git a/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/returnlistener/Consumer.java b/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/returnlistener/Consumer.java new file mode 100644 index 00000000..d509c31e --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/returnlistener/Consumer.java @@ -0,0 +1,48 @@ +package cn.lastwhisper.rabbitmq.api.returnlistener; + +import cn.lastwhisper.rabbitmq.common.Constant; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; +import com.rabbitmq.client.QueueingConsumer; +import com.rabbitmq.client.QueueingConsumer.Delivery; + +public class Consumer { + + + public static void main(String[] args) throws Exception { + + + ConnectionFactory connectionFactory = new ConnectionFactory(); + connectionFactory.setHost(Constant.ip); + connectionFactory.setPort(Constant.port); + connectionFactory.setVirtualHost("/"); + + Connection connection = connectionFactory.newConnection(); + Channel channel = connection.createChannel(); + + String exchangeName = "test_return_exchange"; + String routingKey = "return.#"; + String queueName = "test_return_queue"; + + channel.exchangeDeclare(exchangeName, "topic", true, false, null); + channel.queueDeclare(queueName, true, false, false, null); + channel.queueBind(queueName, exchangeName, routingKey); + + QueueingConsumer queueingConsumer = new QueueingConsumer(channel); + + channel.basicConsume(queueName, true, queueingConsumer); + + while(true){ + + Delivery delivery = queueingConsumer.nextDelivery(); + String msg = new String(delivery.getBody()); + System.err.println("消费者: " + msg); + } + + + + + + } +} diff --git a/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/returnlistener/Producer.java b/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/returnlistener/Producer.java new file mode 100644 index 00000000..2846e6e1 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/api/returnlistener/Producer.java @@ -0,0 +1,56 @@ +package cn.lastwhisper.rabbitmq.api.returnlistener; + +import cn.lastwhisper.rabbitmq.common.Constant; +import com.rabbitmq.client.AMQP.BasicProperties; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; +import com.rabbitmq.client.ReturnListener; + +import java.io.IOException; + +public class Producer { + + + public static void main(String[] args) throws Exception { + + + ConnectionFactory connectionFactory = new ConnectionFactory(); + connectionFactory.setHost(Constant.ip); + connectionFactory.setPort(Constant.port); + connectionFactory.setVirtualHost("/"); + + Connection connection = connectionFactory.newConnection(); + Channel channel = connection.createChannel(); + + String exchange = "test_return_exchange"; + String routingKey = "return.save"; + String routingKeyError = "abc.save"; + + String msg = "Hello RabbitMQ Return Message"; + + + channel.addReturnListener(new ReturnListener() { + @Override + public void handleReturn(int replyCode, String replyText, String exchange, + String routingKey, BasicProperties properties, byte[] body) throws IOException { + + System.err.println("---------handle return----------"); + System.err.println("replyCode: " + replyCode); + System.err.println("replyText: " + replyText); + System.err.println("exchange: " + exchange); + System.err.println("routingKey: " + routingKey); + System.err.println("properties: " + properties); + System.err.println("body: " + new String(body)); + } + }); + + + //channel.basicPublish(exchange, routingKey, true, null, msg.getBytes()); + // mandatory=false,Broker会自动删除不可达消息 + //channel.basicPublish(exchange, routingKeyError, false, null, msg.getBytes()); + // mandatory=true,Broker会处理不可达消息 + channel.basicPublish(exchange, routingKeyError, true, null, msg.getBytes()); + + } +} diff --git a/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/common/Constant.java b/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/common/Constant.java new file mode 100644 index 00000000..dee75848 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/common/Constant.java @@ -0,0 +1,13 @@ +package cn.lastwhisper.rabbitmq.common; + +/** + * + * @author lastwhisper + * @date 2020/2/8 + */ +public interface Constant { + + String ip = "192.168.217.101"; + Integer port = 5672; + +} diff --git a/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/quickstart/Consumer.java b/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/quickstart/Consumer.java new file mode 100644 index 00000000..fb00d005 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/quickstart/Consumer.java @@ -0,0 +1,52 @@ +package cn.lastwhisper.rabbitmq.quickstart; + +import cn.lastwhisper.rabbitmq.common.Constant; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; +import com.rabbitmq.client.QueueingConsumer; + +import java.io.IOException; +import java.util.concurrent.TimeoutException; + +/** + * + * @author lastwhisper + * @date 2020/2/8 + */ +public class Consumer { + + public static void main(String[] args) throws IOException, TimeoutException, InterruptedException { + //1、创建一个ConnectionFactory, 并进行配置 + ConnectionFactory connectionFactory = new ConnectionFactory(); + connectionFactory.setHost(Constant.ip); + connectionFactory.setPort(Constant.port); + connectionFactory.setVirtualHost("/"); + + //2、通过连接工厂创建连接 + Connection connection = connectionFactory.newConnection(); + + //3、通过connection创建一个Channel + Channel channel = connection.createChannel(); + + //4、声明(创建)一个队列 + String queueName = "test001"; + channel.queueDeclare(queueName, true, false, false, null); + + //5、创建消费者 + QueueingConsumer queueingConsumer = new QueueingConsumer(channel); + + //6、设置channel + channel.basicConsume(queueName, true, queueingConsumer); + + while (true) { + //7、 获取消息 + QueueingConsumer.Delivery delivery = queueingConsumer.nextDelivery(); + String msg = new String(delivery.getBody()); + System.err.println("消费端: " + msg); + //Envelope envelope = delivery.getEnvelope(); + } + + } + +} diff --git a/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/quickstart/Producer.java b/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/quickstart/Producer.java new file mode 100644 index 00000000..d9059bae --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-api/src/main/java/cn/lastwhisper/rabbitmq/quickstart/Producer.java @@ -0,0 +1,41 @@ +package cn.lastwhisper.rabbitmq.quickstart; + +import cn.lastwhisper.rabbitmq.common.Constant; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; + +import java.io.IOException; +import java.util.concurrent.TimeoutException; + +/** + * + * @author lastwhisper + * @date 2020/2/8 + */ +public class Producer { + public static void main(String[] args) throws IOException, TimeoutException { + //1、创建一个ConnectionFactory, 并进行配置 + ConnectionFactory connectionFactory = new ConnectionFactory(); + connectionFactory.setHost(Constant.ip); + connectionFactory.setPort(Constant.port); + connectionFactory.setVirtualHost("/"); + + //2、通过连接工厂创建连接 + Connection connection = connectionFactory.newConnection(); + + //3、通过connection创建一个Channel + Channel channel = connection.createChannel(); + + //4、通过Channel发送数据 + for (int i = 0; i < 5; i++) { + String msg = "Hello RabbitMQ!"; + //1 exchange 2 routingKey + channel.basicPublish("", "test001", null, msg.getBytes()); + } + + //5、记得要关闭相关的连接 + channel.close(); + connection.close(); + } +} diff --git a/distributed/mq/rabbitmq/rabbitmq-spring/pom.xml b/distributed/mq/rabbitmq/rabbitmq-spring/pom.xml new file mode 100644 index 00000000..5aebcd53 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-spring/pom.xml @@ -0,0 +1,65 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.2.4.RELEASE + + + cn.lastwhisper + rabbitmq-spring + 0.0.1-SNAPSHOT + rabbitmq-spring + rabbitmq-spring + + + 1.8 + + + + + org.springframework.boot + spring-boot-starter + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.junit.vintage + junit-vintage-engine + + + + + + com.rabbitmq + amqp-client + 5.7.3 + + + org.springframework.boot + spring-boot-starter-amqp + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/distributed/mq/rabbitmq/rabbitmq-spring/src/main/java/cn/lastwhisper/rabbitmq/Application.java b/distributed/mq/rabbitmq/rabbitmq-spring/src/main/java/cn/lastwhisper/rabbitmq/Application.java new file mode 100644 index 00000000..0d2e9291 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-spring/src/main/java/cn/lastwhisper/rabbitmq/Application.java @@ -0,0 +1,13 @@ +package cn.lastwhisper.rabbitmq; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + +} diff --git a/distributed/mq/rabbitmq/rabbitmq-spring/src/main/java/cn/lastwhisper/rabbitmq/adapter/MessageDelegate.java b/distributed/mq/rabbitmq/rabbitmq-spring/src/main/java/cn/lastwhisper/rabbitmq/adapter/MessageDelegate.java new file mode 100644 index 00000000..927de6e5 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-spring/src/main/java/cn/lastwhisper/rabbitmq/adapter/MessageDelegate.java @@ -0,0 +1,57 @@ +package cn.lastwhisper.rabbitmq.adapter; + + +import cn.lastwhisper.rabbitmq.entity.Order; +import cn.lastwhisper.rabbitmq.entity.Packaged; + +import java.io.File; +import java.util.Map; + + +public class MessageDelegate { + + public void handleMessage(byte[] messageBody) { + System.err.println("默认方法, 消息内容:" + new String(messageBody)); + } + + public void consumeMessage(byte[] messageBody) { + System.err.println("字节数组方法, 消息内容:" + new String(messageBody)); + } + + + public void consumeMessage(String messageBody) { + System.err.println("字符串方法, 消息内容:" + messageBody); + } + + + public void method1(String messageBody) { + System.err.println("method1 收到消息内容:" + new String(messageBody)); + } + + public void method2(String messageBody) { + System.err.println("method2 收到消息内容:" + new String(messageBody)); + } + + // + // + //public void consumeMessage(Map messageBody) { + // System.err.println("map方法, 消息内容:" + messageBody); + //} + // + // + //public void consumeMessage(Order order) { + // System.err.println("order对象, 消息内容, id: " + order.getId() + + // ", name: " + order.getName() + + // ", content: " + order.getContent()); + //} + // + //public void consumeMessage(Packaged pack) { + // System.err.println("package对象, 消息内容, id: " + pack.getId() + + // ", name: " + pack.getName() + + // ", content: " + pack.getDescription()); + //} + // + //public void consumeMessage(File file) { + // System.err.println("文件对象 方法, 消息内容:" + file.getName()); + //} +} diff --git a/distributed/mq/rabbitmq/rabbitmq-spring/src/main/java/cn/lastwhisper/rabbitmq/config/RabbitMQConfig.java b/distributed/mq/rabbitmq/rabbitmq-spring/src/main/java/cn/lastwhisper/rabbitmq/config/RabbitMQConfig.java new file mode 100644 index 00000000..69e3fc50 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-spring/src/main/java/cn/lastwhisper/rabbitmq/config/RabbitMQConfig.java @@ -0,0 +1,243 @@ +package cn.lastwhisper.rabbitmq.config; + +import cn.lastwhisper.rabbitmq.adapter.MessageDelegate; +import cn.lastwhisper.rabbitmq.convert.ImageMessageConverter; +import cn.lastwhisper.rabbitmq.convert.PDFMessageConverter; +import cn.lastwhisper.rabbitmq.convert.TextMessageConverter; +import org.springframework.amqp.core.*; +import org.springframework.amqp.rabbit.connection.CachingConnectionFactory; +import org.springframework.amqp.rabbit.connection.ConnectionFactory; +import org.springframework.amqp.rabbit.core.RabbitAdmin; +import org.springframework.amqp.rabbit.core.RabbitTemplate; +import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer; +import org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter; +import org.springframework.amqp.support.ConsumerTagStrategy; +import org.springframework.amqp.support.converter.ContentTypeDelegatingMessageConverter; +import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +@Configuration +@ComponentScan({"cn.lastwhisper.rabbitmq.*"}) +public class RabbitMQConfig { + + /*-----------------------------------------RabbitAdmin---------------------------------------------*/ + + @Bean + public ConnectionFactory connectionFactory() { + CachingConnectionFactory connectionFactory = new CachingConnectionFactory(); + connectionFactory.setAddresses("192.168.217.101:5672"); + connectionFactory.setUsername("guest"); + connectionFactory.setPassword("guest"); + connectionFactory.setVirtualHost("/"); + return connectionFactory; + } + + @Bean + public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory) { + RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory); + rabbitAdmin.setAutoStartup(true); + return rabbitAdmin; + } + + /** + * 针对消费者配置 + * 1. 设置交换机类型 + * 2. 将队列绑定到交换机 + FanoutExchange: 将消息分发到所有的绑定队列,无routingkey的概念 + HeadersExchange :通过添加属性key-value匹配 + DirectExchange:按照routingkey分发到指定队列 + TopicExchange:多关键字匹配 + */ + @Bean + public TopicExchange exchange001() { + return new TopicExchange("topic001", true, false); + } + + @Bean + public Queue queue001() { + return new Queue("queue001", true); //队列持久 + } + + @Bean + public Binding binding001() { + return BindingBuilder.bind(queue001()).to(exchange001()).with("spring.*"); + } + + @Bean + public TopicExchange exchange002() { + return new TopicExchange("topic002", true, false); + } + + @Bean + public Queue queue002() { + return new Queue("queue002", true); //队列持久 + } + + @Bean + public Binding binding002() { + return BindingBuilder.bind(queue002()).to(exchange002()).with("rabbit.*"); + } + + @Bean + public Queue queue003() { + return new Queue("queue003", true); //队列持久 + } + + @Bean + public Binding binding003() { + return BindingBuilder.bind(queue003()).to(exchange001()).with("mq.*"); + } + + @Bean + public Queue queue_image() { + return new Queue("image_queue", true); //队列持久 + } + + @Bean + public Queue queue_pdf() { + return new Queue("pdf_queue", true); //队列持久 + } + + /*-----------------------------------------RabbitTemplate---------------------------------------------*/ + + @Bean + public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) { + return new RabbitTemplate(connectionFactory); + } + + /*-------------------------------------SimpleMessageListener---------------------------------------------*/ + + @Bean + public SimpleMessageListenerContainer messageContainer(ConnectionFactory connectionFactory) { + + SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory); + container.setQueues(queue001(), queue002(), queue003(), queue_image(), queue_pdf()); + container.setConcurrentConsumers(1); + container.setMaxConcurrentConsumers(5); + container.setDefaultRequeueRejected(false); + container.setAcknowledgeMode(AcknowledgeMode.AUTO); + container.setExposeListenerChannel(true); + container.setConsumerTagStrategy(new ConsumerTagStrategy() { + @Override + public String createConsumerTag(String queue) { + return queue + "_" + UUID.randomUUID().toString(); + } + }); + /** + container.setMessageListener(new ChannelAwareMessageListener() { + @Override public void onMessage(Message message, Channel channel) throws Exception { + String msg = new String(message.getBody()); + System.err.println("----------消费者: " + msg); + } + }); + */ + + /** + * 1 适配器方式. 默认是有自己的方法名字的:handleMessage + * 可以自己指定一个方法的名字: consumeMessage + * 也可以添加一个转换器: 从字节数组转换为String + */ + //MessageListenerAdapter adapter = new MessageListenerAdapter(new MessageDelegate()); + //adapter.setDefaultListenerMethod("consumeMessage"); + //// testSendMessage4Text + //adapter.setMessageConverter(new TextMessageConverter()); + //container.setMessageListener(adapter); + + /** + * 2 适配器方式: 我们的队列名称 和 方法名称 也可以进行一一的匹配 + **/ + //MessageListenerAdapter adapter = new MessageListenerAdapter(new MessageDelegate()); + //adapter.setMessageConverter(new TextMessageConverter()); + //Map queueOrTagToMethodName = new HashMap<>(); + //queueOrTagToMethodName.put("queue001", "method1"); + //queueOrTagToMethodName.put("queue002", "method2"); + //adapter.setQueueOrTagToMethodName(queueOrTagToMethodName); + //container.setMessageListener(adapter); + + + // 1.1 支持json格式的转换器 + /** + MessageListenerAdapter adapter = new MessageListenerAdapter(new MessageDelegate()); + adapter.setDefaultListenerMethod("consumeMessage"); + + Jackson2JsonMessageConverter jackson2JsonMessageConverter = new Jackson2JsonMessageConverter(); + adapter.setMessageConverter(jackson2JsonMessageConverter); + + container.setMessageListener(adapter); + */ + + + + // 1.2 DefaultJackson2JavaTypeMapper & Jackson2JsonMessageConverter 支持java对象转换 + /** + MessageListenerAdapter adapter = new MessageListenerAdapter(new MessageDelegate()); + adapter.setDefaultListenerMethod("consumeMessage"); + + Jackson2JsonMessageConverter jackson2JsonMessageConverter = new Jackson2JsonMessageConverter(); + + DefaultJackson2JavaTypeMapper javaTypeMapper = new DefaultJackson2JavaTypeMapper(); + jackson2JsonMessageConverter.setJavaTypeMapper(javaTypeMapper); + + adapter.setMessageConverter(jackson2JsonMessageConverter); + container.setMessageListener(adapter); + */ + + + //1.3 DefaultJackson2JavaTypeMapper & Jackson2JsonMessageConverter 支持java对象多映射转换 + /** + MessageListenerAdapter adapter = new MessageListenerAdapter(new MessageDelegate()); + adapter.setDefaultListenerMethod("consumeMessage"); + Jackson2JsonMessageConverter jackson2JsonMessageConverter = new Jackson2JsonMessageConverter(); + DefaultJackson2JavaTypeMapper javaTypeMapper = new DefaultJackson2JavaTypeMapper(); + + Map> idClassMapping = new HashMap>(); + idClassMapping.put("order", com.bfxy.spring.entity.Order.class); + idClassMapping.put("packaged", com.bfxy.spring.entity.Packaged.class); + + javaTypeMapper.setIdClassMapping(idClassMapping); + + jackson2JsonMessageConverter.setJavaTypeMapper(javaTypeMapper); + adapter.setMessageConverter(jackson2JsonMessageConverter); + container.setMessageListener(adapter); + */ + + //1.4 ext convert + + MessageListenerAdapter adapter = new MessageListenerAdapter(new MessageDelegate()); + adapter.setDefaultListenerMethod("consumeMessage"); + + //全局的转换器: + ContentTypeDelegatingMessageConverter convert = new ContentTypeDelegatingMessageConverter(); + + TextMessageConverter textConvert = new TextMessageConverter(); + convert.addDelegate("text", textConvert); + convert.addDelegate("html/text", textConvert); + convert.addDelegate("xml/text", textConvert); + convert.addDelegate("text/plain", textConvert); + + Jackson2JsonMessageConverter jsonConvert = new Jackson2JsonMessageConverter(); + convert.addDelegate("json", jsonConvert); + convert.addDelegate("application/json", jsonConvert); + + ImageMessageConverter imageConverter = new ImageMessageConverter(); + convert.addDelegate("image/png", imageConverter); + convert.addDelegate("image", imageConverter); + + PDFMessageConverter pdfConverter = new PDFMessageConverter(); + convert.addDelegate("application/pdf", pdfConverter); + + + adapter.setMessageConverter(convert); + container.setMessageListener(adapter); + + return container; + + } + +} \ No newline at end of file diff --git a/distributed/mq/rabbitmq/rabbitmq-spring/src/main/java/cn/lastwhisper/rabbitmq/convert/ConverterBody.java b/distributed/mq/rabbitmq/rabbitmq-spring/src/main/java/cn/lastwhisper/rabbitmq/convert/ConverterBody.java new file mode 100644 index 00000000..0656f8dc --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-spring/src/main/java/cn/lastwhisper/rabbitmq/convert/ConverterBody.java @@ -0,0 +1,22 @@ +package cn.lastwhisper.rabbitmq.convert; + +public class ConverterBody { + + private byte[] body; + + public ConverterBody() { + } + + public ConverterBody(byte[] body) { + this.body = body; + } + + public byte[] getBody() { + return body; + } + + public void setBody(byte[] body) { + this.body = body; + } + +} diff --git a/distributed/mq/rabbitmq/rabbitmq-spring/src/main/java/cn/lastwhisper/rabbitmq/convert/ImageMessageConverter.java b/distributed/mq/rabbitmq/rabbitmq-spring/src/main/java/cn/lastwhisper/rabbitmq/convert/ImageMessageConverter.java new file mode 100644 index 00000000..c6081caf --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-spring/src/main/java/cn/lastwhisper/rabbitmq/convert/ImageMessageConverter.java @@ -0,0 +1,40 @@ +package cn.lastwhisper.rabbitmq.convert; + +import org.springframework.amqp.core.Message; +import org.springframework.amqp.core.MessageProperties; +import org.springframework.amqp.support.converter.MessageConversionException; +import org.springframework.amqp.support.converter.MessageConverter; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.UUID; + +public class ImageMessageConverter implements MessageConverter { + + @Override + public Message toMessage(Object object, MessageProperties messageProperties) throws MessageConversionException { + throw new MessageConversionException(" convert error ! "); + } + + @Override + public Object fromMessage(Message message) throws MessageConversionException { + System.err.println("-----------Image MessageConverter----------"); + + Object _extName = message.getMessageProperties().getHeaders().get("extName"); + String extName = _extName == null ? "png" : _extName.toString(); + + byte[] body = message.getBody(); + String fileName = UUID.randomUUID().toString(); + String path = "d:/010_test/" + fileName + "." + extName; + File f = new File(path); + try { + Files.copy(new ByteArrayInputStream(body), f.toPath()); + } catch (IOException e) { + e.printStackTrace(); + } + return f; + } + +} diff --git a/distributed/mq/rabbitmq/rabbitmq-spring/src/main/java/cn/lastwhisper/rabbitmq/convert/PDFMessageConverter.java b/distributed/mq/rabbitmq/rabbitmq-spring/src/main/java/cn/lastwhisper/rabbitmq/convert/PDFMessageConverter.java new file mode 100644 index 00000000..14e0c849 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-spring/src/main/java/cn/lastwhisper/rabbitmq/convert/PDFMessageConverter.java @@ -0,0 +1,37 @@ +package cn.lastwhisper.rabbitmq.convert; + +import org.springframework.amqp.core.Message; +import org.springframework.amqp.core.MessageProperties; +import org.springframework.amqp.support.converter.MessageConversionException; +import org.springframework.amqp.support.converter.MessageConverter; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.UUID; + +public class PDFMessageConverter implements MessageConverter { + + @Override + public Message toMessage(Object object, MessageProperties messageProperties) throws MessageConversionException { + throw new MessageConversionException(" convert error ! "); + } + + @Override + public Object fromMessage(Message message) throws MessageConversionException { + System.err.println("-----------PDF MessageConverter----------"); + + byte[] body = message.getBody(); + String fileName = UUID.randomUUID().toString(); + String path = "d:/010_test/" + fileName + ".pdf"; + File f = new File(path); + try { + Files.copy(new ByteArrayInputStream(body), f.toPath()); + } catch (IOException e) { + e.printStackTrace(); + } + return f; + } + +} diff --git a/distributed/mq/rabbitmq/rabbitmq-spring/src/main/java/cn/lastwhisper/rabbitmq/convert/TextMessageConverter.java b/distributed/mq/rabbitmq/rabbitmq-spring/src/main/java/cn/lastwhisper/rabbitmq/convert/TextMessageConverter.java new file mode 100644 index 00000000..f27664d9 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-spring/src/main/java/cn/lastwhisper/rabbitmq/convert/TextMessageConverter.java @@ -0,0 +1,25 @@ +package cn.lastwhisper.rabbitmq.convert; + +import org.springframework.amqp.core.Message; +import org.springframework.amqp.core.MessageProperties; +import org.springframework.amqp.support.converter.MessageConversionException; +import org.springframework.amqp.support.converter.MessageConverter; + +public class TextMessageConverter implements MessageConverter { + + @Override + public Message toMessage(Object object, MessageProperties messageProperties) throws MessageConversionException { + return new Message(object.toString().getBytes(), messageProperties); + } + + @Override + public Object fromMessage(Message message) throws MessageConversionException { + String contentType = message.getMessageProperties().getContentType(); + // testSendMessage4Text + if(null != contentType && contentType.contains("text")) { + return new String(message.getBody()); + } + return message.getBody(); + } + +} diff --git a/distributed/mq/rabbitmq/rabbitmq-spring/src/main/java/cn/lastwhisper/rabbitmq/entity/Order.java b/distributed/mq/rabbitmq/rabbitmq-spring/src/main/java/cn/lastwhisper/rabbitmq/entity/Order.java new file mode 100644 index 00000000..959ed8bd --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-spring/src/main/java/cn/lastwhisper/rabbitmq/entity/Order.java @@ -0,0 +1,44 @@ +package cn.lastwhisper.rabbitmq.entity; + +public class Order { + + private String id; + + private String name; + + private String content; + + public Order() { + } + + public Order(String id, String name, String content) { + this.id = id; + this.name = name; + this.content = content; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + +} diff --git a/distributed/mq/rabbitmq/rabbitmq-spring/src/main/java/cn/lastwhisper/rabbitmq/entity/Packaged.java b/distributed/mq/rabbitmq/rabbitmq-spring/src/main/java/cn/lastwhisper/rabbitmq/entity/Packaged.java new file mode 100644 index 00000000..8b32fd59 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-spring/src/main/java/cn/lastwhisper/rabbitmq/entity/Packaged.java @@ -0,0 +1,45 @@ +package cn.lastwhisper.rabbitmq.entity; + +public class Packaged { + + private String id; + + private String name; + + private String description; + + public Packaged() { + } + + public Packaged(String id, String name, String description) { + this.id = id; + this.name = name; + this.description = description; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + +} diff --git a/springboot-aop/principle/src/main/resources/application.properties b/distributed/mq/rabbitmq/rabbitmq-spring/src/main/resources/application.properties similarity index 100% rename from springboot-aop/principle/src/main/resources/application.properties rename to distributed/mq/rabbitmq/rabbitmq-spring/src/main/resources/application.properties diff --git a/distributed/mq/rabbitmq/rabbitmq-spring/src/test/java/cn/lastwhisper/rabbitmq/ApplicationTests.java b/distributed/mq/rabbitmq/rabbitmq-spring/src/test/java/cn/lastwhisper/rabbitmq/ApplicationTests.java new file mode 100644 index 00000000..cdd841d5 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-spring/src/test/java/cn/lastwhisper/rabbitmq/ApplicationTests.java @@ -0,0 +1,204 @@ +package cn.lastwhisper.rabbitmq; + +import cn.lastwhisper.rabbitmq.entity.Order; +import cn.lastwhisper.rabbitmq.entity.Packaged; +import org.junit.jupiter.api.Test; +import org.springframework.amqp.AmqpException; +import org.springframework.amqp.core.*; +import org.springframework.amqp.rabbit.core.RabbitAdmin; +import org.springframework.amqp.rabbit.core.RabbitTemplate; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.HashMap; + +import com.fasterxml.jackson.databind.ObjectMapper; + + +@SpringBootTest +class ApplicationTests { + + @Autowired + private RabbitAdmin rabbitAdmin; + + @Test + public void contextLoads() { + } + + @Test + public void testAdmin() throws Exception { + rabbitAdmin.declareExchange(new DirectExchange("test.direct", false, false)); + + rabbitAdmin.declareExchange(new TopicExchange("test.topic", false, false)); + + rabbitAdmin.declareExchange(new FanoutExchange("test.fanout", false, false)); + + rabbitAdmin.declareQueue(new Queue("test.direct.queue", false)); + + rabbitAdmin.declareQueue(new Queue("test.topic.queue", false)); + + rabbitAdmin.declareQueue(new Queue("test.fanout.queue", false)); + + + rabbitAdmin.declareBinding(new Binding("test.direct.queue", + Binding.DestinationType.QUEUE, + "test.direct", "direct", new HashMap<>())); + + rabbitAdmin.declareBinding( + BindingBuilder + .bind(new Queue("test.topic.queue", false)) //直接创建队列 + .to(new TopicExchange("test.topic", false, false)) //直接创建交换机 建立关联关系 + .with("user.#")); //指定路由Key + + + rabbitAdmin.declareBinding( + BindingBuilder + .bind(new Queue("test.fanout.queue", false)) + .to(new FanoutExchange("test.fanout", false, false))); + + //清空队列数据 + rabbitAdmin.purgeQueue("test.topic.queue", false); + } + + + @Autowired + private RabbitTemplate rabbitTemplate; + + + @Test + public void testSendMessage() throws Exception { + //1 创建消息 + MessageProperties messageProperties = new MessageProperties(); + messageProperties.getHeaders().put("desc", "信息描述.."); + messageProperties.getHeaders().put("type", "自定义消息类型.."); + Message message = new Message("Hello RabbitMQ".getBytes(), messageProperties); + + rabbitTemplate.convertAndSend("topic001", "spring.amqp", message, new MessagePostProcessor() { + @Override + public Message postProcessMessage(Message message) throws AmqpException { + System.err.println("------添加额外的设置---------"); + message.getMessageProperties().getHeaders().put("desc", "额外修改的信息描述"); + message.getMessageProperties().getHeaders().put("attr", "额外新加的属性"); + return message; + } + }); + } + + @Test + public void testSendMessage2() throws Exception { + //1 创建消息 + MessageProperties messageProperties = new MessageProperties(); + messageProperties.setContentType("text/plain"); + Message message = new Message("mq 消息1234".getBytes(), messageProperties); + + rabbitTemplate.send("topic001", "spring.abc", message); + + rabbitTemplate.convertAndSend("topic001", "spring.amqp", "hello object message send!"); + rabbitTemplate.convertAndSend("topic002", "rabbit.abc", "hello object message send!"); + } + + @Test + public void testSendMessage4Text() throws Exception { + //1 创建消息 + MessageProperties messageProperties = new MessageProperties(); + messageProperties.setContentType("text/plain"); + Message message = new Message("mq 消息1234".getBytes(), messageProperties); + + rabbitTemplate.send("topic001", "spring.abc", message); + rabbitTemplate.send("topic002", "rabbit.abc", message); + } + + @Test + public void testSendJsonMessage() throws Exception { + + Order order = new Order(); + order.setId("001"); + order.setName("消息订单"); + order.setContent("描述信息"); + ObjectMapper mapper = new ObjectMapper(); + String json = mapper.writeValueAsString(order); + System.err.println("order 4 json: " + json); + + MessageProperties messageProperties = new MessageProperties(); + //这里注意一定要修改contentType为 application/json + messageProperties.setContentType("application/json"); + Message message = new Message(json.getBytes(), messageProperties); + + rabbitTemplate.send("topic001", "spring.order", message); + } + + @Test + public void testSendJavaMessage() throws Exception { + + Order order = new Order(); + order.setId("001"); + order.setName("订单消息"); + order.setContent("订单描述信息"); + ObjectMapper mapper = new ObjectMapper(); + String json = mapper.writeValueAsString(order); + System.err.println("order 4 json: " + json); + + MessageProperties messageProperties = new MessageProperties(); + //这里注意一定要修改contentType为 application/json + messageProperties.setContentType("application/json"); + messageProperties.getHeaders().put("__TypeId__", "com.bfxy.spring.entity.Order"); + Message message = new Message(json.getBytes(), messageProperties); + + rabbitTemplate.send("topic001", "spring.order", message); + } + + @Test + public void testSendMappingMessage() throws Exception { + + ObjectMapper mapper = new ObjectMapper(); + + Order order = new Order(); + order.setId("001"); + order.setName("订单消息"); + order.setContent("订单描述信息"); + + String json1 = mapper.writeValueAsString(order); + System.err.println("order 4 json: " + json1); + + MessageProperties messageProperties1 = new MessageProperties(); + //这里注意一定要修改contentType为 application/json + messageProperties1.setContentType("application/json"); + messageProperties1.getHeaders().put("__TypeId__", "order"); + Message message1 = new Message(json1.getBytes(), messageProperties1); + rabbitTemplate.send("topic001", "spring.order", message1); + + Packaged pack = new Packaged(); + pack.setId("002"); + pack.setName("包裹消息"); + pack.setDescription("包裹描述信息"); + + String json2 = mapper.writeValueAsString(pack); + System.err.println("pack 4 json: " + json2); + + MessageProperties messageProperties2 = new MessageProperties(); + //这里注意一定要修改contentType为 application/json + messageProperties2.setContentType("application/json"); + messageProperties2.getHeaders().put("__TypeId__", "packaged"); + Message message2 = new Message(json2.getBytes(), messageProperties2); + rabbitTemplate.send("topic001", "spring.pack", message2); + } + + @Test + public void testSendExtConverterMessage() throws Exception { +// byte[] body = Files.readAllBytes(Paths.get("d:/002_books", "picture.png")); +// MessageProperties messageProperties = new MessageProperties(); +// messageProperties.setContentType("image/png"); +// messageProperties.getHeaders().put("extName", "png"); +// Message message = new Message(body, messageProperties); +// rabbitTemplate.send("", "image_queue", message); + + byte[] body = Files.readAllBytes(Paths.get("d:/002_books", "mysql.pdf")); + MessageProperties messageProperties = new MessageProperties(); + messageProperties.setContentType("application/pdf"); + Message message = new Message(body, messageProperties); + rabbitTemplate.send("", "pdf_queue", message); + } + +} diff --git a/distributed/mq/rabbitmq/rabbitmq-springboot-consumer/pom.xml b/distributed/mq/rabbitmq/rabbitmq-springboot-consumer/pom.xml new file mode 100644 index 00000000..0ddaf7fa --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-springboot-consumer/pom.xml @@ -0,0 +1,54 @@ + + + 4.0.0 + + com.bfxy + rabbitmq-springboot-consumer + 0.0.1-SNAPSHOT + jar + + rabbitmq-springboot-consumer + rabbitmq-springboot-consumer + + + org.springframework.boot + spring-boot-starter-parent + 2.0.2.RELEASE + + + + + UTF-8 + UTF-8 + 1.8 + + + + + org.springframework.boot + spring-boot-starter + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.boot + spring-boot-starter-amqp + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + diff --git a/distributed/mq/rabbitmq/rabbitmq-springboot-consumer/src/main/java/com/bfxy/springboot/Application.java b/distributed/mq/rabbitmq/rabbitmq-springboot-consumer/src/main/java/com/bfxy/springboot/Application.java new file mode 100644 index 00000000..b37bc319 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-springboot-consumer/src/main/java/com/bfxy/springboot/Application.java @@ -0,0 +1,12 @@ +package com.bfxy.springboot; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } +} diff --git a/distributed/mq/rabbitmq/rabbitmq-springboot-consumer/src/main/java/com/bfxy/springboot/MainConfig.java b/distributed/mq/rabbitmq/rabbitmq-springboot-consumer/src/main/java/com/bfxy/springboot/MainConfig.java new file mode 100644 index 00000000..634fe239 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-springboot-consumer/src/main/java/com/bfxy/springboot/MainConfig.java @@ -0,0 +1,10 @@ +package com.bfxy.springboot; + +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ComponentScan({"com.bfxy.springboot.*"}) +public class MainConfig { + +} diff --git a/distributed/mq/rabbitmq/rabbitmq-springboot-consumer/src/main/java/com/bfxy/springboot/conusmer/RabbitReceiver.java b/distributed/mq/rabbitmq/rabbitmq-springboot-consumer/src/main/java/com/bfxy/springboot/conusmer/RabbitReceiver.java new file mode 100644 index 00000000..4ac54499 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-springboot-consumer/src/main/java/com/bfxy/springboot/conusmer/RabbitReceiver.java @@ -0,0 +1,78 @@ +package com.bfxy.springboot.conusmer; + +import java.util.Map; + +import org.springframework.amqp.rabbit.annotation.Exchange; +import org.springframework.amqp.rabbit.annotation.Queue; +import org.springframework.amqp.rabbit.annotation.QueueBinding; +import org.springframework.amqp.rabbit.annotation.RabbitHandler; +import org.springframework.amqp.rabbit.annotation.RabbitListener; +import org.springframework.amqp.support.AmqpHeaders; +import org.springframework.messaging.Message; +import org.springframework.messaging.handler.annotation.Headers; +import org.springframework.messaging.handler.annotation.Payload; +import org.springframework.stereotype.Component; + +import com.rabbitmq.client.Channel; + +@Component +public class RabbitReceiver { + + + @RabbitListener(bindings = @QueueBinding( + value = @Queue(value = "queue-1", + durable="true"), + exchange = @Exchange(value = "exchange-1", + durable="true", + type= "topic", + ignoreDeclarationExceptions = "true"), + key = "springboot.*" + ) + ) + @RabbitHandler + public void onMessage(Message message, Channel channel) throws Exception { + System.err.println("--------------------------------------"); + System.err.println("消费端Payload: " + message.getPayload()); + Long deliveryTag = (Long)message.getHeaders().get(AmqpHeaders.DELIVERY_TAG); + //手工ACK + channel.basicAck(deliveryTag, false); + } + + + /** + * + * spring.rabbitmq.listener.order.queue.name=queue-2 + spring.rabbitmq.listener.order.queue.durable=true + spring.rabbitmq.listener.order.exchange.name=exchange-1 + spring.rabbitmq.listener.order.exchange.durable=true + spring.rabbitmq.listener.order.exchange.type=topic + spring.rabbitmq.listener.order.exchange.ignoreDeclarationExceptions=true + spring.rabbitmq.listener.order.key=springboot.* + * @param order + * @param channel + * @param headers + * @throws Exception + */ + @RabbitListener(bindings = @QueueBinding( + value = @Queue(value = "${spring.rabbitmq.listener.order.queue.name}", + durable="${spring.rabbitmq.listener.order.queue.durable}"), + exchange = @Exchange(value = "${spring.rabbitmq.listener.order.exchange.name}", + durable="${spring.rabbitmq.listener.order.exchange.durable}", + type= "${spring.rabbitmq.listener.order.exchange.type}", + ignoreDeclarationExceptions = "${spring.rabbitmq.listener.order.exchange.ignoreDeclarationExceptions}"), + key = "${spring.rabbitmq.listener.order.key}" + ) + ) + @RabbitHandler + public void onOrderMessage(@Payload com.bfxy.springboot.entity.Order order, + Channel channel, + @Headers Map headers) throws Exception { + System.err.println("--------------------------------------"); + System.err.println("消费端order: " + order.getId()); + Long deliveryTag = (Long)headers.get(AmqpHeaders.DELIVERY_TAG); + //手工ACK + channel.basicAck(deliveryTag, false); + } + + +} diff --git a/distributed/mq/rabbitmq/rabbitmq-springboot-consumer/src/main/java/com/bfxy/springboot/entity/Order.java b/distributed/mq/rabbitmq/rabbitmq-springboot-consumer/src/main/java/com/bfxy/springboot/entity/Order.java new file mode 100644 index 00000000..caecc808 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-springboot-consumer/src/main/java/com/bfxy/springboot/entity/Order.java @@ -0,0 +1,36 @@ +package com.bfxy.springboot.entity; + +import java.io.Serializable; + +public class Order implements Serializable { + + private String id; + private String name; + + public Order() { + } + + public Order(String id, String name) { + super(); + this.id = id; + this.name = name; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + +} diff --git a/distributed/mq/rabbitmq/rabbitmq-springboot-consumer/src/main/resources/application.properties b/distributed/mq/rabbitmq/rabbitmq-springboot-consumer/src/main/resources/application.properties new file mode 100644 index 00000000..2db9bf4f --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-springboot-consumer/src/main/resources/application.properties @@ -0,0 +1,19 @@ +spring.rabbitmq.addresses=192.168.11.76:5672 +spring.rabbitmq.username=guest +spring.rabbitmq.password=guest +spring.rabbitmq.virtual-host=/ +spring.rabbitmq.connection-timeout=15000 + +# ֹǩ +spring.rabbitmq.listener.simple.acknowledge-mode=manual +# +spring.rabbitmq.listener.simple.concurrency=5 +spring.rabbitmq.listener.simple.max-concurrency=10 + +spring.rabbitmq.listener.order.queue.name=queue-2 +spring.rabbitmq.listener.order.queue.durable=true +spring.rabbitmq.listener.order.exchange.name=exchange-2 +spring.rabbitmq.listener.order.exchange.durable=true +spring.rabbitmq.listener.order.exchange.type=topic +spring.rabbitmq.listener.order.exchange.ignoreDeclarationExceptions=true +spring.rabbitmq.listener.order.key=springboot.* \ No newline at end of file diff --git a/distributed/mq/rabbitmq/rabbitmq-springboot-consumer/src/test/java/com/bfxy/springboot/ApplicationTests.java b/distributed/mq/rabbitmq/rabbitmq-springboot-consumer/src/test/java/com/bfxy/springboot/ApplicationTests.java new file mode 100644 index 00000000..2b24c504 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-springboot-consumer/src/test/java/com/bfxy/springboot/ApplicationTests.java @@ -0,0 +1,16 @@ +package com.bfxy.springboot; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@SpringBootTest +public class ApplicationTests { + + @Test + public void contextLoads() { + } + +} diff --git a/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/docs/test.sql b/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/docs/test.sql new file mode 100644 index 00000000..9122a3ce --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/docs/test.sql @@ -0,0 +1,19 @@ +-- 表 order 订单结构 +CREATE TABLE IF NOT EXISTS `t_order` ( + `id` varchar(128) NOT NULL, -- 订单ID + `name` varchar(128), -- 订单名称 其他业务熟悉忽略 + `message_id` varchar(128) NOT NULL, -- 消息唯一ID + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- 表 broker_message_log 消息记录结构 +CREATE TABLE IF NOT EXISTS `broker_message_log` ( + `message_id` varchar(128) NOT NULL, -- 消息唯一ID + `message` varchar(4000) DEFAULT NULL, -- 消息内容 + `try_count` int(4) DEFAULT '0', -- 重试次数 + `status` varchar(10) DEFAULT '', -- 消息投递状态 0 投递中 1 投递成功 2 投递失败 + `next_retry` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', --下一次重试时间 或 超时时间 + `create_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', --创建时间 + `update_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', --更新时间 + PRIMARY KEY (`message_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; \ No newline at end of file diff --git a/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/pom.xml b/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/pom.xml new file mode 100644 index 00000000..5420ca08 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/pom.xml @@ -0,0 +1,112 @@ + + + 4.0.0 + + com.bfxy + rabbitmq-springboot-producer-reliable + 0.0.1-SNAPSHOT + jar + + rabbitmq-springboot-producer-reliable + rabbitmq-springboot-producer-reliable + + + org.springframework.boot + spring-boot-starter-parent + 2.0.2.RELEASE + + + + + UTF-8 + UTF-8 + 1.8 + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-test + test + + + + org.springframework.boot + spring-boot-starter-amqp + + + + + org.mybatis.spring.boot + mybatis-spring-boot-starter + 1.1.1 + + + tk.mybatis + mapper-spring-boot-starter + 1.1.0 + + + com.alibaba + druid + 1.0.24 + + + mysql + mysql-connector-java + + + + com.github.miemiedev + mybatis-paginator + 1.2.17 + + + org.mybatis + mybatis + + + + + org.apache.commons + commons-lang3 + + + commons-io + commons-io + 2.4 + + + com.alibaba + fastjson + 1.1.26 + + + javax.servlet + javax.servlet-api + provided + + + log4j + log4j + 1.2.17 + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + diff --git a/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/main/java/com/bfxy/springboot/Application.java b/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/main/java/com/bfxy/springboot/Application.java new file mode 100644 index 00000000..b37bc319 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/main/java/com/bfxy/springboot/Application.java @@ -0,0 +1,12 @@ +package com.bfxy.springboot; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } +} diff --git a/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/main/java/com/bfxy/springboot/MainConfig.java b/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/main/java/com/bfxy/springboot/MainConfig.java new file mode 100644 index 00000000..634fe239 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/main/java/com/bfxy/springboot/MainConfig.java @@ -0,0 +1,10 @@ +package com.bfxy.springboot; + +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ComponentScan({"com.bfxy.springboot.*"}) +public class MainConfig { + +} diff --git a/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/main/java/com/bfxy/springboot/config/database/BaseMapper.java b/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/main/java/com/bfxy/springboot/config/database/BaseMapper.java new file mode 100644 index 00000000..18de13ee --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/main/java/com/bfxy/springboot/config/database/BaseMapper.java @@ -0,0 +1,8 @@ +package com.bfxy.springboot.config.database; + +import tk.mybatis.mapper.common.Mapper; +import tk.mybatis.mapper.common.MySqlMapper; + +public interface BaseMapper extends Mapper, MySqlMapper { + +} diff --git a/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/main/java/com/bfxy/springboot/config/database/DruidDataSourceConfig.java b/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/main/java/com/bfxy/springboot/config/database/DruidDataSourceConfig.java new file mode 100644 index 00000000..5fab0e74 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/main/java/com/bfxy/springboot/config/database/DruidDataSourceConfig.java @@ -0,0 +1,70 @@ +package com.bfxy.springboot.config.database; + + +import java.sql.SQLException; + +import javax.sql.DataSource; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; +import org.springframework.jdbc.datasource.DataSourceTransactionManager; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +import com.alibaba.druid.pool.DruidDataSource; + +@Configuration +@EnableTransactionManagement +public class DruidDataSourceConfig { + + private static Logger logger = LoggerFactory.getLogger(DruidDataSourceConfig.class); + + @Autowired + private DruidDataSourceSettings druidSettings; + + public static String DRIVER_CLASSNAME ; + + @Bean + public static PropertySourcesPlaceholderConfigurer propertyConfigure(){ + return new PropertySourcesPlaceholderConfigurer(); + } + + @Bean + public DataSource dataSource() throws SQLException { + DruidDataSource ds = new DruidDataSource(); + ds.setDriverClassName(druidSettings.getDriverClassName()); + DRIVER_CLASSNAME = druidSettings.getDriverClassName(); + ds.setUrl(druidSettings.getUrl()); + ds.setUsername(druidSettings.getUsername()); + ds.setPassword(druidSettings.getPassword()); + ds.setInitialSize(druidSettings.getInitialSize()); + ds.setMinIdle(druidSettings.getMinIdle()); + ds.setMaxActive(druidSettings.getMaxActive()); + ds.setTimeBetweenEvictionRunsMillis(druidSettings.getTimeBetweenEvictionRunsMillis()); + ds.setMinEvictableIdleTimeMillis(druidSettings.getMinEvictableIdleTimeMillis()); + ds.setValidationQuery(druidSettings.getValidationQuery()); + ds.setTestWhileIdle(druidSettings.isTestWhileIdle()); + ds.setTestOnBorrow(druidSettings.isTestOnBorrow()); + ds.setTestOnReturn(druidSettings.isTestOnReturn()); + ds.setPoolPreparedStatements(druidSettings.isPoolPreparedStatements()); + ds.setMaxPoolPreparedStatementPerConnectionSize(druidSettings.getMaxPoolPreparedStatementPerConnectionSize()); + ds.setFilters(druidSettings.getFilters()); + ds.setConnectionProperties(druidSettings.getConnectionProperties()); + logger.info(" druid datasource config : {} ", ds); + return ds; + } + + @Bean + public PlatformTransactionManager transactionManager() throws Exception { + DataSourceTransactionManager txManager = new DataSourceTransactionManager(); + txManager.setDataSource(dataSource()); + return txManager; + } + +} + + diff --git a/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/main/java/com/bfxy/springboot/config/database/DruidDataSourceSettings.java b/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/main/java/com/bfxy/springboot/config/database/DruidDataSourceSettings.java new file mode 100644 index 00000000..0d20637b --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/main/java/com/bfxy/springboot/config/database/DruidDataSourceSettings.java @@ -0,0 +1,169 @@ + +package com.bfxy.springboot.config.database; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.PropertySource; +import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; +import org.springframework.stereotype.Component; + +@Component +@ConfigurationProperties(prefix="spring.datasource") +@PropertySource("classpath:druid.properties") +public class DruidDataSourceSettings { + + private String driverClassName; + private String url; + private String username; + private String password; + + @Value("${druid.initialSize}") + private int initialSize; + + @Value("${druid.minIdle}") + private int minIdle; + + @Value("${druid.maxActive}") + private int maxActive; + + @Value("${druid.timeBetweenEvictionRunsMillis}") + private long timeBetweenEvictionRunsMillis; + + @Value("${druid.minEvictableIdleTimeMillis}") + private long minEvictableIdleTimeMillis; + + @Value("${druid.validationQuery}") + private String validationQuery; + + @Value("${druid.testWhileIdle}") + private boolean testWhileIdle; + + @Value("${druid.testOnBorrow}") + private boolean testOnBorrow; + + @Value("${druid.testOnReturn}") + private boolean testOnReturn; + + @Value("${druid.poolPreparedStatements}") + private boolean poolPreparedStatements; + + @Value("${druid.maxPoolPreparedStatementPerConnectionSize}") + private int maxPoolPreparedStatementPerConnectionSize; + + @Value("${druid.filters}") + private String filters; + + @Value("${druid.connectionProperties}") + private String connectionProperties; + + @Bean + public static PropertySourcesPlaceholderConfigurer properdtyConfigure(){ + return new PropertySourcesPlaceholderConfigurer(); + } + + public String getDriverClassName() { + return driverClassName; + } + public void setDriverClassName(String driverClassName) { + this.driverClassName = driverClassName; + } + public String getUrl() { + return url; + } + public void setUrl(String url) { + this.url = url; + } + public String getUsername() { + return username; + } + public void setUsername(String username) { + this.username = username; + } + public String getPassword() { + return password; + } + public void setPassword(String password) { + this.password = password; + } + public int getInitialSize() { + return initialSize; + } + public void setInitialSize(int initialSize) { + this.initialSize = initialSize; + } + public int getMinIdle() { + return minIdle; + } + public void setMinIdle(int minIdle) { + this.minIdle = minIdle; + } + public int getMaxActive() { + return maxActive; + } + public void setMaxActive(int maxActive) { + this.maxActive = maxActive; + } + public long getTimeBetweenEvictionRunsMillis() { + return timeBetweenEvictionRunsMillis; + } + public void setTimeBetweenEvictionRunsMillis(long timeBetweenEvictionRunsMillis) { + this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis; + } + public long getMinEvictableIdleTimeMillis() { + return minEvictableIdleTimeMillis; + } + public void setMinEvictableIdleTimeMillis(long minEvictableIdleTimeMillis) { + this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis; + } + public String getValidationQuery() { + return validationQuery; + } + public void setValidationQuery(String validationQuery) { + this.validationQuery = validationQuery; + } + public boolean isTestWhileIdle() { + return testWhileIdle; + } + public void setTestWhileIdle(boolean testWhileIdle) { + this.testWhileIdle = testWhileIdle; + } + public boolean isTestOnBorrow() { + return testOnBorrow; + } + public void setTestOnBorrow(boolean testOnBorrow) { + this.testOnBorrow = testOnBorrow; + } + public boolean isTestOnReturn() { + return testOnReturn; + } + public void setTestOnReturn(boolean testOnReturn) { + this.testOnReturn = testOnReturn; + } + public boolean isPoolPreparedStatements() { + return poolPreparedStatements; + } + public void setPoolPreparedStatements(boolean poolPreparedStatements) { + this.poolPreparedStatements = poolPreparedStatements; + } + public int getMaxPoolPreparedStatementPerConnectionSize() { + return maxPoolPreparedStatementPerConnectionSize; + } + public void setMaxPoolPreparedStatementPerConnectionSize( + int maxPoolPreparedStatementPerConnectionSize) { + this.maxPoolPreparedStatementPerConnectionSize = maxPoolPreparedStatementPerConnectionSize; + } + public String getFilters() { + return filters; + } + public void setFilters(String filters) { + this.filters = filters; + } + public String getConnectionProperties() { + return connectionProperties; + } + public void setConnectionProperties(String connectionProperties) { + this.connectionProperties = connectionProperties; + } + +} diff --git a/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/main/java/com/bfxy/springboot/config/database/MybatisDataSourceConfig.java b/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/main/java/com/bfxy/springboot/config/database/MybatisDataSourceConfig.java new file mode 100644 index 00000000..179f52e9 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/main/java/com/bfxy/springboot/config/database/MybatisDataSourceConfig.java @@ -0,0 +1,42 @@ +package com.bfxy.springboot.config.database; + +import javax.sql.DataSource; + +import org.apache.ibatis.session.SqlSessionFactory; +import org.mybatis.spring.SqlSessionFactoryBean; +import org.mybatis.spring.SqlSessionTemplate; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; +import org.springframework.core.io.support.ResourcePatternResolver; + +@Configuration +public class MybatisDataSourceConfig { + + @Autowired + private DataSource dataSource; + + @Bean(name="sqlSessionFactory") + public SqlSessionFactory sqlSessionFactoryBean() { + SqlSessionFactoryBean bean = new SqlSessionFactoryBean(); + bean.setDataSource(dataSource); + // 添加XML目录 + ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); + try { + bean.setMapperLocations(resolver.getResources("classpath:com/bfxy/springboot/mapping/*.xml")); + SqlSessionFactory sqlSessionFactory = bean.getObject(); + sqlSessionFactory.getConfiguration().setCacheEnabled(Boolean.TRUE); + + return sqlSessionFactory; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Bean + public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) { + return new SqlSessionTemplate(sqlSessionFactory); + } + +} diff --git a/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/main/java/com/bfxy/springboot/config/database/MybatisMapperScanerConfig.java b/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/main/java/com/bfxy/springboot/config/database/MybatisMapperScanerConfig.java new file mode 100644 index 00000000..98e3e95d --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/main/java/com/bfxy/springboot/config/database/MybatisMapperScanerConfig.java @@ -0,0 +1,21 @@ + +package com.bfxy.springboot.config.database; + +import org.mybatis.spring.mapper.MapperScannerConfigurer; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +@AutoConfigureAfter(MybatisDataSourceConfig.class) +public class MybatisMapperScanerConfig { + + @Bean + public MapperScannerConfigurer mapperScannerConfigurer() { + MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer(); + mapperScannerConfigurer.setSqlSessionFactoryBeanName("sqlSessionFactory"); + mapperScannerConfigurer.setBasePackage("com.bfxy.springboot.mapper"); + return mapperScannerConfigurer; + } + +} diff --git a/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/main/java/com/bfxy/springboot/config/task/TaskSchedulerConfig.java b/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/main/java/com/bfxy/springboot/config/task/TaskSchedulerConfig.java new file mode 100644 index 00000000..b3d3dc26 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/main/java/com/bfxy/springboot/config/task/TaskSchedulerConfig.java @@ -0,0 +1,26 @@ +package com.bfxy.springboot.config.task; + +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.scheduling.annotation.SchedulingConfigurer; +import org.springframework.scheduling.config.ScheduledTaskRegistrar; + +@Configuration +@EnableScheduling +public class TaskSchedulerConfig implements SchedulingConfigurer { + + @Override + public void configureTasks(ScheduledTaskRegistrar taskRegistrar) { + taskRegistrar.setScheduler(taskScheduler()); + } + + @Bean(destroyMethod="shutdown") + public Executor taskScheduler(){ + return Executors.newScheduledThreadPool(100); + } + +} diff --git a/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/main/java/com/bfxy/springboot/constant/Constants.java b/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/main/java/com/bfxy/springboot/constant/Constants.java new file mode 100644 index 00000000..c59fed24 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/main/java/com/bfxy/springboot/constant/Constants.java @@ -0,0 +1,12 @@ +package com.bfxy.springboot.constant; + +public final class Constants { + + public static final String ORDER_SENDING = "0"; + + public static final String ORDER_SEND_SUCCESS = "1"; + + public static final String ORDER_SEND_FAILURE = "2"; + + public static final int ORDER_TIMEOUT = 1; /*min*/ +} diff --git a/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/main/java/com/bfxy/springboot/entity/BrokerMessageLog.java b/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/main/java/com/bfxy/springboot/entity/BrokerMessageLog.java new file mode 100644 index 00000000..da668b9b --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/main/java/com/bfxy/springboot/entity/BrokerMessageLog.java @@ -0,0 +1,75 @@ +package com.bfxy.springboot.entity; + +import java.util.Date; + +public class BrokerMessageLog { + private String messageId; + + private String message; + + private Integer tryCount = 0; + + private String status; + + private Date nextRetry; + + private Date createTime; + + private Date updateTime; + + public String getMessageId() { + return messageId; + } + + public void setMessageId(String messageId) { + this.messageId = messageId == null ? null : messageId.trim(); + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message == null ? null : message.trim(); + } + + public Integer getTryCount() { + return tryCount; + } + + public void setTryCount(Integer tryCount) { + this.tryCount = tryCount; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status == null ? null : status.trim(); + } + + public Date getNextRetry() { + return nextRetry; + } + + public void setNextRetry(Date nextRetry) { + this.nextRetry = nextRetry; + } + + public Date getCreateTime() { + return createTime; + } + + public void setCreateTime(Date createTime) { + this.createTime = createTime; + } + + public Date getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(Date updateTime) { + this.updateTime = updateTime; + } +} \ No newline at end of file diff --git a/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/main/java/com/bfxy/springboot/entity/Order.java b/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/main/java/com/bfxy/springboot/entity/Order.java new file mode 100644 index 00000000..b12765c1 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/main/java/com/bfxy/springboot/entity/Order.java @@ -0,0 +1,38 @@ +package com.bfxy.springboot.entity; + +import java.io.Serializable; + +public class Order implements Serializable { + + private static final long serialVersionUID = 9111357402963030257L; + + private String id; + + private String name; + + private String messageId; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id == null ? null : id.trim(); + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name == null ? null : name.trim(); + } + + public String getMessageId() { + return messageId; + } + + public void setMessageId(String messageId) { + this.messageId = messageId == null ? null : messageId.trim(); + } +} \ No newline at end of file diff --git a/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/main/java/com/bfxy/springboot/mapper/BrokerMessageLogMapper.java b/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/main/java/com/bfxy/springboot/mapper/BrokerMessageLogMapper.java new file mode 100644 index 00000000..968ab6eb --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/main/java/com/bfxy/springboot/mapper/BrokerMessageLogMapper.java @@ -0,0 +1,45 @@ +package com.bfxy.springboot.mapper; + +import java.util.Date; +import java.util.List; + +import org.apache.ibatis.annotations.Param; + +import com.bfxy.springboot.entity.BrokerMessageLog; + +public interface BrokerMessageLogMapper { + int deleteByPrimaryKey(String messageId); + + int insert(BrokerMessageLog record); + + int insertSelective(BrokerMessageLog record); + + BrokerMessageLog selectByPrimaryKey(String messageId); + + int updateByPrimaryKeySelective(BrokerMessageLog record); + + int updateByPrimaryKey(BrokerMessageLog record); + + /** + * 查询消息状态为0(发送中) 且已经超时的消息集合 + * @return + */ + List query4StatusAndTimeoutMessage(); + + /** + * 重新发送统计count发送次数 +1 + * @param messageId + * @param updateTime + */ + void update4ReSend(@Param("messageId")String messageId, @Param("updateTime")Date updateTime); + /** + * 更新最终消息发送结果 成功 or 失败 + * @param messageId + * @param status + * @param updateTime + */ + void changeBrokerMessageLogStatus(@Param("messageId")String messageId, @Param("status")String status, @Param("updateTime")Date updateTime); + + + +} \ No newline at end of file diff --git a/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/main/java/com/bfxy/springboot/mapper/OrderMapper.java b/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/main/java/com/bfxy/springboot/mapper/OrderMapper.java new file mode 100644 index 00000000..0d17f02f --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/main/java/com/bfxy/springboot/mapper/OrderMapper.java @@ -0,0 +1,17 @@ +package com.bfxy.springboot.mapper; + +import com.bfxy.springboot.entity.Order; + +public interface OrderMapper { + int deleteByPrimaryKey(String id); + + int insert(Order record); + + int insertSelective(Order record); + + Order selectByPrimaryKey(String id); + + int updateByPrimaryKeySelective(Order record); + + int updateByPrimaryKey(Order record); +} \ No newline at end of file diff --git a/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/main/java/com/bfxy/springboot/mapping/BrokerMessageLogMapper.xml b/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/main/java/com/bfxy/springboot/mapping/BrokerMessageLogMapper.xml new file mode 100644 index 00000000..6eef542d --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/main/java/com/bfxy/springboot/mapping/BrokerMessageLogMapper.xml @@ -0,0 +1,151 @@ + + + + + + + + + + + + + + message_id, message, try_count, status, next_retry, create_time, update_time + + + + delete from broker_message_log + where message_id = #{messageId,jdbcType=VARCHAR} + + + insert into broker_message_log (message_id, message, try_count, + status, next_retry, create_time, + update_time) + values (#{messageId,jdbcType=VARCHAR}, #{message,jdbcType=VARCHAR}, #{tryCount,jdbcType=INTEGER}, + #{status,jdbcType=VARCHAR}, #{nextRetry,jdbcType=TIMESTAMP}, #{createTime,jdbcType=TIMESTAMP}, + #{updateTime,jdbcType=TIMESTAMP}) + + + insert into broker_message_log + + + message_id, + + + message, + + + try_count, + + + status, + + + next_retry, + + + create_time, + + + update_time, + + + + + #{messageId,jdbcType=VARCHAR}, + + + #{message,jdbcType=VARCHAR}, + + + #{tryCount,jdbcType=INTEGER}, + + + #{status,jdbcType=VARCHAR}, + + + #{nextRetry,jdbcType=TIMESTAMP}, + + + #{createTime,jdbcType=TIMESTAMP}, + + + #{updateTime,jdbcType=TIMESTAMP}, + + + + + update broker_message_log + + + message = #{message,jdbcType=VARCHAR}, + + + try_count = #{tryCount,jdbcType=INTEGER}, + + + status = #{status,jdbcType=VARCHAR}, + + + next_retry = #{nextRetry,jdbcType=TIMESTAMP}, + + + create_time = #{createTime,jdbcType=TIMESTAMP}, + + + update_time = #{updateTime,jdbcType=TIMESTAMP}, + + + where message_id = #{messageId,jdbcType=VARCHAR} + + + update broker_message_log + set message = #{message,jdbcType=VARCHAR}, + try_count = #{tryCount,jdbcType=INTEGER}, + status = #{status,jdbcType=VARCHAR}, + next_retry = #{nextRetry,jdbcType=TIMESTAMP}, + create_time = #{createTime,jdbcType=TIMESTAMP}, + update_time = #{updateTime,jdbcType=TIMESTAMP} + where message_id = #{messageId,jdbcType=VARCHAR} + + + + + + + + update broker_message_log bml + set bml.try_count = bml.try_count + 1, + bml.update_time = #{updateTime, jdbcType=TIMESTAMP} + where bml.message_id = #{messageId,jdbcType=VARCHAR} + + + + update broker_message_log bml + set bml.status = #{status,jdbcType=VARCHAR}, + bml.update_time = #{updateTime, jdbcType=TIMESTAMP} + where bml.message_id = #{messageId,jdbcType=VARCHAR} + + + + + + + + + + + \ No newline at end of file diff --git a/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/main/java/com/bfxy/springboot/mapping/OrderMapper.xml b/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/main/java/com/bfxy/springboot/mapping/OrderMapper.xml new file mode 100644 index 00000000..b294d557 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/main/java/com/bfxy/springboot/mapping/OrderMapper.xml @@ -0,0 +1,71 @@ + + + + + + + + + + id, name, message_id + + + + delete from t_order + where id = #{id,jdbcType=VARCHAR} + + + insert into t_order (id, name, message_id + ) + values (#{id,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR}, #{messageId,jdbcType=VARCHAR} + ) + + + insert into t_order + + + id, + + + name, + + + message_id, + + + + + #{id,jdbcType=VARCHAR}, + + + #{name,jdbcType=VARCHAR}, + + + #{messageId,jdbcType=VARCHAR}, + + + + + update t_order + + + name = #{name,jdbcType=VARCHAR}, + + + message_id = #{messageId,jdbcType=VARCHAR}, + + + where id = #{id,jdbcType=VARCHAR} + + + update t_order + set name = #{name,jdbcType=VARCHAR}, + message_id = #{messageId,jdbcType=VARCHAR} + where id = #{id,jdbcType=VARCHAR} + + \ No newline at end of file diff --git a/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/main/java/com/bfxy/springboot/producer/RabbitOrderSender.java b/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/main/java/com/bfxy/springboot/producer/RabbitOrderSender.java new file mode 100644 index 00000000..fd3e5c84 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/main/java/com/bfxy/springboot/producer/RabbitOrderSender.java @@ -0,0 +1,49 @@ +package com.bfxy.springboot.producer; + +import java.util.Date; + +import org.springframework.amqp.rabbit.core.RabbitTemplate; +import org.springframework.amqp.rabbit.core.RabbitTemplate.ConfirmCallback; +import org.springframework.amqp.rabbit.support.CorrelationData; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.bfxy.springboot.constant.Constants; +import com.bfxy.springboot.entity.Order; +import com.bfxy.springboot.mapper.BrokerMessageLogMapper; + +@Component +public class RabbitOrderSender { + + //自动注入RabbitTemplate模板类 + @Autowired + private RabbitTemplate rabbitTemplate; + + @Autowired + private BrokerMessageLogMapper brokerMessageLogMapper; + + //回调函数: confirm确认 + final ConfirmCallback confirmCallback = new RabbitTemplate.ConfirmCallback() { + @Override + public void confirm(CorrelationData correlationData, boolean ack, String cause) { + System.err.println("correlationData: " + correlationData); + String messageId = correlationData.getId(); + if(ack){ + //如果confirm返回成功 则进行更新 + brokerMessageLogMapper.changeBrokerMessageLogStatus(messageId, Constants.ORDER_SEND_SUCCESS, new Date()); + } else { + //失败则进行具体的后续操作:重试 或者补偿等手段 + System.err.println("异常处理..."); + } + } + }; + + //发送消息方法调用: 构建自定义对象消息 + public void sendOrder(Order order) throws Exception { + rabbitTemplate.setConfirmCallback(confirmCallback); + //消息唯一ID + CorrelationData correlationData = new CorrelationData(order.getMessageId()); + rabbitTemplate.convertAndSend("order-exchange11", "order.ABC", order, correlationData); + } + +} diff --git a/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/main/java/com/bfxy/springboot/producer/RabbitSender.java b/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/main/java/com/bfxy/springboot/producer/RabbitSender.java new file mode 100644 index 00000000..452c4829 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/main/java/com/bfxy/springboot/producer/RabbitSender.java @@ -0,0 +1,56 @@ +package com.bfxy.springboot.producer; + +import java.util.Map; + +import org.springframework.amqp.rabbit.core.RabbitTemplate; +import org.springframework.amqp.rabbit.core.RabbitTemplate.ConfirmCallback; +import org.springframework.amqp.rabbit.core.RabbitTemplate.ReturnCallback; +import org.springframework.amqp.rabbit.support.CorrelationData; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.messaging.Message; +import org.springframework.messaging.MessageHeaders; +import org.springframework.messaging.support.MessageBuilder; +import org.springframework.stereotype.Component; + +import com.bfxy.springboot.entity.Order; + +@Component +public class RabbitSender { + + //自动注入RabbitTemplate模板类 + @Autowired + private RabbitTemplate rabbitTemplate; + + //回调函数: confirm确认 + final ConfirmCallback confirmCallback = new RabbitTemplate.ConfirmCallback() { + @Override + public void confirm(CorrelationData correlationData, boolean ack, String cause) { + System.err.println("correlationData: " + correlationData); + System.err.println("ack: " + ack); + if(!ack){ + System.err.println("异常处理...."); + } + } + }; + //回调函数: return返回 + final ReturnCallback returnCallback = new RabbitTemplate.ReturnCallback() { + @Override + public void returnedMessage(org.springframework.amqp.core.Message message, int replyCode, String replyText, + String exchange, String routingKey) { + System.err.println("return exchange: " + exchange + ", routingKey: " + + routingKey + ", replyCode: " + replyCode + ", replyText: " + replyText); + } + }; + + //发送消息方法调用: 构建Message消息 + public void send(Object message, Map properties) throws Exception { + MessageHeaders mhs = new MessageHeaders(properties); + Message msg = MessageBuilder.createMessage(message, mhs); + rabbitTemplate.setConfirmCallback(confirmCallback); + rabbitTemplate.setReturnCallback(returnCallback); + //id + 时间戳 全局唯一 + CorrelationData correlationData = new CorrelationData("1234567890"); + rabbitTemplate.convertAndSend("exchange-1", "springboot.abc", msg, correlationData); + } + +} diff --git a/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/main/java/com/bfxy/springboot/service/OrderService.java b/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/main/java/com/bfxy/springboot/service/OrderService.java new file mode 100644 index 00000000..83fdcdc4 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/main/java/com/bfxy/springboot/service/OrderService.java @@ -0,0 +1,49 @@ +package com.bfxy.springboot.service; + +import java.util.Date; + +import org.apache.commons.lang3.time.DateUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.bfxy.springboot.constant.Constants; +import com.bfxy.springboot.entity.BrokerMessageLog; +import com.bfxy.springboot.entity.Order; +import com.bfxy.springboot.mapper.BrokerMessageLogMapper; +import com.bfxy.springboot.mapper.OrderMapper; +import com.bfxy.springboot.producer.RabbitOrderSender; +import com.bfxy.springboot.utils.FastJsonConvertUtil; + +@Service +public class OrderService { + + @Autowired + private OrderMapper orderMapper; + + @Autowired + private BrokerMessageLogMapper brokerMessageLogMapper; + + @Autowired + private RabbitOrderSender rabbitOrderSender; + + + public void createOrder(Order order) throws Exception { + // order current time + Date orderTime = new Date(); + // order insert + orderMapper.insert(order); + // log insert + BrokerMessageLog brokerMessageLog = new BrokerMessageLog(); + brokerMessageLog.setMessageId(order.getMessageId()); + //save order message as json + brokerMessageLog.setMessage(FastJsonConvertUtil.convertObjectToJSON(order)); + brokerMessageLog.setStatus("0"); + brokerMessageLog.setNextRetry(DateUtils.addMinutes(orderTime, Constants.ORDER_TIMEOUT)); + brokerMessageLog.setCreateTime(new Date()); + brokerMessageLog.setUpdateTime(new Date()); + brokerMessageLogMapper.insert(brokerMessageLog); + // order message sender + rabbitOrderSender.sendOrder(order); + } + +} diff --git a/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/main/java/com/bfxy/springboot/task/RetryMessageTasker.java b/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/main/java/com/bfxy/springboot/task/RetryMessageTasker.java new file mode 100644 index 00000000..db18bb54 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/main/java/com/bfxy/springboot/task/RetryMessageTasker.java @@ -0,0 +1,52 @@ +package com.bfxy.springboot.task; + +import java.util.Date; +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import com.bfxy.springboot.constant.Constants; +import com.bfxy.springboot.entity.BrokerMessageLog; +import com.bfxy.springboot.entity.Order; +import com.bfxy.springboot.mapper.BrokerMessageLogMapper; +import com.bfxy.springboot.producer.RabbitOrderSender; +import com.bfxy.springboot.utils.FastJsonConvertUtil; + +@Component +public class RetryMessageTasker { + + + @Autowired + private RabbitOrderSender rabbitOrderSender; + + @Autowired + private BrokerMessageLogMapper brokerMessageLogMapper; + + @Scheduled(initialDelay = 3000, fixedDelay = 10000) + public void reSend(){ + System.err.println("---------------定时任务开始---------------"); + //pull status = 0 and timeout message + List list = brokerMessageLogMapper.query4StatusAndTimeoutMessage(); + list.forEach(messageLog -> { + if(messageLog.getTryCount() >= 3){ + //update fail message + brokerMessageLogMapper.changeBrokerMessageLogStatus(messageLog.getMessageId(), Constants.ORDER_SEND_FAILURE, new Date()); + } else { + // resend + brokerMessageLogMapper.update4ReSend(messageLog.getMessageId(), new Date()); + Order reSendOrder = FastJsonConvertUtil.convertJSONToObject(messageLog.getMessage(), Order.class); + try { + rabbitOrderSender.sendOrder(reSendOrder); + } catch (Exception e) { + e.printStackTrace(); + System.err.println("-----------异常处理-----------"); + } + } + }); + + } + + +} diff --git a/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/main/java/com/bfxy/springboot/utils/FastJsonConvertUtil.java b/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/main/java/com/bfxy/springboot/utils/FastJsonConvertUtil.java new file mode 100644 index 00000000..46128fa2 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/main/java/com/bfxy/springboot/utils/FastJsonConvertUtil.java @@ -0,0 +1,142 @@ +package com.bfxy.springboot.utils; + +import java.util.ArrayList; +import java.util.List; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.serializer.SerializerFeature; + +/** + * 系统名称:通用平台
+ * 模块名称:通用平台-公共服务
+ * 中文类名:通用平台-公共服务-FastJsonConvert
+ * 概要说明:
+ * @author bhz + * @since 2016年10月10日 上午11:01:52 + */ +public class FastJsonConvertUtil { + + private static final SerializerFeature[] featuresWithNullValue = { SerializerFeature.WriteMapNullValue, SerializerFeature.WriteNullBooleanAsFalse, + SerializerFeature.WriteNullListAsEmpty, SerializerFeature.WriteNullNumberAsZero, SerializerFeature.WriteNullStringAsEmpty }; + + /** + * 方法名称:将JSON字符串转换为实体对象
+ * 概要说明:将JSON字符串转换为实体对象
+ * @param data JSON字符串 + * @param clzss 转换对象 + * @return T + */ + public static T convertJSONToObject(String data, Class clzss) { + try { + T t = JSON.parseObject(data, clzss); + return t; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + /** + * 方法名称:将JSONObject对象转换为实体对象
+ * 概要说明:将JSONObject对象转换为实体对象
+ * @param data JSONObject对象 + * @param clzss 转换对象 + * @return T + */ + public static T convertJSONToObject(JSONObject data, Class clzss) { + try { + T t = JSONObject.toJavaObject(data, clzss); + return t; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + /** + * 方法名称:将JSON字符串数组转为List集合对象
+ * 概要说明:将JSON字符串数组转为List集合对象
+ * @param data JSON字符串数组 + * @param clzss 转换对象 + * @return List集合对象 + */ + public static List convertJSONToArray(String data, Class clzss) { + try { + List t = JSON.parseArray(data, clzss); + return t; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + /** + * 方法名称:将List转为List集合对象
+ * 概要说明:将List转为List集合对象
+ * @param data List + * @param clzss 转换对象 + * @return List集合对象 + */ + public static List convertJSONToArray(List data, Class clzss) { + try { + List t = new ArrayList(); + for (JSONObject jsonObject : data) { + t.add(convertJSONToObject(jsonObject, clzss)); + } + return t; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + /** + * 方法名称:将对象转为JSON字符串
+ * 概要说明:将对象转为JSON字符串
+ * @param obj 任意对象 + * @return JSON字符串 + */ + public static String convertObjectToJSON(Object obj) { + try { + String text = JSON.toJSONString(obj); + return text; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + /** + * 方法名称:将对象转为JSONObject对象
+ * 概要说明:将对象转为JSONObject对象
+ * @param obj 任意对象 + * @return JSONObject对象 + */ + public static JSONObject convertObjectToJSONObject(Object obj){ + try { + JSONObject jsonObject = (JSONObject) JSONObject.toJSON(obj); + return jsonObject; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + + /** + * 方法名称:
+ * 概要说明:
+ * @param obj + * @return + */ + public static String convertObjectToJSONWithNullValue(Object obj) { + try { + String text = JSON.toJSONString(obj, featuresWithNullValue); + return text; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } +} diff --git a/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/main/resources/application.properties b/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/main/resources/application.properties new file mode 100644 index 00000000..b3aa64ba --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/main/resources/application.properties @@ -0,0 +1,28 @@ +spring.rabbitmq.addresses=192.168.11.76:5672 +spring.rabbitmq.username=guest +spring.rabbitmq.password=guest +spring.rabbitmq.virtual-host=/ +spring.rabbitmq.connection-timeout=15000 + +spring.rabbitmq.publisher-confirms=true +spring.rabbitmq.publisher-returns=true +spring.rabbitmq.template.mandatory=true + +server.servlet.context-path=/ +server.port=8001 + +spring.http.encoding.charset=UTF-8 +spring.jackson.date-format=yyyy-MM-dd HH:mm:ss +spring.jackson.time-zone=GMT+8 +spring.jackson.default-property-inclusion=NON_NULL + +spring.datasource.type=com.alibaba.druid.pool.DruidDataSource +spring.datasource.url=jdbc:mysql://localhost:3306/test?characterEncoding=UTF-8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&useUnicode=true +spring.datasource.driver-class-name=com.mysql.jdbc.Driver +spring.datasource.username=root +spring.datasource.password=root + +mybatis.type-aliases-package=com.bfxy.springboot +mybatis.mapper-locations=classpath:com/bfxy/springboot/mapping/*.xml + +logging.level.tk.mybatis=TRACE \ No newline at end of file diff --git a/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/main/resources/druid.properties b/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/main/resources/druid.properties new file mode 100644 index 00000000..34baf7e9 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/main/resources/druid.properties @@ -0,0 +1,26 @@ +##下面为连接池的补充设置,应用到上面所有数据源中 +#初始化大小,最小,最大 +druid.initialSize=5 +druid.minIdle=10 +druid.maxActive=300 +#配置获取连接等待超时的时间 +druid.maxWait=60000 +#配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 +druid.timeBetweenEvictionRunsMillis=60000 +#配置一个连接在池中最小生存的时间,单位是毫秒 +druid.minEvictableIdleTimeMillis=300000 +druid.validationQuery=SELECT 1 FROM DUAL +druid.testWhileIdle=true +druid.testOnBorrow=false +druid.testOnReturn=false +#打开PSCache,并且指定每个连接上PSCache的大小 +druid.poolPreparedStatements=true +druid.maxPoolPreparedStatementPerConnectionSize=20 +#配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙 +druid.filters=stat,wall,log4j +#通过connectProperties属性来打开mergeSql功能;慢SQL记录 +druid.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000 +#合并多个DruidDataSource的监控数据 +druid.useGlobalDataSourceStat=true + + diff --git a/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/test/java/com/bfxy/springboot/ApplicationTests.java b/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/test/java/com/bfxy/springboot/ApplicationTests.java new file mode 100644 index 00000000..38bdbcf9 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-springboot-producer-reliable/src/test/java/com/bfxy/springboot/ApplicationTests.java @@ -0,0 +1,72 @@ +package com.bfxy.springboot; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import com.bfxy.springboot.entity.Order; +import com.bfxy.springboot.producer.RabbitOrderSender; +import com.bfxy.springboot.producer.RabbitSender; +import com.bfxy.springboot.service.OrderService; + +@RunWith(SpringRunner.class) +@SpringBootTest +public class ApplicationTests { + + @Test + public void contextLoads() { + } + + @Autowired + private RabbitSender rabbitSender; + + private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); + + @Test + public void testSender1() throws Exception { + Map properties = new HashMap<>(); + properties.put("number", "12345"); + properties.put("send_time", simpleDateFormat.format(new Date())); + rabbitSender.send("Hello RabbitMQ For Spring Boot!", properties); + } + + + @Autowired + private RabbitOrderSender rabbitOrderSender; + + @Test + public void testSender2() throws Exception { + Order order = new Order(); + order.setId("2018080400000001"); + order.setName("测试订单"); + order.setMessageId(System.currentTimeMillis() + "$" + UUID.randomUUID().toString()); + rabbitOrderSender.sendOrder(order); + } + + + @Autowired + private OrderService orderService; + + @Test + public void testCreateOrder() throws Exception { + Order order = new Order(); + order.setId("2018080400000005"); + order.setName("测试创建订单"); + order.setMessageId(System.currentTimeMillis() + "$" + UUID.randomUUID().toString()); + orderService.createOrder(order); + } + + + + + + +} diff --git a/distributed/mq/rabbitmq/rabbitmq-springboot-producer/.gitignore b/distributed/mq/rabbitmq/rabbitmq-springboot-producer/.gitignore new file mode 100644 index 00000000..82eca336 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-springboot-producer/.gitignore @@ -0,0 +1,25 @@ +/target/ +!.mvn/wrapper/maven-wrapper.jar + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/build/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ \ No newline at end of file diff --git a/distributed/mq/rabbitmq/rabbitmq-springboot-producer/mvnw b/distributed/mq/rabbitmq/rabbitmq-springboot-producer/mvnw new file mode 100644 index 00000000..5bf251c0 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-springboot-producer/mvnw @@ -0,0 +1,225 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Maven2 Start Up Batch script +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# M2_HOME - location of maven2's installed home dir +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "`uname`" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + export JAVA_HOME="`/usr/libexec/java_home`" + else + export JAVA_HOME="/Library/Java/Home" + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=`java-config --jre-home` + fi +fi + +if [ -z "$M2_HOME" ] ; then + ## resolve links - $0 may be a link to maven's home + PRG="$0" + + # need this for relative symlinks + while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG="`dirname "$PRG"`/$link" + fi + done + + saveddir=`pwd` + + M2_HOME=`dirname "$PRG"`/.. + + # make it fully qualified + M2_HOME=`cd "$M2_HOME" && pwd` + + cd "$saveddir" + # echo Using m2 at $M2_HOME +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --unix "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +fi + +# For Migwn, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$M2_HOME" ] && + M2_HOME="`(cd "$M2_HOME"; pwd)`" + [ -n "$JAVA_HOME" ] && + JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" + # TODO classpath? +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="`which javac`" + if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=`which readlink` + if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then + if $darwin ; then + javaHome="`dirname \"$javaExecutable\"`" + javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + else + javaExecutable="`readlink -f \"$javaExecutable\"`" + fi + javaHome="`dirname \"$javaExecutable\"`" + javaHome=`expr "$javaHome" : '\(.*\)/bin'` + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="`which java`" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=`cd "$wdir/.."; pwd` + fi + # end of workaround + done + echo "${basedir}" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + echo "$(tr -s '\n' ' ' < "$1")" + fi +} + +BASE_DIR=`find_maven_basedir "$(pwd)"` +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} +echo $MAVEN_PROJECTBASEDIR +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --path --windows "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` +fi + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +exec "$JAVACMD" \ + $MAVEN_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/distributed/mq/rabbitmq/rabbitmq-springboot-producer/mvnw.cmd b/distributed/mq/rabbitmq/rabbitmq-springboot-producer/mvnw.cmd new file mode 100644 index 00000000..019bd74d --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-springboot-producer/mvnw.cmd @@ -0,0 +1,143 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven2 Start Up Batch script +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" +if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" + +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" +if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%" == "on" pause + +if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% + +exit /B %ERROR_CODE% diff --git a/distributed/mq/rabbitmq/rabbitmq-springboot-producer/pom.xml b/distributed/mq/rabbitmq/rabbitmq-springboot-producer/pom.xml new file mode 100644 index 00000000..aedf76b1 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-springboot-producer/pom.xml @@ -0,0 +1,54 @@ + + + 4.0.0 + + com.bfxy + rabbitmq-springboot-producer + 0.0.1-SNAPSHOT + jar + + rabbitmq-springboot-producer + rabbitmq-springboot-producer + + + org.springframework.boot + spring-boot-starter-parent + 2.0.2.RELEASE + + + + + UTF-8 + UTF-8 + 1.8 + + + + + org.springframework.boot + spring-boot-starter + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.boot + spring-boot-starter-amqp + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + diff --git a/distributed/mq/rabbitmq/rabbitmq-springboot-producer/src/main/java/com/bfxy/springboot/Application.java b/distributed/mq/rabbitmq/rabbitmq-springboot-producer/src/main/java/com/bfxy/springboot/Application.java new file mode 100644 index 00000000..b37bc319 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-springboot-producer/src/main/java/com/bfxy/springboot/Application.java @@ -0,0 +1,12 @@ +package com.bfxy.springboot; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } +} diff --git a/distributed/mq/rabbitmq/rabbitmq-springboot-producer/src/main/java/com/bfxy/springboot/MainConfig.java b/distributed/mq/rabbitmq/rabbitmq-springboot-producer/src/main/java/com/bfxy/springboot/MainConfig.java new file mode 100644 index 00000000..634fe239 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-springboot-producer/src/main/java/com/bfxy/springboot/MainConfig.java @@ -0,0 +1,10 @@ +package com.bfxy.springboot; + +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ComponentScan({"com.bfxy.springboot.*"}) +public class MainConfig { + +} diff --git a/distributed/mq/rabbitmq/rabbitmq-springboot-producer/src/main/java/com/bfxy/springboot/entity/Order.java b/distributed/mq/rabbitmq/rabbitmq-springboot-producer/src/main/java/com/bfxy/springboot/entity/Order.java new file mode 100644 index 00000000..661447e2 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-springboot-producer/src/main/java/com/bfxy/springboot/entity/Order.java @@ -0,0 +1,31 @@ +package com.bfxy.springboot.entity; + +import java.io.Serializable; + +public class Order implements Serializable { + + private String id; + private String name; + + public Order() { + } + public Order(String id, String name) { + super(); + this.id = id; + this.name = name; + } + public String getId() { + return id; + } + public void setId(String id) { + this.id = id; + } + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + + +} diff --git a/distributed/mq/rabbitmq/rabbitmq-springboot-producer/src/main/java/com/bfxy/springboot/producer/RabbitSender.java b/distributed/mq/rabbitmq/rabbitmq-springboot-producer/src/main/java/com/bfxy/springboot/producer/RabbitSender.java new file mode 100644 index 00000000..56ee3dac --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-springboot-producer/src/main/java/com/bfxy/springboot/producer/RabbitSender.java @@ -0,0 +1,66 @@ +package com.bfxy.springboot.producer; + +import java.util.Map; + +import org.springframework.amqp.rabbit.core.RabbitTemplate; +import org.springframework.amqp.rabbit.core.RabbitTemplate.ConfirmCallback; +import org.springframework.amqp.rabbit.core.RabbitTemplate.ReturnCallback; +import org.springframework.amqp.rabbit.support.CorrelationData; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.messaging.Message; +import org.springframework.messaging.MessageHeaders; +import org.springframework.messaging.support.MessageBuilder; +import org.springframework.stereotype.Component; + +import com.bfxy.springboot.entity.Order; + +@Component +public class RabbitSender { + + //自动注入RabbitTemplate模板类 + @Autowired + private RabbitTemplate rabbitTemplate; + + //回调函数: confirm确认 + final ConfirmCallback confirmCallback = new RabbitTemplate.ConfirmCallback() { + @Override + public void confirm(CorrelationData correlationData, boolean ack, String cause) { + System.err.println("correlationData: " + correlationData); + System.err.println("ack: " + ack); + if(!ack){ + System.err.println("异常处理...."); + } + } + }; + + //回调函数: return返回 + final ReturnCallback returnCallback = new RabbitTemplate.ReturnCallback() { + @Override + public void returnedMessage(org.springframework.amqp.core.Message message, int replyCode, String replyText, + String exchange, String routingKey) { + System.err.println("return exchange: " + exchange + ", routingKey: " + + routingKey + ", replyCode: " + replyCode + ", replyText: " + replyText); + } + }; + + //发送消息方法调用: 构建Message消息 + public void send(Object message, Map properties) throws Exception { + MessageHeaders mhs = new MessageHeaders(properties); + Message msg = MessageBuilder.createMessage(message, mhs); + rabbitTemplate.setConfirmCallback(confirmCallback); + rabbitTemplate.setReturnCallback(returnCallback); + //id + 时间戳 全局唯一 + CorrelationData correlationData = new CorrelationData("1234567890"); + rabbitTemplate.convertAndSend("exchange-1", "springboot.abc", msg, correlationData); + } + + //发送消息方法调用: 构建自定义对象消息 + public void sendOrder(Order order) throws Exception { + rabbitTemplate.setConfirmCallback(confirmCallback); + rabbitTemplate.setReturnCallback(returnCallback); + //id + 时间戳 全局唯一 + CorrelationData correlationData = new CorrelationData("0987654321"); + rabbitTemplate.convertAndSend("exchange-2", "springboot.def", order, correlationData); + } + +} diff --git a/distributed/mq/rabbitmq/rabbitmq-springboot-producer/src/main/resources/application.properties b/distributed/mq/rabbitmq/rabbitmq-springboot-producer/src/main/resources/application.properties new file mode 100644 index 00000000..46ba4a6a --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-springboot-producer/src/main/resources/application.properties @@ -0,0 +1,12 @@ +spring.rabbitmq.addresses=192.168.11.76:5672 +spring.rabbitmq.username=guest +spring.rabbitmq.password=guest +spring.rabbitmq.virtual-host=/ +spring.rabbitmq.connection-timeout=15000 + +# Ϣȷģʽ +spring.rabbitmq.publisher-confirms=true +# Ϣģʽ +spring.rabbitmq.publisher-returns=true +# mandatory=true֤Ϣ޷ʱɾ +spring.rabbitmq.template.mandatory=true diff --git a/distributed/mq/rabbitmq/rabbitmq-springboot-producer/src/test/java/com/bfxy/springboot/ApplicationTests.java b/distributed/mq/rabbitmq/rabbitmq-springboot-producer/src/test/java/com/bfxy/springboot/ApplicationTests.java new file mode 100644 index 00000000..3c8aea95 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-springboot-producer/src/test/java/com/bfxy/springboot/ApplicationTests.java @@ -0,0 +1,46 @@ +package com.bfxy.springboot; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import com.bfxy.springboot.entity.Order; +import com.bfxy.springboot.producer.RabbitSender; + +@RunWith(SpringRunner.class) +@SpringBootTest +public class ApplicationTests { + + @Test + public void contextLoads() { + } + + @Autowired + private RabbitSender rabbitSender; + + private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); + + @Test + public void testSender1() throws Exception { + Map properties = new HashMap<>(); + properties.put("number", "12345"); + properties.put("send_time", simpleDateFormat.format(new Date())); + rabbitSender.send("Hello RabbitMQ For Spring Boot!", properties); + } + + @Test + public void testSender2() throws Exception { + Order order = new Order("001", "第一个订单"); + rabbitSender.sendOrder(order); + } + + + +} diff --git a/distributed/mq/rabbitmq/rabbitmq-springcloudstream-consumer/.gitignore b/distributed/mq/rabbitmq/rabbitmq-springcloudstream-consumer/.gitignore new file mode 100644 index 00000000..82eca336 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-springcloudstream-consumer/.gitignore @@ -0,0 +1,25 @@ +/target/ +!.mvn/wrapper/maven-wrapper.jar + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/build/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ \ No newline at end of file diff --git a/distributed/mq/rabbitmq/rabbitmq-springcloudstream-consumer/mvnw b/distributed/mq/rabbitmq/rabbitmq-springcloudstream-consumer/mvnw new file mode 100644 index 00000000..5bf251c0 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-springcloudstream-consumer/mvnw @@ -0,0 +1,225 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Maven2 Start Up Batch script +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# M2_HOME - location of maven2's installed home dir +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "`uname`" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + export JAVA_HOME="`/usr/libexec/java_home`" + else + export JAVA_HOME="/Library/Java/Home" + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=`java-config --jre-home` + fi +fi + +if [ -z "$M2_HOME" ] ; then + ## resolve links - $0 may be a link to maven's home + PRG="$0" + + # need this for relative symlinks + while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG="`dirname "$PRG"`/$link" + fi + done + + saveddir=`pwd` + + M2_HOME=`dirname "$PRG"`/.. + + # make it fully qualified + M2_HOME=`cd "$M2_HOME" && pwd` + + cd "$saveddir" + # echo Using m2 at $M2_HOME +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --unix "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +fi + +# For Migwn, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$M2_HOME" ] && + M2_HOME="`(cd "$M2_HOME"; pwd)`" + [ -n "$JAVA_HOME" ] && + JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" + # TODO classpath? +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="`which javac`" + if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=`which readlink` + if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then + if $darwin ; then + javaHome="`dirname \"$javaExecutable\"`" + javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + else + javaExecutable="`readlink -f \"$javaExecutable\"`" + fi + javaHome="`dirname \"$javaExecutable\"`" + javaHome=`expr "$javaHome" : '\(.*\)/bin'` + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="`which java`" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=`cd "$wdir/.."; pwd` + fi + # end of workaround + done + echo "${basedir}" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + echo "$(tr -s '\n' ' ' < "$1")" + fi +} + +BASE_DIR=`find_maven_basedir "$(pwd)"` +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} +echo $MAVEN_PROJECTBASEDIR +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --path --windows "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` +fi + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +exec "$JAVACMD" \ + $MAVEN_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/distributed/mq/rabbitmq/rabbitmq-springcloudstream-consumer/mvnw.cmd b/distributed/mq/rabbitmq/rabbitmq-springcloudstream-consumer/mvnw.cmd new file mode 100644 index 00000000..019bd74d --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-springcloudstream-consumer/mvnw.cmd @@ -0,0 +1,143 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven2 Start Up Batch script +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" +if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" + +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" +if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%" == "on" pause + +if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% + +exit /B %ERROR_CODE% diff --git a/distributed/mq/rabbitmq/rabbitmq-springcloudstream-consumer/pom.xml b/distributed/mq/rabbitmq/rabbitmq-springcloudstream-consumer/pom.xml new file mode 100644 index 00000000..167f5471 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-springcloudstream-consumer/pom.xml @@ -0,0 +1,62 @@ + + + 4.0.0 + + com.bfxy + rabbitmq-springcloudstream-consumer + 0.0.1-SNAPSHOT + jar + + rabbitmq-springcloudstream-consumer + rabbitmq-spring + + + org.springframework.boot + spring-boot-starter-parent + 1.5.8.RELEASE + + + + + UTF-8 + UTF-8 + 1.8 + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.cloud + spring-cloud-starter-stream-rabbit + 1.3.4.RELEASE + + + org.springframework.boot + spring-boot-starter-actuator + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + diff --git a/distributed/mq/rabbitmq/rabbitmq-springcloudstream-consumer/src/main/java/com/bfxy/rabbitmq/Application.java b/distributed/mq/rabbitmq/rabbitmq-springcloudstream-consumer/src/main/java/com/bfxy/rabbitmq/Application.java new file mode 100644 index 00000000..a2ec9bc1 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-springcloudstream-consumer/src/main/java/com/bfxy/rabbitmq/Application.java @@ -0,0 +1,12 @@ +package com.bfxy.rabbitmq; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } +} diff --git a/distributed/mq/rabbitmq/rabbitmq-springcloudstream-consumer/src/main/java/com/bfxy/rabbitmq/stream/Barista.java b/distributed/mq/rabbitmq/rabbitmq-springcloudstream-consumer/src/main/java/com/bfxy/rabbitmq/stream/Barista.java new file mode 100644 index 00000000..f809d346 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-springcloudstream-consumer/src/main/java/com/bfxy/rabbitmq/stream/Barista.java @@ -0,0 +1,24 @@ +package com.bfxy.rabbitmq.stream; + +import org.springframework.cloud.stream.annotation.Input; +import org.springframework.messaging.SubscribableChannel; + +/** + * 中文类名:
+ * 概要说明:
+ * 这里的Barista接口是定义来作为后面类的参数,这一接口定义来通道类型和通道名称。 + * 通道名称是作为配置用,通道类型则决定了app会使用这一通道进行发送消息还是从中接收消息。 + * @author ashen(Alienware) + * @since 2016年7月22日 + */ + +public interface Barista { + + String INPUT_CHANNEL = "input_channel"; + + //注解@Input声明了它是一个输入类型的通道,名字是Barista.INPUT_CHANNEL,也就是position3的input_channel。这一名字与上述配置app2的配置文件中position1应该一致,表明注入了一个名字叫做input_channel的通道,它的类型是input,订阅的主题是position2处声明的mydest这个主题 + @Input(Barista.INPUT_CHANNEL) + SubscribableChannel loginput(); + + +} \ No newline at end of file diff --git a/distributed/mq/rabbitmq/rabbitmq-springcloudstream-consumer/src/main/java/com/bfxy/rabbitmq/stream/RabbitmqReceiver.java b/distributed/mq/rabbitmq/rabbitmq-springcloudstream-consumer/src/main/java/com/bfxy/rabbitmq/stream/RabbitmqReceiver.java new file mode 100644 index 00000000..6fc882d2 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-springcloudstream-consumer/src/main/java/com/bfxy/rabbitmq/stream/RabbitmqReceiver.java @@ -0,0 +1,24 @@ +package com.bfxy.rabbitmq.stream; + +import org.springframework.amqp.support.AmqpHeaders; +import org.springframework.cloud.stream.annotation.EnableBinding; +import org.springframework.cloud.stream.annotation.StreamListener; +import org.springframework.messaging.Message; +import org.springframework.stereotype.Service; + +import com.rabbitmq.client.Channel; + + +@EnableBinding(Barista.class) +@Service +public class RabbitmqReceiver { + + @StreamListener(Barista.INPUT_CHANNEL) + public void receiver(Message message) throws Exception { + Channel channel = (com.rabbitmq.client.Channel) message.getHeaders().get(AmqpHeaders.CHANNEL); + Long deliveryTag = (Long) message.getHeaders().get(AmqpHeaders.DELIVERY_TAG); + System.out.println("Input Stream 1 接受数据:" + message); + System.out.println("消费完毕------------"); + channel.basicAck(deliveryTag, false); + } +} diff --git a/distributed/mq/rabbitmq/rabbitmq-springcloudstream-consumer/src/main/resources/application.properties b/distributed/mq/rabbitmq/rabbitmq-springcloudstream-consumer/src/main/resources/application.properties new file mode 100644 index 00000000..c7ea51f5 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-springcloudstream-consumer/src/main/resources/application.properties @@ -0,0 +1,19 @@ +server.port=8002 +server.context-path=/consumer + +spring.application.name=consumer +spring.cloud.stream.bindings.input_channel.destination=exchange-3 +spring.cloud.stream.bindings.input_channel.group=queue-3 +spring.cloud.stream.bindings.input_channel.binder=rabbit_cluster +spring.cloud.stream.bindings.input_channel.consumer.concurrency=1 +spring.cloud.stream.rabbit.bindings.input_channel.consumer.requeue-rejected=false +spring.cloud.stream.rabbit.bindings.input_channel.consumer.acknowledge-mode=MANUAL +spring.cloud.stream.rabbit.bindings.input_channel.consumer.recovery-interval=3000 +spring.cloud.stream.rabbit.bindings.input_channel.consumer.durable-subscription=true +spring.cloud.stream.rabbit.bindings.input_channel.consumer.max-concurrency=5 + +spring.cloud.stream.binders.rabbit_cluster.type=rabbit +spring.cloud.stream.binders.rabbit_cluster.environment.spring.rabbitmq.addresses=192.168.11.76:5672 +spring.cloud.stream.binders.rabbit_cluster.environment.spring.rabbitmq.username=guest +spring.cloud.stream.binders.rabbit_cluster.environment.spring.rabbitmq.password=guest +spring.cloud.stream.binders.rabbit_cluster.environment.spring.rabbitmq.virtual-host=/ \ No newline at end of file diff --git a/distributed/mq/rabbitmq/rabbitmq-springcloudstream-consumer/src/test/java/com/bfxy/rabbitmq/ApplicationTests.java b/distributed/mq/rabbitmq/rabbitmq-springcloudstream-consumer/src/test/java/com/bfxy/rabbitmq/ApplicationTests.java new file mode 100644 index 00000000..cc66a6bc --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-springcloudstream-consumer/src/test/java/com/bfxy/rabbitmq/ApplicationTests.java @@ -0,0 +1,16 @@ +package com.bfxy.rabbitmq; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@SpringBootTest +public class ApplicationTests { + + @Test + public void contextLoads() { + } + +} diff --git a/distributed/mq/rabbitmq/rabbitmq-springcloudstream-producer/.gitignore b/distributed/mq/rabbitmq/rabbitmq-springcloudstream-producer/.gitignore new file mode 100644 index 00000000..82eca336 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-springcloudstream-producer/.gitignore @@ -0,0 +1,25 @@ +/target/ +!.mvn/wrapper/maven-wrapper.jar + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/build/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ \ No newline at end of file diff --git a/distributed/mq/rabbitmq/rabbitmq-springcloudstream-producer/mvnw b/distributed/mq/rabbitmq/rabbitmq-springcloudstream-producer/mvnw new file mode 100644 index 00000000..5bf251c0 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-springcloudstream-producer/mvnw @@ -0,0 +1,225 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Maven2 Start Up Batch script +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# M2_HOME - location of maven2's installed home dir +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "`uname`" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + export JAVA_HOME="`/usr/libexec/java_home`" + else + export JAVA_HOME="/Library/Java/Home" + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=`java-config --jre-home` + fi +fi + +if [ -z "$M2_HOME" ] ; then + ## resolve links - $0 may be a link to maven's home + PRG="$0" + + # need this for relative symlinks + while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG="`dirname "$PRG"`/$link" + fi + done + + saveddir=`pwd` + + M2_HOME=`dirname "$PRG"`/.. + + # make it fully qualified + M2_HOME=`cd "$M2_HOME" && pwd` + + cd "$saveddir" + # echo Using m2 at $M2_HOME +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --unix "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +fi + +# For Migwn, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$M2_HOME" ] && + M2_HOME="`(cd "$M2_HOME"; pwd)`" + [ -n "$JAVA_HOME" ] && + JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" + # TODO classpath? +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="`which javac`" + if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=`which readlink` + if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then + if $darwin ; then + javaHome="`dirname \"$javaExecutable\"`" + javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + else + javaExecutable="`readlink -f \"$javaExecutable\"`" + fi + javaHome="`dirname \"$javaExecutable\"`" + javaHome=`expr "$javaHome" : '\(.*\)/bin'` + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="`which java`" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=`cd "$wdir/.."; pwd` + fi + # end of workaround + done + echo "${basedir}" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + echo "$(tr -s '\n' ' ' < "$1")" + fi +} + +BASE_DIR=`find_maven_basedir "$(pwd)"` +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} +echo $MAVEN_PROJECTBASEDIR +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --path --windows "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` +fi + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +exec "$JAVACMD" \ + $MAVEN_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/distributed/mq/rabbitmq/rabbitmq-springcloudstream-producer/mvnw.cmd b/distributed/mq/rabbitmq/rabbitmq-springcloudstream-producer/mvnw.cmd new file mode 100644 index 00000000..019bd74d --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-springcloudstream-producer/mvnw.cmd @@ -0,0 +1,143 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven2 Start Up Batch script +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" +if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" + +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" +if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%" == "on" pause + +if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% + +exit /B %ERROR_CODE% diff --git a/distributed/mq/rabbitmq/rabbitmq-springcloudstream-producer/pom.xml b/distributed/mq/rabbitmq/rabbitmq-springcloudstream-producer/pom.xml new file mode 100644 index 00000000..ff858026 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-springcloudstream-producer/pom.xml @@ -0,0 +1,67 @@ + + + 4.0.0 + + com.bfxy + rabbitmq-springcloudstream-producer + 0.0.1-SNAPSHOT + jar + + rabbitmq-springcloudstream-producer + rabbitmq-spring + + + org.springframework.boot + spring-boot-starter-parent + 1.5.8.RELEASE + + + + + UTF-8 + UTF-8 + 1.8 + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter + + + org.springframework.boot + spring-boot-autoconfigure + + + org.springframework.boot + spring-boot-starter-test + test + + + + org.springframework.cloud + spring-cloud-starter-stream-rabbit + 1.3.4.RELEASE + + + org.springframework.boot + spring-boot-starter-actuator + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + diff --git a/distributed/mq/rabbitmq/rabbitmq-springcloudstream-producer/src/main/java/com/bfxy/rabbitmq/Application.java b/distributed/mq/rabbitmq/rabbitmq-springcloudstream-producer/src/main/java/com/bfxy/rabbitmq/Application.java new file mode 100644 index 00000000..a2ec9bc1 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-springcloudstream-producer/src/main/java/com/bfxy/rabbitmq/Application.java @@ -0,0 +1,12 @@ +package com.bfxy.rabbitmq; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } +} diff --git a/distributed/mq/rabbitmq/rabbitmq-springcloudstream-producer/src/main/java/com/bfxy/rabbitmq/stream/Barista.java b/distributed/mq/rabbitmq/rabbitmq-springcloudstream-producer/src/main/java/com/bfxy/rabbitmq/stream/Barista.java new file mode 100644 index 00000000..61a15cec --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-springcloudstream-producer/src/main/java/com/bfxy/rabbitmq/stream/Barista.java @@ -0,0 +1,30 @@ +package com.bfxy.rabbitmq.stream; + +import org.springframework.cloud.stream.annotation.Output; +import org.springframework.messaging.MessageChannel; + +/** + * 中文类名:
+ * 概要说明:
+ * 这里的Barista接口是定义来作为后面类的参数,这一接口定义来通道类型和通道名称。 + * 通道名称是作为配置用,通道类型则决定了app会使用这一通道进行发送消息还是从中接收消息。 + */ +public interface Barista { + + //String INPUT_CHANNEL = "input_channel"; + String OUTPUT_CHANNEL = "output_channel"; + + //注解@Input声明了它是一个输入类型的通道,名字是Barista.INPUT_CHANNEL,也就是position3的input_channel。这一名字与上述配置app2的配置文件中position1应该一致,表明注入了一个名字叫做input_channel的通道,它的类型是input,订阅的主题是position2处声明的mydest这个主题 +// @Input(Barista.INPUT_CHANNEL) +// SubscribableChannel loginput(); + //注解@Output声明了它是一个输出类型的通道,名字是output_channel。这一名字与app1中通道名一致,表明注入了一个名字为output_channel的通道,类型是output,发布的主题名为mydest。 + @Output(Barista.OUTPUT_CHANNEL) + MessageChannel logoutput(); + +// String INPUT_BASE = "queue-1"; +// String OUTPUT_BASE = "queue-1"; +// @Input(Barista.INPUT_BASE) +// SubscribableChannel input1(); +// MessageChannel output1(); + +} \ No newline at end of file diff --git a/distributed/mq/rabbitmq/rabbitmq-springcloudstream-producer/src/main/java/com/bfxy/rabbitmq/stream/RabbitmqSender.java b/distributed/mq/rabbitmq/rabbitmq-springcloudstream-producer/src/main/java/com/bfxy/rabbitmq/stream/RabbitmqSender.java new file mode 100644 index 00000000..81866bd5 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-springcloudstream-producer/src/main/java/com/bfxy/rabbitmq/stream/RabbitmqSender.java @@ -0,0 +1,36 @@ +package com.bfxy.rabbitmq.stream; + +import java.util.Map; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.stream.annotation.EnableBinding; +import org.springframework.messaging.Message; +import org.springframework.messaging.MessageHeaders; +import org.springframework.messaging.support.MessageBuilder; +import org.springframework.stereotype.Service; + +@EnableBinding(Barista.class) +@Service +public class RabbitmqSender { + + @Autowired + private Barista barista; + + // 发送消息 + public String sendMessage(Object message, Map properties) throws Exception { + try{ + MessageHeaders mhs = new MessageHeaders(properties); + Message msg = MessageBuilder.createMessage(message, mhs); + boolean sendStatus = barista.logoutput().send(msg); + System.err.println("--------------sending -------------------"); + System.out.println("发送数据:" + message + ",sendStatus: " + sendStatus); + }catch (Exception e){ + System.err.println("-------------error-------------"); + e.printStackTrace(); + throw new RuntimeException(e.getMessage()); + + } + return null; + } + +} \ No newline at end of file diff --git a/distributed/mq/rabbitmq/rabbitmq-springcloudstream-producer/src/main/resources/application.properties b/distributed/mq/rabbitmq/rabbitmq-springcloudstream-producer/src/main/resources/application.properties new file mode 100644 index 00000000..15b35d50 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-springcloudstream-producer/src/main/resources/application.properties @@ -0,0 +1,13 @@ +server.port=8001 +server.servlet.context-path=/producer + +spring.application.name=producer +spring.cloud.stream.bindings.output_channel.destination=exchange-3 +spring.cloud.stream.bindings.output_channel.group=queue-3 +spring.cloud.stream.bindings.output_channel.binder=rabbit_cluster + +spring.cloud.stream.binders.rabbit_cluster.type=rabbit +spring.cloud.stream.binders.rabbit_cluster.environment.spring.rabbitmq.addresses=192.168.11.76:5672 +spring.cloud.stream.binders.rabbit_cluster.environment.spring.rabbitmq.username=guest +spring.cloud.stream.binders.rabbit_cluster.environment.spring.rabbitmq.password=guest +spring.cloud.stream.binders.rabbit_cluster.environment.spring.rabbitmq.virtual-host=/ \ No newline at end of file diff --git a/distributed/mq/rabbitmq/rabbitmq-springcloudstream-producer/src/test/java/com/bfxy/rabbitmq/ApplicationTests.java b/distributed/mq/rabbitmq/rabbitmq-springcloudstream-producer/src/test/java/com/bfxy/rabbitmq/ApplicationTests.java new file mode 100644 index 00000000..69c96f86 --- /dev/null +++ b/distributed/mq/rabbitmq/rabbitmq-springcloudstream-producer/src/test/java/com/bfxy/rabbitmq/ApplicationTests.java @@ -0,0 +1,42 @@ +package com.bfxy.rabbitmq; + +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +import org.apache.http.client.utils.DateUtils; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import com.bfxy.rabbitmq.stream.RabbitmqSender; + +@RunWith(SpringRunner.class) +@SpringBootTest +public class ApplicationTests { + + @Autowired + private RabbitmqSender rabbitmqSender; + + + @Test + public void sendMessageTest1() { + for(int i = 0; i < 1; i ++){ + try { + Map properties = new HashMap(); + properties.put("SERIAL_NUMBER", "12345"); + properties.put("BANK_NUMBER", "abc"); + properties.put("PLAT_SEND_TIME", DateUtils.formatDate(new Date(), "yyyy-MM-dd HH:mm:ss.SSS")); + rabbitmqSender.sendMessage("Hello, I am amqp sender num :" + i, properties); + + } catch (Exception e) { + System.out.println("--------error-------"); + e.printStackTrace(); + } + } + //TimeUnit.SECONDS.sleep(Integer.MAX_VALUE); + } + +} diff --git a/distributed/mq/rocketmq/pom.xml b/distributed/mq/rocketmq/pom.xml new file mode 100644 index 00000000..2331cb13 --- /dev/null +++ b/distributed/mq/rocketmq/pom.xml @@ -0,0 +1,18 @@ + + + 4.0.0 + + cn.lastwhisper + rocketmq + 1.0-SNAPSHOT + + + + org.apache.rocketmq + rocketmq-client + 4.6.0 + + + \ No newline at end of file diff --git a/distributed/mq/rocketmq/rocketmq-api/README.md b/distributed/mq/rocketmq/rocketmq-api/README.md new file mode 100644 index 00000000..31ada97b --- /dev/null +++ b/distributed/mq/rocketmq/rocketmq-api/README.md @@ -0,0 +1,30 @@ + +- quickstart 快速入门,生产者发送消息到 broker,broker push 消息到消费者 +- product.sync 生产者发送同步消息 +- product.async 生产者发送异步消息 +- product.oneway 生产者发送单向消息 +- consumer.pull consumer pull broker +- consumer.push broker push consumer +- consumer.broadcast 消费者广播模式消费 +- consumer.retry 消费者重试消息 +- ordermsg 生产者发送有序消息 + - 消息消费时能按照发送的顺序来消费。例如:一个订单产生了三条消息分别是订单创建、订单付款、订单完成。消费时要按照这个顺序消费才能有意义 +- schedulemsg 生产者发送延时消息 + - 消息消费时能按照发送时设置的延长的时间来消费。例如:电商里,提交了一个订单就可以发送一个延时消息,1h后去检查这个订单的状态,如果还是未付款就取消订单释放库存。 + - rocketmq 的延时消息只能按照18个 level 进行延时,不能指定时间 +- batch 发送批量消息 +- filter broker 端进行的消息过滤 +- transaction 事务消息 + - 事务消息共有三种状态,提交状态、回滚状态、中间状态 + - TransactionStatus.CommitTransaction: 提交事务,它允许消费者消费此消息。 + - TransactionStatus.RollbackTransaction: 回滚事务,它代表该消息将被删除,不允许被消费。 + - TransactionStatus.Unknown: 中间状态,它代表需要检查消息队列来确定状态。 + - + + + + + + + + diff --git a/distributed/mq/rocketmq/rocketmq-api/pom.xml b/distributed/mq/rocketmq/rocketmq-api/pom.xml new file mode 100644 index 00000000..aaa9b299 --- /dev/null +++ b/distributed/mq/rocketmq/rocketmq-api/pom.xml @@ -0,0 +1,18 @@ + + + 4.0.0 + + cn.cunchang + rocketmq-api + 1.0-SNAPSHOT + + + + org.apache.rocketmq + rocketmq-client + 4.6.0 + + + \ No newline at end of file diff --git a/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/batch/Consumer.java b/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/batch/Consumer.java new file mode 100644 index 00000000..cbf01c43 --- /dev/null +++ b/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/batch/Consumer.java @@ -0,0 +1,58 @@ +package cn.cunchang.batch; + +import cn.cunchang.contants.Const; +import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer; +import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext; +import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus; +import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently; +import org.apache.rocketmq.client.exception.MQClientException; +import org.apache.rocketmq.common.consumer.ConsumeFromWhere; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.remoting.common.RemotingHelper; + +import java.util.List; + +public class Consumer { + + public static void main(String[] args) throws MQClientException { + DefaultMQPushConsumer consumer = new DefaultMQPushConsumer(); + + //指定NameServer地址,多个地址以 ; 隔开 + consumer.setNamesrvAddr(Const.NAMESRV_ADDR_SINGLE); + + //CONSUME_FROM_LAST_OFFSET 默认策略,从该队列最尾开始消费,跳过历史消息 + //CONSUME_FROM_FIRST_OFFSET 从队列最开始开始消费,即历史消息(还储存在broker的)全部消费一遍 + consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET); + consumer.setConsumerGroup("test_quick_consumer_name"); + + //设置consumer所订阅的Topic和Tag,*代表全部的Tag + consumer.subscribe("BatchTest", "*"); + + consumer.registerMessageListener(new MessageListenerConcurrently() { + @Override + public ConsumeConcurrentlyStatus consumeMessage(List msgs, ConsumeConcurrentlyContext context) { + System.out.printf("\npull 到 %d 条消息",msgs.size()); + for (MessageExt msg : msgs) { + try { + String topic = msg.getTopic(); + String tags = msg.getTags(); + String keys = msg.getKeys(); + + String msgBody = new String(msg.getBody(), RemotingHelper.DEFAULT_CHARSET); + System.err.println("消费消息--- topic: " + topic + ",tags: " + tags + ", keys: " + keys + ",body: " + msgBody); + } catch (Exception e) { + e.printStackTrace(); + // broke消息重发 + return ConsumeConcurrentlyStatus.RECONSUME_LATER; + } + } + //消费成功 + return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; + } + }); + + consumer.start(); + System.err.println("consumer start..."); + + } +} diff --git a/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/batch/ListSplitter.java b/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/batch/ListSplitter.java new file mode 100644 index 00000000..d7377d3f --- /dev/null +++ b/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/batch/ListSplitter.java @@ -0,0 +1,75 @@ +package cn.cunchang.batch; + +import org.apache.rocketmq.common.message.Message; + +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +public class ListSplitter implements Iterator> { + private final int SIZE_LIMIT = 1024 * 1024 *4; + private final List messages; + private int currIndex; + + public ListSplitter(List messages) { + this.messages = messages; + } + + @Override + public boolean hasNext() { + return currIndex < messages.size(); + } + + @Override + public List next() { + // 获取开始切割的消息索引(消息字节小于4MB的消息索引) + int startIndex = getStartIndex(); + // 切割结束位置 + int nextIndex = startIndex; + // 临时存放切割出的消息列表的总字节数 + int totalSize = 0; + // 切割消息列表,从起始位置切割,直到切割出的消息列表的总字节数超过4MB为止 + for (; nextIndex < messages.size() ; nextIndex++) { + // 计算遍历的消息的字节并累加,当超过4MB时退出循环,记录nextIndex;用于切分list + Message message = messages.get(nextIndex); + int tmpSize = calcMessageSize(message); + if (tmpSize + totalSize > SIZE_LIMIT){ + break; + }else { + totalSize += tmpSize; + } + } + List subList = this.messages.subList(startIndex, nextIndex); + // 存放切割结束位置 + currIndex = nextIndex; + return subList; + } + + /** + * 计算开始切割的位置,切割的对象是消息列表,最小粒度就是一个消息对象(一条消息的字节大于4MB不会对该消息对象进行切割) + * 获取起始切割位置就是找到单条消息字节小于4MB的消息索引。对大于4MB的消息跳过。 + */ + private int getStartIndex(){ + // 计算开始索引的消息的字节数 + Message currMessage = messages.get(currIndex); + int tmpSize = calcMessageSize(currMessage); + // 下一个开始位置的消息的字节数不能大于4MB + while (tmpSize > SIZE_LIMIT) { + currIndex ++; + Message message = messages.get(currIndex); + tmpSize = calcMessageSize(message); + } + return currIndex; + } + + private int calcMessageSize(Message message){ + int tmpSize = message.getTopic().length() + message.getBody().length; + Map properties = message.getProperties(); + for (Map.Entry entry : properties.entrySet()) { + tmpSize += entry.getKey().length() + entry.getValue().length(); + } + // 增加日志的开销20字节 + tmpSize = tmpSize+20; + return tmpSize; + } +} diff --git a/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/batch/SimpleBatchProducer.java b/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/batch/SimpleBatchProducer.java new file mode 100644 index 00000000..372f6368 --- /dev/null +++ b/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/batch/SimpleBatchProducer.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.cunchang.batch; + +import java.util.ArrayList; +import java.util.List; +import org.apache.rocketmq.client.producer.DefaultMQProducer; +import org.apache.rocketmq.common.message.Message; + +public class SimpleBatchProducer { + + public static void main(String[] args) throws Exception { + DefaultMQProducer producer = new DefaultMQProducer("BatchProducerGroupName"); + producer.setNamesrvAddr("127.0.0.1:9876"); + producer.start(); + + //If you just send messages of no more than 1MiB at a time, it is easy to use batch + //Messages of the same batch should have: same topic, same waitStoreMsgOK and no schedule support + String topic = "BatchTest"; + List messages = new ArrayList<>(); + messages.add(new Message(topic, "Tag", "OrderID001", "Hello world 0".getBytes())); + messages.add(new Message(topic, "Tag", "OrderID002", "Hello world 1".getBytes())); + messages.add(new Message(topic, "Tag", "OrderID003", "Hello world 2".getBytes())); + + producer.send(messages); + System.err.println("SimpleBatchProducer 批量消息发送成功"); + producer.shutdown(); + } +} diff --git a/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/batch/SplitBatchProducer.java b/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/batch/SplitBatchProducer.java new file mode 100644 index 00000000..df2e3f7f --- /dev/null +++ b/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/batch/SplitBatchProducer.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.cunchang.batch; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import org.apache.rocketmq.client.producer.DefaultMQProducer; +import org.apache.rocketmq.common.message.Message; + +public class SplitBatchProducer { + + public static void main(String[] args) throws Exception { + DefaultMQProducer producer = new DefaultMQProducer("BatchProducerGroupName"); + producer.setNamesrvAddr("127.0.0.1:9876"); + producer.start(); + + //large batch + String topic = "BatchTest"; + List messages = new ArrayList<>(100 * 1000); + for (int i = 0; i < 100 * 1000; i++) { + messages.add(new Message(topic, "Tag", "OrderID" + i, ("Hello world " + i).getBytes())); + } + + //split the large batch into small ones: + ListSplitter splitter = new ListSplitter(messages); + while (splitter.hasNext()) { + List listItem = splitter.next(); + producer.send(listItem); + } + System.err.println("SplitBatchProducer 批量消息发送成功"); + producer.shutdown(); + } + +} diff --git a/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/consumer/broadcast/BroadCastConsumer.java b/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/consumer/broadcast/BroadCastConsumer.java new file mode 100644 index 00000000..2fcb7c74 --- /dev/null +++ b/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/consumer/broadcast/BroadCastConsumer.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package cn.cunchang.consumer.broadcast; + +import java.util.List; + +import cn.cunchang.contants.Const; +import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer; +import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext; +import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus; +import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently; +import org.apache.rocketmq.client.exception.MQClientException; +import org.apache.rocketmq.common.consumer.ConsumeFromWhere; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; + +public class BroadCastConsumer { + + public static void main(String[] args) throws InterruptedException, MQClientException { + DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("please_rename_unique_group_name_1"); + consumer.setNamesrvAddr(Const.NAMESRV_ADDR_SINGLE); + consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET); + // 广播模式消费消息 + consumer.setMessageModel(MessageModel.BROADCASTING); + consumer.subscribe("TopicTest", "TagA || TagC || TagD"); + + consumer.registerMessageListener(new MessageListenerConcurrently() { + + @Override + public ConsumeConcurrentlyStatus consumeMessage(List msgs, + ConsumeConcurrentlyContext context) { + System.out.printf("%s Receive New Messages: %s %n", Thread.currentThread().getName(), msgs); + return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; + } + }); + + consumer.start(); + System.out.printf("Broadcast Consumer Started.%n"); + } +} diff --git a/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/consumer/pull/PullConsumer.java b/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/consumer/pull/PullConsumer.java new file mode 100644 index 00000000..41f7a61f --- /dev/null +++ b/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/consumer/pull/PullConsumer.java @@ -0,0 +1,62 @@ +package cn.cunchang.consumer.pull; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import org.apache.rocketmq.client.consumer.DefaultMQPullConsumer; +import org.apache.rocketmq.client.consumer.PullResult; +import org.apache.rocketmq.client.exception.MQClientException; +import org.apache.rocketmq.common.message.MessageQueue; + +public class PullConsumer { + private static final Map OFFSE_TABLE = new HashMap(); + + public static void main(String[] args) throws MQClientException { + DefaultMQPullConsumer consumer = new DefaultMQPullConsumer("please_rename_unique_group_name_5"); + + consumer.start(); + + Set mqs = consumer.fetchSubscribeMessageQueues("TopicTest1"); + for (MessageQueue mq : mqs) { + System.out.printf("Consume from the queue: %s%n", mq); + SINGLE_MQ: + while (true) { + try { + PullResult pullResult = + consumer.pullBlockIfNotFound(mq, null, getMessageQueueOffset(mq), 32); + System.out.printf("%s%n", pullResult); + putMessageQueueOffset(mq, pullResult.getNextBeginOffset()); + switch (pullResult.getPullStatus()) { + case FOUND: + break; + case NO_MATCHED_MSG: + break; + case NO_NEW_MSG: + break SINGLE_MQ; + case OFFSET_ILLEGAL: + break; + default: + break; + } + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + consumer.shutdown(); + } + + private static long getMessageQueueOffset(MessageQueue mq) { + Long offset = OFFSE_TABLE.get(mq); + if (offset != null) + return offset; + + return 0; + } + + private static void putMessageQueueOffset(MessageQueue mq, long offset) { + OFFSE_TABLE.put(mq, offset); + } + +} diff --git a/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/consumer/pull/PullScheduleConsumer.java b/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/consumer/pull/PullScheduleConsumer.java new file mode 100644 index 00000000..207247b5 --- /dev/null +++ b/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/consumer/pull/PullScheduleConsumer.java @@ -0,0 +1,49 @@ +package cn.cunchang.consumer.pull; + +import org.apache.rocketmq.client.consumer.*; +import org.apache.rocketmq.client.exception.MQClientException; +import org.apache.rocketmq.common.message.MessageQueue; +import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; + +public class PullScheduleConsumer { + + public static void main(String[] args) throws MQClientException { + final MQPullConsumerScheduleService scheduleService = new MQPullConsumerScheduleService("GroupName1"); + + scheduleService.setMessageModel(MessageModel.CLUSTERING); + scheduleService.registerPullTaskCallback("TopicTest", new PullTaskCallback() { + + @Override + public void doPullTask(MessageQueue mq, PullTaskContext context) { + MQPullConsumer consumer = context.getPullConsumer(); + try { + + long offset = consumer.fetchConsumeOffset(mq, false); + if (offset < 0) + offset = 0; + + PullResult pullResult = consumer.pull(mq, "*", offset, 32); + System.out.printf("%s%n", offset + "\t" + mq + "\t" + pullResult); + switch (pullResult.getPullStatus()) { + case FOUND: + break; + case NO_MATCHED_MSG: + break; + case NO_NEW_MSG: + case OFFSET_ILLEGAL: + break; + default: + break; + } + consumer.updateConsumeOffset(mq, pullResult.getNextBeginOffset()); + + context.setPullNextDelayTimeMillis(100); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + + scheduleService.start(); + } +} diff --git a/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/consumer/push/PushConsumer.java b/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/consumer/push/PushConsumer.java new file mode 100644 index 00000000..4342aa1f --- /dev/null +++ b/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/consumer/push/PushConsumer.java @@ -0,0 +1,31 @@ +package cn.cunchang.consumer.push; + +import java.util.List; +import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer; +import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext; +import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus; +import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently; +import org.apache.rocketmq.client.exception.MQClientException; +import org.apache.rocketmq.common.consumer.ConsumeFromWhere; +import org.apache.rocketmq.common.message.MessageExt; + +public class PushConsumer { + + public static void main(String[] args) throws InterruptedException, MQClientException { + DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("consumer_name_push_test"); + consumer.subscribe("push_test_topic", "*"); + consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET); + //wrong time format 2017_0422_221800 + consumer.setConsumeTimestamp("20170422221800"); + consumer.registerMessageListener(new MessageListenerConcurrently() { + + @Override + public ConsumeConcurrentlyStatus consumeMessage(List msgs, ConsumeConcurrentlyContext context) { + System.out.printf("%s Receive New Messages: %s %n", Thread.currentThread().getName(), msgs); + return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; + } + }); + consumer.start(); + System.out.printf("Consumer Started.%n"); + } +} diff --git a/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/consumer/retry/Consumer.java b/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/consumer/retry/Consumer.java new file mode 100644 index 00000000..1a4e2371 --- /dev/null +++ b/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/consumer/retry/Consumer.java @@ -0,0 +1,73 @@ +package cn.cunchang.consumer.retry; + +import cn.cunchang.contants.Const; +import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer; +import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext; +import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus; +import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently; +import org.apache.rocketmq.client.exception.MQClientException; +import org.apache.rocketmq.common.consumer.ConsumeFromWhere; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.remoting.common.RemotingHelper; + +import java.util.List; + +public class Consumer { + + + public static void main(String[] args) throws MQClientException { + + DefaultMQPushConsumer consumer = new DefaultMQPushConsumer(); + //指定NameServer地址,多个地址以 ; 隔开 + consumer.setNamesrvAddr(Const.NAMESRV_ADDR_SINGLE); + //CONSUME_FROM_LAST_OFFSET 默认策略,从该队列最尾开始消费,跳过历史消息 + //CONSUME_FROM_FIRST_OFFSET 从队列最开始开始消费,即历史消息(还储存在broker的)全部消费一遍 + consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET); + consumer.setConsumerGroup("test_quick_ms_consumer_name"); + //设置consumer所订阅的Topic和Tag,*代表全部的Tag + consumer.subscribe("test_quick_topic", "*"); + + consumer.registerMessageListener(new MessageListenerConcurrently() { + @Override + public ConsumeConcurrentlyStatus consumeMessage(List msgs, ConsumeConcurrentlyContext context) { + MessageExt me = msgs.get(0); + try { + String topic = me.getTopic(); + String tags = me.getTags(); + String keys = me.getKeys(); + + // 模拟消息消费失败异常 + //if(keys.equals("key1")) { + // System.err.println("消息消费失败.."); + // int a = 1/0; + //} + + String msgBody = new String(me.getBody(), RemotingHelper.DEFAULT_CHARSET); + System.err.println("topic: " + topic + ",tags: " + tags + ", keys: " + keys + ",body: " + msgBody); + } catch (Exception e) { + e.printStackTrace(); + // 消息重发次数 + int recousumeTimes = me.getReconsumeTimes(); + System.err.println("recousumeTimes: " + recousumeTimes); + if(recousumeTimes == 3) { + /* + * 对于broke消息重发到一定次数的时候 + * 记录日志.... + * 做补偿处理 + */ + System.out.println("消息无法消费 msid="+me.getMsgId()); + return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; + } + + // broke消息重发 + return ConsumeConcurrentlyStatus.RECONSUME_LATER; + } + return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; + } + }); + + consumer.start(); + System.err.println("consumer start..."); + + } +} diff --git a/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/consumer/retry/Producer.java b/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/consumer/retry/Producer.java new file mode 100644 index 00000000..1419294b --- /dev/null +++ b/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/consumer/retry/Producer.java @@ -0,0 +1,34 @@ +package cn.cunchang.consumer.retry; + +import cn.cunchang.contants.Const; +import org.apache.rocketmq.client.exception.MQBrokerException; +import org.apache.rocketmq.client.exception.MQClientException; +import org.apache.rocketmq.client.producer.DefaultMQProducer; +import org.apache.rocketmq.client.producer.SendResult; +import org.apache.rocketmq.common.message.Message; +import org.apache.rocketmq.remoting.exception.RemotingException; + +public class Producer { + + public static void main(String[] args) throws MQClientException, RemotingException, MQBrokerException, InterruptedException { + + DefaultMQProducer producer = new DefaultMQProducer("test_quick_ms_consumer_name"); + + producer.setNamesrvAddr(Const.NAMESRV_ADDR_MASTER_SLAVE); + + producer.start(); + + for (int i = 0; i < 1; i++) { + // 1、创建消息 + Message message = new Message("test_quick_topic", // 主题 + "TagA", // 标签 + "key" + i, // 用户自定义的key ,唯一的标识 + ("Hello RocketMQ" + i).getBytes()); // 消息内容实体(byte[]) + // 2、发送消息 + SendResult sr = producer.send(message); + System.err.println("消息发出:" + sr); + } + producer.shutdown(); + + } +} diff --git a/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/contants/Const.java b/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/contants/Const.java new file mode 100644 index 00000000..9e5a0e4e --- /dev/null +++ b/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/contants/Const.java @@ -0,0 +1,9 @@ +package cn.cunchang.contants; + +public interface Const { + + String NAMESRV_ADDR_SINGLE = "127.0.0.1:9876"; + + String NAMESRV_ADDR_MASTER_SLAVE = "127.0.0.1:9876;192.168.217.102:9876"; + +} diff --git a/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/filter/Consumer.java b/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/filter/Consumer.java new file mode 100644 index 00000000..6a0e7fec --- /dev/null +++ b/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/filter/Consumer.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package cn.cunchang.filter; + +import java.io.File; +import java.io.IOException; +import java.util.List; +import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer; +import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext; +import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus; +import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently; +import org.apache.rocketmq.client.exception.MQClientException; +import org.apache.rocketmq.common.MixAll; +import org.apache.rocketmq.common.message.MessageExt; + +public class Consumer { + + public static void main(String[] args) throws InterruptedException, MQClientException, IOException { + DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("ConsumerGroupNamecc4"); + + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + File classFile = new File(classLoader.getResource("MessageFilterImpl.java").getFile()); + + String filterCode = MixAll.file2String(classFile); + consumer.subscribe("TopicTest", "org.apache.rocketmq.example.filter.MessageFilterImpl", + filterCode); + + consumer.registerMessageListener(new MessageListenerConcurrently() { + + @Override + public ConsumeConcurrentlyStatus consumeMessage(List msgs, + ConsumeConcurrentlyContext context) { + System.out.printf("%s Receive New Messages: %s %n", Thread.currentThread().getName(), msgs); + return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; + } + }); + + consumer.start(); + + System.out.printf("Consumer Started.%n"); + } +} diff --git a/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/filter/Producer.java b/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/filter/Producer.java new file mode 100644 index 00000000..fbda03ae --- /dev/null +++ b/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/filter/Producer.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package cn.cunchang.filter; + +import org.apache.rocketmq.client.exception.MQClientException; +import org.apache.rocketmq.client.producer.DefaultMQProducer; +import org.apache.rocketmq.client.producer.SendResult; +import org.apache.rocketmq.common.message.Message; +import org.apache.rocketmq.remoting.common.RemotingHelper; + +public class Producer { + public static void main(String[] args) throws MQClientException, InterruptedException { + DefaultMQProducer producer = new DefaultMQProducer("ProducerGroupName"); + producer.start(); + + try { + for (int i = 0; i < 6000000; i++) { + Message msg = new Message("TopicFilter7", + "TagA", + "OrderID001", + "Hello world".getBytes(RemotingHelper.DEFAULT_CHARSET)); + + msg.putUserProperty("SequenceId", String.valueOf(i)); + SendResult sendResult = producer.send(msg); + System.out.printf("%s%n", sendResult); + } + } catch (Exception e) { + e.printStackTrace(); + } + producer.shutdown(); + } +} diff --git a/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/filter/SqlConsumer.java b/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/filter/SqlConsumer.java new file mode 100644 index 00000000..d3fc6950 --- /dev/null +++ b/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/filter/SqlConsumer.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.cunchang.filter; + +import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer; +import org.apache.rocketmq.client.consumer.MessageSelector; +import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext; +import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus; +import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently; +import org.apache.rocketmq.client.exception.MQClientException; +import org.apache.rocketmq.common.message.MessageExt; + +import java.util.List; + +public class SqlConsumer { + + public static void main(String[] args) { + DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("please_rename_unique_group_name_4"); + try { + consumer.subscribe("TopicTest", + MessageSelector.bySql("(TAGS is not null and TAGS in ('TagA', 'TagB'))" + + "and (a is not null and a between 0 3)")); + } catch (MQClientException e) { + e.printStackTrace(); + return; + } + + consumer.registerMessageListener(new MessageListenerConcurrently() { + + @Override + public ConsumeConcurrentlyStatus consumeMessage(List msgs, + ConsumeConcurrentlyContext context) { + System.out.printf("%s Receive New Messages: %s %n", Thread.currentThread().getName(), msgs); + return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; + } + }); + + try { + consumer.start(); + } catch (MQClientException e) { + e.printStackTrace(); + return; + } + System.out.printf("Consumer Started.%n"); + } +} diff --git a/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/filter/SqlProducer.java b/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/filter/SqlProducer.java new file mode 100644 index 00000000..f77308fa --- /dev/null +++ b/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/filter/SqlProducer.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.cunchang.filter; + +import org.apache.rocketmq.client.exception.MQClientException; +import org.apache.rocketmq.client.producer.DefaultMQProducer; +import org.apache.rocketmq.client.producer.SendResult; +import org.apache.rocketmq.common.message.Message; +import org.apache.rocketmq.remoting.common.RemotingHelper; + +public class SqlProducer { + + public static void main(String[] args) { + DefaultMQProducer producer = new DefaultMQProducer("please_rename_unique_group_name"); + try { + producer.start(); + } catch (MQClientException e) { + e.printStackTrace(); + return; + } + + for (int i = 0; i < 10; i++) { + try { + String tag; + int div = i % 3; + if (div == 0) { + tag = "TagA"; + } else if (div == 1) { + tag = "TagB"; + } else { + tag = "TagC"; + } + Message msg = new Message("TopicTest", + tag, + ("Hello RocketMQ " + i).getBytes(RemotingHelper.DEFAULT_CHARSET) + ); + msg.putUserProperty("a", String.valueOf(i)); + + SendResult sendResult = producer.send(msg); + System.out.printf("%s%n", sendResult); + } catch (Exception e) { + e.printStackTrace(); + try { + Thread.sleep(1000); + } catch (InterruptedException e1) { + e1.printStackTrace(); + } + } + } + producer.shutdown(); + } +} diff --git a/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/ordermsg/ConsumerInOrder.java b/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/ordermsg/ConsumerInOrder.java new file mode 100644 index 00000000..86eda770 --- /dev/null +++ b/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/ordermsg/ConsumerInOrder.java @@ -0,0 +1,56 @@ +package cn.cunchang.ordermsg; + +import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer; +import org.apache.rocketmq.client.consumer.listener.ConsumeOrderlyContext; +import org.apache.rocketmq.client.consumer.listener.ConsumeOrderlyStatus; +import org.apache.rocketmq.client.consumer.listener.MessageListenerOrderly; +import org.apache.rocketmq.common.consumer.ConsumeFromWhere; +import org.apache.rocketmq.common.message.MessageExt; + +import java.util.List; +import java.util.Random; +import java.util.concurrent.TimeUnit; + +/** +* 顺序消息消费,带事务方式(应用可控制Offset什么时候提交) +*/ +public class ConsumerInOrder { + + public static void main(String[] args) throws Exception { + DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("test_quick_consumer_name"); + consumer.setNamesrvAddr("127.0.0.1:9876"); + /** + * 设置Consumer第一次启动是从队列头部开始消费还是队列尾部开始消费
+ * 如果非第一次启动,那么按照上次消费的位置继续消费 + */ + consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET); + + consumer.subscribe("test_quick_topic", "TagA || TagC || TagD"); + + consumer.registerMessageListener(new MessageListenerOrderly() { + + Random random = new Random(); + + @Override + public ConsumeOrderlyStatus consumeMessage(List msgs, ConsumeOrderlyContext context) { + context.setAutoCommit(true); + for (MessageExt msg : msgs) { + // 可以看到每个queue有唯一的consume线程来消费, 订单对每个queue(分区)有序 + System.out.println("consumeThread=" + Thread.currentThread().getName() + "queueId=" + msg.getQueueId() + ", content:" + new String(msg.getBody())); + } + + try { + //模拟业务逻辑处理中... + TimeUnit.SECONDS.sleep(random.nextInt(10)); + } catch (Exception e) { + e.printStackTrace(); + } + return ConsumeOrderlyStatus.SUCCESS; + } + }); + + consumer.start(); + + System.out.println("Consumer Started."); + } +} \ No newline at end of file diff --git a/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/ordermsg/Producer.java b/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/ordermsg/Producer.java new file mode 100644 index 00000000..bf7f9ecf --- /dev/null +++ b/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/ordermsg/Producer.java @@ -0,0 +1,153 @@ +package cn.cunchang.ordermsg; + +import org.apache.rocketmq.client.producer.DefaultMQProducer; +import org.apache.rocketmq.client.producer.MessageQueueSelector; +import org.apache.rocketmq.client.producer.SendResult; +import org.apache.rocketmq.common.message.Message; +import org.apache.rocketmq.common.message.MessageQueue; + +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +public class Producer { + /** + * Producer,发送顺序消息 + */ + public static void main(String[] args) throws Exception { + DefaultMQProducer producer = new DefaultMQProducer(); + producer.setProducerGroup("test_quick_consumer_name"); + producer.setNamesrvAddr("127.0.0.1:9876"); + producer.start(); + + String[] tags = new String[]{"TagA", "TagC", "TagD"}; + + // 订单列表 + List orderList = new Producer().buildOrders(); + + Date date = new Date(); + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + String dateStr = sdf.format(date); + for (int i = 0; i < 10; i++) { + // 加个时间前缀 + String body = dateStr + " Hello RocketMQ " + orderList.get(i); + Message msg = new Message("test_quick_topic", tags[i % tags.length], "KEY" + i, body.getBytes()); + + SendResult sendResult = producer.send(msg, new MessageQueueSelector() { + /** + * 发送消息的队列选择器 + * 控制发送的顺序消息只依次发送到同一个queue中,消费的时候只从这个queue上依次拉取,则就保证了顺序 + * @param mqs + * @param msg + * @param arg + * @return + */ + @Override + public MessageQueue select(List mqs, Message msg, Object arg) { + Long id = (Long) arg; //根据订单id选择发送queue + long index = id % mqs.size(); + return mqs.get((int) index); + } + }, orderList.get(i).getOrderId());//订单id + + System.out.println(String.format("SendResult status:%s, queueId:%d, body:%s", + sendResult.getSendStatus(), + sendResult.getMessageQueue().getQueueId(), + body)); + } + + producer.shutdown(); + } + + /** + * 订单的步骤 + */ + private static class OrderStep { + private long orderId; + private String desc; + + public long getOrderId() { + return orderId; + } + + public void setOrderId(long orderId) { + this.orderId = orderId; + } + + public String getDesc() { + return desc; + } + + public void setDesc(String desc) { + this.desc = desc; + } + + @Override + public String toString() { + return "OrderStep{" + + "orderId=" + orderId + + ", desc='" + desc + '\'' + + '}'; + } + } + + /** + * 生成模拟订单数据 + */ + private List buildOrders() { + List orderList = new ArrayList(); + + OrderStep orderDemo = new OrderStep(); + orderDemo.setOrderId(15103111039L); + orderDemo.setDesc("创建"); + orderList.add(orderDemo); + + orderDemo = new OrderStep(); + orderDemo.setOrderId(15103111065L); + orderDemo.setDesc("创建"); + orderList.add(orderDemo); + + orderDemo = new OrderStep(); + orderDemo.setOrderId(15103111039L); + orderDemo.setDesc("付款"); + orderList.add(orderDemo); + + orderDemo = new OrderStep(); + orderDemo.setOrderId(15103117235L); + orderDemo.setDesc("创建"); + orderList.add(orderDemo); + + orderDemo = new OrderStep(); + orderDemo.setOrderId(15103111065L); + orderDemo.setDesc("付款"); + orderList.add(orderDemo); + + orderDemo = new OrderStep(); + orderDemo.setOrderId(15103117235L); + orderDemo.setDesc("付款"); + orderList.add(orderDemo); + + orderDemo = new OrderStep(); + orderDemo.setOrderId(15103111065L); + orderDemo.setDesc("完成"); + orderList.add(orderDemo); + + orderDemo = new OrderStep(); + orderDemo.setOrderId(15103111039L); + orderDemo.setDesc("推送"); + orderList.add(orderDemo); + + orderDemo = new OrderStep(); + orderDemo.setOrderId(15103117235L); + orderDemo.setDesc("完成"); + orderList.add(orderDemo); + + orderDemo = new OrderStep(); + orderDemo.setOrderId(15103111039L); + orderDemo.setDesc("完成"); + orderList.add(orderDemo); + + return orderList; + } +} \ No newline at end of file diff --git a/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/producer/PushConsumer.java b/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/producer/PushConsumer.java new file mode 100644 index 00000000..fbdf6d06 --- /dev/null +++ b/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/producer/PushConsumer.java @@ -0,0 +1,59 @@ +package cn.cunchang.producer; + +import cn.cunchang.contants.Const; +import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer; +import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext; +import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus; +import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently; +import org.apache.rocketmq.client.exception.MQClientException; +import org.apache.rocketmq.common.consumer.ConsumeFromWhere; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.remoting.common.RemotingHelper; + +import java.util.List; + +public class PushConsumer { + + public static void main(String[] args) throws MQClientException { + + DefaultMQPushConsumer consumer = new DefaultMQPushConsumer(); + + //指定NameServer地址,多个地址以 ; 隔开 + consumer.setNamesrvAddr(Const.NAMESRV_ADDR_SINGLE); + + //CONSUME_FROM_LAST_OFFSET 默认策略,从该队列最尾开始消费,跳过历史消息 + //CONSUME_FROM_FIRST_OFFSET 从队列最开始开始消费,即历史消息(还储存在broker的)全部消费一遍 + consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET); + consumer.setConsumerGroup("test_quick_consumer_name"); + + //设置consumer所订阅的Topic和Tag,*代表全部的Tag + consumer.subscribe("test_quick_topic", "*"); + + consumer.registerMessageListener(new MessageListenerConcurrently() { + @Override + public ConsumeConcurrentlyStatus consumeMessage(List msgs, ConsumeConcurrentlyContext context) { + System.out.printf("\npull 到 %d 条消息",msgs.size()); + for (MessageExt msg : msgs) { + try { + String topic = msg.getTopic(); + String tags = msg.getTags(); + String keys = msg.getKeys(); + + String msgBody = new String(msg.getBody(), RemotingHelper.DEFAULT_CHARSET); + System.err.println("消费消息--- topic: " + topic + ",tags: " + tags + ", keys: " + keys + ",body: " + msgBody); + } catch (Exception e) { + e.printStackTrace(); + // broke消息重发 + return ConsumeConcurrentlyStatus.RECONSUME_LATER; + } + } + //消费成功 + return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; + } + }); + + consumer.start(); + System.err.println("consumer start..."); + + } +} diff --git a/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/producer/async/AsyncProducer.java b/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/producer/async/AsyncProducer.java new file mode 100644 index 00000000..ab4a8395 --- /dev/null +++ b/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/producer/async/AsyncProducer.java @@ -0,0 +1,57 @@ +package cn.cunchang.producer.async; + +import cn.cunchang.contants.Const; +import org.apache.rocketmq.client.producer.DefaultMQProducer; +import org.apache.rocketmq.client.producer.SendCallback; +import org.apache.rocketmq.client.producer.SendResult; +import org.apache.rocketmq.common.CountDownLatch2; +import org.apache.rocketmq.common.message.Message; +import org.apache.rocketmq.remoting.common.RemotingHelper; + +import java.util.concurrent.TimeUnit; + +public class AsyncProducer { + /** + * 异步消息通常用在对响应时间敏感的业务场景,即发送端不能容忍长时间地等待Broker的响应。 + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + // 实例化消息生产者Producer + DefaultMQProducer producer = new DefaultMQProducer("test_quick_producer_name"); + // 设置NameServer的地址 + producer.setNamesrvAddr(Const.NAMESRV_ADDR_SINGLE); + // 启动Producer实例 + producer.start(); + producer.setRetryTimesWhenSendAsyncFailed(0); + + int messageCount = 100; + // 根据消息数量实例化倒计时计算器 + final CountDownLatch2 countDownLatch = new CountDownLatch2(messageCount); + for (int i = 0; i < messageCount; i++) { + final int index = i; + // 创建消息,并指定Topic,Tag和消息体 + Message msg = new Message("test_quick_topic", + "TagA", + "OrderID"+index, + "Hello RocketMQ AsyncProducer".getBytes(RemotingHelper.DEFAULT_CHARSET)); + // SendCallback接收异步返回结果的回调 + producer.send(msg, new SendCallback() { + @Override + public void onSuccess(SendResult sendResult) { + System.out.printf("%-10d onSuccess %s %n", index, + sendResult.getMsgId()); + } + @Override + public void onException(Throwable e) { + System.out.printf("%-10d onException %s %n", index, e); + e.printStackTrace(); + } + }); + } + // 等待5s + countDownLatch.await(5, TimeUnit.SECONDS); + // 如果不再发送消息,关闭Producer实例。 + producer.shutdown(); + } +} diff --git a/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/producer/oneway/OnewayProducer.java b/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/producer/oneway/OnewayProducer.java new file mode 100644 index 00000000..56e81f1e --- /dev/null +++ b/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/producer/oneway/OnewayProducer.java @@ -0,0 +1,36 @@ +package cn.cunchang.producer.oneway; + +import cn.cunchang.contants.Const; +import org.apache.rocketmq.client.producer.DefaultMQProducer; +import org.apache.rocketmq.common.message.Message; +import org.apache.rocketmq.remoting.common.RemotingHelper; + +public class OnewayProducer { + /** + * 这种方式主要用在不特别关心发送结果的场景,例如日志发送。 + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception{ + // 实例化消息生产者Producer + DefaultMQProducer producer = new DefaultMQProducer(); + // 设置NameServer的地址 + producer.setNamesrvAddr(Const.NAMESRV_ADDR_SINGLE); + // 生产者的组名 + producer.setProducerGroup("test_quick_producer_name"); + // 启动Producer实例 + producer.start(); + + for (int i = 0; i < 100; i++) { + //Create a message instance, specifying topic, tag and message body. + Message msg = new Message("test_quick_topic" /* Topic */, + "TagA" /* Tag */, + ("Hello RocketMQ OnewayProducer" + + i).getBytes(RemotingHelper.DEFAULT_CHARSET) /* Message body */ + ); + //Call send message to deliver message to one of brokers. + producer.sendOneway(msg); + } + producer.shutdown(); + } +} \ No newline at end of file diff --git a/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/producer/sync/SyncProducer.java b/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/producer/sync/SyncProducer.java new file mode 100644 index 00000000..18314734 --- /dev/null +++ b/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/producer/sync/SyncProducer.java @@ -0,0 +1,45 @@ +package cn.cunchang.producer.sync; + +import cn.cunchang.contants.Const; +import org.apache.rocketmq.client.exception.MQBrokerException; +import org.apache.rocketmq.client.exception.MQClientException; +import org.apache.rocketmq.client.producer.DefaultMQProducer; +import org.apache.rocketmq.client.producer.SendResult; +import org.apache.rocketmq.common.message.Message; +import org.apache.rocketmq.remoting.exception.RemotingException; + +public class SyncProducer { + + /** + * 这种可靠性同步地发送方式使用的比较广泛,比如:重要的消息通知,短信通知。 + * @param args + * @throws MQClientException + * @throws RemotingException + * @throws MQBrokerException + * @throws InterruptedException + */ + public static void main(String[] args) throws MQClientException, RemotingException, MQBrokerException, InterruptedException { + // 实例化消息生产者Producer + DefaultMQProducer producer = new DefaultMQProducer(); + // 设置NameServer的地址 + producer.setNamesrvAddr(Const.NAMESRV_ADDR_SINGLE); + // 生产者的组名 + producer.setProducerGroup("test_quick_producer_name"); + // 启动Producer实例 + producer.start(); + + for (int i = 0; i < 5; i++) { + // 1、创建消息 + Message message = new Message("test_quick_topic", // 主题 + "TagA", // 标签,用于消息过滤 + "key" + i, // 用户自定义的key ,用于唯一的标识 + ("Hello RocketMQ SyncProducer" + i).getBytes()); // 消息内容实体(byte[]) + // 2、发送消息 + SendResult result = producer.send(message); + System.out.println("发送消息--- MsgId:" + result.getMsgId() + ",发送状态:" + result.getSendStatus()); + } + // 如果不再发送消息,关闭Producer实例。 + producer.shutdown(); + + } +} diff --git a/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/quickstart/Consumer.java b/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/quickstart/Consumer.java new file mode 100644 index 00000000..361fa8a8 --- /dev/null +++ b/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/quickstart/Consumer.java @@ -0,0 +1,82 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package cn.cunchang.quickstart; + +import java.util.List; +import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer; +import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext; +import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus; +import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently; +import org.apache.rocketmq.client.exception.MQClientException; +import org.apache.rocketmq.common.consumer.ConsumeFromWhere; +import org.apache.rocketmq.common.message.MessageExt; + +/** + * This example shows how to subscribe and consume messages using providing {@link DefaultMQPushConsumer}. + */ +public class Consumer { + + public static void main(String[] args) throws InterruptedException, MQClientException { + + /* + * Instantiate with specified consumer group name. + */ + DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("please_rename_unique_group_name_4"); + + /* + * Specify name server addresses. + *

+ * + * Alternatively, you may specify name server addresses via exporting environmental variable: NAMESRV_ADDR + *

+         * {@code
+         * consumer.setNamesrvAddr("name-server1-ip:9876;name-server2-ip:9876");
+         * }
+         * 
+ */ + + /* + * Specify where to start in case the specified consumer group is a brand new one. + */ + consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET); + + /* + * Subscribe one more more topics to consume. + */ + consumer.subscribe("TopicTest", "*"); + + /* + * Register callback to execute on arrival of messages fetched from brokers. + */ + consumer.registerMessageListener(new MessageListenerConcurrently() { + + @Override + public ConsumeConcurrentlyStatus consumeMessage(List msgs, + ConsumeConcurrentlyContext context) { + System.out.printf("%s Receive New Messages: %s %n", Thread.currentThread().getName(), msgs); + return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; + } + }); + + /* + * Launch the consumer instance. + */ + consumer.start(); + + System.out.printf("Consumer Started.%n"); + } +} diff --git a/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/quickstart/Producer.java b/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/quickstart/Producer.java new file mode 100644 index 00000000..e92dc6da --- /dev/null +++ b/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/quickstart/Producer.java @@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package cn.cunchang.quickstart; + +import org.apache.rocketmq.client.exception.MQClientException; +import org.apache.rocketmq.client.producer.DefaultMQProducer; +import org.apache.rocketmq.client.producer.SendResult; +import org.apache.rocketmq.common.message.Message; +import org.apache.rocketmq.remoting.common.RemotingHelper; + +/** + * This class demonstrates how to send messages to brokers using provided {@link DefaultMQProducer}. + */ +public class Producer { + public static void main(String[] args) throws MQClientException, InterruptedException { + + /* + * Instantiate with a producer group name. + */ + DefaultMQProducer producer = new DefaultMQProducer("please_rename_unique_group_name"); + + /* + * Specify name server addresses. + *

+ * + * Alternatively, you may specify name server addresses via exporting environmental variable: NAMESRV_ADDR + *

+         * {@code
+         * producer.setNamesrvAddr("name-server1-ip:9876;name-server2-ip:9876");
+         * }
+         * 
+ */ + + /* + * Launch the instance. + */ + producer.start(); + + for (int i = 0; i < 1000; i++) { + try { + + /* + * Create a message instance, specifying topic, tag and message body. + */ + Message msg = new Message("TopicTest" /* Topic */, + "TagA" /* Tag */, + ("Hello RocketMQ " + i).getBytes(RemotingHelper.DEFAULT_CHARSET) /* Message body */ + ); + + /* + * Call send message to deliver message to one of brokers. + */ + SendResult sendResult = producer.send(msg); + + System.out.printf("%s%n", sendResult); + } catch (Exception e) { + e.printStackTrace(); + Thread.sleep(1000); + } + } + + /* + * Shut down once the producer instance is not longer in use. + */ + producer.shutdown(); + } +} diff --git a/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/schedulemsg/ScheduledMessageConsumer.java b/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/schedulemsg/ScheduledMessageConsumer.java new file mode 100644 index 00000000..d8b5be38 --- /dev/null +++ b/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/schedulemsg/ScheduledMessageConsumer.java @@ -0,0 +1,32 @@ +package cn.cunchang.schedulemsg; + +import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer; +import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext; +import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus; +import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently; +import org.apache.rocketmq.common.message.MessageExt; + +import java.util.List; + +public class ScheduledMessageConsumer { + public static void main(String[] args) throws Exception { + // 实例化消费者 + DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("ExampleConsumer"); + consumer.setNamesrvAddr("127.0.0.1:9876"); + // 订阅Topics + consumer.subscribe("test_quick_topic", "*"); + // 注册消息监听者 + consumer.registerMessageListener(new MessageListenerConcurrently() { + @Override + public ConsumeConcurrentlyStatus consumeMessage(List messages, ConsumeConcurrentlyContext context) { + for (MessageExt message : messages) { + // Print approximate delay time period + System.out.println("Receive message[msgId=" + message.getMsgId() + "] " + (System.currentTimeMillis() - message.getStoreTimestamp()) + "ms later"); + } + return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; + } + }); + // 启动消费者 + consumer.start(); + } +} \ No newline at end of file diff --git a/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/schedulemsg/ScheduledMessageProducer.java b/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/schedulemsg/ScheduledMessageProducer.java new file mode 100644 index 00000000..d1fd9b00 --- /dev/null +++ b/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/schedulemsg/ScheduledMessageProducer.java @@ -0,0 +1,24 @@ +package cn.cunchang.schedulemsg; + +import org.apache.rocketmq.client.producer.DefaultMQProducer; +import org.apache.rocketmq.common.message.Message; + +public class ScheduledMessageProducer { + public static void main(String[] args) throws Exception { + // 实例化一个生产者来产生延时消息 + DefaultMQProducer producer = new DefaultMQProducer("ExampleProducerGroup"); + producer.setNamesrvAddr("127.0.0.1:9876"); + // 启动生产者 + producer.start(); + int totalMessagesToSend = 100; + for (int i = 0; i < totalMessagesToSend; i++) { + Message message = new Message("test_quick_topic", ("Hello scheduled message " + i).getBytes()); + // 设置延时等级3,这个消息将在10s之后发送(现在只支持固定的几个时间,详看delayTimeLevel) + message.setDelayTimeLevel(3); + // 发送消息 + producer.send(message); + } + // 关闭生产者 + producer.shutdown(); + } +} \ No newline at end of file diff --git a/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/transaction/Consumer.java b/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/transaction/Consumer.java new file mode 100644 index 00000000..e3a3e37c --- /dev/null +++ b/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/transaction/Consumer.java @@ -0,0 +1,53 @@ +package cn.cunchang.transaction; + +import cn.cunchang.contants.Const; +import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer; +import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext; +import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus; +import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently; +import org.apache.rocketmq.client.exception.MQClientException; +import org.apache.rocketmq.common.consumer.ConsumeFromWhere; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.remoting.common.RemotingHelper; + +import java.util.List; + +public class Consumer { + + public static void main(String[] args) throws InterruptedException, MQClientException { + DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("transaction_producer_name_test"); + consumer.setNamesrvAddr(Const.NAMESRV_ADDR_SINGLE); + consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET); + consumer.subscribe("transaction_producer_topic_test", "*"); + + consumer.registerMessageListener(new MessageListenerConcurrently() { + @Override + public ConsumeConcurrentlyStatus consumeMessage(List msgs, ConsumeConcurrentlyContext context) { + aVoid(msgs); + for (MessageExt msg : msgs) { + try { + String topic = msg.getTopic(); + String tags = msg.getTags(); + String keys = msg.getKeys(); + + String msgBody = new String(msg.getBody(), RemotingHelper.DEFAULT_CHARSET); + System.err.println("收到事务消息--- topic: " + topic + ",tags: " + tags + ", keys: " + keys + ",body: " + msgBody); + } catch (Exception e) { + e.printStackTrace(); + // broke消息重发 + return ConsumeConcurrentlyStatus.RECONSUME_LATER; + } + } + //消费成功 + return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; + } + }); + consumer.start(); + System.out.printf("tx Consumer Started.%n"); + } + + public static synchronized void aVoid(List msgs){ + System.out.printf("\npull 到 %d 条消息",msgs.size()); + } + +} diff --git a/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/transaction/TransactionListenerImpl.java b/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/transaction/TransactionListenerImpl.java new file mode 100644 index 00000000..2ec611c7 --- /dev/null +++ b/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/transaction/TransactionListenerImpl.java @@ -0,0 +1,53 @@ +package cn.cunchang.transaction; + +import org.apache.commons.lang3.StringUtils; +import org.apache.rocketmq.client.producer.LocalTransactionState; +import org.apache.rocketmq.client.producer.TransactionListener; +import org.apache.rocketmq.common.message.Message; +import org.apache.rocketmq.common.message.MessageExt; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicInteger; + +public class TransactionListenerImpl implements TransactionListener { + + /** + * 执行本地事务 + * + * @param msg + * @param arg 回调参数 + * @return + */ + @Override + public LocalTransactionState executeLocalTransaction(Message msg, Object arg) { + System.err.println("TransactionListenerImpl executeLocalTransaction 异步执行本地事务 msg:" + msg + " arg:" + arg); + String tags = msg.getTags(); + if(StringUtils.contains(tags,"TagA")){ + // 事务提交 + return LocalTransactionState.COMMIT_MESSAGE; + }else if(StringUtils.contains(tags,"TagB")){ + return LocalTransactionState.ROLLBACK_MESSAGE; + }else{ + return LocalTransactionState.UNKNOW; + } + } + + /** + * 本地事务执行返回LocalTransactionState.UNKNOW时进行回查事务状态 + * + * @param msg + * @return + */ + @Override + public LocalTransactionState checkLocalTransaction(MessageExt msg) { + System.err.println("TransactionListenerImpl checkLocalTransaction 回调消息检查 msg:" + msg); + String tags = msg.getTags(); + if(StringUtils.contains(tags,"TagC")){ + return LocalTransactionState.COMMIT_MESSAGE; + }else if(StringUtils.contains(tags,"TagD")){ + return LocalTransactionState.ROLLBACK_MESSAGE; + }else{ + return LocalTransactionState.UNKNOW; + } + } +} \ No newline at end of file diff --git a/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/transaction/TransactionProducer.java b/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/transaction/TransactionProducer.java new file mode 100644 index 00000000..d1ae9952 --- /dev/null +++ b/distributed/mq/rocketmq/rocketmq-api/src/main/java/cn/cunchang/transaction/TransactionProducer.java @@ -0,0 +1,47 @@ +package cn.cunchang.transaction; + +import cn.cunchang.contants.Const; +import org.apache.rocketmq.client.exception.MQClientException; +import org.apache.rocketmq.client.producer.SendResult; +import org.apache.rocketmq.client.producer.TransactionListener; +import org.apache.rocketmq.client.producer.TransactionMQProducer; +import org.apache.rocketmq.common.message.Message; +import org.apache.rocketmq.remoting.common.RemotingHelper; + +import java.io.UnsupportedEncodingException; +import java.util.concurrent.*; + +public class TransactionProducer { + public static void main(String[] args) throws MQClientException, InterruptedException { + TransactionListener transactionListener = new TransactionListenerImpl(); + TransactionMQProducer producer = new TransactionMQProducer("transaction_producer_name_test"); + ExecutorService executorService = new ThreadPoolExecutor(2, 5, 100, TimeUnit.SECONDS, new ArrayBlockingQueue(2000), new ThreadFactory() { + @Override + public Thread newThread(Runnable r) { + Thread thread = new Thread(r); + thread.setName("client-transaction-msg-check-thread"); + return thread; + } + }); + producer.setNamesrvAddr(Const.NAMESRV_ADDR_SINGLE); + producer.setExecutorService(executorService); + producer.setTransactionListener(transactionListener); + producer.start(); + String[] tags = new String[]{"TagA", "TagB", "TagC", "TagD", "TagE"}; + for (int i = 0; i < 10; i++) { + try { + Message msg = new Message("transaction_producer_topic_test", tags[i % tags.length], "KEY" + i, + ("Hello RocketMQ " + i).getBytes(RemotingHelper.DEFAULT_CHARSET)); + SendResult sendResult = producer.sendMessageInTransaction(msg, "我是回调参数,可能会用到"); + System.out.printf("%s%n", sendResult); + Thread.sleep(10); + } catch (MQClientException | UnsupportedEncodingException e) { + e.printStackTrace(); + } + } + for (int i = 0; i < 100000; i++) { + Thread.sleep(1000); + } + producer.shutdown(); + } +} \ No newline at end of file diff --git a/distributed/mq/rocketmq/springboot-rocketmq/pom.xml b/distributed/mq/rocketmq/springboot-rocketmq/pom.xml new file mode 100644 index 00000000..916c2fed --- /dev/null +++ b/distributed/mq/rocketmq/springboot-rocketmq/pom.xml @@ -0,0 +1,53 @@ + + + 4.0.0 + + springboot-rocketmq + org.example + 0.0.1 + + + + org.apache.rocketmq + rocketmq-spring-boot-starter + 2.1.1 + + + org.springframework.boot + spring-boot-starter + + + org.springframework + spring-core + + + org.springframework + spring-webmvc + + + + + org.springframework.boot + spring-boot-starter-web + 2.1.6.RELEASE + + + org.springframework.boot + spring-boot-starter-test + 2.1.6.RELEASE + + + io.springfox + springfox-swagger-ui + 2.9.2 + + + io.springfox + springfox-swagger2 + 2.9.2 + + + + \ No newline at end of file diff --git a/distributed/mq/rocketmq/springboot-rocketmq/src/main/java/com/roy/rocketmq/RocketMQSBApplication.java b/distributed/mq/rocketmq/springboot-rocketmq/src/main/java/com/roy/rocketmq/RocketMQSBApplication.java new file mode 100644 index 00000000..ee55cb04 --- /dev/null +++ b/distributed/mq/rocketmq/springboot-rocketmq/src/main/java/com/roy/rocketmq/RocketMQSBApplication.java @@ -0,0 +1,18 @@ +package com.roy.rocketmq; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * @author :楼兰 + * @date :Created in 2020/11/28 + * @description: + **/ + +@SpringBootApplication +public class RocketMQSBApplication { + + public static void main(String[] args) { + SpringApplication.run(RocketMQSBApplication.class,args); + } +} diff --git a/distributed/mq/rocketmq/springboot-rocketmq/src/main/java/com/roy/rocketmq/basic/SpringConsumer.java b/distributed/mq/rocketmq/springboot-rocketmq/src/main/java/com/roy/rocketmq/basic/SpringConsumer.java new file mode 100644 index 00000000..c75e1cd1 --- /dev/null +++ b/distributed/mq/rocketmq/springboot-rocketmq/src/main/java/com/roy/rocketmq/basic/SpringConsumer.java @@ -0,0 +1,21 @@ +package com.roy.rocketmq.basic; + +import org.apache.rocketmq.spring.annotation.ConsumeMode; +import org.apache.rocketmq.spring.annotation.RocketMQMessageListener; +import org.apache.rocketmq.spring.core.RocketMQListener; +import org.springframework.stereotype.Component; + +/** + * 注意下@RocketMQMessageListener这个注解的其他属性 + * @author :楼兰 + * @date :Created in 2020/10/22 + * @description: + **/ +@Component +@RocketMQMessageListener(consumerGroup = "MyConsumerGroup", topic = "TestTopic",consumeMode= ConsumeMode.CONCURRENTLY) +public class SpringConsumer implements RocketMQListener { + @Override + public void onMessage(String message) { + System.out.println("Received message : "+ message); + } +} diff --git a/distributed/mq/rocketmq/springboot-rocketmq/src/main/java/com/roy/rocketmq/basic/SpringProducer.java b/distributed/mq/rocketmq/springboot-rocketmq/src/main/java/com/roy/rocketmq/basic/SpringProducer.java new file mode 100644 index 00000000..fb8119fd --- /dev/null +++ b/distributed/mq/rocketmq/springboot-rocketmq/src/main/java/com/roy/rocketmq/basic/SpringProducer.java @@ -0,0 +1,46 @@ +package com.roy.rocketmq.basic; + +import org.apache.rocketmq.client.producer.SendResult; +import org.apache.rocketmq.spring.core.RocketMQTemplate; +import org.apache.rocketmq.spring.support.RocketMQHeaders; +import org.springframework.messaging.Message; +import org.springframework.messaging.support.MessageBuilder; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * @author :楼兰 + * @date :Created in 2020/10/22 + * @description: + **/ +@Component +public class SpringProducer { + + @Resource + private RocketMQTemplate rocketMQTemplate; + + public void sendMessage(String topic,String msg){ + this.rocketMQTemplate.convertAndSend(topic,msg); + } + + public void sendMessageInTransaction(String topic,String msg) throws InterruptedException { + String[] tags = new String[] {"TagA", "TagB", "TagC", "TagD", "TagE"}; + for (int i = 0; i < 10; i++) { + //尝试在Header中加入一些自定义的属性。 + Message message = MessageBuilder.withPayload(msg) + .setHeader(RocketMQHeaders.TRANSACTION_ID,"TransID_"+i) + //发到事务监听器里后,这个自己设定的TAGS属性会丢失。但是上面那个属性不会丢失。 + .setHeader(RocketMQHeaders.TAGS,tags[i % tags.length]) + //MyProp在事务监听器里也能拿到,为什么就单单这个RocketMQHeaders.TAGS拿不到?这只能去调源码了。 + .setHeader("MyProp","MyProp_"+i) + .build(); + String destination =topic+":"+tags[i % tags.length]; + //这里发送事务消息时,还是会转换成RocketMQ的Message对象,再调用RocketMQ的API完成事务消息机制。 + SendResult sendResult = rocketMQTemplate.sendMessageInTransaction(destination, message,destination); + System.out.printf("%s%n", sendResult); + + Thread.sleep(10); + } + } +} diff --git a/distributed/mq/rocketmq/springboot-rocketmq/src/main/java/com/roy/rocketmq/config/ExtRocketMQTemplate.java b/distributed/mq/rocketmq/springboot-rocketmq/src/main/java/com/roy/rocketmq/config/ExtRocketMQTemplate.java new file mode 100644 index 00000000..7569c2cf --- /dev/null +++ b/distributed/mq/rocketmq/springboot-rocketmq/src/main/java/com/roy/rocketmq/config/ExtRocketMQTemplate.java @@ -0,0 +1,13 @@ +package com.roy.rocketmq.config; + +import org.apache.rocketmq.spring.annotation.ExtRocketMQTemplateConfiguration; +import org.apache.rocketmq.spring.core.RocketMQTemplate; + +/** + * @author :楼兰 + * @date :Created in 2020/12/4 + * @description: + **/ +@ExtRocketMQTemplateConfiguration() +public class ExtRocketMQTemplate extends RocketMQTemplate { +} diff --git a/distributed/mq/rocketmq/springboot-rocketmq/src/main/java/com/roy/rocketmq/config/MyTransactionImpl.java b/distributed/mq/rocketmq/springboot-rocketmq/src/main/java/com/roy/rocketmq/config/MyTransactionImpl.java new file mode 100644 index 00000000..8944944b --- /dev/null +++ b/distributed/mq/rocketmq/springboot-rocketmq/src/main/java/com/roy/rocketmq/config/MyTransactionImpl.java @@ -0,0 +1,65 @@ +package com.roy.rocketmq.config; + +import org.apache.commons.lang3.StringUtils; +import org.apache.rocketmq.spring.annotation.RocketMQTransactionListener; +import org.apache.rocketmq.spring.core.RocketMQLocalTransactionListener; +import org.apache.rocketmq.spring.core.RocketMQLocalTransactionState; +import org.apache.rocketmq.spring.support.RocketMQHeaders; +import org.apache.rocketmq.spring.support.RocketMQUtil; +import org.springframework.messaging.Message; +import org.springframework.messaging.converter.StringMessageConverter; + +import java.util.concurrent.ConcurrentHashMap; + +/** + * @author :楼兰 + * @date :Created in 2020/11/5 + * @description: 事务消息监听器 + * 关于@RocketMQTransactionListener 这个注解,有点奇怪。2.0.4版本中,是需要指定txProducerGroup指向一个消息发送者组。不同的组可以有不同的事务消息逻辑。 + * 但是到了2.1.1版本,只能指定rocketMQTemplateBeanMame,也就是说如果你有多个发送者组需要有不同的事务消息逻辑,那就需要定义多个RocketMQTemplate。 + * 而且这个版本中,虽然重现了我们在原生API中的事务消息逻辑,但是测试过程中还是发现一些奇怪的特性,用的时候要注意点。 + **/ +//@RocketMQTransactionListener(txProducerGroup = "springBootGroup2") +@RocketMQTransactionListener(rocketMQTemplateBeanName = "rocketMQTemplate") +public class MyTransactionImpl implements RocketMQLocalTransactionListener { + + private ConcurrentHashMap localTrans = new ConcurrentHashMap<>(); + @Override + public RocketMQLocalTransactionState executeLocalTransaction(Message msg, Object arg) { + Object transId = msg.getHeaders().get(RocketMQHeaders.PREFIX+RocketMQHeaders.TRANSACTION_ID); + String destination = arg.toString(); + localTrans.put(transId,msg); + //这个msg的实现类是GenericMessage,里面实现了toString方法 + //在Header中自定义的RocketMQHeaders.TAGS属性,到这里就没了。但是RocketMQHeaders.TRANSACTION_ID这个属性就还在。 + //而message的Header里面会默认保存RocketMQHeaders里的属性,但是都会加上一个RocketMQHeaders.PREFIX前缀 + System.out.println("executeLocalTransaction msg = "+msg); + //转成RocketMQ的Message对象 + org.apache.rocketmq.common.message.Message message = RocketMQUtil.convertToRocketMessage(new StringMessageConverter(),"UTF-8",destination, msg); + String tags = message.getTags(); + if(StringUtils.contains(tags,"TagA")){ + return RocketMQLocalTransactionState.COMMIT; + }else if(StringUtils.contains(tags,"TagB")){ + return RocketMQLocalTransactionState.ROLLBACK; + }else{ + return RocketMQLocalTransactionState.UNKNOWN; + } + } + //延迟检查的时间间隔要有点奇怪。 + @Override + public RocketMQLocalTransactionState checkLocalTransaction(Message msg) { + String transId = msg.getHeaders().get(RocketMQHeaders.PREFIX+RocketMQHeaders.TRANSACTION_ID).toString(); + Message originalMessage = localTrans.get(transId); + //这里能够获取到自定义的transaction_id属性 + System.out.println("checkLocalTransaction msg = "+originalMessage); + //获取标签时,自定义的RocketMQHeaders.TAGS拿不到,但是框架会封装成一个带RocketMQHeaders.PREFIX的属性 +// String tags = msg.getHeaders().get(RocketMQHeaders.TAGS).toString(); + String tags = msg.getHeaders().get(RocketMQHeaders.PREFIX+RocketMQHeaders.TAGS).toString(); + if(StringUtils.contains(tags,"TagC")){ + return RocketMQLocalTransactionState.COMMIT; + }else if(StringUtils.contains(tags,"TagD")){ + return RocketMQLocalTransactionState.ROLLBACK; + }else{ + return RocketMQLocalTransactionState.UNKNOWN; + } + } +} diff --git a/distributed/mq/rocketmq/springboot-rocketmq/src/main/java/com/roy/rocketmq/config/Swagger2.java b/distributed/mq/rocketmq/springboot-rocketmq/src/main/java/com/roy/rocketmq/config/Swagger2.java new file mode 100644 index 00000000..464b3f5c --- /dev/null +++ b/distributed/mq/rocketmq/springboot-rocketmq/src/main/java/com/roy/rocketmq/config/Swagger2.java @@ -0,0 +1,41 @@ +package com.roy.rocketmq.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import springfox.documentation.builders.ApiInfoBuilder; +import springfox.documentation.builders.PathSelectors; +import springfox.documentation.builders.RequestHandlerSelectors; +import springfox.documentation.service.ApiInfo; +import springfox.documentation.spi.DocumentationType; +import springfox.documentation.spring.web.plugins.Docket; +import springfox.documentation.swagger2.annotations.EnableSwagger2; + +/** + * @author :楼兰 + * @date :Created in 2020/11/5 + * @description: + **/ + +@Configuration +@EnableSwagger2 +public class Swagger2 { + + @Bean + public Docket createRestApi() { + return new Docket(DocumentationType.SWAGGER_2) + .apiInfo(apiInfo()) + .select() +// .apis(RequestHandlerSelectors.basePackage("com.didispace.web")) + .paths(PathSelectors.any()) + .build(); + } + + private ApiInfo apiInfo() { + return new ApiInfoBuilder() + .title("Spring Boot中使用Swagger2构建RESTful APIs") + .description("SpringBoot集成RocketMQ") + .contact("楼兰") + .version("1.0") + .build(); + } +} diff --git a/distributed/mq/rocketmq/springboot-rocketmq/src/main/java/com/roy/rocketmq/controller/MQTestController.java b/distributed/mq/rocketmq/springboot-rocketmq/src/main/java/com/roy/rocketmq/controller/MQTestController.java new file mode 100644 index 00000000..7b2bfde0 --- /dev/null +++ b/distributed/mq/rocketmq/springboot-rocketmq/src/main/java/com/roy/rocketmq/controller/MQTestController.java @@ -0,0 +1,33 @@ +package com.roy.rocketmq.controller; + +import com.roy.rocketmq.basic.SpringProducer; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; + +/** + * @author :楼兰 + * @date :Created in 2020/10/27 + * @description: + **/ +@RestController +@RequestMapping("/MQTest") +public class MQTestController { + + private final String topic = "TestTopic"; + @Resource + private SpringProducer producer; + @RequestMapping("/sendMessage") + public String sendMessage(String message){ + producer.sendMessage(topic,message); + return "消息发送完成"; + } + + //这个发送事务消息的例子中有很多问题,需要注意下。 + @RequestMapping("/sendTransactionMessage") + public String sendTransactionMessage(String message) throws InterruptedException { + producer.sendMessageInTransaction(topic,message); + return "消息发送完成"; + } +} \ No newline at end of file diff --git a/distributed/mq/rocketmq/springboot-rocketmq/src/main/java/com/roy/rocketmq/domain/OrderPaidEvent.java b/distributed/mq/rocketmq/springboot-rocketmq/src/main/java/com/roy/rocketmq/domain/OrderPaidEvent.java new file mode 100644 index 00000000..482203d1 --- /dev/null +++ b/distributed/mq/rocketmq/springboot-rocketmq/src/main/java/com/roy/rocketmq/domain/OrderPaidEvent.java @@ -0,0 +1,39 @@ +package com.roy.rocketmq.domain; + +import java.math.BigDecimal; + +/** + * @author :楼兰 + * @date :Created in 2020/11/28 + * @description: + **/ + +public class OrderPaidEvent { + private String orderId; + + private BigDecimal paidMoney; + + public OrderPaidEvent() { + } + + public OrderPaidEvent(String orderId, BigDecimal paidMoney) { + this.orderId = orderId; + this.paidMoney = paidMoney; + } + + public String getOrderId() { + return orderId; + } + + public void setOrderId(String orderId) { + this.orderId = orderId; + } + + public BigDecimal getPaidMoney() { + return paidMoney; + } + + public void setPaidMoney(BigDecimal paidMoney) { + this.paidMoney = paidMoney; + } +} diff --git a/distributed/mq/rocketmq/springboot-rocketmq/src/main/java/com/roy/rocketmq/domain/ProductWithPayload.java b/distributed/mq/rocketmq/springboot-rocketmq/src/main/java/com/roy/rocketmq/domain/ProductWithPayload.java new file mode 100644 index 00000000..6bb51feb --- /dev/null +++ b/distributed/mq/rocketmq/springboot-rocketmq/src/main/java/com/roy/rocketmq/domain/ProductWithPayload.java @@ -0,0 +1,43 @@ +package com.roy.rocketmq.domain; + +/** + * @author :楼兰 + * @date :Created in 2020/11/28 + * @description: + **/ + +public class ProductWithPayload { + private String productName; + private T payload; + + public ProductWithPayload() { + } + + public ProductWithPayload(String productName, T payload) { + this.productName = productName; + this.payload = payload; + } + + public String getProductName() { + return productName; + } + + public void setProductName(String productName) { + this.productName = productName; + } + + public T getPayload() { + return payload; + } + + public void setPayload(T payload) { + this.payload = payload; + } + + @Override public String toString() { + return "ProductWithPayload{" + + "productName='" + productName + '\'' + + ", payload=" + payload + + '}'; + } +} diff --git a/distributed/mq/rocketmq/springboot-rocketmq/src/main/java/com/roy/rocketmq/domain/User.java b/distributed/mq/rocketmq/springboot-rocketmq/src/main/java/com/roy/rocketmq/domain/User.java new file mode 100644 index 00000000..c2e6d49d --- /dev/null +++ b/distributed/mq/rocketmq/springboot-rocketmq/src/main/java/com/roy/rocketmq/domain/User.java @@ -0,0 +1,38 @@ +package com.roy.rocketmq.domain; + +/** + * @author :楼兰 + * @date :Created in 2020/11/28 + * @description: + **/ + +public class User { + private String userName; + private Byte userAge; + + public String getUserName() { + return userName; + } + + public User setUserName(String userName) { + this.userName = userName; + return this; + } + + public Byte getUserAge() { + return userAge; + } + + public User setUserAge(Byte userAge) { + this.userAge = userAge; + return this; + } + + @Override + public String toString() { + return "User{" + + "userName='" + userName + '\'' + + ", userAge=" + userAge + + '}'; + } +} diff --git a/distributed/mq/rocketmq/springboot-rocketmq/src/main/resources/application.properties b/distributed/mq/rocketmq/springboot-rocketmq/src/main/resources/application.properties new file mode 100644 index 00000000..fcadafe9 --- /dev/null +++ b/distributed/mq/rocketmq/springboot-rocketmq/src/main/resources/application.properties @@ -0,0 +1,2 @@ +rocketmq.name-server=192.168.232.128:9876 +rocketmq.producer.group=springBootGroup \ No newline at end of file diff --git a/distributed/mq/rocketmq/springboot-rocketmq/src/test/java/com/roy/rocketmq/SpringRocketTest.java b/distributed/mq/rocketmq/springboot-rocketmq/src/test/java/com/roy/rocketmq/SpringRocketTest.java new file mode 100644 index 00000000..52a1a9e0 --- /dev/null +++ b/distributed/mq/rocketmq/springboot-rocketmq/src/test/java/com/roy/rocketmq/SpringRocketTest.java @@ -0,0 +1,121 @@ +package com.roy.rocketmq; + +import com.alibaba.fastjson.TypeReference; +import com.roy.rocketmq.domain.OrderPaidEvent; +import com.roy.rocketmq.domain.ProductWithPayload; +import com.roy.rocketmq.domain.User; +import org.apache.rocketmq.client.producer.SendCallback; +import org.apache.rocketmq.client.producer.SendResult; +import org.apache.rocketmq.spring.core.RocketMQLocalRequestCallback; +import org.apache.rocketmq.spring.core.RocketMQTemplate; +import org.apache.rocketmq.spring.support.RocketMQHeaders; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.messaging.Message; +import org.springframework.messaging.MessageHeaders; +import org.springframework.messaging.support.MessageBuilder; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.util.MimeTypeUtils; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; + +/** + * @author :楼兰 + * @date :Created in 2020/11/28 + * @description: + **/ + +@RunWith(SpringRunner.class) +@SpringBootTest +public class SpringRocketTest { + + @Resource + private RocketMQTemplate rocketMQTemplate; + + @Test + public void sendMessageTest(){ + String springTopic="TestTopic"; + //发送字符消息 + SendResult sendResult = rocketMQTemplate.syncSend(springTopic, "Hello, World!"); + System.out.printf("syncSend1 to topic %s sendResult=%s %n", springTopic, sendResult); + + sendResult = rocketMQTemplate.syncSend(springTopic, new User().setUserAge((byte) 18).setUserName("Kitty")); + System.out.printf("syncSend1 to topic %s sendResult=%s %n", springTopic, sendResult); + + sendResult = rocketMQTemplate.syncSend(springTopic, MessageBuilder.withPayload( + new User().setUserAge((byte) 21).setUserName("Lester")).setHeader(MessageHeaders.CONTENT_TYPE, MimeTypeUtils.APPLICATION_JSON_VALUE).build()); + System.out.printf("syncSend1 to topic %s sendResult=%s %n", springTopic, sendResult); + + //发送对象消息 + rocketMQTemplate.asyncSend(springTopic, new OrderPaidEvent("T_001", new BigDecimal("88.00")), new SendCallback() { + @Override + public void onSuccess(SendResult var1) { + System.out.printf("async onSucess SendResult=%s %n", var1); + } + + @Override + public void onException(Throwable var1) { + System.out.printf("async onException Throwable=%s %n", var1); + } + }); + + //发送指定TAG的消息 + rocketMQTemplate.convertAndSend(springTopic + ":tag0", "I'm from tag0"); // tag0 will not be consumer-selected + System.out.printf("syncSend topic %s tag %s %n", springTopic, "tag0"); + rocketMQTemplate.convertAndSend(springTopic + ":tag1", "I'm from tag1"); + System.out.printf("syncSend topic %s tag %s %n", springTopic, "tag1"); + + //同步发送消息并且返回一个String类型的结果。 + String replyString = rocketMQTemplate.sendAndReceive(springTopic, "request string", String.class); + System.out.printf("send %s and receive %s %n", "request string", replyString); + + //同步发送消息并且返回一个Byte数组类型的结果。 + byte[] replyBytes = rocketMQTemplate.sendAndReceive(springTopic, MessageBuilder.withPayload("request byte[]").build(), byte[].class, 3000); + System.out.printf("send %s and receive %s %n", "request byte[]", new String(replyBytes)); + + //同步发送一个带hash参数的请求(排序消息),并返回一个User类型的结果 + User requestUser = new User().setUserAge((byte) 9).setUserName("requestUserName"); + User replyUser = rocketMQTemplate.sendAndReceive(springTopic, requestUser, User.class, "order-id"); + System.out.printf("send %s and receive %s %n", requestUser, replyUser); + //同步发送一个带延迟级别的消息(延迟消息),并返回一个泛型结果 + ProductWithPayload replyGenericObject = rocketMQTemplate.sendAndReceive(springTopic, "request generic", + new TypeReference>() { + }.getType(), 30000, 2); + System.out.printf("send %s and receive %s %n", "request generic", replyGenericObject); + + //异步发送消息,返回String类型结果。 + rocketMQTemplate.sendAndReceive(springTopic, "request string", new RocketMQLocalRequestCallback() { + @Override public void onSuccess(String message) { + System.out.printf("send %s and receive %s %n", "request string", message); + } + + @Override public void onException(Throwable e) { + e.printStackTrace(); + } + }); + //异步发送消息,并返回一个User类型的结果。 + rocketMQTemplate.sendAndReceive(springTopic, new User().setUserAge((byte) 9).setUserName("requestUserName"), new RocketMQLocalRequestCallback() { + @Override public void onSuccess(User message) { + System.out.printf("send user object and receive %s %n", message.toString()); + } + + @Override public void onException(Throwable e) { + e.printStackTrace(); + } + }, 5000); + //发送批量消息 + List msgs = new ArrayList(); + for (int i = 0; i < 10; i++) { + msgs.add(MessageBuilder.withPayload("Hello RocketMQ Batch Msg#" + i). + setHeader(RocketMQHeaders.KEYS, "KEY_" + i).build()); + } + + SendResult sr = rocketMQTemplate.syncSend(springTopic, msgs, 60000); + + System.out.printf("--- Batch messages send result :" + sr); + } +} diff --git a/distributed/mq/rocketmq/springcloud-alibaba-rocketmq/README.md b/distributed/mq/rocketmq/springcloud-alibaba-rocketmq/README.md new file mode 100644 index 00000000..189588e0 --- /dev/null +++ b/distributed/mq/rocketmq/springcloud-alibaba-rocketmq/README.md @@ -0,0 +1,4 @@ + +spring-cloud-starter-stream-rocketmq + + diff --git a/distributed/mq/rocketmq/springcloud-alibaba-rocketmq/pom.xml b/distributed/mq/rocketmq/springcloud-alibaba-rocketmq/pom.xml new file mode 100644 index 00000000..277badd0 --- /dev/null +++ b/distributed/mq/rocketmq/springcloud-alibaba-rocketmq/pom.xml @@ -0,0 +1,20 @@ + + + 4.0.0 + + cn.cunchang + stream-rocketmq + 0.0.1-SNAPSHOT + rocketmq + rocketmq + + + 1.8 + + + + + + + diff --git a/distributed/mq/rocketmq/springcloud-alibaba-rocketmq/rocketmq-consumer/pom.xml b/distributed/mq/rocketmq/springcloud-alibaba-rocketmq/rocketmq-consumer/pom.xml new file mode 100644 index 00000000..124f0268 --- /dev/null +++ b/distributed/mq/rocketmq/springcloud-alibaba-rocketmq/rocketmq-consumer/pom.xml @@ -0,0 +1,65 @@ + + + + 4.0.0 + cn.cunchang + rocketmq-consumer + 0.0.1-SNAPSHOT + rocketmq-consumer + rocketmq-consumer + + + 1.8 + 1.8 + 2.2.4.RELEASE + Hoxton.SR1 + 2.2.0.RELEASE + + + + + + + org.springframework.boot + spring-boot-starter-parent + ${spring.boot.version} + pom + import + + + org.springframework.cloud + spring-cloud-dependencies + ${spring.cloud.version} + pom + import + + + com.alibaba.cloud + spring-cloud-alibaba-dependencies + ${spring.cloud.alibaba.version} + pom + import + + + + + + + + org.springframework.boot + spring-boot-starter-web + + + + + com.alibaba.cloud + spring-cloud-starter-stream-rocketmq + + + + + diff --git a/distributed/mq/rocketmq/springcloud-alibaba-rocketmq/rocketmq-consumer/src/main/java/cn/cunchang/RocketmqConsumerApplication.java b/distributed/mq/rocketmq/springcloud-alibaba-rocketmq/rocketmq-consumer/src/main/java/cn/cunchang/RocketmqConsumerApplication.java new file mode 100644 index 00000000..df89bd57 --- /dev/null +++ b/distributed/mq/rocketmq/springcloud-alibaba-rocketmq/rocketmq-consumer/src/main/java/cn/cunchang/RocketmqConsumerApplication.java @@ -0,0 +1,16 @@ +package cn.cunchang; + +import cn.cunchang.listener.MessageChannel; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.stream.annotation.EnableBinding; + +@EnableBinding(MessageChannel.class) +@SpringBootApplication +public class RocketmqConsumerApplication { + + public static void main(String[] args) { + SpringApplication.run(RocketmqConsumerApplication.class, args); + } + +} diff --git a/distributed/mq/rocketmq/springcloud-alibaba-rocketmq/rocketmq-consumer/src/main/java/cn/cunchang/listener/MessageChannel.java b/distributed/mq/rocketmq/springcloud-alibaba-rocketmq/rocketmq-consumer/src/main/java/cn/cunchang/listener/MessageChannel.java new file mode 100644 index 00000000..4d78d688 --- /dev/null +++ b/distributed/mq/rocketmq/springcloud-alibaba-rocketmq/rocketmq-consumer/src/main/java/cn/cunchang/listener/MessageChannel.java @@ -0,0 +1,14 @@ +package cn.cunchang.listener; + +import org.springframework.cloud.stream.annotation.Input; +import org.springframework.messaging.SubscribableChannel; + +public interface MessageChannel { + + // 输入型消息通道 + String PAY_NOTICE_INPUT = "pay-notice-input"; + + @Input(PAY_NOTICE_INPUT) + SubscribableChannel payNoticeInput(); + +} diff --git a/distributed/mq/rocketmq/springcloud-alibaba-rocketmq/rocketmq-consumer/src/main/java/cn/cunchang/listener/PayNoticeConsumer.java b/distributed/mq/rocketmq/springcloud-alibaba-rocketmq/rocketmq-consumer/src/main/java/cn/cunchang/listener/PayNoticeConsumer.java new file mode 100644 index 00000000..58569b20 --- /dev/null +++ b/distributed/mq/rocketmq/springcloud-alibaba-rocketmq/rocketmq-consumer/src/main/java/cn/cunchang/listener/PayNoticeConsumer.java @@ -0,0 +1,20 @@ +package cn.cunchang.listener; + +import cn.cunchang.message.PayResultMsg; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.cloud.stream.annotation.StreamListener; +import org.springframework.messaging.handler.annotation.Payload; +import org.springframework.stereotype.Component; + +@Component +public class PayNoticeConsumer { + + private Logger logger = LoggerFactory.getLogger(getClass()); + + @StreamListener(MessageChannel.PAY_NOTICE_INPUT) + public void payNoticeInputOnMessage(@Payload PayResultMsg message) { + logger.info("[onMessage][线程编号:{} 消息内容:{}]", Thread.currentThread().getId(), message); + } + +} diff --git a/distributed/mq/rocketmq/springcloud-alibaba-rocketmq/rocketmq-consumer/src/main/java/cn/cunchang/message/PayResultMsg.java b/distributed/mq/rocketmq/springcloud-alibaba-rocketmq/rocketmq-consumer/src/main/java/cn/cunchang/message/PayResultMsg.java new file mode 100644 index 00000000..7b201e68 --- /dev/null +++ b/distributed/mq/rocketmq/springcloud-alibaba-rocketmq/rocketmq-consumer/src/main/java/cn/cunchang/message/PayResultMsg.java @@ -0,0 +1,84 @@ +package cn.cunchang.message; + +/** + * 支付结果消息 + * @author cunchang + */ +public class PayResultMsg { + + /** + * 支付流水号 + */ + private String payNo; + + /** + * 付款账号 + */ + private String payAccNo; + + /** + * 收款账户 + */ + private String revAccNo; + + /** + * 支付金额 + */ + private Long amount; + + /** + * 支付结果,0失败 1成功 + */ + private Integer result; + + public String getPayNo() { + return payNo; + } + + public void setPayNo(String payNo) { + this.payNo = payNo; + } + + public String getPayAccNo() { + return payAccNo; + } + + public void setPayAccNo(String payAccNo) { + this.payAccNo = payAccNo; + } + + public String getRevAccNo() { + return revAccNo; + } + + public void setRevAccNo(String revAccNo) { + this.revAccNo = revAccNo; + } + + public Long getAmount() { + return amount; + } + + public void setAmount(Long amount) { + this.amount = amount; + } + + public Integer getResult() { + return result; + } + + public void setResult(Integer result) { + this.result = result; + } + + @Override + public String toString() { + return "PayResultMsg{" + + "payNo='" + payNo + '\'' + + ", payAccNo='" + payAccNo + '\'' + + ", revAccNo='" + revAccNo + '\'' + + ", amount=" + amount + + ", result=" + result + + '}'; + } +} diff --git a/distributed/mq/rocketmq/springcloud-alibaba-rocketmq/rocketmq-consumer/src/main/resources/application.yml b/distributed/mq/rocketmq/springcloud-alibaba-rocketmq/rocketmq-consumer/src/main/resources/application.yml new file mode 100644 index 00000000..6333035e --- /dev/null +++ b/distributed/mq/rocketmq/springcloud-alibaba-rocketmq/rocketmq-consumer/src/main/resources/application.yml @@ -0,0 +1,28 @@ +spring: + application: + name: stream-rocketmq-consumer + cloud: + # Spring Cloud Stream 配置项,对应 BindingServiceProperties 类 + stream: + # Binding 配置项,对应 BindingProperties Map + bindings: + pay-notice-input: + destination: pay-result # 目的地。这里使用 RocketMQ Topic + content-type: application/json # 内容格式。这里使用 JSON + group: pay-notice-consumer-group # 消费者分组,命名规则:组名+topic名 + + # Spring Cloud Stream RocketMQ 配置项 + rocketmq: + # RocketMQ Binder 配置项,对应 RocketMQBinderConfigurationProperties 类 + binder: + name-server: localhost:9876 # RocketMQ Namesrv 地址 + # RocketMQ 自定义 Binding 配置项,对应 RocketMQBindingProperties Map + bindings: + pay-notice-input: + # RocketMQ Consumer 配置项,对应 RocketMQConsumerProperties 类 + consumer: + enabled: true # 是否开启消费,默认为 true + broadcasting: false # 是否使用广播消费,默认为 false 使用集群消费 + +server: + port: ${random.int[10000,19999]} # 随机端口,方便启动多个消费者 diff --git a/distributed/mq/rocketmq/springcloud-alibaba-rocketmq/rocketmq-producer/pom.xml b/distributed/mq/rocketmq/springcloud-alibaba-rocketmq/rocketmq-producer/pom.xml new file mode 100644 index 00000000..0ee441e4 --- /dev/null +++ b/distributed/mq/rocketmq/springcloud-alibaba-rocketmq/rocketmq-producer/pom.xml @@ -0,0 +1,64 @@ + + + 4.0.0 + + cn.cunchang + rocketmq-producer + 0.0.1-SNAPSHOT + rocketmq-producer + rocketmq-producer + + + 1.8 + 1.8 + 2.2.4.RELEASE + Hoxton.SR1 + 2.2.0.RELEASE + + + + + + + org.springframework.boot + spring-boot-starter-parent + ${spring.boot.version} + pom + import + + + org.springframework.cloud + spring-cloud-dependencies + ${spring.cloud.version} + pom + import + + + com.alibaba.cloud + spring-cloud-alibaba-dependencies + ${spring.cloud.alibaba.version} + pom + import + + + + + + + + org.springframework.boot + spring-boot-starter-web + + + + + com.alibaba.cloud + spring-cloud-starter-stream-rocketmq + + + + diff --git a/distributed/mq/rocketmq/springcloud-alibaba-rocketmq/rocketmq-producer/src/main/java/cn/cunchang/RocketmqProducerApplication.java b/distributed/mq/rocketmq/springcloud-alibaba-rocketmq/rocketmq-producer/src/main/java/cn/cunchang/RocketmqProducerApplication.java new file mode 100644 index 00000000..682a2fdc --- /dev/null +++ b/distributed/mq/rocketmq/springcloud-alibaba-rocketmq/rocketmq-producer/src/main/java/cn/cunchang/RocketmqProducerApplication.java @@ -0,0 +1,16 @@ +package cn.cunchang; + +import cn.cunchang.message.MessageChannel; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.stream.annotation.EnableBinding; + +@EnableBinding(MessageChannel.class) +@SpringBootApplication +public class RocketmqProducerApplication { + + public static void main(String[] args) { + SpringApplication.run(RocketmqProducerApplication.class, args); + } + +} diff --git a/distributed/mq/rocketmq/springcloud-alibaba-rocketmq/rocketmq-producer/src/main/java/cn/cunchang/message/MessageChannel.java b/distributed/mq/rocketmq/springcloud-alibaba-rocketmq/rocketmq-producer/src/main/java/cn/cunchang/message/MessageChannel.java new file mode 100644 index 00000000..54efb948 --- /dev/null +++ b/distributed/mq/rocketmq/springcloud-alibaba-rocketmq/rocketmq-producer/src/main/java/cn/cunchang/message/MessageChannel.java @@ -0,0 +1,14 @@ +package cn.cunchang.message; + +import org.springframework.cloud.stream.annotation.Output; +import org.springframework.messaging.SubscribableChannel; + +public interface MessageChannel { + + // 输入型消息通道 + String PAY_NOTICE_OUTPUT = "pay-notice-output"; + + @Output(PAY_NOTICE_OUTPUT) + SubscribableChannel payNoticeOutput(); + +} diff --git a/distributed/mq/rocketmq/springcloud-alibaba-rocketmq/rocketmq-producer/src/main/java/cn/cunchang/message/PayResultMsg.java b/distributed/mq/rocketmq/springcloud-alibaba-rocketmq/rocketmq-producer/src/main/java/cn/cunchang/message/PayResultMsg.java new file mode 100644 index 00000000..7b201e68 --- /dev/null +++ b/distributed/mq/rocketmq/springcloud-alibaba-rocketmq/rocketmq-producer/src/main/java/cn/cunchang/message/PayResultMsg.java @@ -0,0 +1,84 @@ +package cn.cunchang.message; + +/** + * 支付结果消息 + * @author cunchang + */ +public class PayResultMsg { + + /** + * 支付流水号 + */ + private String payNo; + + /** + * 付款账号 + */ + private String payAccNo; + + /** + * 收款账户 + */ + private String revAccNo; + + /** + * 支付金额 + */ + private Long amount; + + /** + * 支付结果,0失败 1成功 + */ + private Integer result; + + public String getPayNo() { + return payNo; + } + + public void setPayNo(String payNo) { + this.payNo = payNo; + } + + public String getPayAccNo() { + return payAccNo; + } + + public void setPayAccNo(String payAccNo) { + this.payAccNo = payAccNo; + } + + public String getRevAccNo() { + return revAccNo; + } + + public void setRevAccNo(String revAccNo) { + this.revAccNo = revAccNo; + } + + public Long getAmount() { + return amount; + } + + public void setAmount(Long amount) { + this.amount = amount; + } + + public Integer getResult() { + return result; + } + + public void setResult(Integer result) { + this.result = result; + } + + @Override + public String toString() { + return "PayResultMsg{" + + "payNo='" + payNo + '\'' + + ", payAccNo='" + payAccNo + '\'' + + ", revAccNo='" + revAccNo + '\'' + + ", amount=" + amount + + ", result=" + result + + '}'; + } +} diff --git a/distributed/mq/rocketmq/springcloud-alibaba-rocketmq/rocketmq-producer/src/main/java/cn/cunchang/producer/ProducerController.java b/distributed/mq/rocketmq/springcloud-alibaba-rocketmq/rocketmq-producer/src/main/java/cn/cunchang/producer/ProducerController.java new file mode 100644 index 00000000..52e69809 --- /dev/null +++ b/distributed/mq/rocketmq/springcloud-alibaba-rocketmq/rocketmq-producer/src/main/java/cn/cunchang/producer/ProducerController.java @@ -0,0 +1,78 @@ +package cn.cunchang.producer; + +import cn.cunchang.message.MessageChannel; +import cn.cunchang.message.PayResultMsg; +import org.apache.rocketmq.common.message.MessageConst; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.messaging.Message; +import org.springframework.messaging.support.MessageBuilder; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Random; +import java.util.UUID; + +@RestController +@RequestMapping("/producer") +public class ProducerController { + + private Logger logger = LoggerFactory.getLogger(getClass()); + + @Autowired + private MessageChannel messageChannel; + + /** + * http://127.0.0.1:18080/producer/send + * + * @return + */ + @GetMapping("/send") + public boolean send() { + // <2>创建 Message + + String payNo = UUID.randomUUID().toString(); + + PayResultMsg payResultMsg = new PayResultMsg(); + payResultMsg.setPayNo(payNo); + payResultMsg.setPayAccNo("10086"); + payResultMsg.setRevAccNo("10010"); + payResultMsg.setAmount(1000000L); + payResultMsg.setResult(1); + + // <3>创建 Spring Message 对象 + Message message = MessageBuilder.withPayload(payResultMsg) + .setHeader(MessageConst.PROPERTY_TAGS, "pay_notice_tag") // 设置 Tag + .setHeader(MessageConst.PROPERTY_KEYS, payNo) // 设置 key,方便在控制台查找。 + .build(); + System.out.println("topic:pay-result,msg:"+message); + // <4>发送消息 + boolean sendResult = messageChannel.payNoticeOutput().send(message); + logger.info("send,topic:pay-result,msg:{},sendResult:{}",message,sendResult); + return sendResult; + } + + @GetMapping("/send_delay") + public boolean sendDelay() { + // 创建 Message + PayResultMsg payResultMsg = new PayResultMsg(); + payResultMsg.setPayNo(UUID.randomUUID().toString()); + payResultMsg.setPayAccNo("10086"); + payResultMsg.setRevAccNo("10010"); + payResultMsg.setAmount(1000000L); + payResultMsg.setResult(1); + + // <3>创建 Spring Message 对象 + Message message = MessageBuilder.withPayload(payResultMsg) + .setHeader(MessageConst.PROPERTY_DELAY_TIME_LEVEL, "3") // 设置延迟级别为3,10 秒后消费。 + .build(); + // 发送消息 + boolean sendResult = messageChannel.payNoticeOutput().send(message); + logger.info("sendDelay,topic:pay-result,msg:{},sendResult:{}",message,sendResult); + return sendResult; + } + + +} diff --git a/distributed/mq/rocketmq/springcloud-alibaba-rocketmq/rocketmq-producer/src/main/resources/application.yml b/distributed/mq/rocketmq/springcloud-alibaba-rocketmq/rocketmq-producer/src/main/resources/application.yml new file mode 100644 index 00000000..df5ed20e --- /dev/null +++ b/distributed/mq/rocketmq/springcloud-alibaba-rocketmq/rocketmq-producer/src/main/resources/application.yml @@ -0,0 +1,26 @@ +spring: + application: + name: stream-rocketmq-producer + cloud: + # Spring Cloud Stream 配置项,对应 BindingServiceProperties 类 + stream: + # Binding 配置项,对应 BindingProperties Map + bindings: + pay-notice-output: + destination: pay-result # 目的地。这里使用 RocketMQ Topic + content-type: application/json # 内容格式。这里使用 JSON + # Spring Cloud Stream RocketMQ 配置项 + rocketmq: + # RocketMQ Binder 配置项,对应 RocketMQBinderConfigurationProperties 类 + binder: + name-server: localhost:9876 # RocketMQ Namesrv 地址 + # RocketMQ 自定义 Binding 配置项,对应 RocketMQBindingProperties Map + bindings: + pay-notice-output: + # RocketMQ Producer 配置项,对应 RocketMQProducerProperties 类 + producer: + group: pay-center # 生产者分组 + sync: true # 是否同步发送消息,默认为 false 异步。 + +server: + port: 18080 diff --git a/distributed/session/jwt-session/pom.xml b/distributed/session/jwt-session/pom.xml new file mode 100644 index 00000000..aee438d5 --- /dev/null +++ b/distributed/session/jwt-session/pom.xml @@ -0,0 +1,48 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.4.4 + + + cn.cunchang + jwt-session + 0.0.1-SNAPSHOT + jwt-session + jwt-session + + 1.8 + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-test + test + + + + com.auth0 + java-jwt + 3.10.3 + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/distributed/session/jwt-session/src/main/java/cn/cunchang/Application.java b/distributed/session/jwt-session/src/main/java/cn/cunchang/Application.java new file mode 100644 index 00000000..2ba8082d --- /dev/null +++ b/distributed/session/jwt-session/src/main/java/cn/cunchang/Application.java @@ -0,0 +1,13 @@ +package cn.cunchang; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + +} diff --git a/distributed/session/jwt-session/src/main/java/cn/cunchang/config/LoginIntercepter.java b/distributed/session/jwt-session/src/main/java/cn/cunchang/config/LoginIntercepter.java new file mode 100644 index 00000000..304a7c6f --- /dev/null +++ b/distributed/session/jwt-session/src/main/java/cn/cunchang/config/LoginIntercepter.java @@ -0,0 +1,55 @@ +package cn.cunchang.config; + +import com.auth0.jwt.JWT; +import com.auth0.jwt.JWTVerifier; +import com.auth0.jwt.algorithms.Algorithm; +import com.auth0.jwt.exceptions.JWTDecodeException; +import com.auth0.jwt.exceptions.TokenExpiredException; +import com.auth0.jwt.interfaces.DecodedJWT; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; +import org.springframework.web.servlet.AsyncHandlerInterceptor; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +@Component +public class LoginIntercepter implements AsyncHandlerInterceptor { + + public static final String JWT_KEY = "imooc"; + public static final String JWT_TOKEN = "token"; + public static final String UID = "uid"; + public static final String CURRENT_USER = "username"; + + /** + * 返回true, 表示不拦截,继续往下执行 + * 返回false/抛出异常,不再往下执行 + * @param request + * @param response + * @param handler + * @return + * @throws Exception + */ + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { + String token = request.getHeader(JWT_TOKEN); + if (StringUtils.isEmpty(token)) { + throw new RuntimeException("token为空"); + } + + Algorithm algorithm = Algorithm.HMAC256(JWT_KEY); + JWTVerifier verifier = JWT.require(algorithm) + .build(); //Reusable verifier instance + try { + DecodedJWT jwt = verifier.verify(token); + request.setAttribute(UID, jwt.getClaim(UID).asInt()); + request.setAttribute(CURRENT_USER, jwt.getClaim(CURRENT_USER).asString()); + }catch (TokenExpiredException e) { + throw new RuntimeException("token过期"); + }catch (JWTDecodeException e) { + throw new RuntimeException("解码失败,token错误"); + } + + return true; + } +} diff --git a/distributed/session/jwt-session/src/main/java/cn/cunchang/config/WebMvcConfig.java b/distributed/session/jwt-session/src/main/java/cn/cunchang/config/WebMvcConfig.java new file mode 100644 index 00000000..164c8f0d --- /dev/null +++ b/distributed/session/jwt-session/src/main/java/cn/cunchang/config/WebMvcConfig.java @@ -0,0 +1,24 @@ +package cn.cunchang.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@Configuration +public class WebMvcConfig implements WebMvcConfigurer { + + @Autowired + private LoginIntercepter loginIntercepter; + + @Override + public void addInterceptors(InterceptorRegistry registry) { +// registry.addInterceptor(loginIntercepter) +// .addPathPatterns("/user/address") // /user/** +// .addPathPatterns("/user/infoWithJwt"); + + registry.addInterceptor(loginIntercepter) + .addPathPatterns("/user/**") //未登录的都会被拦截 + .excludePathPatterns("/user/login"); + } +} diff --git a/distributed/session/jwt-session/src/main/java/cn/cunchang/controller/UserController.java b/distributed/session/jwt-session/src/main/java/cn/cunchang/controller/UserController.java new file mode 100644 index 00000000..f8d3d1dc --- /dev/null +++ b/distributed/session/jwt-session/src/main/java/cn/cunchang/controller/UserController.java @@ -0,0 +1,58 @@ +package cn.cunchang.controller; + +import com.auth0.jwt.JWT; +import com.auth0.jwt.algorithms.Algorithm; +import org.springframework.web.bind.annotation.*; + +import java.util.Date; + +import static cn.cunchang.config.LoginIntercepter.*; + +@RequestMapping("/user") +@RestController +public class UserController { + + /** + * http://localhost:8080/user/login?username=admin&password=123456 + * + * @param username + * @param password + * @return + */ + @GetMapping("/login") + public String login(@RequestParam String username, @RequestParam String password) { + Algorithm algorithm = Algorithm.HMAC256(JWT_KEY); + String token = JWT.create() + .withClaim(CURRENT_USER, username) + .withClaim(UID, 1) + .withExpiresAt(new Date(System.currentTimeMillis() + 3600000)) + .sign(algorithm); + return token; + } + + /** + * http://localhost:8080/user/current + * + * @param username + * @return + */ + @GetMapping("/current") + public String current(@RequestAttribute String username) { + return "当前登录的是:" + username; + } + + + /** + * http://localhost:8080/user/invalidate + * + * jwt无法使session失效 + * + * @return + */ + @GetMapping("/invalidate") + public void invalidate() { + + } + + +} diff --git a/springboot-integration-examples/spring-validated/src/main/resources/application.properties b/distributed/session/jwt-session/src/main/resources/application.properties similarity index 100% rename from springboot-integration-examples/spring-validated/src/main/resources/application.properties rename to distributed/session/jwt-session/src/main/resources/application.properties diff --git a/distributed/session/jwt-session/src/test/java/cn/cunchang/ApplicationTests.java b/distributed/session/jwt-session/src/test/java/cn/cunchang/ApplicationTests.java new file mode 100644 index 00000000..c13144bc --- /dev/null +++ b/distributed/session/jwt-session/src/test/java/cn/cunchang/ApplicationTests.java @@ -0,0 +1,13 @@ +package cn.cunchang; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class ApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/distributed/session/redis-session/pom.xml b/distributed/session/redis-session/pom.xml new file mode 100644 index 00000000..7acfe7cd --- /dev/null +++ b/distributed/session/redis-session/pom.xml @@ -0,0 +1,47 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.3.3.RELEASE + + + cn.cunchang + redis-session + 0.0.1-SNAPSHOT + redis-session + redis-session + + 1.8 + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-test + test + + + + org.springframework.boot + spring-boot-starter-data-redis + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/distributed/session/redis-session/src/main/java/cn/cunchang/Application.java b/distributed/session/redis-session/src/main/java/cn/cunchang/Application.java new file mode 100644 index 00000000..2ba8082d --- /dev/null +++ b/distributed/session/redis-session/src/main/java/cn/cunchang/Application.java @@ -0,0 +1,13 @@ +package cn.cunchang; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + +} diff --git a/distributed/session/redis-session/src/main/java/cn/cunchang/controller/UserController.java b/distributed/session/redis-session/src/main/java/cn/cunchang/controller/UserController.java new file mode 100644 index 00000000..d365a24d --- /dev/null +++ b/distributed/session/redis-session/src/main/java/cn/cunchang/controller/UserController.java @@ -0,0 +1,60 @@ +package cn.cunchang.controller; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.web.bind.annotation.*; + +import java.util.UUID; +import java.util.concurrent.TimeUnit; + + +@RequestMapping("/user") +@RestController +public class UserController { + + @Autowired + private StringRedisTemplate stringRedisTemplate; + + /** + * http://localhost:8080/user/login?username=admin&password=123456 + *

+ * 与前端配合,登录成功后,cookie记录token + * + * @param username + * @param password + * @return + */ + @GetMapping("/login") + public String login(@RequestParam String username, @RequestParam String password) { + //账号密码正确 + String key = "token_" + UUID.randomUUID().toString(); + stringRedisTemplate.opsForValue().set(key, username, 3600, TimeUnit.SECONDS); + return key; + } + + /** + * http://localhost:8080/user/current + * + * @param token + * @return + */ + @GetMapping("/current") + public String current(@RequestHeader String token) { + return "当前登录的是:" + stringRedisTemplate.opsForValue().get(token); + } + + /** + * http://localhost:8080/user/invalidate + * + * @param token + * @return + */ + @GetMapping("/invalidate") + public String invalidate(@RequestHeader String token) { + System.out.println("失效前 sessionId:" + token); + stringRedisTemplate.delete(token); + System.out.println("失效后 sessionId:" + null); + System.out.println("--------------------------------"); + return "session已失效" + " || sessionId:" + token; + } +} diff --git a/distributed/session/redis-session/src/main/resources/application.yml b/distributed/session/redis-session/src/main/resources/application.yml new file mode 100644 index 00000000..09cc596a --- /dev/null +++ b/distributed/session/redis-session/src/main/resources/application.yml @@ -0,0 +1,4 @@ +spring: + redis: + host: 127.0.0.1 + port: 6379 \ No newline at end of file diff --git a/distributed/session/redis-session/src/test/java/cn/cunchang/ApplicationTests.java b/distributed/session/redis-session/src/test/java/cn/cunchang/ApplicationTests.java new file mode 100644 index 00000000..c13144bc --- /dev/null +++ b/distributed/session/redis-session/src/test/java/cn/cunchang/ApplicationTests.java @@ -0,0 +1,13 @@ +package cn.cunchang; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class ApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/distributed/session/spring-session/pom.xml b/distributed/session/spring-session/pom.xml new file mode 100644 index 00000000..99f73e3d --- /dev/null +++ b/distributed/session/spring-session/pom.xml @@ -0,0 +1,53 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.3.3.RELEASE + + + cn.cuchang + spring-session + 0.0.1-SNAPSHOT + spring-session + spring-session + + 1.8 + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-test + test + + + + org.springframework.boot + spring-boot-starter-data-redis + + + + org.springframework.session + spring-session-data-redis + + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/distributed/session/spring-session/src/main/java/cn/cuchang/Application.java b/distributed/session/spring-session/src/main/java/cn/cuchang/Application.java new file mode 100644 index 00000000..2b694e6a --- /dev/null +++ b/distributed/session/spring-session/src/main/java/cn/cuchang/Application.java @@ -0,0 +1,15 @@ +package cn.cuchang; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession; + +@EnableRedisHttpSession +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + +} diff --git a/distributed/session/spring-session/src/main/java/cn/cuchang/controller/UserController.java b/distributed/session/spring-session/src/main/java/cn/cuchang/controller/UserController.java new file mode 100644 index 00000000..cae5fc84 --- /dev/null +++ b/distributed/session/spring-session/src/main/java/cn/cuchang/controller/UserController.java @@ -0,0 +1,64 @@ +package cn.cuchang.controller; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import javax.servlet.http.HttpSession; + +@RequestMapping("/user") +@RestController +public class UserController { + + /** + * spring-session 与 tomcat-session 机制相同 + * request headers Cookie: JSESSIONID=2BB312D30D6F1246412D081615906D3B; SESSION=ZWJmNjliNDEtZWYxNy00NDg5LWJkZTktMjVkZGRlMzg3NjRl + * response headers Set-Cookie: SESSION=MzE2ZmE1YzMtMzQ0ZC00ZDQ1LWJlYTgtN2NiZGNmMWVlODk4; Path=/; HttpOnly; SameSite=Lax + * + */ + + /** + * http://localhost:8080/user/login?username=admin&password=123456 + * + * @param username + * @param session + * @return + */ + @GetMapping("/login") + public String login(@RequestParam String username, @RequestParam String password, HttpSession session) { + //账号密码正确 + session.setAttribute("login_user", username); + return "登录成功" + " || sessionId:" + session.getId(); + } + + + /** + * http://localhost:8080/user/current + * + * @param session + * @return + */ + @GetMapping("/current") + public String current(HttpSession session) { + return "当前登录的是:" + session.getAttribute("login_user") + " || sessionId:" + session.getId(); + } + + + /** + * http://localhost:8080/user/invalidate + * + * @param session + * @return + */ + @GetMapping("/invalidate") + public String invalidate(HttpSession session) { + System.out.println("失效前 sessionId:" + session.getId()); + session.invalidate(); + System.out.println("失效后 sessionId:" + session.getId()); + System.out.println("--------------------------------"); + return "session已失效" + " || sessionId:" + session.getId(); + } + + +} diff --git a/distributed/session/spring-session/src/main/resources/application.yml b/distributed/session/spring-session/src/main/resources/application.yml new file mode 100644 index 00000000..d6b60a18 --- /dev/null +++ b/distributed/session/spring-session/src/main/resources/application.yml @@ -0,0 +1,9 @@ +spring: + redis: + host: 127.0.0.1 + port: 6379 + session: + store-type: redis + timeout: 3600 + redis: + namespace: login_user #前缀 diff --git a/distributed/session/spring-session/src/test/java/cn/cuchang/ApplicationTests.java b/distributed/session/spring-session/src/test/java/cn/cuchang/ApplicationTests.java new file mode 100644 index 00000000..280d4bdf --- /dev/null +++ b/distributed/session/spring-session/src/test/java/cn/cuchang/ApplicationTests.java @@ -0,0 +1,13 @@ +package cn.cuchang; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class ApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/distributed/session/tomcat-session/pom.xml b/distributed/session/tomcat-session/pom.xml new file mode 100644 index 00000000..75ef685e --- /dev/null +++ b/distributed/session/tomcat-session/pom.xml @@ -0,0 +1,41 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.3.3.RELEASE + + + cn.cuchang + tomcat-session + 0.0.1-SNAPSHOT + tomcat-session + tomcat-session + + 1.8 + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/distributed/session/tomcat-session/src/main/java/cn/cuchang/Application.java b/distributed/session/tomcat-session/src/main/java/cn/cuchang/Application.java new file mode 100644 index 00000000..04b96533 --- /dev/null +++ b/distributed/session/tomcat-session/src/main/java/cn/cuchang/Application.java @@ -0,0 +1,13 @@ +package cn.cuchang; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + +} diff --git a/distributed/session/tomcat-session/src/main/java/cn/cuchang/controller/UserController.java b/distributed/session/tomcat-session/src/main/java/cn/cuchang/controller/UserController.java new file mode 100644 index 00000000..de58137a --- /dev/null +++ b/distributed/session/tomcat-session/src/main/java/cn/cuchang/controller/UserController.java @@ -0,0 +1,61 @@ +package cn.cuchang.controller; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import javax.servlet.http.HttpSession; + +@RequestMapping("/user") +@RestController +public class UserController { + + /** + * http://localhost:8080/user/login?username=admin&password=123456 + * + * @param username + * @param session + * @return + */ + @GetMapping("/login") + public String login(@RequestParam String username, @RequestParam String password, HttpSession session) { + //账号密码正确 + session.setAttribute("login_user", username); + return "登录成功" + " || sessionId:" + session.getId(); + } + + + /** + * http://localhost:8080/user/current + * + * @param session + * @return + */ + @GetMapping("/current") + public String current(HttpSession session) { + return "当前登录的是:" + session.getAttribute("login_user") + " || sessionId:" + session.getId(); + } + + + /** + * http://localhost:8080/user/invalidate + *

+ * 浏览器每次请求都会携带cookie,服务器端重新设置cookie + * request headers Cookie: JSESSIONID=2BB312D30D6F1246412D081615906D3B + * response headers Set-Cookie: JSESSIONID=9A7E034F309B2B0616737CA9937030D7; Path=/; HttpOnly + * + * @param session + * @return + */ + @GetMapping("/invalidate") + public String invalidate(HttpSession session) { + System.out.println("失效前 sessionId:" + session.getId()); + session.invalidate(); + System.out.println("失效后 sessionId:" + session.getId()); + System.out.println("--------------------------------"); + return "session已失效" + " || sessionId:" + session.getId(); + } + + +} diff --git a/springboot-integration-examples/spring-validated/target/classes/application.properties b/distributed/session/tomcat-session/src/main/resources/application.properties similarity index 100% rename from springboot-integration-examples/spring-validated/target/classes/application.properties rename to distributed/session/tomcat-session/src/main/resources/application.properties diff --git a/distributed/session/tomcat-session/src/test/java/cn/cuchang/ApplicationTests.java b/distributed/session/tomcat-session/src/test/java/cn/cuchang/ApplicationTests.java new file mode 100644 index 00000000..280d4bdf --- /dev/null +++ b/distributed/session/tomcat-session/src/test/java/cn/cuchang/ApplicationTests.java @@ -0,0 +1,13 @@ +package cn.cuchang; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class ApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/distributed/sharding-sphere/ShardingSphereDemo/README.md b/distributed/sharding-sphere/ShardingSphereDemo/README.md new file mode 100644 index 00000000..05185ddf --- /dev/null +++ b/distributed/sharding-sphere/ShardingSphereDemo/README.md @@ -0,0 +1,216 @@ + +application.properties;这个是真正用的配置,运行哪个demo,把01、02等等的配置copy就行了 + +# application01.properties; +分表,用到了一库两表 +```sql +CREATE TABLE course_1 ( + cid BIGINT(20) PRIMARY KEY, + cname VARCHAR(50) NOT NULL, + user_id BIGINT(20) NOT NULL, + cstatus varchar(10) NOT NULL +); + +CREATE TABLE course_2 ( + cid BIGINT(20) PRIMARY KEY, + cname VARCHAR(50) NOT NULL, + user_id BIGINT(20) NOT NULL, + cstatus varchar(10) NOT NULL +); +``` + + +```properties +#配置数据源 +# 数据源名称 +spring.shardingsphere.datasource.names=m1 + +spring.shardingsphere.datasource.m1.type=com.alibaba.druid.pool.DruidDataSource +spring.shardingsphere.datasource.m1.driver-class-name=com.mysql.cj.jdbc.Driver +spring.shardingsphere.datasource.m1.url=jdbc:mysql://localhost:3306/coursedb?serverTimezone=GMT%2B8 +spring.shardingsphere.datasource.m1.username=root +spring.shardingsphere.datasource.m1.password=123456 +#配置真实表分布 +spring.shardingsphere.sharding.tables.course.actual-data-nodes=m1.course_$->{1..2} +#主键生成策略 +# 主键字段名 +spring.shardingsphere.sharding.tables.course.key-generator.column=cid +# 主键生成算法 +spring.shardingsphere.sharding.tables.course.key-generator.type=SNOWFLAKE +# 雪花算法的参数 +spring.shardingsphere.sharding.tables.course.key-generator.props.worker.id=1 +#配置分表策略 +spring.shardingsphere.sharding.tables.course.table-strategy.inline.sharding-column=cid +spring.shardingsphere.sharding.tables.course.table-strategy.inline.algorithm-expression=course_$->{cid%2+1} +#其他运行属性 +spring.shardingsphere.props.sql.show = true +spring.main.allow-bean-definition-overriding=true +``` + + + +# application02.properties; + +分库,用到了一个两库两表 + +```properties +#配置多个数据源 +spring.shardingsphere.datasource.names=m1,m2 + +spring.shardingsphere.datasource.m1.type=com.alibaba.druid.pool.DruidDataSource +spring.shardingsphere.datasource.m1.driver-class-name=com.mysql.cj.jdbc.Driver +spring.shardingsphere.datasource.m1.url=jdbc:mysql://localhost:3306/coursedb?serverTimezone=GMT%2B8 +spring.shardingsphere.datasource.m1.username=root +spring.shardingsphere.datasource.m1.password=123456 + +spring.shardingsphere.datasource.m2.type=com.alibaba.druid.pool.DruidDataSource +spring.shardingsphere.datasource.m2.driver-class-name=com.mysql.cj.jdbc.Driver +spring.shardingsphere.datasource.m2.url=jdbc:mysql://localhost:3306/coursedb2?serverTimezone=GMT%2B8 +spring.shardingsphere.datasource.m2.username=root +spring.shardingsphere.datasource.m2.password=123456 +#真实表分布,分库,分表 +spring.shardingsphere.sharding.tables.course.actual-data-nodes=m$->{1..2}.course_$->{1..2} + +#主键生成策略 +# 主键字段名 +spring.shardingsphere.sharding.tables.course.key-generator.column=cid +# 主键生成算法 +spring.shardingsphere.sharding.tables.course.key-generator.type=SNOWFLAKE +# 雪花算法的参数 +spring.shardingsphere.sharding.tables.course.key-generator.props.worker.id=1 +#配置分表策略 +spring.shardingsphere.sharding.tables.course.table-strategy.inline.sharding-column=cid +spring.shardingsphere.sharding.tables.course.table-strategy.inline.algorithm-expression=course_$->{cid%2+1} +#其他运行属性 +spring.shardingsphere.props.sql.show = true +spring.main.allow-bean-definition-overriding=true +``` + + + +## inline策略不支持范围查询 +```properties +#inline分片策略 +spring.shardingsphere.sharding.tables.course.table-strategy.inline.sharding-column=cid +spring.shardingsphere.sharding.tables.course.table-strategy.inline.algorithm-expression=course_$->{cid%2+1} +#inline分库策略 +spring.shardingsphere.sharding.tables.course.database-strategy.inline.sharding-column=cid +spring.shardingsphere.sharding.tables.course.database-strategy.inline.algorithm-expression=m$->{cid%2+1} +``` + +```text +org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.exceptions.PersistenceException: +### Error querying database. Cause: java.lang.IllegalStateException: Inline strategy cannot support this type sharding:RangeRouteValue(columnName=cid, tableName=course, valueRange=[730100102537940992‥730100102990925824]) +### The error may exist in com/roy/shardingDemo/mapper/CourseMapper.java (best guess) +### The error may involve defaultParameterMap +### The error occurred while setting parameters +### SQL: SELECT cid,cname,user_id,cstatus FROM course WHERE cid BETWEEN ? AND ? ORDER BY cid DESC +### Cause: java.lang.IllegalStateException: Inline strategy cannot support this type sharding:RangeRouteValue(columnName=cid, tableName=course, valueRange=[730100102537940992‥730100102990925824]) + + at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:77) + at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:446) + at com.sun.proxy.$Proxy61.selectList(Unknown Source) + at org.mybatis.spring.SqlSessionTemplate.selectList(SqlSessionTemplate.java:230) + at com.baomidou.mybatisplus.core.override.PageMapperMethod.executeForMany(PageMapperMethod.java:173) + at com.baomidou.mybatisplus.core.override.PageMapperMethod.execute(PageMapperMethod.java:86) + at com.baomidou.mybatisplus.core.override.PageMapperProxy.invoke(PageMapperProxy.java:64) + at com.sun.proxy.$Proxy68.selectList(Unknown Source) + at com.roy.shardingDemo.ShardingJDBCTest.queryCourse(ShardingJDBCTest.java:56) + at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) + at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.lang.reflect.Method.invoke(Method.java:498) + at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59) + at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) + at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56) + at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) +``` + +## standard标准分片策略 +解决inline策略不支持范围查询 + + +```properties +#standard标准分片策略 +spring.shardingsphere.sharding.tables.course.table-strategy.standard.sharding-column=cid +spring.shardingsphere.sharding.tables.course.table-strategy.standard.precise-algorithm-class-name=com.roy.shardingDemo.algorithem.MyPreciseTableShardingAlgorithm +spring.shardingsphere.sharding.tables.course.table-strategy.standard.range-algorithm-class-name=com.roy.shardingDemo.algorithem.MyRangeTableShardingAlgorithm + +spring.shardingsphere.sharding.tables.course.database-strategy.standard.sharding-column=cid +spring.shardingsphere.sharding.tables.course.database-strategy.standard.precise-algorithm-class-name=com.roy.shardingDemo.algorithem.MyPreciseDSShardingAlgorithm +spring.shardingsphere.sharding.tables.course.database-strategy.standard.range-algorithm-class-name=com.roy.shardingDemo.algorithem.MyRangeDSShardingAlgorithm +``` + +standard标准分片策略支持自己根据一个分片键,实现精确和范围选择实际库表的逻辑 +缺点:多个分片键字段的复杂查询,会扫全库全表 + + + +## complex复杂分片策略 + +支持自己根据多个分片键分片键,选择实际库表的逻辑 + +```properties +#complex复杂分片策略 +spring.shardingsphere.sharding.tables.course.table-strategy.complex.sharding-columns= cid, user_id +spring.shardingsphere.sharding.tables.course.table-strategy.complex.algorithm-class-name=com.roy.shardingDemo.algorithem.MyComplexTableShardingAlgorithm + +spring.shardingsphere.sharding.tables.course.database-strategy.complex.sharding-columns=cid, user_id +spring.shardingsphere.sharding.tables.course.database-strategy.complex.algorithm-class-name=com.roy.shardingDemo.algorithem.MyComplexDSShardingAlgorithm +``` + + + +## hint强制路由策略 + +强制路由 + +```properties +#hint强制路由策略 +spring.shardingsphere.sharding.tables.course.table-strategy.hint.algorithm-class-name=com.roy.shardingDemo.algorithem.MyHintTableShardingAlgorithm +``` + + + +# application03.properties + +绑定表 + + + +# application04.properties + +读写分离 + +```properties +#配置主从数据源,要基于MySQL主从架构。 +spring.shardingsphere.datasource.names=m0,s0 + +spring.shardingsphere.datasource.m0.type=com.alibaba.druid.pool.DruidDataSource +spring.shardingsphere.datasource.m0.driver-class-name=com.mysql.cj.jdbc.Driver +spring.shardingsphere.datasource.m0.url=jdbc:mysql://localhost:3307/masterdemo?serverTimezone=GMT%2B8 +spring.shardingsphere.datasource.m0.username=root +spring.shardingsphere.datasource.m0.password=123456 + +spring.shardingsphere.datasource.s0.type=com.alibaba.druid.pool.DruidDataSource +spring.shardingsphere.datasource.s0.driver-class-name=com.mysql.cj.jdbc.Driver +spring.shardingsphere.datasource.s0.url=jdbc:mysql://localhost:3308/masterdemo?serverTimezone=GMT%2B8 +spring.shardingsphere.datasource.s0.username=root +spring.shardingsphere.datasource.s0.password=123456 +#读写分离规则, m0 主库,s0 从库 +spring.shardingsphere.sharding.master-slave-rules.ds0.master-data-source-name=m0 +spring.shardingsphere.sharding.master-slave-rules.ds0.slave-data-source-names[0]=s0 +#基于读写分离的表分片 +spring.shardingsphere.sharding.tables.t_dict.actual-data-nodes=ds0.t_dict + +spring.shardingsphere.sharding.tables.t_dict.key-generator.column=dict_id +spring.shardingsphere.sharding.tables.t_dict.key-generator.type=SNOWFLAKE +spring.shardingsphere.sharding.tables.t_dict.key-generator.props.worker.id=1 + +spring.shardingsphere.props.sql.show = true +spring.main.allow-bean-definition-overriding=true +``` + +# application05.properties +主从读写分离 + diff --git a/distributed/sharding-sphere/ShardingSphereDemo/pom.xml b/distributed/sharding-sphere/ShardingSphereDemo/pom.xml new file mode 100644 index 00000000..fdeb5778 --- /dev/null +++ b/distributed/sharding-sphere/ShardingSphereDemo/pom.xml @@ -0,0 +1,64 @@ + + + 4.0.0 + + com.roy + ShardingSphereDemo + 1.0-SNAPSHOT + + + + org.apache.maven.plugins + maven-compiler-plugin + + 8 + 8 + + + + + + + + + org.springframework.boot + spring-boot-dependencies + 2.3.1.RELEASE + pom + import + + + + + + + org.apache.shardingsphere + sharding-jdbc-spring-boot-starter + 4.1.1 + + + org.springframework.boot + spring-boot-starter + + + org.springframework.boot + spring-boot-starter-test + + + com.alibaba + druid + 1.1.22 + + + mysql + mysql-connector-java + + + com.baomidou + mybatis-plus-boot-starter + 3.0.5 + + + \ No newline at end of file diff --git a/distributed/sharding-sphere/ShardingSphereDemo/sql/course.sql b/distributed/sharding-sphere/ShardingSphereDemo/sql/course.sql new file mode 100644 index 00000000..bf0fdafa --- /dev/null +++ b/distributed/sharding-sphere/ShardingSphereDemo/sql/course.sql @@ -0,0 +1,13 @@ +CREATE TABLE course_1 ( + cid BIGINT(20) PRIMARY KEY, + cname VARCHAR(50) NOT NULL, + user_id BIGINT(20) NOT NULL, + cstatus varchar(10) NOT NULL +); + +CREATE TABLE course_2 ( + cid BIGINT(20) PRIMARY KEY, + cname VARCHAR(50) NOT NULL, + user_id BIGINT(20) NOT NULL, + cstatus varchar(10) NOT NULL +); \ No newline at end of file diff --git a/distributed/sharding-sphere/ShardingSphereDemo/sql/t_dict.sql b/distributed/sharding-sphere/ShardingSphereDemo/sql/t_dict.sql new file mode 100644 index 00000000..5b49e836 --- /dev/null +++ b/distributed/sharding-sphere/ShardingSphereDemo/sql/t_dict.sql @@ -0,0 +1,17 @@ +-- 在三个库中创建 +CREATE TABLE `t_dict` ( + `dict_id` bigint(0) PRIMARY KEY NOT NULL, + `ustatus` varchar(100) NOT NULL, + `uvalue` varchar(100) NOT NULL +); +-- 在userdb中创建 +CREATE TABLE `t_dict_1` ( + `dict_id` bigint(0) PRIMARY KEY NOT NULL, + `ustatus` varchar(100) NOT NULL, + `uvalue` varchar(100) NOT NULL +); +CREATE TABLE `t_dict_2` ( + `dict_id` bigint(0) PRIMARY KEY NOT NULL, + `ustatus` varchar(100) NOT NULL, + `uvalue` varchar(100) NOT NULL +); \ No newline at end of file diff --git a/distributed/sharding-sphere/ShardingSphereDemo/sql/t_user.sql b/distributed/sharding-sphere/ShardingSphereDemo/sql/t_user.sql new file mode 100644 index 00000000..1af8f8e4 --- /dev/null +++ b/distributed/sharding-sphere/ShardingSphereDemo/sql/t_user.sql @@ -0,0 +1,20 @@ +-- 在userdb中创建 +CREATE TABLE `t_user` ( + `user_id` bigint(0) PRIMARY KEY NOT NULL, + `username` varchar(100) NOT NULL, + `ustatus` varchar(50) NOT NULL, + `uage` int(3) +); + +CREATE TABLE `t_user_1` ( + `user_id` bigint(0) PRIMARY KEY NOT NULL, + `username` varchar(100) NOT NULL, + `ustatus` varchar(50) NOT NULL, + `uage` int(3) +); +CREATE TABLE `t_user_2` ( + `user_id` bigint(0) PRIMARY KEY NOT NULL, + `username` varchar(100) NOT NULL, + `ustatus` varchar(50) NOT NULL, + `uage` int(3) +); \ No newline at end of file diff --git a/distributed/sharding-sphere/ShardingSphereDemo/src/main/java/com/roy/shardingDemo/ShardingJDBCApplication.java b/distributed/sharding-sphere/ShardingSphereDemo/src/main/java/com/roy/shardingDemo/ShardingJDBCApplication.java new file mode 100644 index 00000000..e413dcf1 --- /dev/null +++ b/distributed/sharding-sphere/ShardingSphereDemo/src/main/java/com/roy/shardingDemo/ShardingJDBCApplication.java @@ -0,0 +1,19 @@ +package com.roy.shardingDemo; + +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * @author :楼兰 + * @date :Created in 2021/1/4 + * @description: + **/ + +@MapperScan("com.roy.shardingDemo.mapper") +@SpringBootApplication +public class ShardingJDBCApplication { + public static void main(String[] args) { + SpringApplication.run(ShardingJDBCApplication.class,args); + } +} diff --git a/distributed/sharding-sphere/ShardingSphereDemo/src/main/java/com/roy/shardingDemo/algorithem/MyComplexDSShardingAlgorithm.java b/distributed/sharding-sphere/ShardingSphereDemo/src/main/java/com/roy/shardingDemo/algorithem/MyComplexDSShardingAlgorithm.java new file mode 100644 index 00000000..851cc6b6 --- /dev/null +++ b/distributed/sharding-sphere/ShardingSphereDemo/src/main/java/com/roy/shardingDemo/algorithem/MyComplexDSShardingAlgorithm.java @@ -0,0 +1,42 @@ +package com.roy.shardingDemo.algorithem; + +import com.google.common.collect.Range; +import org.apache.shardingsphere.api.sharding.complex.ComplexKeysShardingAlgorithm; +import org.apache.shardingsphere.api.sharding.complex.ComplexKeysShardingValue; + +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * @author :楼兰 + * @date :Created in 2021/1/6 + * @description: + **/ + +public class MyComplexDSShardingAlgorithm implements ComplexKeysShardingAlgorithm { +// SELECT cid,cname,user_id,cstatus FROM course +// WHERE cid BETWEEN ? AND ? AND user_id = ? + @Override + public Collection doSharding(Collection availableTargetNames, ComplexKeysShardingValue shardingValue) { + Range cidRange = shardingValue.getColumnNameAndRangeValuesMap().get("cid"); + Collection userIdCol = shardingValue.getColumnNameAndShardingValuesMap().get("user_id"); + + Long upperVal = cidRange.upperEndpoint(); + Long lowerVal = cidRange.lowerEndpoint(); + + List res = new ArrayList<>(); + + for(Long userId: userIdCol){ + //course_{userID%2+1} + BigInteger userIdB = BigInteger.valueOf(userId); + BigInteger target = (userIdB.mod(new BigInteger("2"))).add(new BigInteger("1")); + + res.add("m"+target); + } + + return res; + } +} diff --git a/distributed/sharding-sphere/ShardingSphereDemo/src/main/java/com/roy/shardingDemo/algorithem/MyComplexTableShardingAlgorithm.java b/distributed/sharding-sphere/ShardingSphereDemo/src/main/java/com/roy/shardingDemo/algorithem/MyComplexTableShardingAlgorithm.java new file mode 100644 index 00000000..e1843996 --- /dev/null +++ b/distributed/sharding-sphere/ShardingSphereDemo/src/main/java/com/roy/shardingDemo/algorithem/MyComplexTableShardingAlgorithm.java @@ -0,0 +1,39 @@ +package com.roy.shardingDemo.algorithem; + +import com.google.common.collect.Range; +import org.apache.shardingsphere.api.sharding.complex.ComplexKeysShardingAlgorithm; +import org.apache.shardingsphere.api.sharding.complex.ComplexKeysShardingValue; + +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * @author :楼兰 + * @date :Created in 2021/1/6 + * @description: + **/ + +public class MyComplexTableShardingAlgorithm implements ComplexKeysShardingAlgorithm { + @Override + public Collection doSharding(Collection availableTargetNames, ComplexKeysShardingValue shardingValue) { + Range cidRange = shardingValue.getColumnNameAndRangeValuesMap().get("cid"); + Collection userIdCol = shardingValue.getColumnNameAndShardingValuesMap().get("user_id"); + + Long upperVal = cidRange.upperEndpoint(); + Long lowerVal = cidRange.lowerEndpoint(); + + List res = new ArrayList<>(); + + for(Long userId: userIdCol){ + //course_{userID%2+1} + BigInteger userIdB = BigInteger.valueOf(userId); + BigInteger target = (userIdB.mod(new BigInteger("2"))).add(new BigInteger("1")); + + res.add(shardingValue.getLogicTableName()+"_"+target); + } + + return res; + } +} diff --git a/distributed/sharding-sphere/ShardingSphereDemo/src/main/java/com/roy/shardingDemo/algorithem/MyHintTableShardingAlgorithm.java b/distributed/sharding-sphere/ShardingSphereDemo/src/main/java/com/roy/shardingDemo/algorithem/MyHintTableShardingAlgorithm.java new file mode 100644 index 00000000..9152eaf6 --- /dev/null +++ b/distributed/sharding-sphere/ShardingSphereDemo/src/main/java/com/roy/shardingDemo/algorithem/MyHintTableShardingAlgorithm.java @@ -0,0 +1,24 @@ +package com.roy.shardingDemo.algorithem; + +import org.apache.shardingsphere.api.sharding.hint.HintShardingAlgorithm; +import org.apache.shardingsphere.api.sharding.hint.HintShardingValue; + +import java.util.Arrays; +import java.util.Collection; + +/** + * @author :楼兰 + * @date :Created in 2021/1/6 + * @description: + **/ + +public class MyHintTableShardingAlgorithm implements HintShardingAlgorithm { + @Override + public Collection doSharding(Collection availableTargetNames, HintShardingValue shardingValue) { + String key = shardingValue.getLogicTableName() + "_" + shardingValue.getValues().toArray()[0]; + if(availableTargetNames.contains(key)){ + return Arrays.asList(key); + } + throw new UnsupportedOperationException("route "+ key +" is not supported ,please check your config"); + } +} diff --git a/distributed/sharding-sphere/ShardingSphereDemo/src/main/java/com/roy/shardingDemo/algorithem/MyPreciseDSShardingAlgorithm.java b/distributed/sharding-sphere/ShardingSphereDemo/src/main/java/com/roy/shardingDemo/algorithem/MyPreciseDSShardingAlgorithm.java new file mode 100644 index 00000000..7bb72a21 --- /dev/null +++ b/distributed/sharding-sphere/ShardingSphereDemo/src/main/java/com/roy/shardingDemo/algorithem/MyPreciseDSShardingAlgorithm.java @@ -0,0 +1,32 @@ +package com.roy.shardingDemo.algorithem; + +import org.apache.shardingsphere.api.sharding.standard.PreciseShardingAlgorithm; +import org.apache.shardingsphere.api.sharding.standard.PreciseShardingValue; + +import java.math.BigInteger; +import java.util.Collection; + +/** + * @author :楼兰 + * @date :Created in 2021/1/6 + * @description: + **/ + +public class MyPreciseDSShardingAlgorithm implements PreciseShardingAlgorithm { + //select * from course where cid = ? or cid in (?,?) + @Override + public String doSharding(Collection availableTargetNames, PreciseShardingValue shardingValue) { + String logicTableName = shardingValue.getLogicTableName(); + String cid = shardingValue.getColumnName(); + Long cidValue = shardingValue.getValue(); + //实现 course_$->{cid%2+1) + BigInteger shardingValueB = BigInteger.valueOf(cidValue); + BigInteger resB = (shardingValueB.mod(new BigInteger("2"))).add(new BigInteger("1")); + String key = "m"+resB; + if(availableTargetNames.contains(key)){ + return key; + } + //couse_1, course_2 + throw new UnsupportedOperationException("route "+ key +" is not supported ,please check your config"); + } +} diff --git a/distributed/sharding-sphere/ShardingSphereDemo/src/main/java/com/roy/shardingDemo/algorithem/MyPreciseTableShardingAlgorithm.java b/distributed/sharding-sphere/ShardingSphereDemo/src/main/java/com/roy/shardingDemo/algorithem/MyPreciseTableShardingAlgorithm.java new file mode 100644 index 00000000..09be0830 --- /dev/null +++ b/distributed/sharding-sphere/ShardingSphereDemo/src/main/java/com/roy/shardingDemo/algorithem/MyPreciseTableShardingAlgorithm.java @@ -0,0 +1,38 @@ +package com.roy.shardingDemo.algorithem; + +import org.apache.shardingsphere.api.sharding.standard.PreciseShardingAlgorithm; +import org.apache.shardingsphere.api.sharding.standard.PreciseShardingValue; + +import java.math.BigInteger; +import java.util.Collection; + +/** + * @author :楼兰 + * @date :Created in 2021/1/6 + * @description: + **/ + +public class MyPreciseTableShardingAlgorithm implements PreciseShardingAlgorithm { + + /** + * select * from course where cid = ? or cid in (?,?) + * @param availableTargetNames 真实表 course_1、course_2 + * @param shardingValue 精确条件值 + * @return 查询条件选中的真实表 course_1 or course_2 + */ + @Override + public String doSharding(Collection availableTargetNames, PreciseShardingValue shardingValue) { + String logicTableName = shardingValue.getLogicTableName(); + String cid = shardingValue.getColumnName(); + Long cidValue = shardingValue.getValue(); + //实现 course_$->{cid%2+1) + BigInteger shardingValueB = BigInteger.valueOf(cidValue); + BigInteger resB = (shardingValueB.mod(new BigInteger("2"))).add(new BigInteger("1")); + String key = logicTableName+"_"+resB; + if(availableTargetNames.contains(key)){ + return key; + } + //couse_1, course_2 + throw new UnsupportedOperationException("route "+ key +" is not supported ,please check your config"); + } +} diff --git a/distributed/sharding-sphere/ShardingSphereDemo/src/main/java/com/roy/shardingDemo/algorithem/MyRangeDSShardingAlgorithm.java b/distributed/sharding-sphere/ShardingSphereDemo/src/main/java/com/roy/shardingDemo/algorithem/MyRangeDSShardingAlgorithm.java new file mode 100644 index 00000000..0b44e4c1 --- /dev/null +++ b/distributed/sharding-sphere/ShardingSphereDemo/src/main/java/com/roy/shardingDemo/algorithem/MyRangeDSShardingAlgorithm.java @@ -0,0 +1,25 @@ +package com.roy.shardingDemo.algorithem; + +import org.apache.shardingsphere.api.sharding.standard.RangeShardingAlgorithm; +import org.apache.shardingsphere.api.sharding.standard.RangeShardingValue; + +import java.util.Arrays; +import java.util.Collection; + +/** + * @author :楼兰 + * @date :Created in 2021/1/6 + * @description: + **/ + +public class MyRangeDSShardingAlgorithm implements RangeShardingAlgorithm { + @Override + public Collection doSharding(Collection availableTargetNames, RangeShardingValue shardingValue) { + //select * from course where cid between 1 and 100; + Long upperVal = shardingValue.getValueRange().upperEndpoint();//100 + Long lowerVal = shardingValue.getValueRange().lowerEndpoint();//1 + + String logicTableName = shardingValue.getLogicTableName(); + return Arrays.asList("m1","m2"); + } +} diff --git a/distributed/sharding-sphere/ShardingSphereDemo/src/main/java/com/roy/shardingDemo/algorithem/MyRangeTableShardingAlgorithm.java b/distributed/sharding-sphere/ShardingSphereDemo/src/main/java/com/roy/shardingDemo/algorithem/MyRangeTableShardingAlgorithm.java new file mode 100644 index 00000000..762ead06 --- /dev/null +++ b/distributed/sharding-sphere/ShardingSphereDemo/src/main/java/com/roy/shardingDemo/algorithem/MyRangeTableShardingAlgorithm.java @@ -0,0 +1,32 @@ +package com.roy.shardingDemo.algorithem; + +import org.apache.shardingsphere.api.sharding.standard.RangeShardingAlgorithm; +import org.apache.shardingsphere.api.sharding.standard.RangeShardingValue; +import sun.rmi.runtime.Log; + +import java.util.Arrays; +import java.util.Collection; + +/** + * @author :楼兰 + * @date :Created in 2021/1/6 + * @description: + **/ + +public class MyRangeTableShardingAlgorithm implements RangeShardingAlgorithm { + /** + * select * from course where cid between 1 and 100; + * @param availableTargetNames 真实表 course_1、course_2 + * @param shardingValue 范围条件值 + * @return 查询条件选中的真实表 course_1、course_2 + */ + @Override + public Collection doSharding(Collection availableTargetNames, RangeShardingValue shardingValue) { + + Long upperVal = shardingValue.getValueRange().upperEndpoint();//100 + Long lowerVal = shardingValue.getValueRange().lowerEndpoint();//1 + + String logicTableName = shardingValue.getLogicTableName(); + return Arrays.asList(logicTableName+"_1",logicTableName+"_2"); + } +} diff --git a/distributed/sharding-sphere/ShardingSphereDemo/src/main/java/com/roy/shardingDemo/entity/Course.java b/distributed/sharding-sphere/ShardingSphereDemo/src/main/java/com/roy/shardingDemo/entity/Course.java new file mode 100644 index 00000000..1ed83084 --- /dev/null +++ b/distributed/sharding-sphere/ShardingSphereDemo/src/main/java/com/roy/shardingDemo/entity/Course.java @@ -0,0 +1,57 @@ +package com.roy.shardingDemo.entity; + +/** + * @author :楼兰 + * @date :Created in 2021/1/4 + * @description: + **/ + +public class Course { + + private Long cid; + private String cname; + private Long userId; + private String cstatus; + + public Long getCid() { + return cid; + } + + public void setCid(Long cid) { + this.cid = cid; + } + + public String getCname() { + return cname; + } + + public void setCname(String cname) { + this.cname = cname; + } + + public Long getUserId() { + return userId; + } + + public void setUserId(Long userId) { + this.userId = userId; + } + + public String getCstatus() { + return cstatus; + } + + public void setCstatus(String cstatus) { + this.cstatus = cstatus; + } + + @Override + public String toString() { + return "Course{" + + "cid=" + cid + + ", cname='" + cname + '\'' + + ", userId=" + userId + + ", cstatus='" + cstatus + '\'' + + '}'; + } +} diff --git a/distributed/sharding-sphere/ShardingSphereDemo/src/main/java/com/roy/shardingDemo/entity/Dict.java b/distributed/sharding-sphere/ShardingSphereDemo/src/main/java/com/roy/shardingDemo/entity/Dict.java new file mode 100644 index 00000000..e1271491 --- /dev/null +++ b/distributed/sharding-sphere/ShardingSphereDemo/src/main/java/com/roy/shardingDemo/entity/Dict.java @@ -0,0 +1,48 @@ +package com.roy.shardingDemo.entity; + +import com.baomidou.mybatisplus.annotation.TableName; + +/** + * @author :楼兰 + * @date :Created in 2021/1/5 + * @description: + **/ +@TableName("t_dict") +public class Dict { + private Long dictId; + private String ustatus; + private String uvalue; + + public Long getDictId() { + return dictId; + } + + public void setDictId(Long dictId) { + this.dictId = dictId; + } + + public String getUstatus() { + return ustatus; + } + + public void setUstatus(String ustatus) { + this.ustatus = ustatus; + } + + public String getUvalue() { + return uvalue; + } + + public void setUvalue(String uvalue) { + this.uvalue = uvalue; + } + + @Override + public String toString() { + return "Dict{" + + "dictId=" + dictId + + ", ustatus='" + ustatus + '\'' + + ", uvalue='" + uvalue + '\'' + + '}'; + } +} diff --git a/distributed/sharding-sphere/ShardingSphereDemo/src/main/java/com/roy/shardingDemo/entity/User.java b/distributed/sharding-sphere/ShardingSphereDemo/src/main/java/com/roy/shardingDemo/entity/User.java new file mode 100644 index 00000000..cbdaddd5 --- /dev/null +++ b/distributed/sharding-sphere/ShardingSphereDemo/src/main/java/com/roy/shardingDemo/entity/User.java @@ -0,0 +1,59 @@ +package com.roy.shardingDemo.entity; + +import com.baomidou.mybatisplus.annotation.TableName; + +/** + * @author :楼兰 + * @date :Created in 2021/1/5 + * @description: + **/ +@TableName("user") +public class User { + + private Long userId; + private String username; + private String ustatus; + private int uage; + + public Long getUserId() { + return userId; + } + + public void setUserId(Long userId) { + this.userId = userId; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getUstatus() { + return ustatus; + } + + public void setUstatus(String ustatus) { + this.ustatus = ustatus; + } + + public int getUage() { + return uage; + } + + public void setUage(int uage) { + this.uage = uage; + } + + @Override + public String toString() { + return "User{" + + "userId=" + userId + + ", username='" + username + '\'' + + ", ustatus='" + ustatus + '\'' + + ", uage=" + uage + + '}'; + } +} diff --git a/distributed/sharding-sphere/ShardingSphereDemo/src/main/java/com/roy/shardingDemo/mapper/CourseMapper.java b/distributed/sharding-sphere/ShardingSphereDemo/src/main/java/com/roy/shardingDemo/mapper/CourseMapper.java new file mode 100644 index 00000000..2155b1e0 --- /dev/null +++ b/distributed/sharding-sphere/ShardingSphereDemo/src/main/java/com/roy/shardingDemo/mapper/CourseMapper.java @@ -0,0 +1,13 @@ +package com.roy.shardingDemo.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.roy.shardingDemo.entity.Course; + +/** + * @author :楼兰 + * @date :Created in 2021/1/4 + * @description: + **/ + +public interface CourseMapper extends BaseMapper { +} diff --git a/distributed/sharding-sphere/ShardingSphereDemo/src/main/java/com/roy/shardingDemo/mapper/DictMapper.java b/distributed/sharding-sphere/ShardingSphereDemo/src/main/java/com/roy/shardingDemo/mapper/DictMapper.java new file mode 100644 index 00000000..7ad36404 --- /dev/null +++ b/distributed/sharding-sphere/ShardingSphereDemo/src/main/java/com/roy/shardingDemo/mapper/DictMapper.java @@ -0,0 +1,12 @@ +package com.roy.shardingDemo.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.roy.shardingDemo.entity.Dict; + +/** + * @author :楼兰 + * @date :Created in 2021/1/5 + * @description: + **/ +public interface DictMapper extends BaseMapper { +} diff --git a/distributed/sharding-sphere/ShardingSphereDemo/src/main/java/com/roy/shardingDemo/mapper/UserMapper.java b/distributed/sharding-sphere/ShardingSphereDemo/src/main/java/com/roy/shardingDemo/mapper/UserMapper.java new file mode 100644 index 00000000..9a66da47 --- /dev/null +++ b/distributed/sharding-sphere/ShardingSphereDemo/src/main/java/com/roy/shardingDemo/mapper/UserMapper.java @@ -0,0 +1,18 @@ +package com.roy.shardingDemo.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.roy.shardingDemo.entity.User; +import org.apache.ibatis.annotations.Select; + +import java.util.List; + +/** + * @author :楼兰 + * @date :Created in 2021/1/5 + * @description: + **/ +public interface UserMapper extends BaseMapper { + + @Select("select u.user_id,u.username,d.uvalue ustatus from user u left join t_dict d on u.ustatus = d.ustatus") + public List queryUserStatus(); +} diff --git a/distributed/sharding-sphere/ShardingSphereDemo/src/main/resources/application.properties b/distributed/sharding-sphere/ShardingSphereDemo/src/main/resources/application.properties new file mode 100644 index 00000000..839026ac --- /dev/null +++ b/distributed/sharding-sphere/ShardingSphereDemo/src/main/resources/application.properties @@ -0,0 +1,29 @@ +spring.shardingsphere.datasource.names=m1 + +spring.shardingsphere.datasource.m1.type=com.alibaba.druid.pool.DruidDataSource +spring.shardingsphere.datasource.m1.driver-class-name=com.mysql.cj.jdbc.Driver +spring.shardingsphere.datasource.m1.url=jdbc:mysql://localhost:3306/coursedb?serverTimezone=GMT%2B8 +spring.shardingsphere.datasource.m1.username=root +spring.shardingsphere.datasource.m1.password=123456 + + +spring.shardingsphere.sharding.tables.t_dict.actual-data-nodes=m1.t_dict_$->{1..2} + +spring.shardingsphere.sharding.tables.t_dict.key-generator.column=dict_id +spring.shardingsphere.sharding.tables.t_dict.key-generator.type=SNOWFLAKE +spring.shardingsphere.sharding.tables.t_dict.key-generator.props.worker.id=1 +spring.shardingsphere.sharding.tables.t_dict.table-strategy.inline.sharding-column=ustatus +spring.shardingsphere.sharding.tables.t_dict.table-strategy.inline.algorithm-expression=t_dict_$->{ustatus.toInteger()%2+1} + +spring.shardingsphere.sharding.tables.user.actual-data-nodes=m1.t_user_$->{1..2} +spring.shardingsphere.sharding.tables.user.key-generator.column=user_id +spring.shardingsphere.sharding.tables.user.key-generator.type=SNOWFLAKE +spring.shardingsphere.sharding.tables.user.key-generator.props.worker.id=1 +spring.shardingsphere.sharding.tables.user.table-strategy.inline.sharding-column=ustatus +spring.shardingsphere.sharding.tables.user.table-strategy.inline.algorithm-expression=t_user_$->{ustatus.toInteger()%2+1} +#\u7ED1\u5B9A\u8868\u793A\u4F8B +spring.shardingsphere.sharding.binding-tables[0]=user,t_dict + +spring.shardingsphere.props.sql.show = true +spring.main.allow-bean-definition-overriding=true + diff --git a/distributed/sharding-sphere/ShardingSphereDemo/src/main/resources/application01.properties b/distributed/sharding-sphere/ShardingSphereDemo/src/main/resources/application01.properties new file mode 100644 index 00000000..cdbfcca4 --- /dev/null +++ b/distributed/sharding-sphere/ShardingSphereDemo/src/main/resources/application01.properties @@ -0,0 +1,25 @@ +#\u914D\u7F6E\u6570\u636E\u6E90 +# \u6570\u636E\u6E90\u540D\u79F0 +spring.shardingsphere.datasource.names=m1 + +spring.shardingsphere.datasource.m1.type=com.alibaba.druid.pool.DruidDataSource +spring.shardingsphere.datasource.m1.driver-class-name=com.mysql.cj.jdbc.Driver +spring.shardingsphere.datasource.m1.url=jdbc:mysql://localhost:3306/coursedb?serverTimezone=GMT%2B8 +spring.shardingsphere.datasource.m1.username=root +spring.shardingsphere.datasource.m1.password=123456 +#\u914D\u7F6E\u771F\u5B9E\u8868\u5206\u5E03 +spring.shardingsphere.sharding.tables.course.actual-data-nodes=m1.course_$->{1..2} +#\u4E3B\u952E\u751F\u6210\u7B56\u7565 +# \u4E3B\u952E\u5B57\u6BB5\u540D +spring.shardingsphere.sharding.tables.course.key-generator.column=cid +# \u4E3B\u952E\u751F\u6210\u7B97\u6CD5 +spring.shardingsphere.sharding.tables.course.key-generator.type=SNOWFLAKE +# \u96EA\u82B1\u7B97\u6CD5\u7684\u53C2\u6570 +spring.shardingsphere.sharding.tables.course.key-generator.props.worker.id=1 +#\u914D\u7F6E\u5206\u8868\u7B56\u7565 +spring.shardingsphere.sharding.tables.course.table-strategy.inline.sharding-column=cid +spring.shardingsphere.sharding.tables.course.table-strategy.inline.algorithm-expression=course_$->{cid%2+1} +#\u5176\u4ED6\u8FD0\u884C\u5C5E\u6027 +spring.shardingsphere.props.sql.show = true +spring.main.allow-bean-definition-overriding=true + diff --git a/distributed/sharding-sphere/ShardingSphereDemo/src/main/resources/application02.properties b/distributed/sharding-sphere/ShardingSphereDemo/src/main/resources/application02.properties new file mode 100644 index 00000000..d83d0dc3 --- /dev/null +++ b/distributed/sharding-sphere/ShardingSphereDemo/src/main/resources/application02.properties @@ -0,0 +1,56 @@ +#\u914D\u7F6E\u591A\u4E2A\u6570\u636E\u6E90 +spring.shardingsphere.datasource.names=m1,m2 + +spring.shardingsphere.datasource.m1.type=com.alibaba.druid.pool.DruidDataSource +spring.shardingsphere.datasource.m1.driver-class-name=com.mysql.cj.jdbc.Driver +spring.shardingsphere.datasource.m1.url=jdbc:mysql://localhost:3306/coursedb?serverTimezone=GMT%2B8 +spring.shardingsphere.datasource.m1.username=root +spring.shardingsphere.datasource.m1.password=123456 + +spring.shardingsphere.datasource.m2.type=com.alibaba.druid.pool.DruidDataSource +spring.shardingsphere.datasource.m2.driver-class-name=com.mysql.cj.jdbc.Driver +spring.shardingsphere.datasource.m2.url=jdbc:mysql://localhost:3306/coursedb2?serverTimezone=GMT%2B8 +spring.shardingsphere.datasource.m2.username=root +spring.shardingsphere.datasource.m2.password=123456 +#\u771F\u5B9E\u8868\u5206\u5E03\uFF0C\u5206\u5E93\uFF0C\u5206\u8868 +spring.shardingsphere.sharding.tables.course.actual-data-nodes=m$->{1..2}.course_$->{1..2} + +spring.shardingsphere.sharding.tables.course.key-generator.column=cid +spring.shardingsphere.sharding.tables.course.key-generator.type=SNOWFLAKE +spring.shardingsphere.sharding.tables.course.key-generator.props.worker.id=1 + +#inline\u7B56\u7565\u4E0D\u652F\u6301\u8303\u56F4\u67E5\u8BE2 +#inline\u5206\u7247\u7B56\u7565 +spring.shardingsphere.sharding.tables.course.table-strategy.inline.sharding-column=cid +spring.shardingsphere.sharding.tables.course.table-strategy.inline.algorithm-expression=course_$->{cid%2+1} +#inline\u5206\u5E93\u7B56\u7565 +spring.shardingsphere.sharding.tables.course.database-strategy.inline.sharding-column=cid +spring.shardingsphere.sharding.tables.course.database-strategy.inline.algorithm-expression=m$->{cid%2+1} + +#standard\u6807\u51C6\u5206\u7247\u7B56\u7565 +#spring.shardingsphere.sharding.tables.course.table-strategy.standard.sharding-column=cid +#spring.shardingsphere.sharding.tables.course.table-strategy.standard.precise-algorithm-class-name=com.roy.shardingDemo.algorithem.MyPreciseTableShardingAlgorithm +#spring.shardingsphere.sharding.tables.course.table-strategy.standard.range-algorithm-class-name=com.roy.shardingDemo.algorithem.MyRangeTableShardingAlgorithm +# +#spring.shardingsphere.sharding.tables.course.database-strategy.standard.sharding-column=cid +#spring.shardingsphere.sharding.tables.course.database-strategy.standard.precise-algorithm-class-name=com.roy.shardingDemo.algorithem.MyPreciseDSShardingAlgorithm +#spring.shardingsphere.sharding.tables.course.database-strategy.standard.range-algorithm-class-name=com.roy.shardingDemo.algorithem.MyRangeDSShardingAlgorithm + +##complex\u590D\u6742\u5206\u7247\u7B56\u7565 +#spring.shardingsphere.sharding.tables.course.table-strategy.complex.sharding-columns= cid, user_id +#spring.shardingsphere.sharding.tables.course.table-strategy.complex.algorithm-class-name=com.roy.shardingDemo.algorithem.MyComplexTableShardingAlgorithm +# +#spring.shardingsphere.sharding.tables.course.database-strategy.complex.sharding-columns=cid, user_id +#spring.shardingsphere.sharding.tables.course.database-strategy.complex.algorithm-class-name=com.roy.shardingDemo.algorithem.MyComplexDSShardingAlgorithm + +##hint\u5F3A\u5236\u8DEF\u7531\u7B56\u7565 +#spring.shardingsphere.sharding.tables.course.table-strategy.hint.algorithm-class-name=com.roy.shardingDemo.algorithem.MyHintTableShardingAlgorithm + +##\u5E7F\u64AD\u8868\u914D\u7F6E +#spring.shardingsphere.sharding.broadcast-tables=t_dict +#spring.shardingsphere.sharding.tables.t_dict.key-generator.column=dict_id +#spring.shardingsphere.sharding.tables.t_dict.key-generator.type=SNOWFLAKE + +spring.shardingsphere.props.sql.show = true +spring.main.allow-bean-definition-overriding=true + diff --git a/distributed/sharding-sphere/ShardingSphereDemo/src/main/resources/application03.properties b/distributed/sharding-sphere/ShardingSphereDemo/src/main/resources/application03.properties new file mode 100644 index 00000000..839026ac --- /dev/null +++ b/distributed/sharding-sphere/ShardingSphereDemo/src/main/resources/application03.properties @@ -0,0 +1,29 @@ +spring.shardingsphere.datasource.names=m1 + +spring.shardingsphere.datasource.m1.type=com.alibaba.druid.pool.DruidDataSource +spring.shardingsphere.datasource.m1.driver-class-name=com.mysql.cj.jdbc.Driver +spring.shardingsphere.datasource.m1.url=jdbc:mysql://localhost:3306/coursedb?serverTimezone=GMT%2B8 +spring.shardingsphere.datasource.m1.username=root +spring.shardingsphere.datasource.m1.password=123456 + + +spring.shardingsphere.sharding.tables.t_dict.actual-data-nodes=m1.t_dict_$->{1..2} + +spring.shardingsphere.sharding.tables.t_dict.key-generator.column=dict_id +spring.shardingsphere.sharding.tables.t_dict.key-generator.type=SNOWFLAKE +spring.shardingsphere.sharding.tables.t_dict.key-generator.props.worker.id=1 +spring.shardingsphere.sharding.tables.t_dict.table-strategy.inline.sharding-column=ustatus +spring.shardingsphere.sharding.tables.t_dict.table-strategy.inline.algorithm-expression=t_dict_$->{ustatus.toInteger()%2+1} + +spring.shardingsphere.sharding.tables.user.actual-data-nodes=m1.t_user_$->{1..2} +spring.shardingsphere.sharding.tables.user.key-generator.column=user_id +spring.shardingsphere.sharding.tables.user.key-generator.type=SNOWFLAKE +spring.shardingsphere.sharding.tables.user.key-generator.props.worker.id=1 +spring.shardingsphere.sharding.tables.user.table-strategy.inline.sharding-column=ustatus +spring.shardingsphere.sharding.tables.user.table-strategy.inline.algorithm-expression=t_user_$->{ustatus.toInteger()%2+1} +#\u7ED1\u5B9A\u8868\u793A\u4F8B +spring.shardingsphere.sharding.binding-tables[0]=user,t_dict + +spring.shardingsphere.props.sql.show = true +spring.main.allow-bean-definition-overriding=true + diff --git a/distributed/sharding-sphere/ShardingSphereDemo/src/main/resources/application04.properties b/distributed/sharding-sphere/ShardingSphereDemo/src/main/resources/application04.properties new file mode 100644 index 00000000..90cd795d --- /dev/null +++ b/distributed/sharding-sphere/ShardingSphereDemo/src/main/resources/application04.properties @@ -0,0 +1,27 @@ +#\u914D\u7F6E\u4E3B\u4ECE\u6570\u636E\u6E90\uFF0C\u8981\u57FA\u4E8EMySQL\u4E3B\u4ECE\u67B6\u6784\u3002 +spring.shardingsphere.datasource.names=m0,s0 + +spring.shardingsphere.datasource.m0.type=com.alibaba.druid.pool.DruidDataSource +spring.shardingsphere.datasource.m0.driver-class-name=com.mysql.cj.jdbc.Driver +spring.shardingsphere.datasource.m0.url=jdbc:mysql://localhost:3307/masterdemo?serverTimezone=GMT%2B8 +spring.shardingsphere.datasource.m0.username=root +spring.shardingsphere.datasource.m0.password=123456 + +spring.shardingsphere.datasource.s0.type=com.alibaba.druid.pool.DruidDataSource +spring.shardingsphere.datasource.s0.driver-class-name=com.mysql.cj.jdbc.Driver +spring.shardingsphere.datasource.s0.url=jdbc:mysql://localhost:3308/masterdemo?serverTimezone=GMT%2B8 +spring.shardingsphere.datasource.s0.username=root +spring.shardingsphere.datasource.s0.password=123456 +#\u8BFB\u5199\u5206\u79BB\u89C4\u5219\uFF0C m0 \u4E3B\u5E93\uFF0Cs0 \u4ECE\u5E93 +spring.shardingsphere.sharding.master-slave-rules.ds0.master-data-source-name=m0 +spring.shardingsphere.sharding.master-slave-rules.ds0.slave-data-source-names[0]=s0 +#\u57FA\u4E8E\u8BFB\u5199\u5206\u79BB\u7684\u8868\u5206\u7247 +spring.shardingsphere.sharding.tables.t_dict.actual-data-nodes=ds0.t_dict + +spring.shardingsphere.sharding.tables.t_dict.key-generator.column=dict_id +spring.shardingsphere.sharding.tables.t_dict.key-generator.type=SNOWFLAKE +spring.shardingsphere.sharding.tables.t_dict.key-generator.props.worker.id=1 + +spring.shardingsphere.props.sql.show = true +spring.main.allow-bean-definition-overriding=true + diff --git a/distributed/sharding-sphere/ShardingSphereDemo/src/main/resources/application05.properties b/distributed/sharding-sphere/ShardingSphereDemo/src/main/resources/application05.properties new file mode 100644 index 00000000..2b95a865 --- /dev/null +++ b/distributed/sharding-sphere/ShardingSphereDemo/src/main/resources/application05.properties @@ -0,0 +1,26 @@ +spring.shardingsphere.datasource.names=m0,s0 + +spring.shardingsphere.datasource.m0.type=com.alibaba.druid.pool.DruidDataSource +spring.shardingsphere.datasource.m0.driver-class-name=com.mysql.cj.jdbc.Driver +spring.shardingsphere.datasource.m0.url=jdbc:mysql://localhost:3307/masterdemo?serverTimezone=GMT%2B8 +spring.shardingsphere.datasource.m0.username=root +spring.shardingsphere.datasource.m0.password=123456 + +spring.shardingsphere.datasource.s0.type=com.alibaba.druid.pool.DruidDataSource +spring.shardingsphere.datasource.s0.driver-class-name=com.mysql.cj.jdbc.Driver +spring.shardingsphere.datasource.s0.url=jdbc:mysql://localhost:3308/masterdemo?serverTimezone=GMT%2B8 +spring.shardingsphere.datasource.s0.username=root +spring.shardingsphere.datasource.s0.password=123456 + +spring.shardingsphere.sharding.master-slave-rules.ds0.master-data-source-name=m0 +spring.shardingsphere.sharding.master-slave-rules.ds0.slave-data-source-names[0]=s0 + +spring.shardingsphere.sharding.tables.t_dict.actual-data-nodes=ds0.t_dict + +spring.shardingsphere.sharding.tables.t_dict.key-generator.column=dict_id +spring.shardingsphere.sharding.tables.t_dict.key-generator.type=SNOWFLAKE +spring.shardingsphere.sharding.tables.t_dict.key-generator.props.worker.id=1 + +spring.shardingsphere.props.sql.show = true +spring.main.allow-bean-definition-overriding=true + diff --git a/distributed/sharding-sphere/ShardingSphereDemo/src/test/java/com/roy/shardingDemo/ShardingJDBCTest.java b/distributed/sharding-sphere/ShardingSphereDemo/src/test/java/com/roy/shardingDemo/ShardingJDBCTest.java new file mode 100644 index 00000000..6d4345f4 --- /dev/null +++ b/distributed/sharding-sphere/ShardingSphereDemo/src/test/java/com/roy/shardingDemo/ShardingJDBCTest.java @@ -0,0 +1,137 @@ +package com.roy.shardingDemo; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.roy.shardingDemo.entity.Course; +import com.roy.shardingDemo.entity.Dict; +import com.roy.shardingDemo.entity.User; +import com.roy.shardingDemo.mapper.CourseMapper; +import com.roy.shardingDemo.mapper.DictMapper; +import com.roy.shardingDemo.mapper.UserMapper; +import org.apache.shardingsphere.api.hint.HintManager; +import org.junit.Test; +import org.junit.jupiter.api.Tags; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import javax.annotation.Resource; +import java.util.List; + +/** + * @author :楼兰 + * @date :Created in 2021/1/4 + * @description: + **/ + +@RunWith(SpringRunner.class) +@SpringBootTest +public class ShardingJDBCTest { + @Resource + CourseMapper courseMapper; + @Resource + DictMapper dictMapper; + @Resource + UserMapper userMapper; + + @Test + public void addCourse(){ + for(int i = 0 ; i < 10 ; i ++){ + Course c = new Course(); +// c.setCid(Long.valueOf(i)); + c.setCname("shardingsphere"); + c.setUserId(Long.valueOf(""+(1000+i))); + c.setCstatus("1"); + courseMapper.insert(c); + } + } + + @Test + public void queryCourse(){ + //select * from course + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.orderByDesc("cid"); +// wrapper.eq("cid",730100102537940992L); +// wrapper.in("cid",730100102537940992L,730100102990925824L); + List courses = courseMapper.selectList(wrapper); + System.out.println("条数:"+courses.size()); + for (Course course : courses) { + System.out.println("查询结果:"+ course); + } + } + + @Test + public void queryOrderRange(){ + //select * from course + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.between("cid",730100102537940992L,730100102990925824L); +// wrapper.in() + List courses = courseMapper.selectList(wrapper); + courses.forEach(course -> System.out.println(course)); + } + + @Test + public void queryCourseComplex(){ + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.between("cid",730100102537940992L,730100102990925824L); + wrapper.eq("user_id",1004L); +// wrapper.in() + List courses = courseMapper.selectList(wrapper); + courses.forEach(course -> System.out.println(course)); + } + + @Test + public void queryCourseByHint(){ + HintManager hintManager = HintManager.getInstance(); + hintManager.addTableShardingValue("course",2); + List courses = courseMapper.selectList(null); + courses.forEach(course -> System.out.println(course)); + hintManager.close(); + } + + @Test + public void addDict(){ + Dict d1 = new Dict(); + d1.setUstatus("1"); + d1.setUvalue("正常"); + dictMapper.insert(d1); + + Dict d2 = new Dict(); + d2.setUstatus("0"); + d2.setUvalue("不正常"); + dictMapper.insert(d2); + + for(int i = 0 ; i < 10 ; i ++){ + User user = new User(); + user.setUsername("user No "+i); + user.setUstatus(""+(i%2)); + user.setUage(i*10); + userMapper.insert(user); + } + } + + @Test + public void queryUserStatus(){ + List users = userMapper.queryUserStatus(); + users.forEach(user -> System.out.println(user)); + } + + @Test + public void addDictByMS(){ + Dict d1 = new Dict(); + d1.setUstatus("1"); + d1.setUvalue("正常"); + dictMapper.insert(d1); + + Dict d2 = new Dict(); + d2.setUstatus("0"); + d2.setUvalue("不正常"); + dictMapper.insert(d2); + } + + @Test + public void queryDictByMS(){ + List dicts = dictMapper.selectList(null); + dicts.forEach(dict -> System.out.println(dict)); + } + +} diff --git a/distributed/springcloud-debug/consumer/pom.xml b/distributed/springcloud-debug/consumer/pom.xml new file mode 100644 index 00000000..4fc58712 --- /dev/null +++ b/distributed/springcloud-debug/consumer/pom.xml @@ -0,0 +1,46 @@ + + + + springcloud-debug + cn.cunchang + 1.0-SNAPSHOT + + 4.0.0 + + consumer + + + 8 + 8 + + + + + + org.springframework.boot + spring-boot-starter-web + + + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-discovery + + + + org.springframework.cloud + spring-cloud-starter-openfeign + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + \ No newline at end of file diff --git a/distributed/springcloud-debug/consumer/src/main/java/cn/cunchang/ConsumerApplication.java b/distributed/springcloud-debug/consumer/src/main/java/cn/cunchang/ConsumerApplication.java new file mode 100644 index 00000000..01503bcb --- /dev/null +++ b/distributed/springcloud-debug/consumer/src/main/java/cn/cunchang/ConsumerApplication.java @@ -0,0 +1,30 @@ +package cn.cunchang; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.openfeign.EnableFeignClients; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@EnableFeignClients +@SpringBootApplication +public class ConsumerApplication { + + public static void main(String[] args) { + SpringApplication.run(ConsumerApplication.class, args); + } + + @Autowired + private HelloFeignClient helloFeignClient; + + @GetMapping("/sayHello") + public String test(String name) { + String result = helloFeignClient.sayHello(name); + return result; + } + +} + + diff --git a/distributed/springcloud-debug/consumer/src/main/java/cn/cunchang/HelloFeignClient.java b/distributed/springcloud-debug/consumer/src/main/java/cn/cunchang/HelloFeignClient.java new file mode 100644 index 00000000..a1c68eca --- /dev/null +++ b/distributed/springcloud-debug/consumer/src/main/java/cn/cunchang/HelloFeignClient.java @@ -0,0 +1,12 @@ +package cn.cunchang; + +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; + +@FeignClient(value = "producer") +public interface HelloFeignClient { + @RequestMapping(value = "/hello", method = RequestMethod.GET) + String sayHello(@RequestParam("name") String name); +} \ No newline at end of file diff --git a/distributed/springcloud-debug/consumer/src/main/resources/application.yml b/distributed/springcloud-debug/consumer/src/main/resources/application.yml new file mode 100644 index 00000000..d9beaa1e --- /dev/null +++ b/distributed/springcloud-debug/consumer/src/main/resources/application.yml @@ -0,0 +1,20 @@ +server: + port: 8055 + +spring: + application: + name: consumer #微服务名称 + + #配置nacos注册中心地址 + cloud: + nacos: + discovery: + server-addr: 127.0.0.1:8848 + + + +management: + endpoints: + web: + exposure: + include: '*' diff --git a/distributed/springcloud-debug/pom.xml b/distributed/springcloud-debug/pom.xml new file mode 100644 index 00000000..879711f2 --- /dev/null +++ b/distributed/springcloud-debug/pom.xml @@ -0,0 +1,65 @@ + + + 4.0.0 + pom + + consumer + producer + + + + org.springframework.boot + spring-boot-starter-parent + 2.3.2.RELEASE + + + + cn.cunchang + springcloud-debug + 1.0-SNAPSHOT + + + 8 + 8 + Hoxton.SR8 + 2.2.5.RELEASE + + + + + org.springframework.boot + spring-boot-starter + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + + + org.springframework.cloud + spring-cloud-dependencies + ${spring-cloud.version} + pom + import + + + com.alibaba.cloud + spring-cloud-alibaba-dependencies + ${spring-cloud-alibaba.version} + pom + import + + + + + + \ No newline at end of file diff --git a/distributed/springcloud-debug/producer/pom.xml b/distributed/springcloud-debug/producer/pom.xml new file mode 100644 index 00000000..f989a257 --- /dev/null +++ b/distributed/springcloud-debug/producer/pom.xml @@ -0,0 +1,46 @@ + + + + springcloud-debug + cn.cunchang + 1.0-SNAPSHOT + + 4.0.0 + + producer + + + 8 + 8 + + + + + + org.springframework.boot + spring-boot-starter-web + + + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-discovery + + + + org.springframework.cloud + spring-cloud-starter-openfeign + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + \ No newline at end of file diff --git a/distributed/springcloud-debug/producer/src/main/java/cn/cunchang/HelloController.java b/distributed/springcloud-debug/producer/src/main/java/cn/cunchang/HelloController.java new file mode 100644 index 00000000..692d45e4 --- /dev/null +++ b/distributed/springcloud-debug/producer/src/main/java/cn/cunchang/HelloController.java @@ -0,0 +1,13 @@ +package cn.cunchang; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class HelloController { + @GetMapping("/hello") + public String hello(@RequestParam("name") String name) { + return "hello " + name; + } +} \ No newline at end of file diff --git a/distributed/springcloud-debug/producer/src/main/java/cn/cunchang/ProducerApplication.java b/distributed/springcloud-debug/producer/src/main/java/cn/cunchang/ProducerApplication.java new file mode 100644 index 00000000..a2983df4 --- /dev/null +++ b/distributed/springcloud-debug/producer/src/main/java/cn/cunchang/ProducerApplication.java @@ -0,0 +1,15 @@ +package cn.cunchang; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class ProducerApplication { + + public static void main(String[] args) { + SpringApplication.run(ProducerApplication.class, args); + } + +} + + diff --git a/distributed/springcloud-debug/producer/src/main/resources/application.yml b/distributed/springcloud-debug/producer/src/main/resources/application.yml new file mode 100644 index 00000000..2a95114e --- /dev/null +++ b/distributed/springcloud-debug/producer/src/main/resources/application.yml @@ -0,0 +1,20 @@ +server: + port: 8056 + +spring: + application: + name: producer #微服务名称 + + #配置nacos注册中心地址 + cloud: + nacos: + discovery: + server-addr: 127.0.0.1:8848 + + + +management: + endpoints: + web: + exposure: + include: '*' diff --git a/springcloud/api-gateway/pom.xml b/distributed/springcloud-netflix/api-gateway/pom.xml similarity index 100% rename from springcloud/api-gateway/pom.xml rename to distributed/springcloud-netflix/api-gateway/pom.xml diff --git a/springcloud/api-gateway/src/main/java/cn/lastwhisper/apigateway/ApiGatewayApplication.java b/distributed/springcloud-netflix/api-gateway/src/main/java/cn/lastwhisper/apigateway/ApiGatewayApplication.java similarity index 100% rename from springcloud/api-gateway/src/main/java/cn/lastwhisper/apigateway/ApiGatewayApplication.java rename to distributed/springcloud-netflix/api-gateway/src/main/java/cn/lastwhisper/apigateway/ApiGatewayApplication.java diff --git a/springcloud/api-gateway/src/main/java/cn/lastwhisper/apigateway/config/CorsConfig.java b/distributed/springcloud-netflix/api-gateway/src/main/java/cn/lastwhisper/apigateway/config/CorsConfig.java similarity index 100% rename from springcloud/api-gateway/src/main/java/cn/lastwhisper/apigateway/config/CorsConfig.java rename to distributed/springcloud-netflix/api-gateway/src/main/java/cn/lastwhisper/apigateway/config/CorsConfig.java diff --git a/springcloud/api-gateway/src/main/java/cn/lastwhisper/apigateway/config/ZuulConfig.java b/distributed/springcloud-netflix/api-gateway/src/main/java/cn/lastwhisper/apigateway/config/ZuulConfig.java similarity index 100% rename from springcloud/api-gateway/src/main/java/cn/lastwhisper/apigateway/config/ZuulConfig.java rename to distributed/springcloud-netflix/api-gateway/src/main/java/cn/lastwhisper/apigateway/config/ZuulConfig.java diff --git a/springcloud/api-gateway/src/main/java/cn/lastwhisper/apigateway/constant/CookieConstant.java b/distributed/springcloud-netflix/api-gateway/src/main/java/cn/lastwhisper/apigateway/constant/CookieConstant.java similarity index 100% rename from springcloud/api-gateway/src/main/java/cn/lastwhisper/apigateway/constant/CookieConstant.java rename to distributed/springcloud-netflix/api-gateway/src/main/java/cn/lastwhisper/apigateway/constant/CookieConstant.java diff --git a/springcloud/api-gateway/src/main/java/cn/lastwhisper/apigateway/constant/RedisConstant.java b/distributed/springcloud-netflix/api-gateway/src/main/java/cn/lastwhisper/apigateway/constant/RedisConstant.java similarity index 100% rename from springcloud/api-gateway/src/main/java/cn/lastwhisper/apigateway/constant/RedisConstant.java rename to distributed/springcloud-netflix/api-gateway/src/main/java/cn/lastwhisper/apigateway/constant/RedisConstant.java diff --git a/springcloud/api-gateway/src/main/java/cn/lastwhisper/apigateway/exception/RateLimitException.java b/distributed/springcloud-netflix/api-gateway/src/main/java/cn/lastwhisper/apigateway/exception/RateLimitException.java similarity index 100% rename from springcloud/api-gateway/src/main/java/cn/lastwhisper/apigateway/exception/RateLimitException.java rename to distributed/springcloud-netflix/api-gateway/src/main/java/cn/lastwhisper/apigateway/exception/RateLimitException.java diff --git a/springcloud/api-gateway/src/main/java/cn/lastwhisper/apigateway/filter/AuthBuyerFilter.java b/distributed/springcloud-netflix/api-gateway/src/main/java/cn/lastwhisper/apigateway/filter/AuthBuyerFilter.java similarity index 100% rename from springcloud/api-gateway/src/main/java/cn/lastwhisper/apigateway/filter/AuthBuyerFilter.java rename to distributed/springcloud-netflix/api-gateway/src/main/java/cn/lastwhisper/apigateway/filter/AuthBuyerFilter.java diff --git a/springcloud/api-gateway/src/main/java/cn/lastwhisper/apigateway/filter/AuthFilter.java b/distributed/springcloud-netflix/api-gateway/src/main/java/cn/lastwhisper/apigateway/filter/AuthFilter.java similarity index 100% rename from springcloud/api-gateway/src/main/java/cn/lastwhisper/apigateway/filter/AuthFilter.java rename to distributed/springcloud-netflix/api-gateway/src/main/java/cn/lastwhisper/apigateway/filter/AuthFilter.java diff --git a/springcloud/api-gateway/src/main/java/cn/lastwhisper/apigateway/filter/AuthSellerFilter.java b/distributed/springcloud-netflix/api-gateway/src/main/java/cn/lastwhisper/apigateway/filter/AuthSellerFilter.java similarity index 100% rename from springcloud/api-gateway/src/main/java/cn/lastwhisper/apigateway/filter/AuthSellerFilter.java rename to distributed/springcloud-netflix/api-gateway/src/main/java/cn/lastwhisper/apigateway/filter/AuthSellerFilter.java diff --git a/springcloud/api-gateway/src/main/java/cn/lastwhisper/apigateway/filter/PostResponseHeaderFilter.java b/distributed/springcloud-netflix/api-gateway/src/main/java/cn/lastwhisper/apigateway/filter/PostResponseHeaderFilter.java similarity index 100% rename from springcloud/api-gateway/src/main/java/cn/lastwhisper/apigateway/filter/PostResponseHeaderFilter.java rename to distributed/springcloud-netflix/api-gateway/src/main/java/cn/lastwhisper/apigateway/filter/PostResponseHeaderFilter.java diff --git a/springcloud/api-gateway/src/main/java/cn/lastwhisper/apigateway/filter/PreTokenFilter.java b/distributed/springcloud-netflix/api-gateway/src/main/java/cn/lastwhisper/apigateway/filter/PreTokenFilter.java similarity index 100% rename from springcloud/api-gateway/src/main/java/cn/lastwhisper/apigateway/filter/PreTokenFilter.java rename to distributed/springcloud-netflix/api-gateway/src/main/java/cn/lastwhisper/apigateway/filter/PreTokenFilter.java diff --git a/springcloud/api-gateway/src/main/java/cn/lastwhisper/apigateway/filter/RateLimiterFilter.java b/distributed/springcloud-netflix/api-gateway/src/main/java/cn/lastwhisper/apigateway/filter/RateLimiterFilter.java similarity index 100% rename from springcloud/api-gateway/src/main/java/cn/lastwhisper/apigateway/filter/RateLimiterFilter.java rename to distributed/springcloud-netflix/api-gateway/src/main/java/cn/lastwhisper/apigateway/filter/RateLimiterFilter.java diff --git a/springcloud/api-gateway/src/main/java/cn/lastwhisper/apigateway/utils/CookieUtil.java b/distributed/springcloud-netflix/api-gateway/src/main/java/cn/lastwhisper/apigateway/utils/CookieUtil.java similarity index 100% rename from springcloud/api-gateway/src/main/java/cn/lastwhisper/apigateway/utils/CookieUtil.java rename to distributed/springcloud-netflix/api-gateway/src/main/java/cn/lastwhisper/apigateway/utils/CookieUtil.java diff --git a/distributed/springcloud-netflix/api-gateway/src/main/resources/bootstrap.yml b/distributed/springcloud-netflix/api-gateway/src/main/resources/bootstrap.yml new file mode 100644 index 00000000..2b66546b --- /dev/null +++ b/distributed/springcloud-netflix/api-gateway/src/main/resources/bootstrap.yml @@ -0,0 +1,34 @@ +spring: + application: + name: api-gateway + cloud: + config: + discovery: + enabled: true + service-id: CONFIG + profile: dev +eureka: + client: + service-url: + defaultZone: http://localhost:8761/eureka/ +server: + port: 8083 +#1.修改路由映射名(有简洁写法) +#2.忽略某些路由 +zuul: + #全部服务忽略敏感头(全部服务都可以传递cookie) + sensitive-headers: + routes: + # /myProduct/product/list -> /product/product/list + product: #这个名字随便写,写aaaaa也没事 + path: /shop-api/product/** +# serviceId: product + sensitiveHeaders: #敏感头 + #简洁写法 +# product: /myProduct/** + #排除某些路由 + order: + path: /shop-api/order/** + sensitiveHeaders: #敏感头 + ignored-patterns: + - /**/product/listForOrder \ No newline at end of file diff --git a/springcloud/api-gateway/src/test/java/cn/lastwhisper/apigateway/ApiGatewayApplicationTests.java b/distributed/springcloud-netflix/api-gateway/src/test/java/cn/lastwhisper/apigateway/ApiGatewayApplicationTests.java similarity index 100% rename from springcloud/api-gateway/src/test/java/cn/lastwhisper/apigateway/ApiGatewayApplicationTests.java rename to distributed/springcloud-netflix/api-gateway/src/test/java/cn/lastwhisper/apigateway/ApiGatewayApplicationTests.java diff --git a/springcloud/client/pom.xml b/distributed/springcloud-netflix/client/pom.xml similarity index 100% rename from springcloud/client/pom.xml rename to distributed/springcloud-netflix/client/pom.xml diff --git a/springcloud/client/src/main/java/cn/lastwhisper/client/ClientApplication.java b/distributed/springcloud-netflix/client/src/main/java/cn/lastwhisper/client/ClientApplication.java similarity index 100% rename from springcloud/client/src/main/java/cn/lastwhisper/client/ClientApplication.java rename to distributed/springcloud-netflix/client/src/main/java/cn/lastwhisper/client/ClientApplication.java diff --git a/springcloud/client/src/main/resources/application.yml b/distributed/springcloud-netflix/client/src/main/resources/application.yml similarity index 100% rename from springcloud/client/src/main/resources/application.yml rename to distributed/springcloud-netflix/client/src/main/resources/application.yml diff --git a/springcloud/client/src/test/java/cn/lastwhisper/client/ClientApplicationTests.java b/distributed/springcloud-netflix/client/src/test/java/cn/lastwhisper/client/ClientApplicationTests.java similarity index 100% rename from springcloud/client/src/test/java/cn/lastwhisper/client/ClientApplicationTests.java rename to distributed/springcloud-netflix/client/src/test/java/cn/lastwhisper/client/ClientApplicationTests.java diff --git a/distributed/springcloud-netflix/config/Dockerfile b/distributed/springcloud-netflix/config/Dockerfile new file mode 100644 index 00000000..5277a36d --- /dev/null +++ b/distributed/springcloud-netflix/config/Dockerfile @@ -0,0 +1,10 @@ +FROM hub.c.163.com/library/java:8-alpine + +MAINTAINER 15037584397@163.com + +ADD target/*.jar app.jar + +EXPOSE 8080 + +ENTRYPOINT ["java","-jar","/app.jar"] + diff --git a/springcloud/config/pom.xml b/distributed/springcloud-netflix/config/pom.xml similarity index 100% rename from springcloud/config/pom.xml rename to distributed/springcloud-netflix/config/pom.xml diff --git a/springcloud/config/src/main/java/cn/lastwhisper/config/ConfigApplication.java b/distributed/springcloud-netflix/config/src/main/java/cn/lastwhisper/config/ConfigApplication.java similarity index 100% rename from springcloud/config/src/main/java/cn/lastwhisper/config/ConfigApplication.java rename to distributed/springcloud-netflix/config/src/main/java/cn/lastwhisper/config/ConfigApplication.java diff --git a/distributed/springcloud-netflix/config/src/main/resources/application.yml b/distributed/springcloud-netflix/config/src/main/resources/application.yml new file mode 100644 index 00000000..804fdd12 --- /dev/null +++ b/distributed/springcloud-netflix/config/src/main/resources/application.yml @@ -0,0 +1,22 @@ +spring: + application: + name: config + cloud: + config: + server: + git: + uri: https://gitee.com/ggb2312/config-repo + username: gjgb2312@gmail.com + password: 15037584397.gg + basedir: C:\Users\Administrator\tmp\gitconfig +eureka: + client: + service-url: + defaultZone: http://localhost:8761/eureka/ +server: + port: 8082 +management: + endpoints: + web: + exposure: + include: "*" \ No newline at end of file diff --git a/springcloud/config/src/test/java/cn/lastwhisper/config/ConfigApplicationTests.java b/distributed/springcloud-netflix/config/src/test/java/cn/lastwhisper/config/ConfigApplicationTests.java similarity index 100% rename from springcloud/config/src/test/java/cn/lastwhisper/config/ConfigApplicationTests.java rename to distributed/springcloud-netflix/config/src/test/java/cn/lastwhisper/config/ConfigApplicationTests.java diff --git a/distributed/springcloud-netflix/doc/API.md b/distributed/springcloud-netflix/doc/API.md new file mode 100644 index 00000000..03a3f17c --- /dev/null +++ b/distributed/springcloud-netflix/doc/API.md @@ -0,0 +1,133 @@ +# API + +### 商品列表 + +``` +GET /product/list +``` + +参数 + +``` +无 +``` + +返回 + +``` +{ + "code": 0, + "msg": "成功", + "data": [ + { + "name": "热榜", + "type": 1, + "foods": [ + { + "id": "123456", + "name": "皮蛋粥", + "price": 1.2, + "description": "好吃的皮蛋粥", + "icon": "http://xxx.com", + } + ] + }, + { + "name": "好吃的", + "type": 2, + "foods": [ + { + "id": "123457", + "name": "慕斯蛋糕", + "price": 10.9, + "description": "美味爽口", + "icon": "http://xxx.com", + } + ] + } + ] +} +``` + + +### 创建订单 + +``` +POST /order/create +``` + +参数 + +``` +name: "张三" +phone: "18868822111" +address: "慕课网总部" +openid: "ew3euwhd7sjw9diwkq" //用户的微信openid +items: [{ + productId: "157875196366160022", + productQuantity: 2 //购买数量 +}] + +``` + +返回 + +``` +{ + "code": 0, + "msg": "成功", + "data": { + "orderId": "147283992738221" + } +} + +``` + + +### 买家登录 + +``` +GET /login/buyer +``` + +参数 + +``` +openid: abc +``` + +返回 + +`cookie里设置openid=abc` + +``` +{ + code: 0, + msg: "成功", + data: null +} +``` + +### 卖家登录 + +``` +GET /login/seller +``` + +参数 + +``` +openid: xyz +``` + +返回 + +`cookie里设置token=UUID, redis设置key=UUID, value=xyz` + +``` +{ + code: 0, + msg: "成功", + data: null +} +``` \ No newline at end of file diff --git a/distributed/springcloud-netflix/doc/README.md b/distributed/springcloud-netflix/doc/README.md new file mode 100644 index 00000000..0d4fb3b3 --- /dev/null +++ b/distributed/springcloud-netflix/doc/README.md @@ -0,0 +1,23 @@ +# 一、项目端口划分 +eureka 分布式注册中心模块 8761 +config 分布式配置中心模块 8082 +api-gateway zuul网关模块 8083 +order 订单业务模块 8081 +product 产品业务模块 8085 +user 用户业务 模块 8084 +client 测试注册中心模块(暂时无用) +# 二、集成sleuth和zipkin步骤 +1.添加依赖 +2.添加yml + +## 测试zipkin +1、启动eureka、config、order、product +2、url:http://localhost:8081/order/create +body: +```shell script +name:张三 +phone:18868822111 +address:北京西二旗 +openid:ew3euwhd7sjw9diwkq +items:[{productId:"157875196366160022",productQuantity:2}] +``` diff --git a/springcloud/springcloud.sql b/distributed/springcloud-netflix/doc/springcloud.sql similarity index 100% rename from springcloud/springcloud.sql rename to distributed/springcloud-netflix/doc/springcloud.sql diff --git "a/distributed/springcloud-netflix/doc/\346\200\235\350\200\203\344\270\216\346\224\266\350\216\267.txt" "b/distributed/springcloud-netflix/doc/\346\200\235\350\200\203\344\270\216\346\224\266\350\216\267.txt" new file mode 100644 index 00000000..a9fd358d --- /dev/null +++ "b/distributed/springcloud-netflix/doc/\346\200\235\350\200\203\344\270\216\346\224\266\350\216\267.txt" @@ -0,0 +1,23 @@ +1、为什么需要DTO(Data Transfer Object),以OrderDTO为例。 +由于接口的入参涉及到OrderDetail、OrderMaster,而OrderMaster与OrderDetail可能有一对多的关系, +所以需要一个DTO封装OrderDetail与OrderMaster的数据,作为Controller与Service的中转。 +2、为什么需要VO? +(1)实体类与页面需要的数据很大程度不一致,需要封装VO数据进行返回 +(2)安全性 +3、为什么需要form? +接收接口入参,from转dto做不同级别的参数校验。 +参数校验级别分为: + (1)from入参json串不为空 + (2)from转dto时OrderDTO +4、为什么需要enum? +将一些表中的状态,比如订单(支付、未支付、等待支付)状态进行枚举表示,统一管理 + +https://www.cnblogs.com/qixuejia/p/4390086.html + + +一、项目:领域模型、vo、dto、po、domain、form、enums、utils +二、spring测试:继承 +三、日志:log4j、sfl4j、logback等日志区别,以及作用 +四、valid、json转换的使用 +五、常量,枚举的使用场景 +六、异常怎么用,怎么处理 diff --git a/distributed/springcloud-netflix/eureka/Dockerfile b/distributed/springcloud-netflix/eureka/Dockerfile new file mode 100644 index 00000000..e95e2f2f --- /dev/null +++ b/distributed/springcloud-netflix/eureka/Dockerfile @@ -0,0 +1,10 @@ +FROM hub.c.163.com/library/java:8-alpine + +MAINTAINER 15037584397@163.com + +ADD target/*.jar app.jar + +EXPOSE 8761 + +ENTRYPOINT ["java","-jar","/app.jar"] + diff --git a/springcloud/eureka/pom.xml b/distributed/springcloud-netflix/eureka/pom.xml similarity index 100% rename from springcloud/eureka/pom.xml rename to distributed/springcloud-netflix/eureka/pom.xml diff --git a/springcloud/eureka/src/main/java/cn/lastwhisper/eureka/EurekaApplication.java b/distributed/springcloud-netflix/eureka/src/main/java/cn/lastwhisper/eureka/EurekaApplication.java similarity index 100% rename from springcloud/eureka/src/main/java/cn/lastwhisper/eureka/EurekaApplication.java rename to distributed/springcloud-netflix/eureka/src/main/java/cn/lastwhisper/eureka/EurekaApplication.java diff --git a/springcloud/eureka/src/main/resources/application.yml b/distributed/springcloud-netflix/eureka/src/main/resources/application.yml similarity index 100% rename from springcloud/eureka/src/main/resources/application.yml rename to distributed/springcloud-netflix/eureka/src/main/resources/application.yml diff --git a/springcloud/eureka/src/test/java/cn/lastwhisper/eureka/EurekaApplicationTests.java b/distributed/springcloud-netflix/eureka/src/test/java/cn/lastwhisper/eureka/EurekaApplicationTests.java similarity index 100% rename from springcloud/eureka/src/test/java/cn/lastwhisper/eureka/EurekaApplicationTests.java rename to distributed/springcloud-netflix/eureka/src/test/java/cn/lastwhisper/eureka/EurekaApplicationTests.java diff --git a/springcloud/order-old/pom.xml b/distributed/springcloud-netflix/order-old/pom.xml similarity index 100% rename from springcloud/order-old/pom.xml rename to distributed/springcloud-netflix/order-old/pom.xml diff --git a/springcloud/order-old/src/main/java/cn/lastwhisper/order/OrderApplication.java b/distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/OrderApplication.java similarity index 100% rename from springcloud/order-old/src/main/java/cn/lastwhisper/order/OrderApplication.java rename to distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/OrderApplication.java diff --git a/springcloud/order-old/src/main/java/cn/lastwhisper/order/client/ProductClient.java b/distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/client/ProductClient.java similarity index 100% rename from springcloud/order-old/src/main/java/cn/lastwhisper/order/client/ProductClient.java rename to distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/client/ProductClient.java diff --git a/springcloud/order-old/src/main/java/cn/lastwhisper/order/conf/RestTemplateConfig.java b/distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/conf/RestTemplateConfig.java similarity index 100% rename from springcloud/order-old/src/main/java/cn/lastwhisper/order/conf/RestTemplateConfig.java rename to distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/conf/RestTemplateConfig.java diff --git a/springcloud/order-old/src/main/java/cn/lastwhisper/order/controller/FeignClientController.java b/distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/controller/FeignClientController.java similarity index 100% rename from springcloud/order-old/src/main/java/cn/lastwhisper/order/controller/FeignClientController.java rename to distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/controller/FeignClientController.java diff --git a/springcloud/order-old/src/main/java/cn/lastwhisper/order/controller/OrderController.java b/distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/controller/OrderController.java similarity index 100% rename from springcloud/order-old/src/main/java/cn/lastwhisper/order/controller/OrderController.java rename to distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/controller/OrderController.java diff --git a/springcloud/order-old/src/main/java/cn/lastwhisper/order/controller/RestTemplateClientController.java b/distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/controller/RestTemplateClientController.java similarity index 100% rename from springcloud/order-old/src/main/java/cn/lastwhisper/order/controller/RestTemplateClientController.java rename to distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/controller/RestTemplateClientController.java diff --git a/springcloud/order-old/src/main/java/cn/lastwhisper/order/convert/OrderForm2OrderDTOConvert.java b/distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/convert/OrderForm2OrderDTOConvert.java similarity index 100% rename from springcloud/order-old/src/main/java/cn/lastwhisper/order/convert/OrderForm2OrderDTOConvert.java rename to distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/convert/OrderForm2OrderDTOConvert.java diff --git a/springcloud/order-old/src/main/java/cn/lastwhisper/order/domain/OrderDetail.java b/distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/domain/OrderDetail.java similarity index 100% rename from springcloud/order-old/src/main/java/cn/lastwhisper/order/domain/OrderDetail.java rename to distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/domain/OrderDetail.java diff --git a/springcloud/order-old/src/main/java/cn/lastwhisper/order/domain/OrderMaster.java b/distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/domain/OrderMaster.java similarity index 100% rename from springcloud/order-old/src/main/java/cn/lastwhisper/order/domain/OrderMaster.java rename to distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/domain/OrderMaster.java diff --git a/springcloud/order-old/src/main/java/cn/lastwhisper/order/domain/ProductInfo.java b/distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/domain/ProductInfo.java similarity index 100% rename from springcloud/order-old/src/main/java/cn/lastwhisper/order/domain/ProductInfo.java rename to distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/domain/ProductInfo.java diff --git a/springcloud/order-old/src/main/java/cn/lastwhisper/order/dto/CartDTO.java b/distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/dto/CartDTO.java similarity index 100% rename from springcloud/order-old/src/main/java/cn/lastwhisper/order/dto/CartDTO.java rename to distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/dto/CartDTO.java diff --git a/springcloud/order-old/src/main/java/cn/lastwhisper/order/dto/OrderDTO.java b/distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/dto/OrderDTO.java similarity index 100% rename from springcloud/order-old/src/main/java/cn/lastwhisper/order/dto/OrderDTO.java rename to distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/dto/OrderDTO.java diff --git a/springcloud/order-old/src/main/java/cn/lastwhisper/order/enums/OrderStatusEnum.java b/distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/enums/OrderStatusEnum.java similarity index 100% rename from springcloud/order-old/src/main/java/cn/lastwhisper/order/enums/OrderStatusEnum.java rename to distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/enums/OrderStatusEnum.java diff --git a/springcloud/order-old/src/main/java/cn/lastwhisper/order/enums/PayStatusEnum.java b/distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/enums/PayStatusEnum.java similarity index 100% rename from springcloud/order-old/src/main/java/cn/lastwhisper/order/enums/PayStatusEnum.java rename to distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/enums/PayStatusEnum.java diff --git a/springcloud/order-old/src/main/java/cn/lastwhisper/order/enums/ResultEnum.java b/distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/enums/ResultEnum.java similarity index 100% rename from springcloud/order-old/src/main/java/cn/lastwhisper/order/enums/ResultEnum.java rename to distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/enums/ResultEnum.java diff --git a/springcloud/order-old/src/main/java/cn/lastwhisper/order/exception/OrderException.java b/distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/exception/OrderException.java similarity index 100% rename from springcloud/order-old/src/main/java/cn/lastwhisper/order/exception/OrderException.java rename to distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/exception/OrderException.java diff --git a/springcloud/order-old/src/main/java/cn/lastwhisper/order/form/OrderForm.java b/distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/form/OrderForm.java similarity index 100% rename from springcloud/order-old/src/main/java/cn/lastwhisper/order/form/OrderForm.java rename to distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/form/OrderForm.java diff --git a/springcloud/order-old/src/main/java/cn/lastwhisper/order/repository/OrderDetailRepository.java b/distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/repository/OrderDetailRepository.java similarity index 100% rename from springcloud/order-old/src/main/java/cn/lastwhisper/order/repository/OrderDetailRepository.java rename to distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/repository/OrderDetailRepository.java diff --git a/springcloud/order-old/src/main/java/cn/lastwhisper/order/repository/OrderMasterRepository.java b/distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/repository/OrderMasterRepository.java similarity index 100% rename from springcloud/order-old/src/main/java/cn/lastwhisper/order/repository/OrderMasterRepository.java rename to distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/repository/OrderMasterRepository.java diff --git a/springcloud/order-old/src/main/java/cn/lastwhisper/order/service/OrderService.java b/distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/service/OrderService.java similarity index 100% rename from springcloud/order-old/src/main/java/cn/lastwhisper/order/service/OrderService.java rename to distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/service/OrderService.java diff --git a/springcloud/order-old/src/main/java/cn/lastwhisper/order/service/impl/OrderServiceImpl.java b/distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/service/impl/OrderServiceImpl.java similarity index 100% rename from springcloud/order-old/src/main/java/cn/lastwhisper/order/service/impl/OrderServiceImpl.java rename to distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/service/impl/OrderServiceImpl.java diff --git a/springcloud/order-old/src/main/java/cn/lastwhisper/order/utils/KeyUtil.java b/distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/utils/KeyUtil.java similarity index 100% rename from springcloud/order-old/src/main/java/cn/lastwhisper/order/utils/KeyUtil.java rename to distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/utils/KeyUtil.java diff --git a/springcloud/order-old/src/main/java/cn/lastwhisper/order/utils/ResultVOUtil.java b/distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/utils/ResultVOUtil.java similarity index 100% rename from springcloud/order-old/src/main/java/cn/lastwhisper/order/utils/ResultVOUtil.java rename to distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/utils/ResultVOUtil.java diff --git a/springcloud/order-old/src/main/java/cn/lastwhisper/order/vo/ResultVO.java b/distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/vo/ResultVO.java similarity index 100% rename from springcloud/order-old/src/main/java/cn/lastwhisper/order/vo/ResultVO.java rename to distributed/springcloud-netflix/order-old/src/main/java/cn/lastwhisper/order/vo/ResultVO.java diff --git a/springcloud/order-old/src/main/resources/application.yml b/distributed/springcloud-netflix/order-old/src/main/resources/application.yml similarity index 100% rename from springcloud/order-old/src/main/resources/application.yml rename to distributed/springcloud-netflix/order-old/src/main/resources/application.yml diff --git a/springcloud/order-old/src/test/java/cn/lastwhisper/order/OrderApplicationTests.java b/distributed/springcloud-netflix/order-old/src/test/java/cn/lastwhisper/order/OrderApplicationTests.java similarity index 100% rename from springcloud/order-old/src/test/java/cn/lastwhisper/order/OrderApplicationTests.java rename to distributed/springcloud-netflix/order-old/src/test/java/cn/lastwhisper/order/OrderApplicationTests.java diff --git a/springcloud/order-old/src/test/java/cn/lastwhisper/order/repository/OrderDetailRepositoryTest.java b/distributed/springcloud-netflix/order-old/src/test/java/cn/lastwhisper/order/repository/OrderDetailRepositoryTest.java similarity index 100% rename from springcloud/order-old/src/test/java/cn/lastwhisper/order/repository/OrderDetailRepositoryTest.java rename to distributed/springcloud-netflix/order-old/src/test/java/cn/lastwhisper/order/repository/OrderDetailRepositoryTest.java diff --git a/springcloud/order-old/src/test/java/cn/lastwhisper/order/repository/OrderMasterRepositoryTest.java b/distributed/springcloud-netflix/order-old/src/test/java/cn/lastwhisper/order/repository/OrderMasterRepositoryTest.java similarity index 100% rename from springcloud/order-old/src/test/java/cn/lastwhisper/order/repository/OrderMasterRepositoryTest.java rename to distributed/springcloud-netflix/order-old/src/test/java/cn/lastwhisper/order/repository/OrderMasterRepositoryTest.java diff --git a/springcloud/order/order-client/pom.xml b/distributed/springcloud-netflix/order/order-client/pom.xml similarity index 100% rename from springcloud/order/order-client/pom.xml rename to distributed/springcloud-netflix/order/order-client/pom.xml diff --git a/distributed/springcloud-netflix/order/order-client/src/main/java/cn/lastwhisper/order/client/OrderClient.java b/distributed/springcloud-netflix/order/order-client/src/main/java/cn/lastwhisper/order/client/OrderClient.java new file mode 100644 index 00000000..a02e0351 --- /dev/null +++ b/distributed/springcloud-netflix/order/order-client/src/main/java/cn/lastwhisper/order/client/OrderClient.java @@ -0,0 +1,20 @@ +package cn.lastwhisper.order.client; + +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.PostMapping; + +/** + * + * @author lastwhisper + * @date 2019/10/28 + */ +@FeignClient("order") +public interface OrderClient { + + /** + * 一个睡3s的方法 + */ + @PostMapping("/order/orderThread3") + void orderThread3(); + +} diff --git a/springcloud/order/order-common/pom.xml b/distributed/springcloud-netflix/order/order-common/pom.xml similarity index 100% rename from springcloud/order/order-common/pom.xml rename to distributed/springcloud-netflix/order/order-common/pom.xml diff --git a/distributed/springcloud-netflix/order/order-server/pom.xml b/distributed/springcloud-netflix/order/order-server/pom.xml new file mode 100644 index 00000000..a2f160ea --- /dev/null +++ b/distributed/springcloud-netflix/order/order-server/pom.xml @@ -0,0 +1,126 @@ + + + + order + cn.lastwhisper + 0.0.1-SNAPSHOT + + 4.0.0 + + order-server + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.cloud + spring-cloud-starter-netflix-eureka-client + + + + org.springframework.cloud + spring-cloud-starter-openfeign + + + + org.springframework.cloud + spring-cloud-config-client + + + + org.springframework.boot + spring-boot-starter-amqp + + + + org.springframework.cloud + spring-cloud-starter-stream-rabbit + + + + org.springframework.boot + spring-boot-starter-data-redis + + + + org.springframework.cloud + spring-cloud-starter-netflix-hystrix + + + + + org.springframework.cloud + spring-cloud-starter-netflix-hystrix-dashboard + + + + org.springframework.boot + spring-boot-starter-actuator + + + + + org.springframework.cloud + spring-cloud-starter-zipkin + + + + mysql + mysql-connector-java + runtime + + + + org.projectlombok + lombok + true + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.junit.vintage + junit-vintage-engine + + + + + + com.google.code.gson + gson + 2.8.6 + + + + cn.lastwhisper + product-client + + + + cn.lastwhisper + product-common + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + \ No newline at end of file diff --git a/springcloud/order/order-server/src/main/java/cn/lastwhisper/order/OrderApplication.java b/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/OrderApplication.java similarity index 100% rename from springcloud/order/order-server/src/main/java/cn/lastwhisper/order/OrderApplication.java rename to distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/OrderApplication.java diff --git a/springcloud/order/order-server/src/main/java/cn/lastwhisper/order/conf/RestTemplateConfig.java b/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/conf/RestTemplateConfig.java similarity index 100% rename from springcloud/order/order-server/src/main/java/cn/lastwhisper/order/conf/RestTemplateConfig.java rename to distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/conf/RestTemplateConfig.java diff --git a/springcloud/order/order-server/src/main/java/cn/lastwhisper/order/controller/EnvController.java b/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/controller/EnvController.java similarity index 100% rename from springcloud/order/order-server/src/main/java/cn/lastwhisper/order/controller/EnvController.java rename to distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/controller/EnvController.java diff --git a/springcloud/order/order-server/src/main/java/cn/lastwhisper/order/controller/FeignClientController.java b/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/controller/FeignClientController.java similarity index 88% rename from springcloud/order/order-server/src/main/java/cn/lastwhisper/order/controller/FeignClientController.java rename to distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/controller/FeignClientController.java index b5cf254f..8eb3daf5 100644 --- a/springcloud/order/order-server/src/main/java/cn/lastwhisper/order/controller/FeignClientController.java +++ b/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/controller/FeignClientController.java @@ -6,6 +6,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RestController; import java.util.Arrays; @@ -46,4 +47,11 @@ public String decreaseStock() { return "ok"; } + @GetMapping("/orderTest") + public String orderTest() { + productClient.productThread3(); + return "success"; + } + + } diff --git a/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/controller/HystrixController.java b/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/controller/HystrixController.java new file mode 100644 index 00000000..9e0cf5ec --- /dev/null +++ b/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/controller/HystrixController.java @@ -0,0 +1,75 @@ +package cn.lastwhisper.order.controller; + +import com.netflix.hystrix.contrib.javanica.annotation.DefaultProperties; +import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; +import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.client.RestTemplate; + +import java.util.Collections; + +/** + * Hystrix学习 + * @author lastwhisper + * @date 2019/11/3 + */ +@RestController +@DefaultProperties(defaultFallback = "defaultFallback") +@RequestMapping("/order") +public class HystrixController { + + + //@HystrixCommand( + // fallbackMethod = "fallback", + // commandProperties = { + // @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1000"),//超时降级 + // @HystrixProperty(name = "circuitBreaker.enabled", value = "true"),//同意使用断路器来熔断请求 + // //timeInMilliseconds/numBuckets内,最小请求数 + // @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"), + // //断路器打开后的休眠时间窗口,休眠结束后,断路器进入"半打开"状态 + // @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "10000"), + // //断路器打开的错误比条件(在timeInMilliseconds内,请求超过requestVolumeThreshold前提下,错误比超60,开启断路器) + // @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "60") + // }, + // threadPoolProperties = { + // // 线程池参数 + // @HystrixProperty(name = "coreSize", value = "20"), + // @HystrixProperty(name = "maxQueueSize", value = "10"), + // @HystrixProperty(name = "keepAliveTimeMinutes", value = "1000"), + // @HystrixProperty(name = "queueSizeRejectionThreshold", value = "8"), + // //滚动时间窗口长度,被分成多个numBuckets,该参数需要被numBuckets整除 + // @HystrixProperty(name = "metrics.rollingStats.timeInMilliseconds", value = "1500"), + // @HystrixProperty(name = "metrics.rollingStats.numBuckets", value = "12") + // }) + + @GetMapping("/getProductInfoList") + //@HystrixCommand(fallbackMethod = "fallback") + //@HystrixCommand(commandProperties = { + // @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000") + //}) + @HystrixCommand(commandProperties = { + @HystrixProperty(name = "circuitBreaker.enabled", value = "true"), + @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"), + @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "10000"), + @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "60") + }) + //@HystrixCommand + public String getProductInfoList(@RequestParam("number") Integer number) { + if (number % 2 == 0) { + return "success"; + } + RestTemplate restTemplate = new RestTemplate(); + return restTemplate.postForObject("http://localhost:8080/product/listForOrder", Collections.singletonList("157875227953464068"), String.class); + } + + public String fallback() { + return "服务降级方法"; + } + + public String defaultFallback() { + return "默认服务降级方法"; + } +} diff --git a/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/controller/OrderController.java b/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/controller/OrderController.java new file mode 100644 index 00000000..472d2cc4 --- /dev/null +++ b/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/controller/OrderController.java @@ -0,0 +1,90 @@ +package cn.lastwhisper.order.controller; + +import cn.lastwhisper.order.convert.OrderForm2OrderDTOConvert; +import cn.lastwhisper.order.dto.OrderDTO; +import cn.lastwhisper.order.enums.ResultEnum; +import cn.lastwhisper.order.exception.OrderException; +import cn.lastwhisper.order.form.OrderForm; +import cn.lastwhisper.order.service.OrderService; +import cn.lastwhisper.order.utils.ResultVOUtil; +import cn.lastwhisper.order.vo.ResultVO; +import cn.lastwhisper.product.client.ProductClient; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.util.CollectionUtils; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import javax.validation.Valid; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +/** + * 订单 + * @author lastwhisper + * @date 2019/10/26 + */ +@RestController +@RequestMapping("/order") +@Slf4j +public class OrderController { + + @Autowired + private ProductClient productClient; + + @Autowired + private OrderService orderService; + + /** + * 保存主订单以及订单详情 + * 1.参数校验() + * 2.查询商品信息(调用商品服务) + * 3.计算总价 + * 4.扣库存(调用商品服务) + * 5.订单入库 + */ + @PostMapping("/create") + public ResultVO> create(@Valid OrderForm orderForm, + BindingResult bindingResult) { + // 1.参数校验 + if (bindingResult.hasErrors()) { + log.error("[创建订单]参数不正确, orderForm={}", orderForm); + throw new OrderException(ResultEnum.PARAM_ERROR.getCode(), + Objects.requireNonNull(bindingResult.getFieldError()).getDefaultMessage()); + } + OrderDTO orderDTO = OrderForm2OrderDTOConvert.convert(orderForm); + if (CollectionUtils.isEmpty(orderDTO.getOrderDetailList())) { + log.error("[创建订单]购物车商品信息为空"); + throw new OrderException(ResultEnum.CART_EMPTY); + } + + // 2.创建订单 + OrderDTO order = orderService.create(orderDTO); + + Map map = new HashMap<>(); + map.put("orderId", order.getOrderId()); + + return ResultVOUtil.success(map); + + } + + @PostMapping("/finish") + public ResultVO finish(@RequestParam("orderId") String orderId) { + return ResultVOUtil.success(orderService.finish(orderId)); + } + + + @PostMapping("/orderThread3") + public void orderThread3() { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + +} diff --git a/springcloud/order/order-server/src/main/java/cn/lastwhisper/order/controller/RestTemplateClientController.java b/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/controller/RestTemplateClientController.java similarity index 100% rename from springcloud/order/order-server/src/main/java/cn/lastwhisper/order/controller/RestTemplateClientController.java rename to distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/controller/RestTemplateClientController.java diff --git a/springcloud/order/order-server/src/main/java/cn/lastwhisper/order/controller/SendMessageController.java b/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/controller/SendMessageController.java similarity index 100% rename from springcloud/order/order-server/src/main/java/cn/lastwhisper/order/controller/SendMessageController.java rename to distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/controller/SendMessageController.java diff --git a/springcloud/order/order-server/src/main/java/cn/lastwhisper/order/convert/OrderForm2OrderDTOConvert.java b/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/convert/OrderForm2OrderDTOConvert.java similarity index 100% rename from springcloud/order/order-server/src/main/java/cn/lastwhisper/order/convert/OrderForm2OrderDTOConvert.java rename to distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/convert/OrderForm2OrderDTOConvert.java diff --git a/springcloud/order/order-server/src/main/java/cn/lastwhisper/order/domain/OrderDetail.java b/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/domain/OrderDetail.java similarity index 100% rename from springcloud/order/order-server/src/main/java/cn/lastwhisper/order/domain/OrderDetail.java rename to distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/domain/OrderDetail.java diff --git a/springcloud/order/order-server/src/main/java/cn/lastwhisper/order/domain/OrderMaster.java b/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/domain/OrderMaster.java similarity index 100% rename from springcloud/order/order-server/src/main/java/cn/lastwhisper/order/domain/OrderMaster.java rename to distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/domain/OrderMaster.java diff --git a/springcloud/order/order-server/src/main/java/cn/lastwhisper/order/domain/ProductInfo.java b/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/domain/ProductInfo.java similarity index 100% rename from springcloud/order/order-server/src/main/java/cn/lastwhisper/order/domain/ProductInfo.java rename to distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/domain/ProductInfo.java diff --git a/springcloud/order/order-server/src/main/java/cn/lastwhisper/order/dto/CartDTO.java b/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/dto/CartDTO.java similarity index 100% rename from springcloud/order/order-server/src/main/java/cn/lastwhisper/order/dto/CartDTO.java rename to distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/dto/CartDTO.java diff --git a/springcloud/order/order-server/src/main/java/cn/lastwhisper/order/dto/OrderDTO.java b/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/dto/OrderDTO.java similarity index 100% rename from springcloud/order/order-server/src/main/java/cn/lastwhisper/order/dto/OrderDTO.java rename to distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/dto/OrderDTO.java diff --git a/springcloud/order/order-server/src/main/java/cn/lastwhisper/order/enums/OrderStatusEnum.java b/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/enums/OrderStatusEnum.java similarity index 100% rename from springcloud/order/order-server/src/main/java/cn/lastwhisper/order/enums/OrderStatusEnum.java rename to distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/enums/OrderStatusEnum.java diff --git a/springcloud/order/order-server/src/main/java/cn/lastwhisper/order/enums/PayStatusEnum.java b/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/enums/PayStatusEnum.java similarity index 100% rename from springcloud/order/order-server/src/main/java/cn/lastwhisper/order/enums/PayStatusEnum.java rename to distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/enums/PayStatusEnum.java diff --git a/springcloud/order/order-server/src/main/java/cn/lastwhisper/order/enums/ResultEnum.java b/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/enums/ResultEnum.java similarity index 100% rename from springcloud/order/order-server/src/main/java/cn/lastwhisper/order/enums/ResultEnum.java rename to distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/enums/ResultEnum.java diff --git a/springcloud/order/order-server/src/main/java/cn/lastwhisper/order/exception/OrderException.java b/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/exception/OrderException.java similarity index 100% rename from springcloud/order/order-server/src/main/java/cn/lastwhisper/order/exception/OrderException.java rename to distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/exception/OrderException.java diff --git a/springcloud/order/order-server/src/main/java/cn/lastwhisper/order/form/OrderForm.java b/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/form/OrderForm.java similarity index 100% rename from springcloud/order/order-server/src/main/java/cn/lastwhisper/order/form/OrderForm.java rename to distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/form/OrderForm.java diff --git a/springcloud/order/order-server/src/main/java/cn/lastwhisper/order/message/AmqpReceiver.java b/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/message/AmqpReceiver.java similarity index 100% rename from springcloud/order/order-server/src/main/java/cn/lastwhisper/order/message/AmqpReceiver.java rename to distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/message/AmqpReceiver.java diff --git a/springcloud/order/order-server/src/main/java/cn/lastwhisper/order/message/ProductInfoReceiver.java b/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/message/ProductInfoReceiver.java similarity index 96% rename from springcloud/order/order-server/src/main/java/cn/lastwhisper/order/message/ProductInfoReceiver.java rename to distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/message/ProductInfoReceiver.java index 7098104e..346243de 100644 --- a/springcloud/order/order-server/src/main/java/cn/lastwhisper/order/message/ProductInfoReceiver.java +++ b/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/message/ProductInfoReceiver.java @@ -17,7 +17,7 @@ * @author lastwhisper * @date 2019/10/31 */ -@Component +//@Component @Slf4j public class ProductInfoReceiver { @@ -34,6 +34,7 @@ public void process(String message) { log.info("从队列【{}】接收到消息:{}", "productInfo", productInfoOutputList); //存储到redis + assert productInfoOutputList != null; for (ProductInfoOutput productInfoOutput : productInfoOutputList) { stringRedisTemplate.opsForValue().set(String.format(PRODUCT_STOCK_TEMPLATE, productInfoOutput.getProductId()), String.valueOf(productInfoOutput.getProductStock())); diff --git a/springcloud/order/order-server/src/main/java/cn/lastwhisper/order/message/StreamClient.java b/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/message/StreamClient.java similarity index 100% rename from springcloud/order/order-server/src/main/java/cn/lastwhisper/order/message/StreamClient.java rename to distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/message/StreamClient.java diff --git a/springcloud/order/order-server/src/main/java/cn/lastwhisper/order/message/StreamReceiver.java b/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/message/StreamReceiver.java similarity index 100% rename from springcloud/order/order-server/src/main/java/cn/lastwhisper/order/message/StreamReceiver.java rename to distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/message/StreamReceiver.java diff --git a/springcloud/order/order-server/src/main/java/cn/lastwhisper/order/repository/OrderDetailRepository.java b/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/repository/OrderDetailRepository.java similarity index 100% rename from springcloud/order/order-server/src/main/java/cn/lastwhisper/order/repository/OrderDetailRepository.java rename to distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/repository/OrderDetailRepository.java diff --git a/springcloud/order/order-server/src/main/java/cn/lastwhisper/order/repository/OrderMasterRepository.java b/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/repository/OrderMasterRepository.java similarity index 100% rename from springcloud/order/order-server/src/main/java/cn/lastwhisper/order/repository/OrderMasterRepository.java rename to distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/repository/OrderMasterRepository.java diff --git a/springcloud/order/order-server/src/main/java/cn/lastwhisper/order/service/OrderService.java b/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/service/OrderService.java similarity index 100% rename from springcloud/order/order-server/src/main/java/cn/lastwhisper/order/service/OrderService.java rename to distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/service/OrderService.java diff --git a/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/service/impl/OrderServiceImpl.java b/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/service/impl/OrderServiceImpl.java new file mode 100644 index 00000000..5fd6ae8b --- /dev/null +++ b/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/service/impl/OrderServiceImpl.java @@ -0,0 +1,121 @@ +package cn.lastwhisper.order.service.impl; + +import cn.lastwhisper.order.domain.OrderDetail; +import cn.lastwhisper.order.domain.OrderMaster; +import cn.lastwhisper.order.dto.OrderDTO; +import cn.lastwhisper.order.enums.OrderStatusEnum; +import cn.lastwhisper.order.enums.PayStatusEnum; +import cn.lastwhisper.order.enums.ResultEnum; +import cn.lastwhisper.order.exception.OrderException; +import cn.lastwhisper.order.repository.OrderDetailRepository; +import cn.lastwhisper.order.repository.OrderMasterRepository; +import cn.lastwhisper.order.service.OrderService; +import cn.lastwhisper.order.utils.KeyUtil; +import cn.lastwhisper.product.client.ProductClient; +import cn.lastwhisper.product.common.DecreaseStockInput; +import cn.lastwhisper.product.common.ProductInfoOutput; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +import javax.transaction.Transactional; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +/** + * + * @author lastwhisper + * @date 2019/10/26 + */ +@Service +public class OrderServiceImpl implements OrderService { + + @Autowired + private OrderMasterRepository orderMasterRepository; + + @Autowired + private OrderDetailRepository orderDetailRepository; + + @Autowired + private ProductClient productClient; + + @Override + @Transactional + public OrderDTO create(OrderDTO orderDTO) { + String orderId = KeyUtil.genUniqueKey(); + + // 参数校验?controller层做 + // 1.查询商品信息(调用商品服务) + List productIdList = orderDTO.getOrderDetailList().stream() + .map(OrderDetail::getProductId).collect(Collectors.toList()); + List productInfoList = productClient.listForOrder(productIdList); + // 2.计算总价 + BigDecimal orderAmount = new BigDecimal(BigInteger.ZERO); + for (OrderDetail orderDetail : orderDTO.getOrderDetailList()) { + for (ProductInfoOutput productInfo : productInfoList) { + if (orderDetail.getProductId().equals(productInfo.getProductId())) { + orderAmount = productInfo.getProductPrice() + .multiply(BigDecimal.valueOf(orderDetail.getProductQuantity())) + .add(orderAmount); + BeanUtils.copyProperties(productInfo, orderDetail); + orderDetail.setOrderId(orderId); + orderDetail.setDetailId(KeyUtil.genUniqueKey()); + // 保存订单详情 + orderDetailRepository.save(orderDetail); + } + } + } + // 3.扣库存(调用商品服务) + List decreaseStockInputList = orderDTO.getOrderDetailList().stream() + .map(o -> new DecreaseStockInput(o.getProductId(), o.getProductQuantity())) + .collect(Collectors.toList()); + productClient.decreaseStock(decreaseStockInputList); + // 4.订单入库 + OrderMaster orderMaster = new OrderMaster(); + orderDTO.setOrderId(orderId); + //相同字段 + BeanUtils.copyProperties(orderDTO, orderMaster); + //不同字段 + orderMaster.setOrderAmount(BigDecimal.valueOf(5499)); + orderMaster.setOrderStatus(OrderStatusEnum.NEW.getCode()); + orderMaster.setPayStatus(PayStatusEnum.WAIT.getCode()); + orderMasterRepository.save(orderMaster); + + + productClient.productThread3(); + return orderDTO; + } + + @Override + @Transactional + public OrderDTO finish(String orderId) { + //1.查询订单 + Optional optionalOrderMaster = orderMasterRepository.findById(orderId); + if (!optionalOrderMaster.isPresent()) { + throw new OrderException(ResultEnum.ORDER_NOT_EXIST); + } + //2.修改订单状态 + OrderMaster orderMaster = optionalOrderMaster.get(); + if(!OrderStatusEnum.NEW.getCode().equals(orderMaster.getOrderStatus())){ + throw new OrderException(ResultEnum.ORDER_STATUS_ERROR); + } + orderMaster.setOrderStatus(OrderStatusEnum.FINISHED.getCode()); + orderMasterRepository.save(orderMaster); + //3.封装OrderDTO + List orderDetailList = orderDetailRepository.findByOrOrderId(orderId); + if (CollectionUtils.isEmpty(orderDetailList)) { + throw new OrderException(ResultEnum.ORDER_DETAIL_NOT_EXIST); + } + + OrderDTO orderDTO = new OrderDTO(); + BeanUtils.copyProperties(orderMaster,orderDTO); + orderDTO.setOrderDetailList(orderDetailList); + + return orderDTO; + } + +} diff --git a/springcloud/order/order-server/src/main/java/cn/lastwhisper/order/utils/JsonUtil.java b/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/utils/JsonUtil.java similarity index 100% rename from springcloud/order/order-server/src/main/java/cn/lastwhisper/order/utils/JsonUtil.java rename to distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/utils/JsonUtil.java diff --git a/springcloud/order/order-server/src/main/java/cn/lastwhisper/order/utils/KeyUtil.java b/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/utils/KeyUtil.java similarity index 100% rename from springcloud/order/order-server/src/main/java/cn/lastwhisper/order/utils/KeyUtil.java rename to distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/utils/KeyUtil.java diff --git a/springcloud/order/order-server/src/main/java/cn/lastwhisper/order/utils/ResultVOUtil.java b/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/utils/ResultVOUtil.java similarity index 100% rename from springcloud/order/order-server/src/main/java/cn/lastwhisper/order/utils/ResultVOUtil.java rename to distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/utils/ResultVOUtil.java diff --git a/springcloud/order/order-server/src/main/java/cn/lastwhisper/order/vo/ResultVO.java b/distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/vo/ResultVO.java similarity index 100% rename from springcloud/order/order-server/src/main/java/cn/lastwhisper/order/vo/ResultVO.java rename to distributed/springcloud-netflix/order/order-server/src/main/java/cn/lastwhisper/order/vo/ResultVO.java diff --git a/distributed/springcloud-netflix/order/order-server/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/distributed/springcloud-netflix/order/order-server/src/main/resources/META-INF/additional-spring-configuration-metadata.json new file mode 100644 index 00000000..a013af2f --- /dev/null +++ b/distributed/springcloud-netflix/order/order-server/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -0,0 +1,8 @@ +{ + "properties": [ + { + "name": "hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds", + "type": "java.lang.String", + "description": "Description for hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds." + } +] } \ No newline at end of file diff --git a/springcloud/order/order-server/src/main/resources/application.txt b/distributed/springcloud-netflix/order/order-server/src/main/resources/application.txt similarity index 100% rename from springcloud/order/order-server/src/main/resources/application.txt rename to distributed/springcloud-netflix/order/order-server/src/main/resources/application.txt diff --git a/distributed/springcloud-netflix/order/order-server/src/main/resources/bootstrap.yml b/distributed/springcloud-netflix/order/order-server/src/main/resources/bootstrap.yml new file mode 100644 index 00000000..c6a6d153 --- /dev/null +++ b/distributed/springcloud-netflix/order/order-server/src/main/resources/bootstrap.yml @@ -0,0 +1,47 @@ +spring: + application: + name: order + cloud: + config: + discovery: + enabled: true + service-id: CONFIG + profile: test + # stream: + # bindings: + # myMessage: + # group: order + # content-type: application/json + # zipkin地址 + zipkin: + base-url: http://localhost:9411/ + sender: + type: web + # sleuth抽样百分比 + sleuth: + sampler: + probability: 1 +eureka: + client: + service-url: + defaultZone: http://localhost:8761/eureka/ +hystrix: + command: + default: + execution: + isolation: + thread: + timeoutInMilliseconds: 1000 + getProductInfoList: + execution: + isolation: + thread: + timeoutInMilliseconds: 1000 +management: + server: + servlet: + context-path: / +# 设置日志级别 +logging: + level: + org.springframework.cloud.openfeign: debug \ No newline at end of file diff --git a/springcloud/order/order-server/src/test/java/cn/lastwhisper/order/MqSenderTest.java b/distributed/springcloud-netflix/order/order-server/src/test/java/cn/lastwhisper/order/MqSenderTest.java similarity index 100% rename from springcloud/order/order-server/src/test/java/cn/lastwhisper/order/MqSenderTest.java rename to distributed/springcloud-netflix/order/order-server/src/test/java/cn/lastwhisper/order/MqSenderTest.java diff --git a/springcloud/order/order-server/src/test/java/cn/lastwhisper/order/OrderApplicationTests.java b/distributed/springcloud-netflix/order/order-server/src/test/java/cn/lastwhisper/order/OrderApplicationTests.java similarity index 94% rename from springcloud/order/order-server/src/test/java/cn/lastwhisper/order/OrderApplicationTests.java rename to distributed/springcloud-netflix/order/order-server/src/test/java/cn/lastwhisper/order/OrderApplicationTests.java index 2967ca3c..a2b55963 100644 --- a/springcloud/order/order-server/src/test/java/cn/lastwhisper/order/OrderApplicationTests.java +++ b/distributed/springcloud-netflix/order/order-server/src/test/java/cn/lastwhisper/order/OrderApplicationTests.java @@ -1,6 +1,5 @@ package cn.lastwhisper.order; -import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.TestPropertySource; diff --git a/springcloud/order/order-server/src/test/java/cn/lastwhisper/order/repository/OrderDetailRepositoryTest.java b/distributed/springcloud-netflix/order/order-server/src/test/java/cn/lastwhisper/order/repository/OrderDetailRepositoryTest.java similarity index 100% rename from springcloud/order/order-server/src/test/java/cn/lastwhisper/order/repository/OrderDetailRepositoryTest.java rename to distributed/springcloud-netflix/order/order-server/src/test/java/cn/lastwhisper/order/repository/OrderDetailRepositoryTest.java diff --git a/springcloud/order/order-server/src/test/java/cn/lastwhisper/order/repository/OrderMasterRepositoryTest.java b/distributed/springcloud-netflix/order/order-server/src/test/java/cn/lastwhisper/order/repository/OrderMasterRepositoryTest.java similarity index 100% rename from springcloud/order/order-server/src/test/java/cn/lastwhisper/order/repository/OrderMasterRepositoryTest.java rename to distributed/springcloud-netflix/order/order-server/src/test/java/cn/lastwhisper/order/repository/OrderMasterRepositoryTest.java diff --git a/distributed/springcloud-netflix/order/pom.xml b/distributed/springcloud-netflix/order/pom.xml new file mode 100644 index 00000000..d031e0e0 --- /dev/null +++ b/distributed/springcloud-netflix/order/pom.xml @@ -0,0 +1,66 @@ + + + + 4.0.0 + pom + + order-common + order-client + order-server + + + cn.lastwhisper + order + 0.0.1-SNAPSHOT + order + 订单服务 + + + org.springframework.boot + spring-boot-starter-parent + 2.0.2.RELEASE + + + + + UTF-8 + UTF-8 + 1.8 + Finchley.RELEASE + + 0.0.1-SNAPSHOT + 0.0.1-SNAPSHOT + 0.0.1-SNAPSHOT + + + + + + org.springframework.cloud + spring-cloud-dependencies + ${spring-cloud.version} + pom + import + + + cn.lastwhisper + order-common + ${order-common.version} + + + cn.lastwhisper + product-client + ${product-client.version} + + + + cn.lastwhisper + product-common + ${product-common.version} + + + + + \ No newline at end of file diff --git a/distributed/springcloud-netflix/pom.xml b/distributed/springcloud-netflix/pom.xml new file mode 100644 index 00000000..a81114cb --- /dev/null +++ b/distributed/springcloud-netflix/pom.xml @@ -0,0 +1,14 @@ + + + 4.0.0 + + cn.lastwhisper + springcloud-netflix + pom + 1.0-SNAPSHOT + + + + \ No newline at end of file diff --git a/springcloud/product-old/pom.xml b/distributed/springcloud-netflix/product-old/pom.xml similarity index 100% rename from springcloud/product-old/pom.xml rename to distributed/springcloud-netflix/product-old/pom.xml diff --git a/springcloud/product-old/src/main/java/cn/lastwhisper/product/ProductApplication.java b/distributed/springcloud-netflix/product-old/src/main/java/cn/lastwhisper/product/ProductApplication.java similarity index 100% rename from springcloud/product-old/src/main/java/cn/lastwhisper/product/ProductApplication.java rename to distributed/springcloud-netflix/product-old/src/main/java/cn/lastwhisper/product/ProductApplication.java diff --git a/springcloud/product-old/src/main/java/cn/lastwhisper/product/controller/ProductController.java b/distributed/springcloud-netflix/product-old/src/main/java/cn/lastwhisper/product/controller/ProductController.java similarity index 100% rename from springcloud/product-old/src/main/java/cn/lastwhisper/product/controller/ProductController.java rename to distributed/springcloud-netflix/product-old/src/main/java/cn/lastwhisper/product/controller/ProductController.java diff --git a/springcloud/product-old/src/main/java/cn/lastwhisper/product/controller/ServerController.java b/distributed/springcloud-netflix/product-old/src/main/java/cn/lastwhisper/product/controller/ServerController.java similarity index 100% rename from springcloud/product-old/src/main/java/cn/lastwhisper/product/controller/ServerController.java rename to distributed/springcloud-netflix/product-old/src/main/java/cn/lastwhisper/product/controller/ServerController.java diff --git a/springcloud/product-old/src/main/java/cn/lastwhisper/product/domain/ProductCategory.java b/distributed/springcloud-netflix/product-old/src/main/java/cn/lastwhisper/product/domain/ProductCategory.java similarity index 100% rename from springcloud/product-old/src/main/java/cn/lastwhisper/product/domain/ProductCategory.java rename to distributed/springcloud-netflix/product-old/src/main/java/cn/lastwhisper/product/domain/ProductCategory.java diff --git a/springcloud/product-old/src/main/java/cn/lastwhisper/product/domain/ProductInfo.java b/distributed/springcloud-netflix/product-old/src/main/java/cn/lastwhisper/product/domain/ProductInfo.java similarity index 100% rename from springcloud/product-old/src/main/java/cn/lastwhisper/product/domain/ProductInfo.java rename to distributed/springcloud-netflix/product-old/src/main/java/cn/lastwhisper/product/domain/ProductInfo.java diff --git a/springcloud/product-old/src/main/java/cn/lastwhisper/product/dto/CartDTO.java b/distributed/springcloud-netflix/product-old/src/main/java/cn/lastwhisper/product/dto/CartDTO.java similarity index 100% rename from springcloud/product-old/src/main/java/cn/lastwhisper/product/dto/CartDTO.java rename to distributed/springcloud-netflix/product-old/src/main/java/cn/lastwhisper/product/dto/CartDTO.java diff --git a/springcloud/product-old/src/main/java/cn/lastwhisper/product/enums/ProductStatusEnum.java b/distributed/springcloud-netflix/product-old/src/main/java/cn/lastwhisper/product/enums/ProductStatusEnum.java similarity index 100% rename from springcloud/product-old/src/main/java/cn/lastwhisper/product/enums/ProductStatusEnum.java rename to distributed/springcloud-netflix/product-old/src/main/java/cn/lastwhisper/product/enums/ProductStatusEnum.java diff --git a/springcloud/product-old/src/main/java/cn/lastwhisper/product/enums/ResultEnum.java b/distributed/springcloud-netflix/product-old/src/main/java/cn/lastwhisper/product/enums/ResultEnum.java similarity index 100% rename from springcloud/product-old/src/main/java/cn/lastwhisper/product/enums/ResultEnum.java rename to distributed/springcloud-netflix/product-old/src/main/java/cn/lastwhisper/product/enums/ResultEnum.java diff --git a/springcloud/product-old/src/main/java/cn/lastwhisper/product/exception/ProductExecption.java b/distributed/springcloud-netflix/product-old/src/main/java/cn/lastwhisper/product/exception/ProductExecption.java similarity index 100% rename from springcloud/product-old/src/main/java/cn/lastwhisper/product/exception/ProductExecption.java rename to distributed/springcloud-netflix/product-old/src/main/java/cn/lastwhisper/product/exception/ProductExecption.java diff --git a/springcloud/product-old/src/main/java/cn/lastwhisper/product/repository/ProductCategoryRepository.java b/distributed/springcloud-netflix/product-old/src/main/java/cn/lastwhisper/product/repository/ProductCategoryRepository.java similarity index 100% rename from springcloud/product-old/src/main/java/cn/lastwhisper/product/repository/ProductCategoryRepository.java rename to distributed/springcloud-netflix/product-old/src/main/java/cn/lastwhisper/product/repository/ProductCategoryRepository.java diff --git a/springcloud/product-old/src/main/java/cn/lastwhisper/product/repository/ProductInfoRepository.java b/distributed/springcloud-netflix/product-old/src/main/java/cn/lastwhisper/product/repository/ProductInfoRepository.java similarity index 100% rename from springcloud/product-old/src/main/java/cn/lastwhisper/product/repository/ProductInfoRepository.java rename to distributed/springcloud-netflix/product-old/src/main/java/cn/lastwhisper/product/repository/ProductInfoRepository.java diff --git a/springcloud/product-old/src/main/java/cn/lastwhisper/product/service/CategoryService.java b/distributed/springcloud-netflix/product-old/src/main/java/cn/lastwhisper/product/service/CategoryService.java similarity index 100% rename from springcloud/product-old/src/main/java/cn/lastwhisper/product/service/CategoryService.java rename to distributed/springcloud-netflix/product-old/src/main/java/cn/lastwhisper/product/service/CategoryService.java diff --git a/springcloud/product-old/src/main/java/cn/lastwhisper/product/service/ProductService.java b/distributed/springcloud-netflix/product-old/src/main/java/cn/lastwhisper/product/service/ProductService.java similarity index 100% rename from springcloud/product-old/src/main/java/cn/lastwhisper/product/service/ProductService.java rename to distributed/springcloud-netflix/product-old/src/main/java/cn/lastwhisper/product/service/ProductService.java diff --git a/springcloud/product-old/src/main/java/cn/lastwhisper/product/service/impl/CategoryServiceImpl.java b/distributed/springcloud-netflix/product-old/src/main/java/cn/lastwhisper/product/service/impl/CategoryServiceImpl.java similarity index 100% rename from springcloud/product-old/src/main/java/cn/lastwhisper/product/service/impl/CategoryServiceImpl.java rename to distributed/springcloud-netflix/product-old/src/main/java/cn/lastwhisper/product/service/impl/CategoryServiceImpl.java diff --git a/springcloud/product-old/src/main/java/cn/lastwhisper/product/service/impl/ProductServiceImpl.java b/distributed/springcloud-netflix/product-old/src/main/java/cn/lastwhisper/product/service/impl/ProductServiceImpl.java similarity index 100% rename from springcloud/product-old/src/main/java/cn/lastwhisper/product/service/impl/ProductServiceImpl.java rename to distributed/springcloud-netflix/product-old/src/main/java/cn/lastwhisper/product/service/impl/ProductServiceImpl.java diff --git a/springcloud/product-old/src/main/java/cn/lastwhisper/product/utils/ResultVOUtil.java b/distributed/springcloud-netflix/product-old/src/main/java/cn/lastwhisper/product/utils/ResultVOUtil.java similarity index 100% rename from springcloud/product-old/src/main/java/cn/lastwhisper/product/utils/ResultVOUtil.java rename to distributed/springcloud-netflix/product-old/src/main/java/cn/lastwhisper/product/utils/ResultVOUtil.java diff --git a/springcloud/product-old/src/main/java/cn/lastwhisper/product/vo/ProductInfoVO.java b/distributed/springcloud-netflix/product-old/src/main/java/cn/lastwhisper/product/vo/ProductInfoVO.java similarity index 100% rename from springcloud/product-old/src/main/java/cn/lastwhisper/product/vo/ProductInfoVO.java rename to distributed/springcloud-netflix/product-old/src/main/java/cn/lastwhisper/product/vo/ProductInfoVO.java diff --git a/springcloud/product-old/src/main/java/cn/lastwhisper/product/vo/ProductVO.java b/distributed/springcloud-netflix/product-old/src/main/java/cn/lastwhisper/product/vo/ProductVO.java similarity index 100% rename from springcloud/product-old/src/main/java/cn/lastwhisper/product/vo/ProductVO.java rename to distributed/springcloud-netflix/product-old/src/main/java/cn/lastwhisper/product/vo/ProductVO.java diff --git a/springcloud/product-old/src/main/java/cn/lastwhisper/product/vo/ResultVO.java b/distributed/springcloud-netflix/product-old/src/main/java/cn/lastwhisper/product/vo/ResultVO.java similarity index 100% rename from springcloud/product-old/src/main/java/cn/lastwhisper/product/vo/ResultVO.java rename to distributed/springcloud-netflix/product-old/src/main/java/cn/lastwhisper/product/vo/ResultVO.java diff --git a/springcloud/product-old/src/main/resources/application.yml b/distributed/springcloud-netflix/product-old/src/main/resources/application.yml similarity index 100% rename from springcloud/product-old/src/main/resources/application.yml rename to distributed/springcloud-netflix/product-old/src/main/resources/application.yml diff --git a/springcloud/product-old/src/test/java/cn/lastwhisper/product/ProductApplicationTests.java b/distributed/springcloud-netflix/product-old/src/test/java/cn/lastwhisper/product/ProductApplicationTests.java similarity index 100% rename from springcloud/product-old/src/test/java/cn/lastwhisper/product/ProductApplicationTests.java rename to distributed/springcloud-netflix/product-old/src/test/java/cn/lastwhisper/product/ProductApplicationTests.java diff --git a/springcloud/product-old/src/test/java/cn/lastwhisper/product/repository/ProductCategoryRepositoryTest.java b/distributed/springcloud-netflix/product-old/src/test/java/cn/lastwhisper/product/repository/ProductCategoryRepositoryTest.java similarity index 100% rename from springcloud/product-old/src/test/java/cn/lastwhisper/product/repository/ProductCategoryRepositoryTest.java rename to distributed/springcloud-netflix/product-old/src/test/java/cn/lastwhisper/product/repository/ProductCategoryRepositoryTest.java diff --git a/springcloud/product-old/src/test/java/cn/lastwhisper/product/repository/ProductInfoRepositoryTest.java b/distributed/springcloud-netflix/product-old/src/test/java/cn/lastwhisper/product/repository/ProductInfoRepositoryTest.java similarity index 100% rename from springcloud/product-old/src/test/java/cn/lastwhisper/product/repository/ProductInfoRepositoryTest.java rename to distributed/springcloud-netflix/product-old/src/test/java/cn/lastwhisper/product/repository/ProductInfoRepositoryTest.java diff --git a/springcloud/product-old/src/test/java/cn/lastwhisper/product/service/CategoryServiceTest.java b/distributed/springcloud-netflix/product-old/src/test/java/cn/lastwhisper/product/service/CategoryServiceTest.java similarity index 100% rename from springcloud/product-old/src/test/java/cn/lastwhisper/product/service/CategoryServiceTest.java rename to distributed/springcloud-netflix/product-old/src/test/java/cn/lastwhisper/product/service/CategoryServiceTest.java diff --git a/springcloud/product-old/src/test/java/cn/lastwhisper/product/service/ProductServiceTest.java b/distributed/springcloud-netflix/product-old/src/test/java/cn/lastwhisper/product/service/ProductServiceTest.java similarity index 100% rename from springcloud/product-old/src/test/java/cn/lastwhisper/product/service/ProductServiceTest.java rename to distributed/springcloud-netflix/product-old/src/test/java/cn/lastwhisper/product/service/ProductServiceTest.java diff --git a/springcloud/product/pom.xml b/distributed/springcloud-netflix/product/pom.xml similarity index 100% rename from springcloud/product/pom.xml rename to distributed/springcloud-netflix/product/pom.xml diff --git a/springcloud/product/product-client/pom.xml b/distributed/springcloud-netflix/product/product-client/pom.xml similarity index 100% rename from springcloud/product/product-client/pom.xml rename to distributed/springcloud-netflix/product/product-client/pom.xml diff --git a/springcloud/product/product-client/src/main/java/cn/lastwhisper/product/client/ProductClient.java b/distributed/springcloud-netflix/product/product-client/src/main/java/cn/lastwhisper/product/client/ProductClient.java similarity index 87% rename from springcloud/product/product-client/src/main/java/cn/lastwhisper/product/client/ProductClient.java rename to distributed/springcloud-netflix/product/product-client/src/main/java/cn/lastwhisper/product/client/ProductClient.java index 75fc5af2..7c697fc8 100644 --- a/springcloud/product/product-client/src/main/java/cn/lastwhisper/product/client/ProductClient.java +++ b/distributed/springcloud-netflix/product/product-client/src/main/java/cn/lastwhisper/product/client/ProductClient.java @@ -25,4 +25,11 @@ public interface ProductClient { @PostMapping("/product/decreaseStock") void decreaseStock(@RequestBody List cartDTOList); + + /** + * 一个睡3s的方法 + */ + @PostMapping("/product/productThread3") + void productThread3(); + } diff --git a/springcloud/product/product-common/pom.xml b/distributed/springcloud-netflix/product/product-common/pom.xml similarity index 100% rename from springcloud/product/product-common/pom.xml rename to distributed/springcloud-netflix/product/product-common/pom.xml diff --git a/springcloud/product/product-common/src/main/java/cn/lastwhisper/product/common/DecreaseStockInput.java b/distributed/springcloud-netflix/product/product-common/src/main/java/cn/lastwhisper/product/common/DecreaseStockInput.java similarity index 100% rename from springcloud/product/product-common/src/main/java/cn/lastwhisper/product/common/DecreaseStockInput.java rename to distributed/springcloud-netflix/product/product-common/src/main/java/cn/lastwhisper/product/common/DecreaseStockInput.java diff --git a/springcloud/product/product-common/src/main/java/cn/lastwhisper/product/common/ProductInfoOutput.java b/distributed/springcloud-netflix/product/product-common/src/main/java/cn/lastwhisper/product/common/ProductInfoOutput.java similarity index 100% rename from springcloud/product/product-common/src/main/java/cn/lastwhisper/product/common/ProductInfoOutput.java rename to distributed/springcloud-netflix/product/product-common/src/main/java/cn/lastwhisper/product/common/ProductInfoOutput.java diff --git a/distributed/springcloud-netflix/product/product-server/pom.xml b/distributed/springcloud-netflix/product/product-server/pom.xml new file mode 100644 index 00000000..1a2a5e7a --- /dev/null +++ b/distributed/springcloud-netflix/product/product-server/pom.xml @@ -0,0 +1,88 @@ + + + + product + cn.lastwhisper + 0.0.1-SNAPSHOT + + 4.0.0 + + product-server + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.cloud + spring-cloud-starter-netflix-eureka-client + + + + org.springframework.cloud + spring-cloud-config-client + + + + org.springframework.boot + spring-boot-starter-amqp + + + + + org.springframework.cloud + spring-cloud-starter-zipkin + + + + mysql + mysql-connector-java + runtime + + + org.projectlombok + lombok + true + + + org.springframework.boot + spring-boot-starter-test + test + + + org.junit.vintage + junit-vintage-engine + + + + + + product-common + cn.lastwhisper + + + + cn.lastwhisper + order-client + 0.0.1-SNAPSHOT + compile + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + \ No newline at end of file diff --git a/distributed/springcloud-netflix/product/product-server/src/main/java/cn/lastwhisper/product/ProductApplication.java b/distributed/springcloud-netflix/product/product-server/src/main/java/cn/lastwhisper/product/ProductApplication.java new file mode 100644 index 00000000..f50accc2 --- /dev/null +++ b/distributed/springcloud-netflix/product/product-server/src/main/java/cn/lastwhisper/product/ProductApplication.java @@ -0,0 +1,17 @@ +package cn.lastwhisper.product; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; +import org.springframework.cloud.openfeign.EnableFeignClients; + +@EnableFeignClients(basePackages = "cn.lastwhisper.order.client") +@SpringBootApplication +@EnableDiscoveryClient +public class ProductApplication { + + public static void main(String[] args) { + SpringApplication.run(ProductApplication.class, args); + } + +} diff --git a/distributed/springcloud-netflix/product/product-server/src/main/java/cn/lastwhisper/product/controller/ProductController.java b/distributed/springcloud-netflix/product/product-server/src/main/java/cn/lastwhisper/product/controller/ProductController.java new file mode 100644 index 00000000..e284bd00 --- /dev/null +++ b/distributed/springcloud-netflix/product/product-server/src/main/java/cn/lastwhisper/product/controller/ProductController.java @@ -0,0 +1,113 @@ +package cn.lastwhisper.product.controller; + +import cn.lastwhisper.order.client.OrderClient; +import cn.lastwhisper.product.domain.ProductCategory; +import cn.lastwhisper.product.domain.ProductInfo; +import cn.lastwhisper.product.dto.CartDTO; +import cn.lastwhisper.product.service.CategoryService; +import cn.lastwhisper.product.service.ProductService; +import cn.lastwhisper.product.utils.ResultVOUtil; +import cn.lastwhisper.product.vo.ProductInfoVO; +import cn.lastwhisper.product.vo.ProductVO; +import cn.lastwhisper.product.vo.ResultVO; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +/** + * + * @author lastwhisper + * @date 2019/10/24 + */ +@RestController +@RequestMapping("product") +public class ProductController { + + @Autowired + private ProductService productService; + + @Autowired + private CategoryService categoryService; + + @Autowired + private OrderClient orderClient; + + /** + * 1. 查询所有在架的商品列表 + * 2. 获取类目type列表 + * 3. 根据type列表查询类目列表 + * 4. 根据接口json数据格式构造数据 + */ + @RequestMapping("/list") + public ResultVO list() { + //1. 查询所有在架的商品列表 + List productInfoList = productService.findUpAll(); + //2. 获取类目type列表 + List categoryTypeList = productInfoList.stream() + .map(ProductInfo::getCategoryType) + .collect(Collectors.toList()); + //3. 根据type列表查询类目列表 + List productCategoryList = categoryService.findByCategoryTypeIn(categoryTypeList); + //4. 根据接口json数据格式构造数据 + // 4.1 第一层:category list + List productVOList = new ArrayList<>(); + for (ProductCategory productCategory : productCategoryList) { + ProductVO productVO = new ProductVO(); + productVO.setCategoryName(productCategory.getCategoryName()); + productVO.setCategoryType(productCategory.getCategoryType()); + // 4.2 第二层:product list + List productInfoVOList = new ArrayList(); + for (ProductInfo productInfo : productInfoList) { + // 只有当类目相同时才将类目下的商品挂载到该类目下 + if (productCategory.getCategoryType().equals(productInfo.getCategoryType())) { + ProductInfoVO productInfoVO = new ProductInfoVO(); + BeanUtils.copyProperties(productInfo, productInfoVO); + productInfoVOList.add(productInfoVO); + } + } + productVO.setProductInfoVOList(productInfoVOList); + productVOList.add(productVO); + } + // 4.3 最外层 + //ResultVO> resultVO = new ResultVO<>(); + //resultVO.setCode(0); + //resultVO.setMsg("成功"); + //resultVO.setData(productVOList); + + return ResultVOUtil.success(productVOList); + } + + @PostMapping("/listForOrder") + public List listForOrder(@RequestBody List productIdList) { + //try { + // Thread.sleep(2000); + //} catch (InterruptedException e) { + // e.printStackTrace(); + //} + return productService.findList(productIdList); + } + + @PostMapping("/decreaseStock") + public void decreaseStock(@RequestBody List cartDTOList) { + productService.decreaseStock(cartDTOList); + } + + @PostMapping("/productThread3") + public void productThread3() { + try { + Thread.sleep(100); + orderClient.orderThread3(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + +} diff --git a/springcloud/product/product-server/src/main/java/cn/lastwhisper/product/controller/ServerController.java b/distributed/springcloud-netflix/product/product-server/src/main/java/cn/lastwhisper/product/controller/ServerController.java similarity index 100% rename from springcloud/product/product-server/src/main/java/cn/lastwhisper/product/controller/ServerController.java rename to distributed/springcloud-netflix/product/product-server/src/main/java/cn/lastwhisper/product/controller/ServerController.java diff --git a/springcloud/product/product-server/src/main/java/cn/lastwhisper/product/domain/ProductCategory.java b/distributed/springcloud-netflix/product/product-server/src/main/java/cn/lastwhisper/product/domain/ProductCategory.java similarity index 100% rename from springcloud/product/product-server/src/main/java/cn/lastwhisper/product/domain/ProductCategory.java rename to distributed/springcloud-netflix/product/product-server/src/main/java/cn/lastwhisper/product/domain/ProductCategory.java diff --git a/springcloud/product/product-server/src/main/java/cn/lastwhisper/product/domain/ProductInfo.java b/distributed/springcloud-netflix/product/product-server/src/main/java/cn/lastwhisper/product/domain/ProductInfo.java similarity index 100% rename from springcloud/product/product-server/src/main/java/cn/lastwhisper/product/domain/ProductInfo.java rename to distributed/springcloud-netflix/product/product-server/src/main/java/cn/lastwhisper/product/domain/ProductInfo.java diff --git a/springcloud/product/product-server/src/main/java/cn/lastwhisper/product/dto/CartDTO.java b/distributed/springcloud-netflix/product/product-server/src/main/java/cn/lastwhisper/product/dto/CartDTO.java similarity index 100% rename from springcloud/product/product-server/src/main/java/cn/lastwhisper/product/dto/CartDTO.java rename to distributed/springcloud-netflix/product/product-server/src/main/java/cn/lastwhisper/product/dto/CartDTO.java diff --git a/springcloud/product/product-server/src/main/java/cn/lastwhisper/product/enums/ProductStatusEnum.java b/distributed/springcloud-netflix/product/product-server/src/main/java/cn/lastwhisper/product/enums/ProductStatusEnum.java similarity index 100% rename from springcloud/product/product-server/src/main/java/cn/lastwhisper/product/enums/ProductStatusEnum.java rename to distributed/springcloud-netflix/product/product-server/src/main/java/cn/lastwhisper/product/enums/ProductStatusEnum.java diff --git a/springcloud/product/product-server/src/main/java/cn/lastwhisper/product/enums/ResultEnum.java b/distributed/springcloud-netflix/product/product-server/src/main/java/cn/lastwhisper/product/enums/ResultEnum.java similarity index 100% rename from springcloud/product/product-server/src/main/java/cn/lastwhisper/product/enums/ResultEnum.java rename to distributed/springcloud-netflix/product/product-server/src/main/java/cn/lastwhisper/product/enums/ResultEnum.java diff --git a/springcloud/product/product-server/src/main/java/cn/lastwhisper/product/exception/ProductExecption.java b/distributed/springcloud-netflix/product/product-server/src/main/java/cn/lastwhisper/product/exception/ProductExecption.java similarity index 100% rename from springcloud/product/product-server/src/main/java/cn/lastwhisper/product/exception/ProductExecption.java rename to distributed/springcloud-netflix/product/product-server/src/main/java/cn/lastwhisper/product/exception/ProductExecption.java diff --git a/springcloud/product/product-server/src/main/java/cn/lastwhisper/product/repository/ProductCategoryRepository.java b/distributed/springcloud-netflix/product/product-server/src/main/java/cn/lastwhisper/product/repository/ProductCategoryRepository.java similarity index 100% rename from springcloud/product/product-server/src/main/java/cn/lastwhisper/product/repository/ProductCategoryRepository.java rename to distributed/springcloud-netflix/product/product-server/src/main/java/cn/lastwhisper/product/repository/ProductCategoryRepository.java diff --git a/springcloud/product/product-server/src/main/java/cn/lastwhisper/product/repository/ProductInfoRepository.java b/distributed/springcloud-netflix/product/product-server/src/main/java/cn/lastwhisper/product/repository/ProductInfoRepository.java similarity index 100% rename from springcloud/product/product-server/src/main/java/cn/lastwhisper/product/repository/ProductInfoRepository.java rename to distributed/springcloud-netflix/product/product-server/src/main/java/cn/lastwhisper/product/repository/ProductInfoRepository.java diff --git a/springcloud/product/product-server/src/main/java/cn/lastwhisper/product/service/CategoryService.java b/distributed/springcloud-netflix/product/product-server/src/main/java/cn/lastwhisper/product/service/CategoryService.java similarity index 100% rename from springcloud/product/product-server/src/main/java/cn/lastwhisper/product/service/CategoryService.java rename to distributed/springcloud-netflix/product/product-server/src/main/java/cn/lastwhisper/product/service/CategoryService.java diff --git a/springcloud/product/product-server/src/main/java/cn/lastwhisper/product/service/ProductService.java b/distributed/springcloud-netflix/product/product-server/src/main/java/cn/lastwhisper/product/service/ProductService.java similarity index 100% rename from springcloud/product/product-server/src/main/java/cn/lastwhisper/product/service/ProductService.java rename to distributed/springcloud-netflix/product/product-server/src/main/java/cn/lastwhisper/product/service/ProductService.java diff --git a/springcloud/product/product-server/src/main/java/cn/lastwhisper/product/service/impl/CategoryServiceImpl.java b/distributed/springcloud-netflix/product/product-server/src/main/java/cn/lastwhisper/product/service/impl/CategoryServiceImpl.java similarity index 100% rename from springcloud/product/product-server/src/main/java/cn/lastwhisper/product/service/impl/CategoryServiceImpl.java rename to distributed/springcloud-netflix/product/product-server/src/main/java/cn/lastwhisper/product/service/impl/CategoryServiceImpl.java diff --git a/springcloud/product/product-server/src/main/java/cn/lastwhisper/product/service/impl/ProductServiceImpl.java b/distributed/springcloud-netflix/product/product-server/src/main/java/cn/lastwhisper/product/service/impl/ProductServiceImpl.java similarity index 100% rename from springcloud/product/product-server/src/main/java/cn/lastwhisper/product/service/impl/ProductServiceImpl.java rename to distributed/springcloud-netflix/product/product-server/src/main/java/cn/lastwhisper/product/service/impl/ProductServiceImpl.java diff --git a/springcloud/product/product-server/src/main/java/cn/lastwhisper/product/utils/JsonUtil.java b/distributed/springcloud-netflix/product/product-server/src/main/java/cn/lastwhisper/product/utils/JsonUtil.java similarity index 100% rename from springcloud/product/product-server/src/main/java/cn/lastwhisper/product/utils/JsonUtil.java rename to distributed/springcloud-netflix/product/product-server/src/main/java/cn/lastwhisper/product/utils/JsonUtil.java diff --git a/springcloud/product/product-server/src/main/java/cn/lastwhisper/product/utils/ResultVOUtil.java b/distributed/springcloud-netflix/product/product-server/src/main/java/cn/lastwhisper/product/utils/ResultVOUtil.java similarity index 100% rename from springcloud/product/product-server/src/main/java/cn/lastwhisper/product/utils/ResultVOUtil.java rename to distributed/springcloud-netflix/product/product-server/src/main/java/cn/lastwhisper/product/utils/ResultVOUtil.java diff --git a/springcloud/product/product-server/src/main/java/cn/lastwhisper/product/vo/ProductInfoVO.java b/distributed/springcloud-netflix/product/product-server/src/main/java/cn/lastwhisper/product/vo/ProductInfoVO.java similarity index 100% rename from springcloud/product/product-server/src/main/java/cn/lastwhisper/product/vo/ProductInfoVO.java rename to distributed/springcloud-netflix/product/product-server/src/main/java/cn/lastwhisper/product/vo/ProductInfoVO.java diff --git a/springcloud/product/product-server/src/main/java/cn/lastwhisper/product/vo/ProductVO.java b/distributed/springcloud-netflix/product/product-server/src/main/java/cn/lastwhisper/product/vo/ProductVO.java similarity index 100% rename from springcloud/product/product-server/src/main/java/cn/lastwhisper/product/vo/ProductVO.java rename to distributed/springcloud-netflix/product/product-server/src/main/java/cn/lastwhisper/product/vo/ProductVO.java diff --git a/springcloud/product/product-server/src/main/java/cn/lastwhisper/product/vo/ResultVO.java b/distributed/springcloud-netflix/product/product-server/src/main/java/cn/lastwhisper/product/vo/ResultVO.java similarity index 100% rename from springcloud/product/product-server/src/main/java/cn/lastwhisper/product/vo/ResultVO.java rename to distributed/springcloud-netflix/product/product-server/src/main/java/cn/lastwhisper/product/vo/ResultVO.java diff --git a/springcloud/product/product-server/src/main/resources/application.txt b/distributed/springcloud-netflix/product/product-server/src/main/resources/application.txt similarity index 100% rename from springcloud/product/product-server/src/main/resources/application.txt rename to distributed/springcloud-netflix/product/product-server/src/main/resources/application.txt diff --git a/distributed/springcloud-netflix/product/product-server/src/main/resources/bootstrap.yml b/distributed/springcloud-netflix/product/product-server/src/main/resources/bootstrap.yml new file mode 100644 index 00000000..32b1747a --- /dev/null +++ b/distributed/springcloud-netflix/product/product-server/src/main/resources/bootstrap.yml @@ -0,0 +1,26 @@ +spring: + application: + name: product + cloud: + config: + discovery: + enabled: true + service-id: CONFIG + profile: dev + # zipkin地址 + zipkin: + base-url: http://localhost:9411/ + sender: + type: web + # sleuth抽样百分比 + sleuth: + sampler: + probability: 1 +eureka: + client: + service-url: + defaultZone: http://localhost:8761/eureka/ +# 设置日志级别 +logging: + level: + org.springframework.cloud.openfeign: debug \ No newline at end of file diff --git a/springcloud/user/pom.xml b/distributed/springcloud-netflix/user/pom.xml similarity index 100% rename from springcloud/user/pom.xml rename to distributed/springcloud-netflix/user/pom.xml diff --git a/springcloud/user/user-server/pom.xml b/distributed/springcloud-netflix/user/user-server/pom.xml similarity index 100% rename from springcloud/user/user-server/pom.xml rename to distributed/springcloud-netflix/user/user-server/pom.xml diff --git a/springcloud/user/user-server/src/main/java/cn/lastwhisper/user/UserApplication.java b/distributed/springcloud-netflix/user/user-server/src/main/java/cn/lastwhisper/user/UserApplication.java similarity index 100% rename from springcloud/user/user-server/src/main/java/cn/lastwhisper/user/UserApplication.java rename to distributed/springcloud-netflix/user/user-server/src/main/java/cn/lastwhisper/user/UserApplication.java diff --git a/springcloud/user/user-server/src/main/java/cn/lastwhisper/user/constant/CookieConstant.java b/distributed/springcloud-netflix/user/user-server/src/main/java/cn/lastwhisper/user/constant/CookieConstant.java similarity index 100% rename from springcloud/user/user-server/src/main/java/cn/lastwhisper/user/constant/CookieConstant.java rename to distributed/springcloud-netflix/user/user-server/src/main/java/cn/lastwhisper/user/constant/CookieConstant.java diff --git a/springcloud/user/user-server/src/main/java/cn/lastwhisper/user/constant/RedisConstant.java b/distributed/springcloud-netflix/user/user-server/src/main/java/cn/lastwhisper/user/constant/RedisConstant.java similarity index 100% rename from springcloud/user/user-server/src/main/java/cn/lastwhisper/user/constant/RedisConstant.java rename to distributed/springcloud-netflix/user/user-server/src/main/java/cn/lastwhisper/user/constant/RedisConstant.java diff --git a/springcloud/user/user-server/src/main/java/cn/lastwhisper/user/controller/LoginController.java b/distributed/springcloud-netflix/user/user-server/src/main/java/cn/lastwhisper/user/controller/LoginController.java similarity index 100% rename from springcloud/user/user-server/src/main/java/cn/lastwhisper/user/controller/LoginController.java rename to distributed/springcloud-netflix/user/user-server/src/main/java/cn/lastwhisper/user/controller/LoginController.java diff --git a/springcloud/user/user-server/src/main/java/cn/lastwhisper/user/domain/UserInfo.java b/distributed/springcloud-netflix/user/user-server/src/main/java/cn/lastwhisper/user/domain/UserInfo.java similarity index 100% rename from springcloud/user/user-server/src/main/java/cn/lastwhisper/user/domain/UserInfo.java rename to distributed/springcloud-netflix/user/user-server/src/main/java/cn/lastwhisper/user/domain/UserInfo.java diff --git a/springcloud/user/user-server/src/main/java/cn/lastwhisper/user/enums/ResultEnum.java b/distributed/springcloud-netflix/user/user-server/src/main/java/cn/lastwhisper/user/enums/ResultEnum.java similarity index 100% rename from springcloud/user/user-server/src/main/java/cn/lastwhisper/user/enums/ResultEnum.java rename to distributed/springcloud-netflix/user/user-server/src/main/java/cn/lastwhisper/user/enums/ResultEnum.java diff --git a/springcloud/user/user-server/src/main/java/cn/lastwhisper/user/enums/RoleEnum.java b/distributed/springcloud-netflix/user/user-server/src/main/java/cn/lastwhisper/user/enums/RoleEnum.java similarity index 100% rename from springcloud/user/user-server/src/main/java/cn/lastwhisper/user/enums/RoleEnum.java rename to distributed/springcloud-netflix/user/user-server/src/main/java/cn/lastwhisper/user/enums/RoleEnum.java diff --git a/springcloud/user/user-server/src/main/java/cn/lastwhisper/user/repository/UserRepository.java b/distributed/springcloud-netflix/user/user-server/src/main/java/cn/lastwhisper/user/repository/UserRepository.java similarity index 100% rename from springcloud/user/user-server/src/main/java/cn/lastwhisper/user/repository/UserRepository.java rename to distributed/springcloud-netflix/user/user-server/src/main/java/cn/lastwhisper/user/repository/UserRepository.java diff --git a/springcloud/user/user-server/src/main/java/cn/lastwhisper/user/service/UserService.java b/distributed/springcloud-netflix/user/user-server/src/main/java/cn/lastwhisper/user/service/UserService.java similarity index 100% rename from springcloud/user/user-server/src/main/java/cn/lastwhisper/user/service/UserService.java rename to distributed/springcloud-netflix/user/user-server/src/main/java/cn/lastwhisper/user/service/UserService.java diff --git a/springcloud/user/user-server/src/main/java/cn/lastwhisper/user/service/impl/UserServiceImpl.java b/distributed/springcloud-netflix/user/user-server/src/main/java/cn/lastwhisper/user/service/impl/UserServiceImpl.java similarity index 100% rename from springcloud/user/user-server/src/main/java/cn/lastwhisper/user/service/impl/UserServiceImpl.java rename to distributed/springcloud-netflix/user/user-server/src/main/java/cn/lastwhisper/user/service/impl/UserServiceImpl.java diff --git a/springcloud/user/user-server/src/main/java/cn/lastwhisper/user/utils/CookieUtil.java b/distributed/springcloud-netflix/user/user-server/src/main/java/cn/lastwhisper/user/utils/CookieUtil.java similarity index 100% rename from springcloud/user/user-server/src/main/java/cn/lastwhisper/user/utils/CookieUtil.java rename to distributed/springcloud-netflix/user/user-server/src/main/java/cn/lastwhisper/user/utils/CookieUtil.java diff --git a/springcloud/user/user-server/src/main/java/cn/lastwhisper/user/utils/JsonUtil.java b/distributed/springcloud-netflix/user/user-server/src/main/java/cn/lastwhisper/user/utils/JsonUtil.java similarity index 100% rename from springcloud/user/user-server/src/main/java/cn/lastwhisper/user/utils/JsonUtil.java rename to distributed/springcloud-netflix/user/user-server/src/main/java/cn/lastwhisper/user/utils/JsonUtil.java diff --git a/springcloud/user/user-server/src/main/java/cn/lastwhisper/user/utils/ResultVOUtil.java b/distributed/springcloud-netflix/user/user-server/src/main/java/cn/lastwhisper/user/utils/ResultVOUtil.java similarity index 100% rename from springcloud/user/user-server/src/main/java/cn/lastwhisper/user/utils/ResultVOUtil.java rename to distributed/springcloud-netflix/user/user-server/src/main/java/cn/lastwhisper/user/utils/ResultVOUtil.java diff --git a/springcloud/user/user-server/src/main/java/cn/lastwhisper/user/vo/ResultVO.java b/distributed/springcloud-netflix/user/user-server/src/main/java/cn/lastwhisper/user/vo/ResultVO.java similarity index 100% rename from springcloud/user/user-server/src/main/java/cn/lastwhisper/user/vo/ResultVO.java rename to distributed/springcloud-netflix/user/user-server/src/main/java/cn/lastwhisper/user/vo/ResultVO.java diff --git a/springcloud/user/user-server/src/main/resources/bootstrap.yml b/distributed/springcloud-netflix/user/user-server/src/main/resources/bootstrap.yml similarity index 100% rename from springcloud/user/user-server/src/main/resources/bootstrap.yml rename to distributed/springcloud-netflix/user/user-server/src/main/resources/bootstrap.yml diff --git a/springcloud/user/user-server/src/test/java/cn/lastwhisper/test/UserApplicationTests.java b/distributed/springcloud-netflix/user/user-server/src/test/java/cn/lastwhisper/test/UserApplicationTests.java similarity index 100% rename from springcloud/user/user-server/src/test/java/cn/lastwhisper/test/UserApplicationTests.java rename to distributed/springcloud-netflix/user/user-server/src/test/java/cn/lastwhisper/test/UserApplicationTests.java diff --git a/distributed/transaction/README.md b/distributed/transaction/README.md new file mode 100644 index 00000000..6494d044 --- /dev/null +++ b/distributed/transaction/README.md @@ -0,0 +1,5 @@ +分布式事务 + +- demo :产生分布式事务的案例 +- seata-AT-demo:AT模式解决方案 + diff --git a/distributed/transaction/demo/account-service/pom.xml b/distributed/transaction/demo/account-service/pom.xml new file mode 100644 index 00000000..f306a58a --- /dev/null +++ b/distributed/transaction/demo/account-service/pom.xml @@ -0,0 +1,40 @@ + + + + seata-demo + cn.itcast.demo + 1.0-SNAPSHOT + + 4.0.0 + + account-service + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.cloud + spring-cloud-starter-netflix-eureka-client + + + mysql + mysql-connector-java + + + com.baomidou + mybatis-plus-boot-starter + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + \ No newline at end of file diff --git a/distributed/transaction/demo/account-service/src/main/java/cn/itcast/account/AccountApplication.java b/distributed/transaction/demo/account-service/src/main/java/cn/itcast/account/AccountApplication.java new file mode 100644 index 00000000..14674828 --- /dev/null +++ b/distributed/transaction/demo/account-service/src/main/java/cn/itcast/account/AccountApplication.java @@ -0,0 +1,16 @@ +package cn.itcast.account; + +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * @author 虎哥 + */ +@MapperScan("cn.itcast.account.mapper") +@SpringBootApplication +public class AccountApplication { + public static void main(String[] args) { + SpringApplication.run(AccountApplication.class, args); + } +} diff --git a/distributed/transaction/demo/account-service/src/main/java/cn/itcast/account/entity/Account.java b/distributed/transaction/demo/account-service/src/main/java/cn/itcast/account/entity/Account.java new file mode 100644 index 00000000..3ac25e0a --- /dev/null +++ b/distributed/transaction/demo/account-service/src/main/java/cn/itcast/account/entity/Account.java @@ -0,0 +1,17 @@ +package cn.itcast.account.entity; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +/** + * @author 虎哥 + */ +@Data +@TableName("account_tbl") +public class Account { + @TableId + private Long id; + private String userId; + private Integer money; +} diff --git a/distributed/transaction/demo/account-service/src/main/java/cn/itcast/account/mapper/AccountMapper.java b/distributed/transaction/demo/account-service/src/main/java/cn/itcast/account/mapper/AccountMapper.java new file mode 100644 index 00000000..42b2f9b0 --- /dev/null +++ b/distributed/transaction/demo/account-service/src/main/java/cn/itcast/account/mapper/AccountMapper.java @@ -0,0 +1,15 @@ +package cn.itcast.account.mapper; + +import cn.itcast.account.entity.Account; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Update; + +/** + * @author 虎哥 + */ +public interface AccountMapper extends BaseMapper { + + @Update("update account_tbl set money = money - ${money} where user_id = #{userId}") + int debit(@Param("userId") String userId, @Param("money") int money); +} diff --git a/distributed/transaction/demo/account-service/src/main/java/cn/itcast/account/service/AccountService.java b/distributed/transaction/demo/account-service/src/main/java/cn/itcast/account/service/AccountService.java new file mode 100644 index 00000000..7b5123ad --- /dev/null +++ b/distributed/transaction/demo/account-service/src/main/java/cn/itcast/account/service/AccountService.java @@ -0,0 +1,8 @@ +package cn.itcast.account.service; + +public interface AccountService { + /** + * 从用户账户中借出 + */ + void debit(String userId, int money); +} \ No newline at end of file diff --git a/distributed/transaction/demo/account-service/src/main/java/cn/itcast/account/service/impl/AccountServiceImpl.java b/distributed/transaction/demo/account-service/src/main/java/cn/itcast/account/service/impl/AccountServiceImpl.java new file mode 100644 index 00000000..5deb5dbe --- /dev/null +++ b/distributed/transaction/demo/account-service/src/main/java/cn/itcast/account/service/impl/AccountServiceImpl.java @@ -0,0 +1,32 @@ +package cn.itcast.account.service.impl; + +import cn.itcast.account.mapper.AccountMapper; +import cn.itcast.account.service.AccountService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +/** + * @author 虎哥 + */ +@Slf4j +@Service +public class AccountServiceImpl implements AccountService { + private final AccountMapper accountMapper; + + public AccountServiceImpl(AccountMapper accountMapper) { + this.accountMapper = accountMapper; + } + + @Override + @Transactional + public void debit(String userId, int money) { + log.info("开始扣款"); + try { + accountMapper.debit(userId, money); + } catch (Exception e) { + throw new RuntimeException("扣款失败,可能是余额不足!"); + } + log.info("扣款成功"); + } +} diff --git a/distributed/transaction/demo/account-service/src/main/java/cn/itcast/account/web/AccountController.java b/distributed/transaction/demo/account-service/src/main/java/cn/itcast/account/web/AccountController.java new file mode 100644 index 00000000..0be5d75d --- /dev/null +++ b/distributed/transaction/demo/account-service/src/main/java/cn/itcast/account/web/AccountController.java @@ -0,0 +1,28 @@ +package cn.itcast.account.web; + +import cn.itcast.account.service.AccountService; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * @author 虎哥 + */ +@RestController +@RequestMapping("account") +public class AccountController { + + private final AccountService accountService; + + public AccountController(AccountService accountService) { + this.accountService = accountService; + } + + @PutMapping("/{userId}/{money}") + public ResponseEntity debit(@PathVariable("userId") String userId, @PathVariable("money") Integer money){ + accountService.debit(userId, money); + return ResponseEntity.noContent().build(); + } +} diff --git a/distributed/transaction/demo/account-service/src/main/resources/application.yml b/distributed/transaction/demo/account-service/src/main/resources/application.yml new file mode 100644 index 00000000..356a1476 --- /dev/null +++ b/distributed/transaction/demo/account-service/src/main/resources/application.yml @@ -0,0 +1,24 @@ +server: + port: 8083 +spring: + application: + name: account-service + datasource: + driver-class-name: com.mysql.jdbc.Driver + url: jdbc:mysql:///seata_demo?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&useSSL=false + username: root + password: 123456 +eureka: + client: + service-url: + defaultZone: http://127.0.0.1:8761/eureka +mybatis-plus: + global-config: + db-config: + insert-strategy: not_null + update-strategy: not_null + id-type: auto +logging: + level: + org.springframework.cloud.alibaba.seata.web: debug + cn.itcast: debug \ No newline at end of file diff --git a/distributed/transaction/demo/eureka-server/pom.xml b/distributed/transaction/demo/eureka-server/pom.xml new file mode 100644 index 00000000..f65149d5 --- /dev/null +++ b/distributed/transaction/demo/eureka-server/pom.xml @@ -0,0 +1,28 @@ + + + + seata-demo + cn.itcast.demo + 1.0-SNAPSHOT + + 4.0.0 + + eureka-server + + + + org.springframework.cloud + spring-cloud-starter-netflix-eureka-server + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + \ No newline at end of file diff --git a/distributed/transaction/demo/eureka-server/src/main/java/cn/itcast/eureka/EurekaApplication.java b/distributed/transaction/demo/eureka-server/src/main/java/cn/itcast/eureka/EurekaApplication.java new file mode 100644 index 00000000..3d13ae11 --- /dev/null +++ b/distributed/transaction/demo/eureka-server/src/main/java/cn/itcast/eureka/EurekaApplication.java @@ -0,0 +1,16 @@ +package cn.itcast.eureka; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; + +/** + * @author 虎哥 + */ +@EnableEurekaServer +@SpringBootApplication +public class EurekaApplication { + public static void main(String[] args) { + SpringApplication.run(EurekaApplication.class, args); + } +} diff --git a/distributed/transaction/demo/eureka-server/src/main/resources/application.yml b/distributed/transaction/demo/eureka-server/src/main/resources/application.yml new file mode 100644 index 00000000..cf2ce780 --- /dev/null +++ b/distributed/transaction/demo/eureka-server/src/main/resources/application.yml @@ -0,0 +1,14 @@ +server: + port: 8761 +spring: + application: + name: eureka-server +ribbon: + eureka: + enabled: true +eureka: + client: + registerWithEureka: false + fetchRegistry: false + serviceUrl: + defaultZone: http://localhost:${server.port}/eureka/ \ No newline at end of file diff --git a/distributed/transaction/demo/order-service/pom.xml b/distributed/transaction/demo/order-service/pom.xml new file mode 100644 index 00000000..4272ff39 --- /dev/null +++ b/distributed/transaction/demo/order-service/pom.xml @@ -0,0 +1,44 @@ + + + + seata-demo + cn.itcast.demo + 1.0-SNAPSHOT + + 4.0.0 + + order-service + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.cloud + spring-cloud-starter-netflix-eureka-client + + + mysql + mysql-connector-java + + + com.baomidou + mybatis-plus-boot-starter + + + org.springframework.cloud + spring-cloud-starter-openfeign + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + \ No newline at end of file diff --git a/distributed/transaction/demo/order-service/src/main/java/cn/itcast/order/OrderApplication.java b/distributed/transaction/demo/order-service/src/main/java/cn/itcast/order/OrderApplication.java new file mode 100644 index 00000000..42c9661d --- /dev/null +++ b/distributed/transaction/demo/order-service/src/main/java/cn/itcast/order/OrderApplication.java @@ -0,0 +1,18 @@ +package cn.itcast.order; + +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.openfeign.EnableFeignClients; + +/** + * @author 虎哥 + */ +@MapperScan("cn.itcast.order.mapper") +@EnableFeignClients +@SpringBootApplication +public class OrderApplication { + public static void main(String[] args) { + SpringApplication.run(OrderApplication.class, args); + } +} diff --git a/distributed/transaction/demo/order-service/src/main/java/cn/itcast/order/client/AccountClient.java b/distributed/transaction/demo/order-service/src/main/java/cn/itcast/order/client/AccountClient.java new file mode 100644 index 00000000..6efb7039 --- /dev/null +++ b/distributed/transaction/demo/order-service/src/main/java/cn/itcast/order/client/AccountClient.java @@ -0,0 +1,15 @@ +package cn.itcast.order.client; + +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PutMapping; + +/** + * @author 虎哥 + */ +@FeignClient("account-service") +public interface AccountClient { + + @PutMapping("/account/{userId}/{money}") + void debit(@PathVariable("userId") String userId, @PathVariable("money") Integer money); +} diff --git a/distributed/transaction/demo/order-service/src/main/java/cn/itcast/order/client/StorageClient.java b/distributed/transaction/demo/order-service/src/main/java/cn/itcast/order/client/StorageClient.java new file mode 100644 index 00000000..5ae5deae --- /dev/null +++ b/distributed/transaction/demo/order-service/src/main/java/cn/itcast/order/client/StorageClient.java @@ -0,0 +1,14 @@ +package cn.itcast.order.client; + +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PutMapping; + +/** + * @author 虎哥 + */ +@FeignClient("storage-service") +public interface StorageClient { + @PutMapping("/storage/{code}/{count}") + void deduct(@PathVariable("code") String code, @PathVariable("count") Integer count); +} diff --git a/distributed/transaction/demo/order-service/src/main/java/cn/itcast/order/entity/Order.java b/distributed/transaction/demo/order-service/src/main/java/cn/itcast/order/entity/Order.java new file mode 100644 index 00000000..b71c2560 --- /dev/null +++ b/distributed/transaction/demo/order-service/src/main/java/cn/itcast/order/entity/Order.java @@ -0,0 +1,20 @@ +package cn.itcast.order.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +/** + * @author 虎哥 + */ +@Data +@TableName("order_tbl") +public class Order { + @TableId(type = IdType.AUTO) + private Long id; + private String userId; + private String commodityCode; + private Integer count; + private Integer money; +} diff --git a/distributed/transaction/demo/order-service/src/main/java/cn/itcast/order/mapper/OrderMapper.java b/distributed/transaction/demo/order-service/src/main/java/cn/itcast/order/mapper/OrderMapper.java new file mode 100644 index 00000000..b90f5993 --- /dev/null +++ b/distributed/transaction/demo/order-service/src/main/java/cn/itcast/order/mapper/OrderMapper.java @@ -0,0 +1,10 @@ +package cn.itcast.order.mapper; + +import cn.itcast.order.entity.Order; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + * @author 虎哥 + */ +public interface OrderMapper extends BaseMapper { +} diff --git a/distributed/transaction/demo/order-service/src/main/java/cn/itcast/order/service/OrderService.java b/distributed/transaction/demo/order-service/src/main/java/cn/itcast/order/service/OrderService.java new file mode 100644 index 00000000..3063dad1 --- /dev/null +++ b/distributed/transaction/demo/order-service/src/main/java/cn/itcast/order/service/OrderService.java @@ -0,0 +1,11 @@ +package cn.itcast.order.service; + +import cn.itcast.order.entity.Order; + +public interface OrderService { + + /** + * 创建订单 + */ + Long create(Order order); +} \ No newline at end of file diff --git a/distributed/transaction/demo/order-service/src/main/java/cn/itcast/order/service/impl/OrderServiceImpl.java b/distributed/transaction/demo/order-service/src/main/java/cn/itcast/order/service/impl/OrderServiceImpl.java new file mode 100644 index 00000000..1192654b --- /dev/null +++ b/distributed/transaction/demo/order-service/src/main/java/cn/itcast/order/service/impl/OrderServiceImpl.java @@ -0,0 +1,46 @@ +package cn.itcast.order.service.impl; + +import cn.itcast.order.client.AccountClient; +import cn.itcast.order.client.StorageClient; +import cn.itcast.order.entity.Order; +import cn.itcast.order.mapper.OrderMapper; +import cn.itcast.order.service.OrderService; +import feign.FeignException; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +/** + * @author 虎哥 + */ +@Slf4j +@Service +public class OrderServiceImpl implements OrderService { + + private final AccountClient accountClient; + private final StorageClient storageClient; + private final OrderMapper orderMapper; + + public OrderServiceImpl(AccountClient accountClient, StorageClient storageClient, OrderMapper orderMapper) { + this.accountClient = accountClient; + this.storageClient = storageClient; + this.orderMapper = orderMapper; + } + + @Override + @Transactional + public Long create(Order order) { + // 创建订单 + orderMapper.insert(order); + try { + // 扣库存 + storageClient.deduct(order.getCommodityCode(), order.getCount()); + // 扣款 + accountClient.debit(order.getUserId(), order.getMoney()); + } catch (FeignException e) { + log.error("下单失败,原因:{}", e.contentUTF8()); + throw new RuntimeException(e.contentUTF8()); + } + return order.getId(); + } +} diff --git a/distributed/transaction/demo/order-service/src/main/java/cn/itcast/order/web/OrderController.java b/distributed/transaction/demo/order-service/src/main/java/cn/itcast/order/web/OrderController.java new file mode 100644 index 00000000..fcfb48c5 --- /dev/null +++ b/distributed/transaction/demo/order-service/src/main/java/cn/itcast/order/web/OrderController.java @@ -0,0 +1,29 @@ +package cn.itcast.order.web; + +import cn.itcast.order.entity.Order; +import cn.itcast.order.service.OrderService; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * @author 虎哥 + */ +@RestController +@RequestMapping("order") +public class OrderController { + + private final OrderService orderService; + + public OrderController(OrderService orderService) { + this.orderService = orderService; + } + + @PostMapping + public ResponseEntity createOrder(Order order){ + Long orderId = orderService.create(order); + return ResponseEntity.status(HttpStatus.CREATED).body(orderId); + } +} diff --git a/distributed/transaction/demo/order-service/src/main/resources/application.yml b/distributed/transaction/demo/order-service/src/main/resources/application.yml new file mode 100644 index 00000000..44f65362 --- /dev/null +++ b/distributed/transaction/demo/order-service/src/main/resources/application.yml @@ -0,0 +1,27 @@ +server: + port: 8082 +spring: + application: + name: order-service + datasource: + driver-class-name: com.mysql.jdbc.Driver + url: jdbc:mysql:///seata_demo?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&useSSL=false + username: root + password: 123456 +eureka: + client: + service-url: + defaultZone: http://127.0.0.1:8761/eureka + instance: + prefer-ip-address: true + hostname: 127.0.0.1 +mybatis-plus: + global-config: + db-config: + insert-strategy: not_null + update-strategy: not_null + id-type: auto +logging: + level: + org.springframework.cloud.alibaba.seata.web: debug + cn.itcast: debug \ No newline at end of file diff --git a/distributed/transaction/demo/pom.xml b/distributed/transaction/demo/pom.xml new file mode 100644 index 00000000..7459ded2 --- /dev/null +++ b/distributed/transaction/demo/pom.xml @@ -0,0 +1,93 @@ + + + 4.0.0 + + cn.itcast.demo + seata-demo + 1.0-SNAPSHOT + + storage-service + account-service + order-service + eureka-server + + pom + + + org.springframework.boot + spring-boot-starter-parent + 2.1.12.RELEASE + + + + + UTF-8 + UTF-8 + 1.8 + Greenwich.SR5 + 3.3.0 + 5.1.47 + 2.1.0.RELEASE + 1.1.0 + + + + + + + org.springframework.cloud + spring-cloud-dependencies + ${spring-cloud.version} + pom + import + + + + mysql + mysql-connector-java + ${mysql.version} + + + com.baomidou + mybatis-plus-boot-starter + ${mybatis.plus.version} + + + com.alibaba.cloud + spring-cloud-alibaba-seata + ${alibaba.seata.version} + + + seata-all + io.seata + + + + + seata-all + io.seata + ${seata.version} + + + + + + + org.apache.commons + commons-lang3 + 3.4 + + + org.projectlombok + lombok + + + + org.springframework.boot + spring-boot-starter-test + test + + + \ No newline at end of file diff --git a/distributed/transaction/demo/storage-service/pom.xml b/distributed/transaction/demo/storage-service/pom.xml new file mode 100644 index 00000000..3c9d9958 --- /dev/null +++ b/distributed/transaction/demo/storage-service/pom.xml @@ -0,0 +1,40 @@ + + + + seata-demo + cn.itcast.demo + 1.0-SNAPSHOT + + 4.0.0 + + storage-service + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.cloud + spring-cloud-starter-netflix-eureka-client + + + mysql + mysql-connector-java + + + com.baomidou + mybatis-plus-boot-starter + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + \ No newline at end of file diff --git a/distributed/transaction/demo/storage-service/src/main/java/cn/itcast/storage/StorageApplication.java b/distributed/transaction/demo/storage-service/src/main/java/cn/itcast/storage/StorageApplication.java new file mode 100644 index 00000000..52310a96 --- /dev/null +++ b/distributed/transaction/demo/storage-service/src/main/java/cn/itcast/storage/StorageApplication.java @@ -0,0 +1,16 @@ +package cn.itcast.storage; + +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * @author 虎哥 + */ +@MapperScan("cn.itcast.storage.mapper") +@SpringBootApplication +public class StorageApplication { + public static void main(String[] args) { + SpringApplication.run(StorageApplication.class, args); + } +} diff --git a/distributed/transaction/demo/storage-service/src/main/java/cn/itcast/storage/entity/Storage.java b/distributed/transaction/demo/storage-service/src/main/java/cn/itcast/storage/entity/Storage.java new file mode 100644 index 00000000..c96afff7 --- /dev/null +++ b/distributed/transaction/demo/storage-service/src/main/java/cn/itcast/storage/entity/Storage.java @@ -0,0 +1,17 @@ +package cn.itcast.storage.entity; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +/** + * @author 虎哥 + */ +@Data +@TableName("storage_tbl") +public class Storage { + @TableId + private Long id; + private String commodityCode; + private Integer count; +} diff --git a/distributed/transaction/demo/storage-service/src/main/java/cn/itcast/storage/mapper/StorageMapper.java b/distributed/transaction/demo/storage-service/src/main/java/cn/itcast/storage/mapper/StorageMapper.java new file mode 100644 index 00000000..afea1ee2 --- /dev/null +++ b/distributed/transaction/demo/storage-service/src/main/java/cn/itcast/storage/mapper/StorageMapper.java @@ -0,0 +1,14 @@ +package cn.itcast.storage.mapper; + +import cn.itcast.storage.entity.Storage; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Update; + +/** + * @author 虎哥 + */ +public interface StorageMapper extends BaseMapper { + @Update("update storage_tbl set `count` = `count` - #{count} where commodity_code = #{code}") + int deduct(@Param("code") String commodityCode, @Param("count") int count); +} diff --git a/distributed/transaction/demo/storage-service/src/main/java/cn/itcast/storage/service/StorageService.java b/distributed/transaction/demo/storage-service/src/main/java/cn/itcast/storage/service/StorageService.java new file mode 100644 index 00000000..e0b594af --- /dev/null +++ b/distributed/transaction/demo/storage-service/src/main/java/cn/itcast/storage/service/StorageService.java @@ -0,0 +1,9 @@ +package cn.itcast.storage.service; + +public interface StorageService{ + + /** + * 扣除存储数量 + */ + void deduct(String commodityCode, int count); +} \ No newline at end of file diff --git a/distributed/transaction/demo/storage-service/src/main/java/cn/itcast/storage/service/impl/StorageServiceImpl.java b/distributed/transaction/demo/storage-service/src/main/java/cn/itcast/storage/service/impl/StorageServiceImpl.java new file mode 100644 index 00000000..7d430da0 --- /dev/null +++ b/distributed/transaction/demo/storage-service/src/main/java/cn/itcast/storage/service/impl/StorageServiceImpl.java @@ -0,0 +1,31 @@ +package cn.itcast.storage.service.impl; + +import cn.itcast.storage.mapper.StorageMapper; +import cn.itcast.storage.service.StorageService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +/** + * @author 虎哥 + */ +@Slf4j +@Service +public class StorageServiceImpl implements StorageService { + + @Autowired + private StorageMapper storageMapper; + + @Transactional + @Override + public void deduct(String commodityCode, int count) { + log.info("开始扣减库存"); + try { + storageMapper.deduct(commodityCode, count); + } catch (Exception e) { + throw new RuntimeException("扣减库存失败,可能是库存不足!"); + } + log.info("扣减库存成功"); + } +} diff --git a/distributed/transaction/demo/storage-service/src/main/java/cn/itcast/storage/web/StorageController.java b/distributed/transaction/demo/storage-service/src/main/java/cn/itcast/storage/web/StorageController.java new file mode 100644 index 00000000..1e953e76 --- /dev/null +++ b/distributed/transaction/demo/storage-service/src/main/java/cn/itcast/storage/web/StorageController.java @@ -0,0 +1,34 @@ +package cn.itcast.storage.web; + +import cn.itcast.storage.service.StorageService; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * @author 虎哥 + */ +@RestController +@RequestMapping("storage") +public class StorageController { + + private final StorageService storageService; + + public StorageController(StorageService storageService) { + this.storageService = storageService; + } + + /** + * 扣减库存 + * @param code 商品编号 + * @param count 要扣减的数量 + * @return 无 + */ + @PutMapping("/{code}/{count}") + public ResponseEntity deduct(@PathVariable("code") String code,@PathVariable("count") Integer count){ + storageService.deduct(code, count); + return ResponseEntity.noContent().build(); + } +} diff --git a/distributed/transaction/demo/storage-service/src/main/resources/application.yml b/distributed/transaction/demo/storage-service/src/main/resources/application.yml new file mode 100644 index 00000000..277e7f31 --- /dev/null +++ b/distributed/transaction/demo/storage-service/src/main/resources/application.yml @@ -0,0 +1,24 @@ +server: + port: 8081 +spring: + application: + name: storage-service + datasource: + driver-class-name: com.mysql.jdbc.Driver + url: jdbc:mysql:///seata_demo?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&useSSL=false + username: root + password: 123456 +eureka: + client: + service-url: + defaultZone: http://127.0.0.1:8761/eureka +mybatis-plus: + global-config: + db-config: + insert-strategy: not_null + update-strategy: not_null + id-type: auto +logging: + level: + org.springframework.cloud.alibaba.seata.web: debug + cn.itcast: debug \ No newline at end of file diff --git a/distributed/transaction/seata-AT-demo/account-service/pom.xml b/distributed/transaction/seata-AT-demo/account-service/pom.xml new file mode 100644 index 00000000..15d62906 --- /dev/null +++ b/distributed/transaction/seata-AT-demo/account-service/pom.xml @@ -0,0 +1,56 @@ + + + + seata-demo + cn.itcast.demo + 1.0-SNAPSHOT + + 4.0.0 + + account-service + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.cloud + spring-cloud-starter-netflix-eureka-client + + + mysql + mysql-connector-java + + + com.baomidou + mybatis-plus-boot-starter + + + com.alibaba.cloud + spring-cloud-alibaba-seata + ${alibaba.seata.version} + + + seata-all + io.seata + + + + + seata-all + io.seata + ${seata.version} + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + \ No newline at end of file diff --git a/distributed/transaction/seata-AT-demo/account-service/src/main/java/cn/itcast/account/AccountApplication.java b/distributed/transaction/seata-AT-demo/account-service/src/main/java/cn/itcast/account/AccountApplication.java new file mode 100644 index 00000000..14674828 --- /dev/null +++ b/distributed/transaction/seata-AT-demo/account-service/src/main/java/cn/itcast/account/AccountApplication.java @@ -0,0 +1,16 @@ +package cn.itcast.account; + +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * @author 虎哥 + */ +@MapperScan("cn.itcast.account.mapper") +@SpringBootApplication +public class AccountApplication { + public static void main(String[] args) { + SpringApplication.run(AccountApplication.class, args); + } +} diff --git a/distributed/transaction/seata-AT-demo/account-service/src/main/java/cn/itcast/account/config/DataSourceProxyConfig.java b/distributed/transaction/seata-AT-demo/account-service/src/main/java/cn/itcast/account/config/DataSourceProxyConfig.java new file mode 100644 index 00000000..27c4157d --- /dev/null +++ b/distributed/transaction/seata-AT-demo/account-service/src/main/java/cn/itcast/account/config/DataSourceProxyConfig.java @@ -0,0 +1,22 @@ +package cn.itcast.account.config; + +import io.seata.rm.datasource.DataSourceProxy; +import org.apache.ibatis.session.SqlSessionFactory; +import org.mybatis.spring.SqlSessionFactoryBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import javax.sql.DataSource; + +@Configuration +public class DataSourceProxyConfig { + + @Bean + public SqlSessionFactory sqlSessionFactoryBean(DataSource dataSource) throws Exception { + // 因为使用的是mybatis,这里定义SqlSessionFactoryBean + SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean(); + // 配置数据源代理 + sqlSessionFactoryBean.setDataSource(new DataSourceProxy(dataSource)); + return sqlSessionFactoryBean.getObject(); + } +} \ No newline at end of file diff --git a/distributed/transaction/seata-AT-demo/account-service/src/main/java/cn/itcast/account/entity/Account.java b/distributed/transaction/seata-AT-demo/account-service/src/main/java/cn/itcast/account/entity/Account.java new file mode 100644 index 00000000..3ac25e0a --- /dev/null +++ b/distributed/transaction/seata-AT-demo/account-service/src/main/java/cn/itcast/account/entity/Account.java @@ -0,0 +1,17 @@ +package cn.itcast.account.entity; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +/** + * @author 虎哥 + */ +@Data +@TableName("account_tbl") +public class Account { + @TableId + private Long id; + private String userId; + private Integer money; +} diff --git a/distributed/transaction/seata-AT-demo/account-service/src/main/java/cn/itcast/account/mapper/AccountMapper.java b/distributed/transaction/seata-AT-demo/account-service/src/main/java/cn/itcast/account/mapper/AccountMapper.java new file mode 100644 index 00000000..42b2f9b0 --- /dev/null +++ b/distributed/transaction/seata-AT-demo/account-service/src/main/java/cn/itcast/account/mapper/AccountMapper.java @@ -0,0 +1,15 @@ +package cn.itcast.account.mapper; + +import cn.itcast.account.entity.Account; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Update; + +/** + * @author 虎哥 + */ +public interface AccountMapper extends BaseMapper { + + @Update("update account_tbl set money = money - ${money} where user_id = #{userId}") + int debit(@Param("userId") String userId, @Param("money") int money); +} diff --git a/distributed/transaction/seata-AT-demo/account-service/src/main/java/cn/itcast/account/service/AccountService.java b/distributed/transaction/seata-AT-demo/account-service/src/main/java/cn/itcast/account/service/AccountService.java new file mode 100644 index 00000000..7b5123ad --- /dev/null +++ b/distributed/transaction/seata-AT-demo/account-service/src/main/java/cn/itcast/account/service/AccountService.java @@ -0,0 +1,8 @@ +package cn.itcast.account.service; + +public interface AccountService { + /** + * 从用户账户中借出 + */ + void debit(String userId, int money); +} \ No newline at end of file diff --git a/distributed/transaction/seata-AT-demo/account-service/src/main/java/cn/itcast/account/service/impl/AccountServiceImpl.java b/distributed/transaction/seata-AT-demo/account-service/src/main/java/cn/itcast/account/service/impl/AccountServiceImpl.java new file mode 100644 index 00000000..5deb5dbe --- /dev/null +++ b/distributed/transaction/seata-AT-demo/account-service/src/main/java/cn/itcast/account/service/impl/AccountServiceImpl.java @@ -0,0 +1,32 @@ +package cn.itcast.account.service.impl; + +import cn.itcast.account.mapper.AccountMapper; +import cn.itcast.account.service.AccountService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +/** + * @author 虎哥 + */ +@Slf4j +@Service +public class AccountServiceImpl implements AccountService { + private final AccountMapper accountMapper; + + public AccountServiceImpl(AccountMapper accountMapper) { + this.accountMapper = accountMapper; + } + + @Override + @Transactional + public void debit(String userId, int money) { + log.info("开始扣款"); + try { + accountMapper.debit(userId, money); + } catch (Exception e) { + throw new RuntimeException("扣款失败,可能是余额不足!"); + } + log.info("扣款成功"); + } +} diff --git a/distributed/transaction/seata-AT-demo/account-service/src/main/java/cn/itcast/account/web/AccountController.java b/distributed/transaction/seata-AT-demo/account-service/src/main/java/cn/itcast/account/web/AccountController.java new file mode 100644 index 00000000..0be5d75d --- /dev/null +++ b/distributed/transaction/seata-AT-demo/account-service/src/main/java/cn/itcast/account/web/AccountController.java @@ -0,0 +1,28 @@ +package cn.itcast.account.web; + +import cn.itcast.account.service.AccountService; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * @author 虎哥 + */ +@RestController +@RequestMapping("account") +public class AccountController { + + private final AccountService accountService; + + public AccountController(AccountService accountService) { + this.accountService = accountService; + } + + @PutMapping("/{userId}/{money}") + public ResponseEntity debit(@PathVariable("userId") String userId, @PathVariable("money") Integer money){ + accountService.debit(userId, money); + return ResponseEntity.noContent().build(); + } +} diff --git a/distributed/transaction/seata-AT-demo/account-service/src/main/resources/application.yml b/distributed/transaction/seata-AT-demo/account-service/src/main/resources/application.yml new file mode 100644 index 00000000..4c669ca1 --- /dev/null +++ b/distributed/transaction/seata-AT-demo/account-service/src/main/resources/application.yml @@ -0,0 +1,29 @@ +server: + port: 8083 +spring: + application: + name: account-service + datasource: + driver-class-name: com.mysql.jdbc.Driver + url: jdbc:mysql:///seata_demo?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&useSSL=false + username: root + password: 123456 + cloud: + alibaba: + seata: + tx-service-group: test_tx_group # 定义事务组的名称 + +eureka: + client: + service-url: + defaultZone: http://127.0.0.1:8761/eureka +mybatis-plus: + global-config: + db-config: + insert-strategy: not_null + update-strategy: not_null + id-type: auto +logging: + level: + org.springframework.cloud.alibaba.seata.web: debug + cn.itcast: debug \ No newline at end of file diff --git a/distributed/transaction/seata-AT-demo/account-service/src/main/resources/file.conf b/distributed/transaction/seata-AT-demo/account-service/src/main/resources/file.conf new file mode 100644 index 00000000..3103c110 --- /dev/null +++ b/distributed/transaction/seata-AT-demo/account-service/src/main/resources/file.conf @@ -0,0 +1,65 @@ +transport { + # tcp udt unix-domain-socket + type = "TCP" + #NIO NATIVE + server = "NIO" + #enable heartbeat + heartbeat = true + # the client batch send request enable + enableClientBatchSendRequest = true + #thread factory for netty + threadFactory { + bossThreadPrefix = "NettyBoss" + workerThreadPrefix = "NettyServerNIOWorker" + serverExecutorThread-prefix = "NettyServerBizHandler" + shareBossWorker = false + clientSelectorThreadPrefix = "NettyClientSelector" + clientSelectorThreadSize = 1 + clientWorkerThreadPrefix = "NettyClientWorkerThread" + # netty boss thread size,will not be used for UDT + bossThreadSize = 1 + #auto default pin or 8 + workerThreadSize = "default" + } + shutdown { + # when destroy server, wait seconds + wait = 3 + } + serialization = "seata" + compressor = "none" +} +service { + vgroupMapping.test_tx_group = "seata_tc_server" + #only support when registry.type=file, please don't set multiple addresses + seata_tc_server.grouplist = "127.0.0.1:8091" + #degrade, current not support + enableDegrade = false + #disable seata + disableGlobalTransaction = false +} + +client { + rm { + asyncCommitBufferLimit = 10000 + lock { + retryInterval = 10 + retryTimes = 30 + retryPolicyBranchRollbackOnConflict = true + } + reportRetryCount = 5 + tableMetaCheckEnable = false + reportSuccessEnable = false + } + tm { + commitRetryCount = 5 + rollbackRetryCount = 5 + } + undo { + dataValidation = true + logSerialization = "jackson" + logTable = "undo_log" + } + log { + exceptionRate = 100 + } +} \ No newline at end of file diff --git a/distributed/transaction/seata-AT-demo/account-service/src/main/resources/registry.conf b/distributed/transaction/seata-AT-demo/account-service/src/main/resources/registry.conf new file mode 100644 index 00000000..0e8a8659 --- /dev/null +++ b/distributed/transaction/seata-AT-demo/account-service/src/main/resources/registry.conf @@ -0,0 +1,34 @@ +registry { + # 指定注册中心类型,这里使用eureka类型 + type = "eureka" + # 各种注册中心的配置。。这里省略,只保留了eureka和Zookeeper + eureka { + serviceUrl = "http://localhost:8761/eureka" + application = "seata_tc_server" + weight = "1" + } + zk { + cluster = "default" + serverAddr = "127.0.0.1:2181" + session.timeout = 6000 + connect.timeout = 2000 + } +} + +config { + # 配置文件方式,可以支持 file、nacos 、apollo、zk、consul、etcd3 + type = "file" + nacos { + serverAddr = "localhost" + namespace = "" + group = "SEATA_GROUP" + } + zk { + serverAddr = "127.0.0.1:2181" + session.timeout = 6000 + connect.timeout = 2000 + } + file { + name = "file.conf" + } +} \ No newline at end of file diff --git a/distributed/transaction/seata-AT-demo/eureka-server/pom.xml b/distributed/transaction/seata-AT-demo/eureka-server/pom.xml new file mode 100644 index 00000000..f65149d5 --- /dev/null +++ b/distributed/transaction/seata-AT-demo/eureka-server/pom.xml @@ -0,0 +1,28 @@ + + + + seata-demo + cn.itcast.demo + 1.0-SNAPSHOT + + 4.0.0 + + eureka-server + + + + org.springframework.cloud + spring-cloud-starter-netflix-eureka-server + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + \ No newline at end of file diff --git a/distributed/transaction/seata-AT-demo/eureka-server/src/main/java/cn/itcast/eureka/EurekaApplication.java b/distributed/transaction/seata-AT-demo/eureka-server/src/main/java/cn/itcast/eureka/EurekaApplication.java new file mode 100644 index 00000000..3d13ae11 --- /dev/null +++ b/distributed/transaction/seata-AT-demo/eureka-server/src/main/java/cn/itcast/eureka/EurekaApplication.java @@ -0,0 +1,16 @@ +package cn.itcast.eureka; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; + +/** + * @author 虎哥 + */ +@EnableEurekaServer +@SpringBootApplication +public class EurekaApplication { + public static void main(String[] args) { + SpringApplication.run(EurekaApplication.class, args); + } +} diff --git a/distributed/transaction/seata-AT-demo/eureka-server/src/main/resources/application.yml b/distributed/transaction/seata-AT-demo/eureka-server/src/main/resources/application.yml new file mode 100644 index 00000000..cf2ce780 --- /dev/null +++ b/distributed/transaction/seata-AT-demo/eureka-server/src/main/resources/application.yml @@ -0,0 +1,14 @@ +server: + port: 8761 +spring: + application: + name: eureka-server +ribbon: + eureka: + enabled: true +eureka: + client: + registerWithEureka: false + fetchRegistry: false + serviceUrl: + defaultZone: http://localhost:${server.port}/eureka/ \ No newline at end of file diff --git a/distributed/transaction/seata-AT-demo/order-service/pom.xml b/distributed/transaction/seata-AT-demo/order-service/pom.xml new file mode 100644 index 00000000..bac29e00 --- /dev/null +++ b/distributed/transaction/seata-AT-demo/order-service/pom.xml @@ -0,0 +1,61 @@ + + + + seata-demo + cn.itcast.demo + 1.0-SNAPSHOT + + 4.0.0 + + order-service + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.cloud + spring-cloud-starter-netflix-eureka-client + + + mysql + mysql-connector-java + + + com.baomidou + mybatis-plus-boot-starter + + + org.springframework.cloud + spring-cloud-starter-openfeign + + + + com.alibaba.cloud + spring-cloud-alibaba-seata + ${alibaba.seata.version} + + + seata-all + io.seata + + + + + seata-all + io.seata + ${seata.version} + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + \ No newline at end of file diff --git a/distributed/transaction/seata-AT-demo/order-service/src/main/java/cn/itcast/order/OrderApplication.java b/distributed/transaction/seata-AT-demo/order-service/src/main/java/cn/itcast/order/OrderApplication.java new file mode 100644 index 00000000..42c9661d --- /dev/null +++ b/distributed/transaction/seata-AT-demo/order-service/src/main/java/cn/itcast/order/OrderApplication.java @@ -0,0 +1,18 @@ +package cn.itcast.order; + +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.openfeign.EnableFeignClients; + +/** + * @author 虎哥 + */ +@MapperScan("cn.itcast.order.mapper") +@EnableFeignClients +@SpringBootApplication +public class OrderApplication { + public static void main(String[] args) { + SpringApplication.run(OrderApplication.class, args); + } +} diff --git a/distributed/transaction/seata-AT-demo/order-service/src/main/java/cn/itcast/order/client/AccountClient.java b/distributed/transaction/seata-AT-demo/order-service/src/main/java/cn/itcast/order/client/AccountClient.java new file mode 100644 index 00000000..6efb7039 --- /dev/null +++ b/distributed/transaction/seata-AT-demo/order-service/src/main/java/cn/itcast/order/client/AccountClient.java @@ -0,0 +1,15 @@ +package cn.itcast.order.client; + +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PutMapping; + +/** + * @author 虎哥 + */ +@FeignClient("account-service") +public interface AccountClient { + + @PutMapping("/account/{userId}/{money}") + void debit(@PathVariable("userId") String userId, @PathVariable("money") Integer money); +} diff --git a/distributed/transaction/seata-AT-demo/order-service/src/main/java/cn/itcast/order/client/StorageClient.java b/distributed/transaction/seata-AT-demo/order-service/src/main/java/cn/itcast/order/client/StorageClient.java new file mode 100644 index 00000000..5ae5deae --- /dev/null +++ b/distributed/transaction/seata-AT-demo/order-service/src/main/java/cn/itcast/order/client/StorageClient.java @@ -0,0 +1,14 @@ +package cn.itcast.order.client; + +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PutMapping; + +/** + * @author 虎哥 + */ +@FeignClient("storage-service") +public interface StorageClient { + @PutMapping("/storage/{code}/{count}") + void deduct(@PathVariable("code") String code, @PathVariable("count") Integer count); +} diff --git a/distributed/transaction/seata-AT-demo/order-service/src/main/java/cn/itcast/order/config/DataSourceProxyConfig.java b/distributed/transaction/seata-AT-demo/order-service/src/main/java/cn/itcast/order/config/DataSourceProxyConfig.java new file mode 100644 index 00000000..840ff68c --- /dev/null +++ b/distributed/transaction/seata-AT-demo/order-service/src/main/java/cn/itcast/order/config/DataSourceProxyConfig.java @@ -0,0 +1,23 @@ +package cn.itcast.order.config; + +import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean; +import io.seata.rm.datasource.DataSourceProxy; +import org.apache.ibatis.session.SqlSessionFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import javax.sql.DataSource; + +@Configuration +public class DataSourceProxyConfig { + + @Bean + public SqlSessionFactory sqlSessionFactoryBean(DataSource dataSource) throws Exception { + // 订单服务中引入了mybatis-plus,所以要使用特殊的SqlSessionFactoryBean + MybatisSqlSessionFactoryBean sqlSessionFactoryBean = new MybatisSqlSessionFactoryBean(); + // 代理数据源 + sqlSessionFactoryBean.setDataSource(new DataSourceProxy(dataSource)); + // 生成SqlSessionFactory + return sqlSessionFactoryBean.getObject(); + } +} \ No newline at end of file diff --git a/distributed/transaction/seata-AT-demo/order-service/src/main/java/cn/itcast/order/entity/Order.java b/distributed/transaction/seata-AT-demo/order-service/src/main/java/cn/itcast/order/entity/Order.java new file mode 100644 index 00000000..b71c2560 --- /dev/null +++ b/distributed/transaction/seata-AT-demo/order-service/src/main/java/cn/itcast/order/entity/Order.java @@ -0,0 +1,20 @@ +package cn.itcast.order.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +/** + * @author 虎哥 + */ +@Data +@TableName("order_tbl") +public class Order { + @TableId(type = IdType.AUTO) + private Long id; + private String userId; + private String commodityCode; + private Integer count; + private Integer money; +} diff --git a/distributed/transaction/seata-AT-demo/order-service/src/main/java/cn/itcast/order/mapper/OrderMapper.java b/distributed/transaction/seata-AT-demo/order-service/src/main/java/cn/itcast/order/mapper/OrderMapper.java new file mode 100644 index 00000000..b90f5993 --- /dev/null +++ b/distributed/transaction/seata-AT-demo/order-service/src/main/java/cn/itcast/order/mapper/OrderMapper.java @@ -0,0 +1,10 @@ +package cn.itcast.order.mapper; + +import cn.itcast.order.entity.Order; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + * @author 虎哥 + */ +public interface OrderMapper extends BaseMapper { +} diff --git a/distributed/transaction/seata-AT-demo/order-service/src/main/java/cn/itcast/order/service/OrderService.java b/distributed/transaction/seata-AT-demo/order-service/src/main/java/cn/itcast/order/service/OrderService.java new file mode 100644 index 00000000..3063dad1 --- /dev/null +++ b/distributed/transaction/seata-AT-demo/order-service/src/main/java/cn/itcast/order/service/OrderService.java @@ -0,0 +1,11 @@ +package cn.itcast.order.service; + +import cn.itcast.order.entity.Order; + +public interface OrderService { + + /** + * 创建订单 + */ + Long create(Order order); +} \ No newline at end of file diff --git a/distributed/transaction/seata-AT-demo/order-service/src/main/java/cn/itcast/order/service/impl/OrderServiceImpl.java b/distributed/transaction/seata-AT-demo/order-service/src/main/java/cn/itcast/order/service/impl/OrderServiceImpl.java new file mode 100644 index 00000000..ad23ac37 --- /dev/null +++ b/distributed/transaction/seata-AT-demo/order-service/src/main/java/cn/itcast/order/service/impl/OrderServiceImpl.java @@ -0,0 +1,47 @@ +package cn.itcast.order.service.impl; + +import cn.itcast.order.client.AccountClient; +import cn.itcast.order.client.StorageClient; +import cn.itcast.order.entity.Order; +import cn.itcast.order.mapper.OrderMapper; +import cn.itcast.order.service.OrderService; +import feign.FeignException; +import io.seata.spring.annotation.GlobalTransactional; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +/** + * @author 虎哥 + */ +@Slf4j +@Service +public class OrderServiceImpl implements OrderService { + + private final AccountClient accountClient; + private final StorageClient storageClient; + private final OrderMapper orderMapper; + + public OrderServiceImpl(AccountClient accountClient, StorageClient storageClient, OrderMapper orderMapper) { + this.accountClient = accountClient; + this.storageClient = storageClient; + this.orderMapper = orderMapper; + } + + @Override +// @Transactional + @GlobalTransactional + public Long create(Order order) { + // 创建订单 + orderMapper.insert(order); + try { + // 扣库存 + storageClient.deduct(order.getCommodityCode(), order.getCount()); + // 扣款 + accountClient.debit(order.getUserId(), order.getMoney()); + } catch (FeignException e) { + log.error("下单失败,原因:{}", e.contentUTF8()); + throw new RuntimeException(e.contentUTF8()); + } + return order.getId(); + } +} diff --git a/distributed/transaction/seata-AT-demo/order-service/src/main/java/cn/itcast/order/web/OrderController.java b/distributed/transaction/seata-AT-demo/order-service/src/main/java/cn/itcast/order/web/OrderController.java new file mode 100644 index 00000000..fcfb48c5 --- /dev/null +++ b/distributed/transaction/seata-AT-demo/order-service/src/main/java/cn/itcast/order/web/OrderController.java @@ -0,0 +1,29 @@ +package cn.itcast.order.web; + +import cn.itcast.order.entity.Order; +import cn.itcast.order.service.OrderService; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * @author 虎哥 + */ +@RestController +@RequestMapping("order") +public class OrderController { + + private final OrderService orderService; + + public OrderController(OrderService orderService) { + this.orderService = orderService; + } + + @PostMapping + public ResponseEntity createOrder(Order order){ + Long orderId = orderService.create(order); + return ResponseEntity.status(HttpStatus.CREATED).body(orderId); + } +} diff --git a/distributed/transaction/seata-AT-demo/order-service/src/main/resources/application.yml b/distributed/transaction/seata-AT-demo/order-service/src/main/resources/application.yml new file mode 100644 index 00000000..98771382 --- /dev/null +++ b/distributed/transaction/seata-AT-demo/order-service/src/main/resources/application.yml @@ -0,0 +1,32 @@ +server: + port: 8082 +spring: + application: + name: order-service + datasource: + driver-class-name: com.mysql.jdbc.Driver + url: jdbc:mysql:///seata_demo?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&useSSL=false + username: root + password: 123456 + cloud: + alibaba: + seata: + tx-service-group: test_tx_group # 定义事务组的名称 + +eureka: + client: + service-url: + defaultZone: http://127.0.0.1:8761/eureka + instance: + prefer-ip-address: true + hostname: 127.0.0.1 +mybatis-plus: + global-config: + db-config: + insert-strategy: not_null + update-strategy: not_null + id-type: auto +logging: + level: + org.springframework.cloud.alibaba.seata.web: debug + cn.itcast: debug \ No newline at end of file diff --git a/distributed/transaction/seata-AT-demo/order-service/src/main/resources/file.conf b/distributed/transaction/seata-AT-demo/order-service/src/main/resources/file.conf new file mode 100644 index 00000000..3103c110 --- /dev/null +++ b/distributed/transaction/seata-AT-demo/order-service/src/main/resources/file.conf @@ -0,0 +1,65 @@ +transport { + # tcp udt unix-domain-socket + type = "TCP" + #NIO NATIVE + server = "NIO" + #enable heartbeat + heartbeat = true + # the client batch send request enable + enableClientBatchSendRequest = true + #thread factory for netty + threadFactory { + bossThreadPrefix = "NettyBoss" + workerThreadPrefix = "NettyServerNIOWorker" + serverExecutorThread-prefix = "NettyServerBizHandler" + shareBossWorker = false + clientSelectorThreadPrefix = "NettyClientSelector" + clientSelectorThreadSize = 1 + clientWorkerThreadPrefix = "NettyClientWorkerThread" + # netty boss thread size,will not be used for UDT + bossThreadSize = 1 + #auto default pin or 8 + workerThreadSize = "default" + } + shutdown { + # when destroy server, wait seconds + wait = 3 + } + serialization = "seata" + compressor = "none" +} +service { + vgroupMapping.test_tx_group = "seata_tc_server" + #only support when registry.type=file, please don't set multiple addresses + seata_tc_server.grouplist = "127.0.0.1:8091" + #degrade, current not support + enableDegrade = false + #disable seata + disableGlobalTransaction = false +} + +client { + rm { + asyncCommitBufferLimit = 10000 + lock { + retryInterval = 10 + retryTimes = 30 + retryPolicyBranchRollbackOnConflict = true + } + reportRetryCount = 5 + tableMetaCheckEnable = false + reportSuccessEnable = false + } + tm { + commitRetryCount = 5 + rollbackRetryCount = 5 + } + undo { + dataValidation = true + logSerialization = "jackson" + logTable = "undo_log" + } + log { + exceptionRate = 100 + } +} \ No newline at end of file diff --git a/distributed/transaction/seata-AT-demo/order-service/src/main/resources/registry.conf b/distributed/transaction/seata-AT-demo/order-service/src/main/resources/registry.conf new file mode 100644 index 00000000..0e8a8659 --- /dev/null +++ b/distributed/transaction/seata-AT-demo/order-service/src/main/resources/registry.conf @@ -0,0 +1,34 @@ +registry { + # 指定注册中心类型,这里使用eureka类型 + type = "eureka" + # 各种注册中心的配置。。这里省略,只保留了eureka和Zookeeper + eureka { + serviceUrl = "http://localhost:8761/eureka" + application = "seata_tc_server" + weight = "1" + } + zk { + cluster = "default" + serverAddr = "127.0.0.1:2181" + session.timeout = 6000 + connect.timeout = 2000 + } +} + +config { + # 配置文件方式,可以支持 file、nacos 、apollo、zk、consul、etcd3 + type = "file" + nacos { + serverAddr = "localhost" + namespace = "" + group = "SEATA_GROUP" + } + zk { + serverAddr = "127.0.0.1:2181" + session.timeout = 6000 + connect.timeout = 2000 + } + file { + name = "file.conf" + } +} \ No newline at end of file diff --git a/distributed/transaction/seata-AT-demo/pom.xml b/distributed/transaction/seata-AT-demo/pom.xml new file mode 100644 index 00000000..7459ded2 --- /dev/null +++ b/distributed/transaction/seata-AT-demo/pom.xml @@ -0,0 +1,93 @@ + + + 4.0.0 + + cn.itcast.demo + seata-demo + 1.0-SNAPSHOT + + storage-service + account-service + order-service + eureka-server + + pom + + + org.springframework.boot + spring-boot-starter-parent + 2.1.12.RELEASE + + + + + UTF-8 + UTF-8 + 1.8 + Greenwich.SR5 + 3.3.0 + 5.1.47 + 2.1.0.RELEASE + 1.1.0 + + + + + + + org.springframework.cloud + spring-cloud-dependencies + ${spring-cloud.version} + pom + import + + + + mysql + mysql-connector-java + ${mysql.version} + + + com.baomidou + mybatis-plus-boot-starter + ${mybatis.plus.version} + + + com.alibaba.cloud + spring-cloud-alibaba-seata + ${alibaba.seata.version} + + + seata-all + io.seata + + + + + seata-all + io.seata + ${seata.version} + + + + + + + org.apache.commons + commons-lang3 + 3.4 + + + org.projectlombok + lombok + + + + org.springframework.boot + spring-boot-starter-test + test + + + \ No newline at end of file diff --git a/distributed/transaction/seata-AT-demo/storage-service/pom.xml b/distributed/transaction/seata-AT-demo/storage-service/pom.xml new file mode 100644 index 00000000..24ede774 --- /dev/null +++ b/distributed/transaction/seata-AT-demo/storage-service/pom.xml @@ -0,0 +1,56 @@ + + + + seata-demo + cn.itcast.demo + 1.0-SNAPSHOT + + 4.0.0 + + storage-service + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.cloud + spring-cloud-starter-netflix-eureka-client + + + mysql + mysql-connector-java + + + com.baomidou + mybatis-plus-boot-starter + + + com.alibaba.cloud + spring-cloud-alibaba-seata + ${alibaba.seata.version} + + + seata-all + io.seata + + + + + seata-all + io.seata + ${seata.version} + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + \ No newline at end of file diff --git a/distributed/transaction/seata-AT-demo/storage-service/src/main/java/cn/itcast/storage/StorageApplication.java b/distributed/transaction/seata-AT-demo/storage-service/src/main/java/cn/itcast/storage/StorageApplication.java new file mode 100644 index 00000000..52310a96 --- /dev/null +++ b/distributed/transaction/seata-AT-demo/storage-service/src/main/java/cn/itcast/storage/StorageApplication.java @@ -0,0 +1,16 @@ +package cn.itcast.storage; + +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * @author 虎哥 + */ +@MapperScan("cn.itcast.storage.mapper") +@SpringBootApplication +public class StorageApplication { + public static void main(String[] args) { + SpringApplication.run(StorageApplication.class, args); + } +} diff --git a/distributed/transaction/seata-AT-demo/storage-service/src/main/java/cn/itcast/storage/config/DataSourceProxyConfig.java b/distributed/transaction/seata-AT-demo/storage-service/src/main/java/cn/itcast/storage/config/DataSourceProxyConfig.java new file mode 100644 index 00000000..0400e720 --- /dev/null +++ b/distributed/transaction/seata-AT-demo/storage-service/src/main/java/cn/itcast/storage/config/DataSourceProxyConfig.java @@ -0,0 +1,22 @@ +package cn.itcast.storage.config; + +import io.seata.rm.datasource.DataSourceProxy; +import org.apache.ibatis.session.SqlSessionFactory; +import org.mybatis.spring.SqlSessionFactoryBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import javax.sql.DataSource; + +@Configuration +public class DataSourceProxyConfig { + + @Bean + public SqlSessionFactory sqlSessionFactoryBean(DataSource dataSource) throws Exception { + // 因为使用的是mybatis,这里定义SqlSessionFactoryBean + SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean(); + // 配置数据源代理 + sqlSessionFactoryBean.setDataSource(new DataSourceProxy(dataSource)); + return sqlSessionFactoryBean.getObject(); + } +} \ No newline at end of file diff --git a/distributed/transaction/seata-AT-demo/storage-service/src/main/java/cn/itcast/storage/entity/Storage.java b/distributed/transaction/seata-AT-demo/storage-service/src/main/java/cn/itcast/storage/entity/Storage.java new file mode 100644 index 00000000..c96afff7 --- /dev/null +++ b/distributed/transaction/seata-AT-demo/storage-service/src/main/java/cn/itcast/storage/entity/Storage.java @@ -0,0 +1,17 @@ +package cn.itcast.storage.entity; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +/** + * @author 虎哥 + */ +@Data +@TableName("storage_tbl") +public class Storage { + @TableId + private Long id; + private String commodityCode; + private Integer count; +} diff --git a/distributed/transaction/seata-AT-demo/storage-service/src/main/java/cn/itcast/storage/mapper/StorageMapper.java b/distributed/transaction/seata-AT-demo/storage-service/src/main/java/cn/itcast/storage/mapper/StorageMapper.java new file mode 100644 index 00000000..afea1ee2 --- /dev/null +++ b/distributed/transaction/seata-AT-demo/storage-service/src/main/java/cn/itcast/storage/mapper/StorageMapper.java @@ -0,0 +1,14 @@ +package cn.itcast.storage.mapper; + +import cn.itcast.storage.entity.Storage; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Update; + +/** + * @author 虎哥 + */ +public interface StorageMapper extends BaseMapper { + @Update("update storage_tbl set `count` = `count` - #{count} where commodity_code = #{code}") + int deduct(@Param("code") String commodityCode, @Param("count") int count); +} diff --git a/distributed/transaction/seata-AT-demo/storage-service/src/main/java/cn/itcast/storage/service/StorageService.java b/distributed/transaction/seata-AT-demo/storage-service/src/main/java/cn/itcast/storage/service/StorageService.java new file mode 100644 index 00000000..e0b594af --- /dev/null +++ b/distributed/transaction/seata-AT-demo/storage-service/src/main/java/cn/itcast/storage/service/StorageService.java @@ -0,0 +1,9 @@ +package cn.itcast.storage.service; + +public interface StorageService{ + + /** + * 扣除存储数量 + */ + void deduct(String commodityCode, int count); +} \ No newline at end of file diff --git a/distributed/transaction/seata-AT-demo/storage-service/src/main/java/cn/itcast/storage/service/impl/StorageServiceImpl.java b/distributed/transaction/seata-AT-demo/storage-service/src/main/java/cn/itcast/storage/service/impl/StorageServiceImpl.java new file mode 100644 index 00000000..7d430da0 --- /dev/null +++ b/distributed/transaction/seata-AT-demo/storage-service/src/main/java/cn/itcast/storage/service/impl/StorageServiceImpl.java @@ -0,0 +1,31 @@ +package cn.itcast.storage.service.impl; + +import cn.itcast.storage.mapper.StorageMapper; +import cn.itcast.storage.service.StorageService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +/** + * @author 虎哥 + */ +@Slf4j +@Service +public class StorageServiceImpl implements StorageService { + + @Autowired + private StorageMapper storageMapper; + + @Transactional + @Override + public void deduct(String commodityCode, int count) { + log.info("开始扣减库存"); + try { + storageMapper.deduct(commodityCode, count); + } catch (Exception e) { + throw new RuntimeException("扣减库存失败,可能是库存不足!"); + } + log.info("扣减库存成功"); + } +} diff --git a/distributed/transaction/seata-AT-demo/storage-service/src/main/java/cn/itcast/storage/web/StorageController.java b/distributed/transaction/seata-AT-demo/storage-service/src/main/java/cn/itcast/storage/web/StorageController.java new file mode 100644 index 00000000..1e953e76 --- /dev/null +++ b/distributed/transaction/seata-AT-demo/storage-service/src/main/java/cn/itcast/storage/web/StorageController.java @@ -0,0 +1,34 @@ +package cn.itcast.storage.web; + +import cn.itcast.storage.service.StorageService; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * @author 虎哥 + */ +@RestController +@RequestMapping("storage") +public class StorageController { + + private final StorageService storageService; + + public StorageController(StorageService storageService) { + this.storageService = storageService; + } + + /** + * 扣减库存 + * @param code 商品编号 + * @param count 要扣减的数量 + * @return 无 + */ + @PutMapping("/{code}/{count}") + public ResponseEntity deduct(@PathVariable("code") String code,@PathVariable("count") Integer count){ + storageService.deduct(code, count); + return ResponseEntity.noContent().build(); + } +} diff --git a/distributed/transaction/seata-AT-demo/storage-service/src/main/resources/application.yml b/distributed/transaction/seata-AT-demo/storage-service/src/main/resources/application.yml new file mode 100644 index 00000000..619e5f70 --- /dev/null +++ b/distributed/transaction/seata-AT-demo/storage-service/src/main/resources/application.yml @@ -0,0 +1,29 @@ +server: + port: 8081 +spring: + application: + name: storage-service + datasource: + driver-class-name: com.mysql.jdbc.Driver + url: jdbc:mysql:///seata_demo?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&useSSL=false + username: root + password: 123456 + cloud: + alibaba: + seata: + tx-service-group: test_tx_group # 定义事务组的名称 + +eureka: + client: + service-url: + defaultZone: http://127.0.0.1:8761/eureka +mybatis-plus: + global-config: + db-config: + insert-strategy: not_null + update-strategy: not_null + id-type: auto +logging: + level: + org.springframework.cloud.alibaba.seata.web: debug + cn.itcast: debug \ No newline at end of file diff --git a/distributed/transaction/seata-AT-demo/storage-service/src/main/resources/file.conf b/distributed/transaction/seata-AT-demo/storage-service/src/main/resources/file.conf new file mode 100644 index 00000000..3103c110 --- /dev/null +++ b/distributed/transaction/seata-AT-demo/storage-service/src/main/resources/file.conf @@ -0,0 +1,65 @@ +transport { + # tcp udt unix-domain-socket + type = "TCP" + #NIO NATIVE + server = "NIO" + #enable heartbeat + heartbeat = true + # the client batch send request enable + enableClientBatchSendRequest = true + #thread factory for netty + threadFactory { + bossThreadPrefix = "NettyBoss" + workerThreadPrefix = "NettyServerNIOWorker" + serverExecutorThread-prefix = "NettyServerBizHandler" + shareBossWorker = false + clientSelectorThreadPrefix = "NettyClientSelector" + clientSelectorThreadSize = 1 + clientWorkerThreadPrefix = "NettyClientWorkerThread" + # netty boss thread size,will not be used for UDT + bossThreadSize = 1 + #auto default pin or 8 + workerThreadSize = "default" + } + shutdown { + # when destroy server, wait seconds + wait = 3 + } + serialization = "seata" + compressor = "none" +} +service { + vgroupMapping.test_tx_group = "seata_tc_server" + #only support when registry.type=file, please don't set multiple addresses + seata_tc_server.grouplist = "127.0.0.1:8091" + #degrade, current not support + enableDegrade = false + #disable seata + disableGlobalTransaction = false +} + +client { + rm { + asyncCommitBufferLimit = 10000 + lock { + retryInterval = 10 + retryTimes = 30 + retryPolicyBranchRollbackOnConflict = true + } + reportRetryCount = 5 + tableMetaCheckEnable = false + reportSuccessEnable = false + } + tm { + commitRetryCount = 5 + rollbackRetryCount = 5 + } + undo { + dataValidation = true + logSerialization = "jackson" + logTable = "undo_log" + } + log { + exceptionRate = 100 + } +} \ No newline at end of file diff --git a/distributed/transaction/seata-AT-demo/storage-service/src/main/resources/registry.conf b/distributed/transaction/seata-AT-demo/storage-service/src/main/resources/registry.conf new file mode 100644 index 00000000..0e8a8659 --- /dev/null +++ b/distributed/transaction/seata-AT-demo/storage-service/src/main/resources/registry.conf @@ -0,0 +1,34 @@ +registry { + # 指定注册中心类型,这里使用eureka类型 + type = "eureka" + # 各种注册中心的配置。。这里省略,只保留了eureka和Zookeeper + eureka { + serviceUrl = "http://localhost:8761/eureka" + application = "seata_tc_server" + weight = "1" + } + zk { + cluster = "default" + serverAddr = "127.0.0.1:2181" + session.timeout = 6000 + connect.timeout = 2000 + } +} + +config { + # 配置文件方式,可以支持 file、nacos 、apollo、zk、consul、etcd3 + type = "file" + nacos { + serverAddr = "localhost" + namespace = "" + group = "SEATA_GROUP" + } + zk { + serverAddr = "127.0.0.1:2181" + session.timeout = 6000 + connect.timeout = 2000 + } + file { + name = "file.conf" + } +} \ No newline at end of file diff --git a/distributed/transaction/seata_demo.sql b/distributed/transaction/seata_demo.sql new file mode 100644 index 00000000..0a298a90 --- /dev/null +++ b/distributed/transaction/seata_demo.sql @@ -0,0 +1,69 @@ + +SET NAMES utf8mb4; +SET FOREIGN_KEY_CHECKS = 0; + +-- ---------------------------- +-- Table structure for account_tbl +-- ---------------------------- +DROP TABLE IF EXISTS `account_tbl`; +CREATE TABLE `account_tbl` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `money` int(11) UNSIGNED NULL DEFAULT 0, + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact; + +-- ---------------------------- +-- Records of account_tbl +-- ---------------------------- +INSERT INTO `account_tbl` VALUES (1, 'user202003032042012', 1000); + +-- ---------------------------- +-- Table structure for order_tbl +-- ---------------------------- +DROP TABLE IF EXISTS `order_tbl`; +CREATE TABLE `order_tbl` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `commodity_code` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `count` int(11) NULL DEFAULT 0, + `money` int(11) NULL DEFAULT 0, + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact; + +-- ---------------------------- +-- Table structure for storage_tbl +-- ---------------------------- +DROP TABLE IF EXISTS `storage_tbl`; +CREATE TABLE `storage_tbl` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `commodity_code` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `count` int(11) UNSIGNED NULL DEFAULT 0, + PRIMARY KEY (`id`) USING BTREE, + UNIQUE INDEX `commodity_code`(`commodity_code`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact; + +-- ---------------------------- +-- Records of storage_tbl +-- ---------------------------- +INSERT INTO `storage_tbl` VALUES (1, '100202003032041', 10); + +-- ---------------------------- +-- Table structure for undo_log +-- ---------------------------- +DROP TABLE IF EXISTS `undo_log`; +CREATE TABLE `undo_log` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `branch_id` bigint(20) NOT NULL, + `xid` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, + `context` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, + `rollback_info` longblob NOT NULL, + `log_status` int(11) NOT NULL, + `log_created` datetime(0) NOT NULL, + `log_modified` datetime(0) NOT NULL, + `ext` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + PRIMARY KEY (`id`) USING BTREE, + UNIQUE INDEX `ux_undo_log`(`xid`, `branch_id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact; + +SET FOREIGN_KEY_CHECKS = 1; diff --git "a/distributed/transaction/\345\210\206\345\270\203\345\274\217\344\272\213\345\212\241.zip" "b/distributed/transaction/\345\210\206\345\270\203\345\274\217\344\272\213\345\212\241.zip" new file mode 100644 index 00000000..6ba7dd9e Binary files /dev/null and "b/distributed/transaction/\345\210\206\345\270\203\345\274\217\344\272\213\345\212\241.zip" differ diff --git a/framework/flyway/pom.xml b/framework/flyway/pom.xml new file mode 100644 index 00000000..e42c823a --- /dev/null +++ b/framework/flyway/pom.xml @@ -0,0 +1,31 @@ + + + 4.0.0 + + cn.lastwhisper + flyway + 1.0-SNAPSHOT + + + 1.8 + + + + + + org.flywaydb + flyway-core + 6.0.6 + + + + + mysql + mysql-connector-java + 8.0.17 + + + + \ No newline at end of file diff --git a/framework/flyway/src/main/java/cn/lastwhisper/flyway/App.java b/framework/flyway/src/main/java/cn/lastwhisper/flyway/App.java new file mode 100644 index 00000000..65cc37f8 --- /dev/null +++ b/framework/flyway/src/main/java/cn/lastwhisper/flyway/App.java @@ -0,0 +1,16 @@ +package cn.lastwhisper.flyway; + +import org.flywaydb.core.Flyway; + +public class App { + public static void main(String[] args) { + // Create the Flyway instance and point it to the database + Flyway flyway = Flyway.configure().dataSource( + "jdbc:mysql://localhost:3306/application?serverTimezone=UTC&useUnicode=true&characterEncoding=UTF-8", + "root", "root").load(); + + // Start the migration + // 默认 flyway.locations=classpath:/db/migration + flyway.migrate(); + } +} \ No newline at end of file diff --git a/springboot-integration-examples/springboot-flyway/src/main/resources/db/migration/V1__Create_person_table.sql b/framework/flyway/src/main/resources/db/migration/V1__Create_person_table.sql similarity index 100% rename from springboot-integration-examples/springboot-flyway/src/main/resources/db/migration/V1__Create_person_table.sql rename to framework/flyway/src/main/resources/db/migration/V1__Create_person_table.sql diff --git a/springboot-integration-examples/springboot-flyway/src/main/resources/db/migration/V2__Add_people.sql b/framework/flyway/src/main/resources/db/migration/V2__Add_people.sql similarity index 100% rename from springboot-integration-examples/springboot-flyway/src/main/resources/db/migration/V2__Add_people.sql rename to framework/flyway/src/main/resources/db/migration/V2__Add_people.sql diff --git a/framework/guava/pom.xml b/framework/guava/pom.xml new file mode 100644 index 00000000..f3d4370d --- /dev/null +++ b/framework/guava/pom.xml @@ -0,0 +1,25 @@ + + + + 4.0.0 + + guava + cn.lastwhisper + 1.0-SNAPSHOT + + + + junit + junit + 4.13 + + + + com.google.guava + guava + 30.1.1-jre + + + \ No newline at end of file diff --git a/framework/guava/src/main/java/cn/lastwhisper/bloomfilter/TestBloomFilter.java b/framework/guava/src/main/java/cn/lastwhisper/bloomfilter/TestBloomFilter.java new file mode 100644 index 00000000..25de3af6 --- /dev/null +++ b/framework/guava/src/main/java/cn/lastwhisper/bloomfilter/TestBloomFilter.java @@ -0,0 +1,23 @@ +package cn.lastwhisper.bloomfilter; + +import com.google.common.hash.BloomFilter; +import com.google.common.hash.Funnel; +import com.google.common.hash.Funnels; + +public class TestBloomFilter { + + public static void main(String[] args) { + Funnel funnel = Funnels.integerFunnel(); + int size = 1000_000; + double errorChance = 0.001; //错误率 + BloomFilter filter = BloomFilter.create(funnel, size, errorChance); + for (int i = 0; i < size; i++) { + filter.put(i); + } + for (int i = 0; i < size; i++) { + if (!filter.mightContain(i)) { + System.out.println("发现不存在的数据 : " + i); + } + } + } +} \ No newline at end of file diff --git a/framework/guava/src/main/java/cn/lastwhisper/cache/TestCache.java b/framework/guava/src/main/java/cn/lastwhisper/cache/TestCache.java new file mode 100644 index 00000000..5d29b051 --- /dev/null +++ b/framework/guava/src/main/java/cn/lastwhisper/cache/TestCache.java @@ -0,0 +1,40 @@ +package cn.lastwhisper.cache; + +import com.google.common.cache.*; +import org.junit.Test; + +import java.util.concurrent.TimeUnit; + +/** + * Guava的Cache + * @author lastwhisper + * @date 2020/6/2 + */ +public class TestCache { + + // https://github.com/zhuzhenke/common-caches + @Test + public void testCacheUse() throws Exception{ + + LoadingCache loadingCache = CacheBuilder.newBuilder() + .expireAfterAccess(10, TimeUnit.SECONDS) + .maximumSize(1000) + .removalListener(new RemovalListener() { + @Override + public void onRemoval(RemovalNotification notification) { + + } + }) + .build(new CacheLoader() { + @Override + public String load(String key) throws Exception { + return key; + } + }); + + System.out.println(loadingCache.get("key")); + + + } + +} diff --git a/framework/guava/src/main/java/cn/lastwhisper/collection/MapTest.java b/framework/guava/src/main/java/cn/lastwhisper/collection/MapTest.java new file mode 100644 index 00000000..8daede52 --- /dev/null +++ b/framework/guava/src/main/java/cn/lastwhisper/collection/MapTest.java @@ -0,0 +1,282 @@ +package cn.lastwhisper.collection; + +import com.google.common.collect.*; +import org.junit.Test; + +import java.util.*; + +/** + * 参考:https://mp.weixin.qq.com/s/LOZ-p6divRjO9ZTcus101A + * + * @author cunchang + * @date 2022/3/17 1:54 PM + */ +public class MapTest { + + /** + *

+ * 案例:记录员工每个月工作的天数 + * 使用hashmap的话,得两个嵌套 + */ + @Test + public void test双键Map() { + // java中的Map只允许有一个key和一个value存在。 + // guava中的Table允许一个value存在两个key。Table中的两个key分别被称为rowKey和columnKey,也就是行和列。 + Table table = HashBasedTable.create(); + //存放元素 + table.put("Hydra", "Jan", 20); + table.put("Hydra", "Feb", 28); + + table.put("Trunks", "Jan", 28); + table.put("Trunks", "Feb", 16); + + //取出元素 + Integer dayCount = table.get("Hydra", "Feb"); + System.out.println("取出元素:" + dayCount); + +// 1、获得key或value的集合 + //rowKey或columnKey的集合 + System.out.println("---rowKey或columnKey的集合"); + Set rowKeys = table.rowKeySet(); + Set columnKeys = table.columnKeySet(); + //value集合 + Collection values = table.values(); + System.out.println("rowKeys:" + rowKeys); + System.out.println("columnKeys:" + columnKeys); + System.out.println("values:" + values); + +// 2、计算key对应的所有value的和 + // 以统计所有rowKey对应的value之和为例: + System.out.println("---统计所有rowKey对应的value之和"); + for (String key : table.rowKeySet()) { + Set> rows = table.row(key).entrySet(); + int total = 0; + for (Map.Entry row : rows) { + total += row.getValue(); + } + System.out.println(key + ": " + total); + } +// 3、转换rowKey和columnKey + // 行和列的转置,直接调用Tables的静态方法transpose + System.out.println("---行和列的转置"); + Table table2 = Tables.transpose(table); + Set> cells = table2.cellSet(); + cells.forEach(cell -> + System.out.println(cell.getRowKey() + "," + cell.getColumnKey() + ":" + cell.getValue()) + ); + +// 4、转为嵌套的Map + // 将数据还原成嵌套Map的那种形式,使用Table的rowMap或columnMap方法就可以实现了 + System.out.println("---转为嵌套的Map"); + Map> rowMap = table.rowMap(); + Map> columnMap = table.columnMap(); + System.out.println("rowMap: " + rowMap); + System.out.println("columnMap: " + columnMap); + } + + /** + * 在普通Map中,如果要想根据value查找对应的key,没什么简便的办法,无论是使用for循环还是迭代器,都需要遍历整个Map。 + */ + @Test + public void test双向Map() { + HashBiMap biMap = HashBiMap.create(); + biMap.put("Hydra", "Programmer"); + biMap.put("Tony", "IronMan"); + biMap.put("Thanos", "Titan"); + //使用key获取value + System.out.println("使用key获取value:" + biMap.get("Tony")); + + BiMap inverse = biMap.inverse(); + //使用value获取key + System.out.println("使用value获取key:" + inverse.get("Titan")); + } + + /** + * 上面我们用inverse方法反转了原来BiMap的键值映射,但是这个反转后的BiMap并不是一个新的对象, + * 它实现了一种视图的关联,所以对反转后的BiMap执行的所有操作会作用于原先的BiMap上。 + */ + @Test + public void test双向Map_坑_反转后操作的影响() { + HashBiMap biMap = HashBiMap.create(); + biMap.put("Hydra", "Programmer"); + biMap.put("Tony", "IronMan"); + biMap.put("Thanos", "Titan"); + BiMap inverse = biMap.inverse(); + + // 原先值为IronMan时对应的键是Tony,虽然没有直接修改,但是现在键变成了Stark + inverse.put("IronMan", "Stark"); + System.out.println(biMap); + } + + @Test + public void test双向Map_坑_value不可重复() { + // 双向的BiMap,key和value都不允许重复 + HashBiMap biMap = HashBiMap.create(); + biMap.put("Tony", "IronMan"); + // java.lang.IllegalArgumentException: value already present: IronMan + biMap.put("Stark", "IronMan"); + } + + @Test + public void test双向Map_坑_value不可重复2() { + // 把新的key映射到已有的value上,使用forcePut方法强制替换掉原有的key + HashBiMap biMap = HashBiMap.create(); + biMap.put("Tony", "IronMan"); + biMap.forcePut("Stark", "IronMan"); + // 由于BiMap的value是不允许重复的,因此它的values方法返回的是没有重复的Set,而不是普通Collection: + Set values = biMap.values(); + } + + /** + * 将一个键映射到多个值 + */ + @Test + public void test多值Map() { + Multimap multimap = ArrayListMultimap.create(); + multimap.put("day", 1); + multimap.put("day", 2); + multimap.put("day", 8); + multimap.put("month", 3); + // {month=[3], day=[1, 2, 8]} + System.out.println(multimap); + + // 1、获取值的集合 + System.out.println("---获取值的集合"); + Collection day = multimap.get("day"); + // 如果在创建时指定为ArrayListMultimap类型,那么get方法将返回一个List: + // 同理,你还可以创建HashMultimap、TreeMultimap等类型的Multimap。 + ArrayListMultimap multimap2 = ArrayListMultimap.create(); + List day2 = multimap2.get("day"); + // Multimap的get方法会返回一个非null的集合,但是这个集合的内容可能是空,看一下下面的例子: + List day22 = multimap2.get("day"); + List year2 = multimap2.get("year"); + System.out.println(day22); + System.out.println(year2); + + } + + /** + * 和BiMap的使用类似,使用get方法返回的集合也不是一个独立的对象, + * 可以理解为集合视图的关联,对这个新集合的操作仍然会作用于原始的Multimap上 + */ + @Test + public void test多值Map_操作get后的集合() { + ArrayListMultimap multimap = ArrayListMultimap.create(); + multimap.put("day", 1); + multimap.put("day", 2); + multimap.put("day", 8); + multimap.put("month", 3); + + List day = multimap.get("day"); + List month = multimap.get("month"); + + System.out.println("before:" + multimap); + day.remove(0);//这个0是下标 + month.add(12); + System.out.println("after:" + multimap); + } + + /** + * 使用asMap方法,可以将Multimap转换为Map的形式, + * 同样这个Map也可以看做一个关联的视图,在这个Map上的操作会作用于原始的Multimap + */ + @Test + public void test多值Map_转换为Map() { + Multimap multimap = ArrayListMultimap.create(); + multimap.put("day", 1); + multimap.put("day", 2); + multimap.put("day", 8); + multimap.put("month", 3); + + Map> map = multimap.asMap(); + for (String key : map.keySet()) { + System.out.println(key + " : " + map.get(key)); + } + map.get("day").add(20); + System.out.println(multimap); + } + + @Test + public void test多值Map_坑_数量问题() { + Multimap multimap = ArrayListMultimap.create(); + multimap.put("day", 1); + multimap.put("day", 2); + multimap.put("day", 8); + multimap.put("month", 3); + + for (Map.Entry entry : multimap.entries()) { + System.out.println(entry.getKey() + "," + entry.getValue()); + } + + // size()方法返回的是所有key到单个value的映射,因此结果为4,entries()方法同理 + System.out.println(multimap.size()); + System.out.println(multimap.entries().size()); + // 但是它的keySet中保存的是不同的key的个数,例如下面这行代码打印的结果就会是2 + System.out.println(multimap.keySet().size()); + } + + public static String getRank(int score) { + if (0 <= score && score < 60) + return "fail"; + else if (60 <= score && score <= 90) + return "satisfactory"; + else if (90 < score && score <= 100) + return "excellent"; + return null; + } + + /** + * 要根据分数对考试成绩进行分类 + * guava中的RangeMap描述了一种从区间到特定值的映射关系,让我们能够以更为优雅的方法来书写代码 + */ + @Test + public void test范围Map() { + RangeMap rangeMap = TreeRangeMap.create(); + rangeMap.put(Range.closedOpen(0, 60), "fail"); + rangeMap.put(Range.closed(60, 90), "satisfactory"); + rangeMap.put(Range.openClosed(90, 100), "excellent"); + + System.out.println(rangeMap.get(59)); + System.out.println(rangeMap.get(60)); + System.out.println(rangeMap.get(90)); + System.out.println(rangeMap.get(91)); + + rangeMap.remove(Range.closed(70, 80)); + System.out.println(rangeMap.get(75)); + } + + /** + * ClassToInstanceMap相对普通Map + * 1、取出对象时省去了复杂的强制类型转换 + * 2、通过泛型保证value要符合key所对应的类型 + */ + @Test + public void test实例Map() { + ClassToInstanceMap instanceMap = MutableClassToInstanceMap.create(); + HashMap hashMap = new HashMap<>(); + TreeMap treeMap = new TreeMap<>(); + ArrayList list = new ArrayList<>(); + + instanceMap.putInstance(HashMap.class, hashMap); + instanceMap.putInstance(TreeMap.class, treeMap); + // HashMap和TreeMap都集成了Map父类,但是如果想放入其他类型,就会编译报错 +// instanceMap.putInstance(ArrayList.class,list); + } + + @Test + public void test实例Map对比普通Map() { + Map map = new HashMap<>(); + + HashMap hashMap = new HashMap<>(); + TreeMap treeMap = new TreeMap<>(); + ArrayList list = new ArrayList<>(); + + map.put(HashMap.class, hashMap); + map.put(TreeMap.class, treeMap); + // 1、类型转换 + treeMap = (TreeMap) map.get(TreeMap.class); + // 2、无法限制只存某些Class + map.put(ArrayList.class, list); + } + +} diff --git a/framework/guava/src/main/java/cn/lastwhisper/limit/TestRateLimiter.java b/framework/guava/src/main/java/cn/lastwhisper/limit/TestRateLimiter.java new file mode 100644 index 00000000..2cf1bb06 --- /dev/null +++ b/framework/guava/src/main/java/cn/lastwhisper/limit/TestRateLimiter.java @@ -0,0 +1,39 @@ +package cn.lastwhisper.limit; + +import com.google.common.util.concurrent.RateLimiter; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +/** + * Guava的RateLimiter限流基于令牌桶算法 + * @author lastwhisper + */ +public class TestRateLimiter { + + /** + * 单机全局限流器(限制QPS为1)(放入拦截器,对HTTP接口限流) + */ + private static RateLimiter limiter = RateLimiter.create(1.0); + + /** + * 固定10个线程,模拟十个用户并发 + */ + private static ExecutorService pool = Executors.newFixedThreadPool(10); + + static class Task implements Runnable { + @Override + public void run() { + limiter.acquire(); // 对应web项目,就是在业务代码之前执行(拦截器、AOP) + System.out.println(System.currentTimeMillis()); + } + } + + public static void main(String[] args) { + for (int i = 0; i < 50; i++) { + pool.submit(new Task()); + } + } + + +} diff --git a/framework/guava/src/main/java/cn/lastwhisper/limit/TokenBucket.java b/framework/guava/src/main/java/cn/lastwhisper/limit/TokenBucket.java new file mode 100644 index 00000000..3e2632a4 --- /dev/null +++ b/framework/guava/src/main/java/cn/lastwhisper/limit/TokenBucket.java @@ -0,0 +1,39 @@ +package cn.lastwhisper.limit; + +// 因为令牌桶对业务有一定的容忍度 +public class TokenBucket { + + private int bucketNums = 100; // 桶的容量 + private int rate = 1; // 流入速度 + private int nowTokens; // 当前令牌数量 + private long timestamp = getNowTime(); // 时间 + + private long getNowTime() { + return System.currentTimeMillis(); + } + + private int min(int tokens) { + return Math.min(bucketNums, tokens); + } + + public boolean getToken() { + // 记录来拿令牌的时间 + long nowTime = getNowTime(); + // 添加令牌【判断该有多少个令牌】 + nowTokens = nowTokens + (int) ((nowTime - timestamp) * rate); + // 添加以后的令牌数量与桶的容量那个小 + nowTokens = min(nowTokens); + System.out.println("当前令牌数量" + nowTokens); + // 修改拿令牌的时间 + timestamp = nowTime; + // 判断令牌是否足够 + if (nowTokens < 1) { + return false; + } else { + nowTokens -= 1; + return true; + } + } + + +} \ No newline at end of file diff --git a/framework/hutool/pom.xml b/framework/hutool/pom.xml new file mode 100644 index 00000000..11821973 --- /dev/null +++ b/framework/hutool/pom.xml @@ -0,0 +1,32 @@ + + + 4.0.0 + + cn.cunchang + hutool + 1.0-SNAPSHOT + + + 8 + 8 + + + + + + junit + junit + 4.12 + test + + + + cn.hutool + hutool-all + 5.8.0 + + + + \ No newline at end of file diff --git a/framework/hutool/src/main/java/cn/cunchang/IDUtilTest.java b/framework/hutool/src/main/java/cn/cunchang/IDUtilTest.java new file mode 100644 index 00000000..3f2e5a80 --- /dev/null +++ b/framework/hutool/src/main/java/cn/cunchang/IDUtilTest.java @@ -0,0 +1,17 @@ +package cn.cunchang; + +import cn.hutool.core.util.IdUtil; + +/** + * @author cunchang + * @date 2022/5/15 11:43 PM + */ +public class IDUtilTest { + + public static void main(String[] args) { + System.out.println(IdUtil.getSnowflakeNextId()); +// System.out.println(IdUtil.objectId()); + + + } +} diff --git a/framework/hutool/src/main/java/cn/cunchang/ZipUtilTest.java b/framework/hutool/src/main/java/cn/cunchang/ZipUtilTest.java new file mode 100644 index 00000000..06928b9d --- /dev/null +++ b/framework/hutool/src/main/java/cn/cunchang/ZipUtilTest.java @@ -0,0 +1,24 @@ +package cn.cunchang; + +import cn.hutool.core.util.ZipUtil; + +import java.io.File; + +/** + * 解压文件 + * @author cunchang + * @date 2022/5/9 2:51 PM + */ +public class ZipUtilTest { + + public static void main(String[] args) { + //将test.zip解压到e:\\aaa目录下,返回解压到的目录 + File unzip = ZipUtil.unzip("/Users/cunchang/Downloads/1.zip", "/Users/cunchang/Downloads/receipt"); + System.out.println(unzip.getAbsoluteFile()); + String[] filePaths = unzip.list(); + for (String filePath : filePaths) { + System.out.println(unzip.getAbsoluteFile()+"/"+filePath); + } + } + +} diff --git a/framework/pinyin4j/pom.xml b/framework/pinyin4j/pom.xml new file mode 100644 index 00000000..b0b580b2 --- /dev/null +++ b/framework/pinyin4j/pom.xml @@ -0,0 +1,20 @@ + + + 4.0.0 + + cn.lastwhisper + pinyin4j + 1.0-SNAPSHOT + + + + + com.belerweb + pinyin4j + 2.5.0 + + + + \ No newline at end of file diff --git a/framework/pinyin4j/src/main/java/cn/lastwhisper/DeCode.java b/framework/pinyin4j/src/main/java/cn/lastwhisper/DeCode.java new file mode 100644 index 00000000..d9ebccd7 --- /dev/null +++ b/framework/pinyin4j/src/main/java/cn/lastwhisper/DeCode.java @@ -0,0 +1,20 @@ +package cn.lastwhisper; + +/** + * + * @author lastwhisper + * @date 2020/6/8 + */ +public class DeCode { + + public static void main(String[] args) { + final String words = "原谅女儿离开父亲 昨日看到急报提示 " + + "阴祸氏突袭数据库 然后立刻离开城门 " + + "发现事情并不单纯 于是就跟随他来此 " + + "如果我没法再找寻 根据这追踪器书信 " + + "一定就会发现原因 "; + String binary = PinYinUtil.word2Tonal(words); + System.out.println(PinYinUtil.binary2Ascii(binary)); + } + +} diff --git a/framework/pinyin4j/src/main/java/cn/lastwhisper/PinYinUtil.java b/framework/pinyin4j/src/main/java/cn/lastwhisper/PinYinUtil.java new file mode 100644 index 00000000..2bdc9d03 --- /dev/null +++ b/framework/pinyin4j/src/main/java/cn/lastwhisper/PinYinUtil.java @@ -0,0 +1,171 @@ +package cn.lastwhisper; + +import net.sourceforge.pinyin4j.PinyinHelper; +import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType; +import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat; +import net.sourceforge.pinyin4j.format.HanyuPinyinToneType; +import net.sourceforge.pinyin4j.format.HanyuPinyinVCharType; +import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination; + +import static net.sourceforge.pinyin4j.format.HanyuPinyinCaseType.LOWERCASE; +import static net.sourceforge.pinyin4j.format.HanyuPinyinToneType.WITHOUT_TONE; +import static net.sourceforge.pinyin4j.format.HanyuPinyinToneType.WITH_TONE_NUMBER; +import static net.sourceforge.pinyin4j.format.HanyuPinyinVCharType.WITH_V; + +/** + * @author lastwhisper + */ +public class PinYinUtil { + + /** + * @param words 汉字字符串 + */ + public static String words2Pinyin(String words) { + return words2Pinyin(words, getDefaultPinyinFormat()); + } + + /** + * @param words 汉字字符串 + * @param pinyinFormat 汉字转拼音格式化模式 + */ + public static String words2Pinyin(String words, HanyuPinyinOutputFormat pinyinFormat) { + return words2Pinyin(words.toCharArray(), pinyinFormat); + } + + /** + * @param chars 汉字字符数组 + * @param pinyinFormat 汉字转拼音格式化模式 + */ + public static String words2Pinyin(char[] chars, HanyuPinyinOutputFormat pinyinFormat) { + StringBuilder pinyinBuilder = new StringBuilder(); + try { + for (char word : chars) { + //是否为汉字字符 + if (Character.toString(word).matches("[\\u4E00-\\u9FA5]+")) { + // 多音字 + String[] py = PinyinHelper.toHanyuPinyinStringArray(word, pinyinFormat); + pinyinBuilder.append(py[0]); + } else { + pinyinBuilder.append(word); + } + } + } catch (BadHanyuPinyinOutputFormatCombination e) { + e.printStackTrace(); + } + return pinyinBuilder.toString(); + } + + /** + * 小写、音标无声调无音符、v表示ü + * @return net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat + */ + public static HanyuPinyinOutputFormat getDefaultPinyinFormat() { + return getPinyinFormat(LOWERCASE, WITHOUT_TONE, WITH_V); + } + + /** + * 小写、音标有声调无音符、v表示ü + * @return net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat + */ + public static HanyuPinyinOutputFormat getToneNumberPinyinFormat() { + return getPinyinFormat(LOWERCASE, WITH_TONE_NUMBER, WITH_V); + } + + /** + * 获取汉语拼音格式化器 + * @param caseType 大小写 + * @see HanyuPinyinCaseType + * UPPERCASE:大写 (ZHONG) + * LOWERCASE:小写 (zhong) + * @param toneType 音标格式 + * @see HanyuPinyinToneType + * WITHOUT_TONE:无音标 (zhong) + * WITH_TONE_NUMBER:1-4数字表示英标 (zhong4) + * WITH_TONE_MARK:直接用音标符(必须WITH_U_UNICODE否则异常) (zhòng) + * @param charType charType + * @see HanyuPinyinVCharType + * WITH_V:用v表示ü (nv) + * WITH_U_AND_COLON:用"u:"表示ü (nu:) + * WITH_U_UNICODE:直接用ü (nü) + * @return net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat + */ + public static HanyuPinyinOutputFormat getPinyinFormat(HanyuPinyinCaseType caseType, HanyuPinyinToneType toneType, HanyuPinyinVCharType charType) { + HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat(); + format.setCaseType(caseType); + format.setToneType(toneType); + format.setVCharType(charType); + return format; + } + + /** + * 汉字串转声调 + * @param words 字符串 + * @return java.lang.String 声调串 + * 1,2,3,4 + */ + public static String word2ToneNumber(String words) { + String tones = words2Pinyin(words, getToneNumberPinyinFormat()); + StringBuilder toneNumBuilder = new StringBuilder(); + for (int i = 0; i < tones.length(); i++) { + char c = tones.charAt(i); + if (isTonal(c)) { + toneNumBuilder.append(c); + } + } + return toneNumBuilder.toString(); + } + + private static boolean isTonal(char c) { + return isLow(c) || isHeight(c); + } + + private static boolean isLow(char c) { + return c == 49 || c == 50; + } + + private static boolean isHeight(char c) { + return c == 51 || c == 52; + } + + /** + * 汉字串转平仄 + * @param words 字符串 + * @return java.lang.String 平仄 + * 1,2:平、3,4:仄 + * 平:0、仄:1 + */ + public static String word2Tonal(String words) { + String tones = words2Pinyin(words, getToneNumberPinyinFormat()); + StringBuilder tonalNumBuilder = new StringBuilder(); + for (int i = 0; i < tones.length(); i++) { + char c = tones.charAt(i); + if (isLow(c)) { + tonalNumBuilder.append(0); + } else if (isHeight(c)) { + tonalNumBuilder.append(1); + } + } + return tonalNumBuilder.toString(); + } + + /** + * @param binary 二进制串 + * @return java.lang.String 对应的ASCII + */ + public static String binary2Ascii(String binary) { + StringBuilder asciiBuilder = new StringBuilder(); + for (int i = 0; i < binary.length(); i += 8) { + asciiBuilder.append((char) Integer.parseInt(binary.substring(i, i + 8), 2)); + } + return asciiBuilder.toString(); + } + + public static void main(String[] args) { + String words = "原谅女儿离开父亲 昨日看到急报提示 "; + String tonal = word2Tonal(words); + System.out.println(tonal); + String str = binary2Ascii(tonal); + System.out.println(str); + } + +} \ No newline at end of file diff --git a/framework/tika/pom.xml b/framework/tika/pom.xml new file mode 100644 index 00000000..cfba6fe7 --- /dev/null +++ b/framework/tika/pom.xml @@ -0,0 +1,64 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.3.3.RELEASE + + + cn.lastwhisper + tika + 0.0.1-SNAPSHOT + tika + tika demo + + + 1.8 + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-devtools + runtime + true + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.junit.vintage + junit-vintage-engine + + + + + + + org.apache.tika + tika-core + 1.24.1 + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/framework/tika/src/main/java/cn/lastwhisper/TikaApplication.java b/framework/tika/src/main/java/cn/lastwhisper/TikaApplication.java new file mode 100644 index 00000000..2d19c1d7 --- /dev/null +++ b/framework/tika/src/main/java/cn/lastwhisper/TikaApplication.java @@ -0,0 +1,13 @@ +package cn.lastwhisper; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class TikaApplication { + + public static void main(String[] args) { + SpringApplication.run(TikaApplication.class, args); + } + +} diff --git a/springboot-integration-examples/springboot-dubbo-tcc-instance/src/main/resources/application.properties b/framework/tika/src/main/resources/application.properties similarity index 100% rename from springboot-integration-examples/springboot-dubbo-tcc-instance/src/main/resources/application.properties rename to framework/tika/src/main/resources/application.properties diff --git a/framework/tika/src/test/java/cn/lastwhisper/TikaApplicationTests.java b/framework/tika/src/test/java/cn/lastwhisper/TikaApplicationTests.java new file mode 100644 index 00000000..f779b7a1 --- /dev/null +++ b/framework/tika/src/test/java/cn/lastwhisper/TikaApplicationTests.java @@ -0,0 +1,15 @@ +package cn.lastwhisper; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class TikaApplicationTests { + + @Test + void contextLoads() { + + + } + +} diff --git a/framework/tika/src/test/java/cn/lastwhisper/TikaTest.java b/framework/tika/src/test/java/cn/lastwhisper/TikaTest.java new file mode 100644 index 00000000..b70bc85b --- /dev/null +++ b/framework/tika/src/test/java/cn/lastwhisper/TikaTest.java @@ -0,0 +1,73 @@ +package cn.lastwhisper; + +import org.apache.tika.Tika; +import org.apache.tika.config.TikaConfig; +import org.apache.tika.detect.Detector; +import org.apache.tika.exception.TikaException; +import org.apache.tika.metadata.HttpHeaders; +import org.apache.tika.metadata.Metadata; +import org.apache.tika.mime.MediaType; +import org.apache.tika.mime.MimeType; +import org.apache.tika.mime.MimeTypes; +import org.apache.tika.parser.AutoDetectParser; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; + +/** + * @author cunchang + * @date 2020/8/26 下午7:38 + */ +public class TikaTest { + + public static void main(String[] args) throws IOException, TikaException { + + List fileNames = new ArrayList<>(); + fileNames.add("template.xls"); + fileNames.add("mapreduce-osdi04.pdf"); + fileNames.add("测试.docx"); + fileNames.add("测试.xlsx"); + fileNames.add("测试.xlsx"); + fileNames.add("transportation.png"); + fileNames.add("timg.gif"); + fileNames.add("timg"); + + for (String fileName : fileNames) { + InputStream stream = TikaTest.class.getClassLoader().getResourceAsStream(fileName); + System.out.print(fileName+"\t"); + getMimeType(stream); + } + + + + } + + public static void getType(InputStream is) throws TikaException, IOException { + TikaConfig tikaConfig = new TikaConfig(); + + Detector detector = tikaConfig.getDetector(); + Metadata metadata = new Metadata(); + MediaType mediaType = detector.detect(is, metadata); + System.out.println(mediaType.getBaseType()); + System.out.println(mediaType.getSubtype()); + System.out.println("-------------------------------------------------------"); + } + + public static void getMimeType(InputStream inputStream) throws TikaException, IOException { + AutoDetectParser parser = new AutoDetectParser(); + Metadata metadata = new Metadata(); + DefaultHandler handler = new DefaultHandler(); + try { + parser.parse(inputStream, handler, metadata); + } catch (TikaException | SAXException | IOException e) { + e.printStackTrace(); + } + System.out.println(metadata.get(HttpHeaders.CONTENT_TYPE)); + } +} diff --git a/framework/tika/src/test/resources/TikaApplication.java b/framework/tika/src/test/resources/TikaApplication.java new file mode 100644 index 00000000..2d19c1d7 --- /dev/null +++ b/framework/tika/src/test/resources/TikaApplication.java @@ -0,0 +1,13 @@ +package cn.lastwhisper; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class TikaApplication { + + public static void main(String[] args) { + SpringApplication.run(TikaApplication.class, args); + } + +} diff --git a/springboot-integration-examples/springboot-duboo-filter/src/main/resources/application.properties b/framework/tika/src/test/resources/application.properties similarity index 100% rename from springboot-integration-examples/springboot-duboo-filter/src/main/resources/application.properties rename to framework/tika/src/test/resources/application.properties diff --git a/framework/tika/src/test/resources/mapreduce-osdi04.pdf b/framework/tika/src/test/resources/mapreduce-osdi04.pdf new file mode 100644 index 00000000..fce88256 Binary files /dev/null and b/framework/tika/src/test/resources/mapreduce-osdi04.pdf differ diff --git a/framework/tika/src/test/resources/office.xlsx b/framework/tika/src/test/resources/office.xlsx new file mode 100644 index 00000000..c6a50d20 Binary files /dev/null and b/framework/tika/src/test/resources/office.xlsx differ diff --git a/framework/tika/src/test/resources/template.xls b/framework/tika/src/test/resources/template.xls new file mode 100644 index 00000000..509416be Binary files /dev/null and b/framework/tika/src/test/resources/template.xls differ diff --git a/framework/tika/src/test/resources/timg b/framework/tika/src/test/resources/timg new file mode 100644 index 00000000..83a692a3 Binary files /dev/null and b/framework/tika/src/test/resources/timg differ diff --git a/framework/tika/src/test/resources/timg.gif b/framework/tika/src/test/resources/timg.gif new file mode 100644 index 00000000..0ccdd16c Binary files /dev/null and b/framework/tika/src/test/resources/timg.gif differ diff --git a/framework/tika/src/test/resources/timg.jpg b/framework/tika/src/test/resources/timg.jpg new file mode 100644 index 00000000..83a692a3 Binary files /dev/null and b/framework/tika/src/test/resources/timg.jpg differ diff --git a/framework/tika/src/test/resources/timg.jpg.zip b/framework/tika/src/test/resources/timg.jpg.zip new file mode 100644 index 00000000..15250d23 Binary files /dev/null and b/framework/tika/src/test/resources/timg.jpg.zip differ diff --git a/framework/tika/src/test/resources/transportation.png b/framework/tika/src/test/resources/transportation.png new file mode 100644 index 00000000..e4521f86 Binary files /dev/null and b/framework/tika/src/test/resources/transportation.png differ diff --git "a/framework/tika/src/test/resources/\346\265\213\350\257\225.docx" "b/framework/tika/src/test/resources/\346\265\213\350\257\225.docx" new file mode 100644 index 00000000..d4021512 Binary files /dev/null and "b/framework/tika/src/test/resources/\346\265\213\350\257\225.docx" differ diff --git "a/framework/tika/src/test/resources/\346\265\213\350\257\225.xlsx" "b/framework/tika/src/test/resources/\346\265\213\350\257\225.xlsx" new file mode 100644 index 00000000..7e62b3d2 Binary files /dev/null and "b/framework/tika/src/test/resources/\346\265\213\350\257\225.xlsx" differ diff --git a/java-advance/README.md b/java-advance/README.md new file mode 100644 index 00000000..4f211e21 --- /dev/null +++ b/java-advance/README.md @@ -0,0 +1,52 @@ +# 进阶 + +- annotation;java注解相关:编译期处理注解、运行时解析并修改注解 +- groovy;Groovy可以被视为Java的一种脚本化改良版。 + +- javaagent:代码注入 + +- javassist:*Javassist*是一个开源的分析、编辑和创建Java字节码的类库 +- network:java实现正向代理 +- proxy:java动态代理 +- spi:服务提供者接口(Service Provider Interface,简写为SPI)是JDK内置的一种服务提供发现机制。 + + + +# annotation + +- **JSR 175: A Metadata Facility for the Java**TM **Programming Language** +- **JSR 269: Pluggable Annotation Processing API** + + + +# spi + +面向对象的设计推荐模块之间基于接口编程,模块之间不对实现类进行硬编码。一旦代码里涉及具体的实现类,就违反了可拔插的原则:如果需要替换组建的一种实现,就需要修改框架的代码。SPI机制正是解决这个问题。 + +Java中SPI机制主要思想是将装配的控制权移到程序之外,是“基于接口的编程+策略模式+配置文件”组合实现的动态加载机制,有点类似Spring的IOC机制。在模块化设计中这个机制尤其重要,其核心思想就是解耦。 + +**缺点** + +- 不能按需加载。虽然 ServiceLoader 做了延迟加载,但是只能通过遍历的方式全部获取。如果其中某些实现类很耗时,而且你也不需要加载它,那么就形成了资源浪费 +- 获取某个实现类的方式不够灵活,只能通过迭代器的形式获取 + +> Dubbo SPI 实现方式对以上两点进行了业务优化。 + +# javaagent + +**简介** + +javaagent是一种能够在不影响正常编译的情况下,修改字节码。java作为一种强类型的语言,不通过编译就不能能够进行jar包的生成。而有了javaagent技术,就可以在字节码这个层面对类和方法进行修改。同时,也可以把javaagent理解成一种代码注入的方式。但是这种注入比起spring的aop更加的优美。 + +**主要作用** + +- 可以在加载java文件之前做拦截把字节码做修改 +- 可以在运行期将已经加载的类的字节码做变更,但是这种情况下会有很多的限制,后面会详细说 + 还有其他的一些小众的功能 +- 获取所有已经被加载过的类 +- 获取所有已经被初始化过了的类(执行过了clinit方法,是上面的一个子集) +- 获取某个对象的大小 +- 将某个jar加入到bootstrapclasspath里作为高优先级被bootstrapClassloader加载 +- 将某个jar加入到classpath里供AppClassload去加载 +- 设置某些native方法的前缀,主要在查找native方法的时候做规则匹配 + diff --git a/java-advance/annotation/PluggableAnnotationProcessingAPI/mylombok-test/pom.xml b/java-advance/annotation/PluggableAnnotationProcessingAPI/mylombok-test/pom.xml new file mode 100644 index 00000000..b6c3074c --- /dev/null +++ b/java-advance/annotation/PluggableAnnotationProcessingAPI/mylombok-test/pom.xml @@ -0,0 +1,23 @@ + + + 4.0.0 + + cn.cunchang + mylombok-test + 1.0-SNAPSHOT + + + 8 + 8 + + + + + cn.cunchang + mylombok + 1.0-SNAPSHOT + + + \ No newline at end of file diff --git a/java-advance/annotation/PluggableAnnotationProcessingAPI/mylombok-test/src/main/java/cn/cunchang/Person.java b/java-advance/annotation/PluggableAnnotationProcessingAPI/mylombok-test/src/main/java/cn/cunchang/Person.java new file mode 100644 index 00000000..433c3e52 --- /dev/null +++ b/java-advance/annotation/PluggableAnnotationProcessingAPI/mylombok-test/src/main/java/cn/cunchang/Person.java @@ -0,0 +1,8 @@ +package cn.cunchang; + +@MyGetter +public class Person { + + private String name; + +} diff --git a/java-advance/annotation/PluggableAnnotationProcessingAPI/mylombok/pom.xml b/java-advance/annotation/PluggableAnnotationProcessingAPI/mylombok/pom.xml new file mode 100644 index 00000000..86b5ddbd --- /dev/null +++ b/java-advance/annotation/PluggableAnnotationProcessingAPI/mylombok/pom.xml @@ -0,0 +1,62 @@ + + + 4.0.0 + + cn.cunchang + mylombok + 1.0-SNAPSHOT + + + 8 + 8 + + + + + tools + tools + 1.0 + system + ${java.home}/../lib/tools.jar + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + + -proc:none + + 1.8 + 1.8 + + + + default-compile + + -proc:none + 1.8 + 1.8 + + + + default-testCompile + + 1.8 + 1.8 + + + + + + + + + diff --git a/java-advance/annotation/PluggableAnnotationProcessingAPI/mylombok/src/main/java/cn/cunchang/MyGetter.java b/java-advance/annotation/PluggableAnnotationProcessingAPI/mylombok/src/main/java/cn/cunchang/MyGetter.java new file mode 100644 index 00000000..1f997898 --- /dev/null +++ b/java-advance/annotation/PluggableAnnotationProcessingAPI/mylombok/src/main/java/cn/cunchang/MyGetter.java @@ -0,0 +1,15 @@ +package cn.cunchang; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * @author cunchang + */ +@Retention(RetentionPolicy.SOURCE) +@Target(ElementType.TYPE) +public @interface MyGetter { + +} diff --git a/java-advance/annotation/PluggableAnnotationProcessingAPI/mylombok/src/main/java/cn/cunchang/MyGetterProcessor.java b/java-advance/annotation/PluggableAnnotationProcessingAPI/mylombok/src/main/java/cn/cunchang/MyGetterProcessor.java new file mode 100644 index 00000000..e3758e43 --- /dev/null +++ b/java-advance/annotation/PluggableAnnotationProcessingAPI/mylombok/src/main/java/cn/cunchang/MyGetterProcessor.java @@ -0,0 +1,98 @@ +package cn.cunchang; + +import com.sun.source.tree.Tree; +import com.sun.tools.javac.api.JavacTrees; +import com.sun.tools.javac.code.Flags; +import com.sun.tools.javac.code.Type; +import com.sun.tools.javac.processing.JavacProcessingEnvironment; +import com.sun.tools.javac.tree.JCTree; +import com.sun.tools.javac.tree.TreeMaker; +import com.sun.tools.javac.tree.TreeTranslator; +import com.sun.tools.javac.util.*; + +import javax.annotation.processing.*; +import javax.lang.model.SourceVersion; +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; +import javax.tools.Diagnostic; +import java.util.Set; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + + +@SupportedSourceVersion(SourceVersion.RELEASE_8) +@SupportedAnnotationTypes("cn.cunchang.MyGetter") +public class MyGetterProcessor extends AbstractProcessor { + + private Messager messager; // 编译时期输入日志的 + private JavacTrees javacTrees; // 提供了待处理的抽象语法树 + private TreeMaker treeMaker; // 封装了创建AST节点的一些方法 + private Names names; // 提供了创建标识符的方法 + + @Override + public synchronized void init(ProcessingEnvironment processingEnv) { + super.init(processingEnv); + this.messager = processingEnv.getMessager(); + this.javacTrees = JavacTrees.instance(processingEnv); + Context context = ((JavacProcessingEnvironment) processingEnv).getContext(); + this.treeMaker = TreeMaker.instance(context); + this.names = Names.instance(context); + } + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + Set elementsAnnotatedWith = roundEnv.getElementsAnnotatedWith(MyGetter.class); + elementsAnnotatedWith.forEach(e -> { + JCTree tree = javacTrees.getTree(e); + tree.accept(new TreeTranslator() { + @Override + public void visitClassDef(JCTree.JCClassDecl jcClassDecl) { + List jcVariableDeclList = List.nil(); + // 在抽象树中找出所有的变量 + for (JCTree jcTree : jcClassDecl.defs) { + if (jcTree.getKind().equals(Tree.Kind.VARIABLE)) { + JCTree.JCVariableDecl jcVariableDecl = (JCTree.JCVariableDecl) jcTree; + jcVariableDeclList = jcVariableDeclList.append(jcVariableDecl); + } + } + // 对于变量进行生成方法的操作 + jcVariableDeclList.forEach(jcVariableDecl -> { + messager.printMessage(Diagnostic.Kind.NOTE, jcVariableDecl.getName() + " has been processed"); + jcClassDecl.defs = jcClassDecl.defs.prepend(makeGetterMethodDecl(jcVariableDecl)); + }); + super.visitClassDef(jcClassDecl); + } + }); + }); + return true; + } + + private JCTree.JCMethodDecl makeGetterMethodDecl(JCTree.JCVariableDecl jcVariableDecl) { + ListBuffer statements = new ListBuffer<>(); + // 生成表达式 例如 this.a = a; + JCTree.JCExpressionStatement aThis = makeAssignment(treeMaker.Select(treeMaker.Ident( + names.fromString("this")), jcVariableDecl.getName()), treeMaker.Ident(jcVariableDecl.getName())); + statements.append(aThis); + JCTree.JCBlock block = treeMaker.Block(0, statements.toList()); + + // 生成入参 + JCTree.JCVariableDecl param = treeMaker.VarDef(treeMaker.Modifiers(Flags.PARAMETER), + jcVariableDecl.getName(), jcVariableDecl.vartype, null); + List parameters = List.of(param); + + // 生成返回对象 + JCTree.JCExpression methodType = treeMaker.Type(new Type.JCVoidType()); + return treeMaker.MethodDef(treeMaker.Modifiers(Flags.PUBLIC), + getNewMethodName(jcVariableDecl.getName()), methodType, List.nil(), + parameters, List.nil(), block, null); + } + + private Name getNewMethodName(Name name) { + String s = name.toString(); + return names.fromString("get" + s.substring(0, 1).toUpperCase() + s.substring(1, name.length())); + } + + private JCTree.JCExpressionStatement makeAssignment(JCTree.JCExpression lhs, JCTree.JCExpression rhs) { + return treeMaker.Exec(treeMaker.Assign(lhs,rhs)); + } +} diff --git a/java-advance/annotation/PluggableAnnotationProcessingAPI/mylombok/src/main/resources/META-INF/services/javax.annotation.processing.Processor b/java-advance/annotation/PluggableAnnotationProcessingAPI/mylombok/src/main/resources/META-INF/services/javax.annotation.processing.Processor new file mode 100644 index 00000000..d0e62499 --- /dev/null +++ b/java-advance/annotation/PluggableAnnotationProcessingAPI/mylombok/src/main/resources/META-INF/services/javax.annotation.processing.Processor @@ -0,0 +1 @@ +cn.cunchang.MyGetterProcessor \ No newline at end of file diff --git a/java-advance/annotation/README.md b/java-advance/annotation/README.md new file mode 100644 index 00000000..11ba12d8 --- /dev/null +++ b/java-advance/annotation/README.md @@ -0,0 +1,24 @@ +# annotation + +JSR 175: A Metadata Facility for the JavaTM Programming Language + + + + + + + +# Pluggable Annotation Processing API + + + +JSR 269: Pluggable Annotation Processing API + +参考:https://juejin.cn/post/6844904106545381384?utm_source=ZHShareTargetIDMore&utm_medium=social&utm_oi=825791253932290048#heading-16 + + + + + + + diff --git a/java-advance/annotation/annatation/pom.xml b/java-advance/annotation/annatation/pom.xml new file mode 100644 index 00000000..d890a7cd --- /dev/null +++ b/java-advance/annotation/annatation/pom.xml @@ -0,0 +1,26 @@ + + + 4.0.0 + + cn.cunchang + annatation + 1.0-SNAPSHOT + + JSR 175: A Metadata Facility for the JavaTM Programming Language + + + 8 + 8 + + + + + junit + junit + 4.13 + + + + \ No newline at end of file diff --git a/java-advance/annotation/annatation/src/main/java/cn/cunchang/AnnotationTest.java b/java-advance/annotation/annatation/src/main/java/cn/cunchang/AnnotationTest.java new file mode 100644 index 00000000..a6eb5ea4 --- /dev/null +++ b/java-advance/annotation/annatation/src/main/java/cn/cunchang/AnnotationTest.java @@ -0,0 +1,85 @@ +package cn.cunchang; + +import cn.cunchang.dynamicvalue.JsonProperty; +import cn.cunchang.syntax.MyAnnotation; +import org.junit.Test; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.Arrays; +import java.util.Map; +import java.util.Objects; + +/** + * jdk5新特性:注解 + * + * @author cunchang + */ +public class AnnotationTest { + + @Test + public void test一个什么都有的注解() throws Exception { + Class clazz = Class.forName("cn.cunchang.syntax.UseAnnotation"); + // 类上的注解 + if (clazz.isAnnotationPresent(MyAnnotation.class)) { + MyAnnotation annotation = clazz.getAnnotation(MyAnnotation.class); + System.err.println("使用类上的注解"); + printMyAnnotation(annotation); + } + // 方法上的注解 + Method[] methods = clazz.getDeclaredMethods(); + for (Method method : methods) { + MyAnnotation annotation = method.getAnnotation(MyAnnotation.class); + System.err.println("使用方法上的注解"); + printMyAnnotation(annotation); + } + } + + public void printMyAnnotation(MyAnnotation annotation) { + if(Objects.isNull(annotation)){ + return; + } + System.out.println(annotation.color()); + System.out.println(annotation.value()); + System.out.println(Arrays.toString(annotation.arrayAttr())); + System.out.println(annotation.clazz()); + System.out.println(annotation.enumLevel()); + System.out.println(annotation.annotation().value()); + } + + /** + * Changing Annotation Parameters At Runtime + *

+ * https://segmentfault.com/a/1190000011213222 + * + * @throws Exception + */ + @Test + public void test运行期动态修改注解value() throws Exception { + Class clazz = Class.forName("cn.cunchang.dynamicvalue.StudentRsp"); + //获取 StudentRsp 的 name 字段 + Field field = clazz.getDeclaredField("name"); + //获取 name 字段上的 JsonProperty 注解实例 + JsonProperty jsonProperty = field.getAnnotation(JsonProperty.class); + + System.out.println("当前 jsonProperty value:" + jsonProperty.value()); + + //获取 JsonProperty 这个代理实例所持有的 InvocationHandler + InvocationHandler invocationHandler = Proxy.getInvocationHandler(jsonProperty); + // 获取 AnnotationInvocationHandler 的 memberValues 字段 + Field hField = invocationHandler.getClass().getDeclaredField("memberValues"); + // 设置访问权限 + hField.setAccessible(true); + // 获取 memberValues + Map memberValues = (Map) hField.get(invocationHandler); + // 修改 value 属性值 + memberValues.put("value", "beisen_pro_name"); + + // 获取 JsonProperty 的 value 属性值 + System.out.println("当前 jsonProperty value:" + jsonProperty.value()); + + } + +} diff --git a/java-advance/annotation/annatation/src/main/java/cn/cunchang/corejava/buttons3/ButtonFrame.java b/java-advance/annotation/annatation/src/main/java/cn/cunchang/corejava/buttons3/ButtonFrame.java new file mode 100644 index 00000000..782effcd --- /dev/null +++ b/java-advance/annotation/annatation/src/main/java/cn/cunchang/corejava/buttons3/ButtonFrame.java @@ -0,0 +1,59 @@ +package cn.cunchang.corejava.buttons3; + +import java.awt.*; +import javax.swing.*; + +import cn.cunchang.corejava.runtimeAnnotations.ActionListenerFor; +import cn.cunchang.corejava.runtimeAnnotations.ActionListenerInstaller; + +/** + * A frame with a button panel. + * @version 1.00 2004-08-17 + * @author Cay Horstmann + */ +public class ButtonFrame extends JFrame +{ + private static final int DEFAULT_WIDTH = 300; + private static final int DEFAULT_HEIGHT = 200; + + private JPanel panel; + private JButton yellowButton; + private JButton blueButton; + private JButton redButton; + + public ButtonFrame() + { + setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT); + + panel = new JPanel(); + add(panel); + + yellowButton = new JButton("Yellow"); + blueButton = new JButton("Blue"); + redButton = new JButton("Red"); + + panel.add(yellowButton); + panel.add(blueButton); + panel.add(redButton); + + ActionListenerInstaller.processAnnotations(this); + } + + @ActionListenerFor(source = "yellowButton") + public void yellowBackground() + { + panel.setBackground(Color.YELLOW); + } + + @ActionListenerFor(source = "blueButton") + public void blueBackground() + { + panel.setBackground(Color.BLUE); + } + + @ActionListenerFor(source = "redButton") + public void redBackground() + { + panel.setBackground(Color.RED); + } +} diff --git a/java-advance/annotation/annatation/src/main/java/cn/cunchang/corejava/buttons3/ButtonTest.java b/java-advance/annotation/annatation/src/main/java/cn/cunchang/corejava/buttons3/ButtonTest.java new file mode 100644 index 00000000..de248322 --- /dev/null +++ b/java-advance/annotation/annatation/src/main/java/cn/cunchang/corejava/buttons3/ButtonTest.java @@ -0,0 +1,23 @@ +package cn.cunchang.corejava.buttons3; + +import java.awt.*; +import javax.swing.*; + +/** + * @version 1.01 2016-05-10 + * @author Cay Horstmann + */ +public class ButtonTest +{ + public static void main(String[] args) + { + EventQueue.invokeLater(() -> + { + + ButtonFrame frame = new ButtonFrame(); + frame.setTitle("ButtonTest"); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.setVisible(true); + }); + } +} \ No newline at end of file diff --git a/java-advance/annotation/annatation/src/main/java/cn/cunchang/corejava/runtimeAnnotations/ActionListenerFor.java b/java-advance/annotation/annatation/src/main/java/cn/cunchang/corejava/runtimeAnnotations/ActionListenerFor.java new file mode 100644 index 00000000..33495d4f --- /dev/null +++ b/java-advance/annotation/annatation/src/main/java/cn/cunchang/corejava/runtimeAnnotations/ActionListenerFor.java @@ -0,0 +1,15 @@ +package cn.cunchang.corejava.runtimeAnnotations; + +import java.lang.annotation.*; + +/** + * @version 1.00 2004-08-17 + * @author Cay Horstmann + */ + +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface ActionListenerFor +{ + String source(); +} diff --git a/java-advance/annotation/annatation/src/main/java/cn/cunchang/corejava/runtimeAnnotations/ActionListenerInstaller.java b/java-advance/annotation/annatation/src/main/java/cn/cunchang/corejava/runtimeAnnotations/ActionListenerInstaller.java new file mode 100644 index 00000000..18924fee --- /dev/null +++ b/java-advance/annotation/annatation/src/main/java/cn/cunchang/corejava/runtimeAnnotations/ActionListenerInstaller.java @@ -0,0 +1,62 @@ +package cn.cunchang.corejava.runtimeAnnotations; + +import java.awt.event.*; +import java.lang.reflect.*; + +/** + * @version 1.00 2004-08-17 + * @author Cay Horstmann + */ +public class ActionListenerInstaller +{ + /** + * Processes all ActionListenerFor annotations in the given object. + * @param obj an object whose methods may have ActionListenerFor annotations + */ + public static void processAnnotations(Object obj) + { + try + { + Class cl = obj.getClass(); + // 获取所有方法 + for (Method m : cl.getDeclaredMethods()) + { + ActionListenerFor a = m.getAnnotation(ActionListenerFor.class); + if (a != null) + { + // 获取方法上的注解,ActionListenerFor 里面的 source 值 + Field f = cl.getDeclaredField(a.source()); + f.setAccessible(true); + addListener(f.get(obj), obj, m); + } + } + } + catch (ReflectiveOperationException e) + { + e.printStackTrace(); + } + } + + /** + * Adds an action listener that calls a given method. + * @param source the event source to which an action listener is added + * @param param the implicit parameter of the method that the listener calls + * @param m the method that the listener calls + */ + public static void addListener(Object source, final Object param, final Method m) + throws ReflectiveOperationException + { + InvocationHandler handler = new InvocationHandler() + { + public Object invoke(Object proxy, Method mm, Object[] args) throws Throwable + { + return m.invoke(param); + } + }; + + Object listener = Proxy.newProxyInstance(null, + new Class[] { ActionListener.class }, handler); + Method adder = source.getClass().getMethod("addActionListener", ActionListener.class); + adder.invoke(source, listener); + } +} diff --git a/java-advance/annotation/annatation/src/main/java/cn/cunchang/dynamicvalue/JsonProperty.java b/java-advance/annotation/annatation/src/main/java/cn/cunchang/dynamicvalue/JsonProperty.java new file mode 100644 index 00000000..ee598dc8 --- /dev/null +++ b/java-advance/annotation/annatation/src/main/java/cn/cunchang/dynamicvalue/JsonProperty.java @@ -0,0 +1,15 @@ +package cn.cunchang.dynamicvalue; + + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.METHOD, ElementType.TYPE, ElementType.FIELD}) +public @interface JsonProperty { + + String value(); + +} diff --git a/java-advance/annotation/annatation/src/main/java/cn/cunchang/dynamicvalue/StudentRsp.java b/java-advance/annotation/annatation/src/main/java/cn/cunchang/dynamicvalue/StudentRsp.java new file mode 100644 index 00000000..1a1608a7 --- /dev/null +++ b/java-advance/annotation/annatation/src/main/java/cn/cunchang/dynamicvalue/StudentRsp.java @@ -0,0 +1,17 @@ +package cn.cunchang.dynamicvalue; + +/** + * @author cunchang + * @date 2021/4/19 8:02 下午 + */ +public class StudentRsp { + + /** + * stable beisen_test_name + * real beisen_pro_name + */ + @JsonProperty("beisen_test_name") + public String name; + + +} diff --git a/java-advance/annotation/annatation/src/main/java/cn/cunchang/syntax/Level.java b/java-advance/annotation/annatation/src/main/java/cn/cunchang/syntax/Level.java new file mode 100644 index 00000000..11d359f3 --- /dev/null +++ b/java-advance/annotation/annatation/src/main/java/cn/cunchang/syntax/Level.java @@ -0,0 +1,3 @@ +package cn.cunchang.syntax; + +public enum Level {BAD, INDIFFERENT, GOOD} \ No newline at end of file diff --git a/java-advance/annotation/annatation/src/main/java/cn/cunchang/syntax/MetaAnnotation.java b/java-advance/annotation/annatation/src/main/java/cn/cunchang/syntax/MetaAnnotation.java new file mode 100644 index 00000000..a9efae29 --- /dev/null +++ b/java-advance/annotation/annatation/src/main/java/cn/cunchang/syntax/MetaAnnotation.java @@ -0,0 +1,7 @@ +package cn.cunchang.syntax; + +public @interface MetaAnnotation { + + String value() default "MetaAnnotation default value"; + +} \ No newline at end of file diff --git a/java-advance/annotation/annatation/src/main/java/cn/cunchang/syntax/MyAnnotation.java b/java-advance/annotation/annatation/src/main/java/cn/cunchang/syntax/MyAnnotation.java new file mode 100644 index 00000000..d3ecda43 --- /dev/null +++ b/java-advance/annotation/annatation/src/main/java/cn/cunchang/syntax/MyAnnotation.java @@ -0,0 +1,37 @@ +package cn.cunchang.syntax; + +// 自定义注解 + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + + +@Retention(RetentionPolicy.RUNTIME)//保留策略 +@Target({ElementType.METHOD, ElementType.TYPE})//作用目标 // 为什么是TYPE,因为Class的父类是Type +public @interface MyAnnotation { + // 八大基本数据类型、String、Class、Enum、注解类型对应的数组类型 + + String color() default "green"; + + String value();//value比较特殊 + + int[] arrayAttr() default {1, 2, 3}; + + Class clazz() default Formatter.class; + + Level enumLevel() default Level.GOOD; + + MetaAnnotation annotation() default @MetaAnnotation("xxx"); + +} + + +interface Formatter { +} + + + + + diff --git a/java-advance/annotation/annatation/src/main/java/cn/cunchang/syntax/UseAnnotation.java b/java-advance/annotation/annatation/src/main/java/cn/cunchang/syntax/UseAnnotation.java new file mode 100644 index 00000000..58e93f6a --- /dev/null +++ b/java-advance/annotation/annatation/src/main/java/cn/cunchang/syntax/UseAnnotation.java @@ -0,0 +1,23 @@ +package cn.cunchang.syntax; + +/** + * @author cunchang + */ + +@MyAnnotation(color = "red", value = "/user/login", + arrayAttr = {4, 5, 6}, enumLevel = Level.INDIFFERENT, + annotation = @MetaAnnotation("yyy"), clazz = Formatter.class) +public class UseAnnotation { + + @MyAnnotation("yyy") + @SuppressWarnings("deprecation") + public static void deprecatedFun() { + sayHello(); + } + + @Deprecated + public static void sayHello() { + System.out.println("被弃用的函数"); + } + +} diff --git a/java-advance/groovy/README.md b/java-advance/groovy/README.md new file mode 100644 index 00000000..1a6b7677 --- /dev/null +++ b/java-advance/groovy/README.md @@ -0,0 +1 @@ +groovy动态解析脚本 \ No newline at end of file diff --git a/java-advance/groovy/pom.xml b/java-advance/groovy/pom.xml new file mode 100644 index 00000000..24cfd548 --- /dev/null +++ b/java-advance/groovy/pom.xml @@ -0,0 +1,47 @@ + + + 4.0.0 + + cn.cunchang + groovy + 1.0-SNAPSHOT + + + 8 + 8 + + + + + org.codehaus.groovy + groovy-all + 2.4.10 + + + junit + junit + 4.12 + + + + org.projectlombok + lombok + 1.18.24 + true + + + + com.alibaba + fastjson + 1.2.80 + + + + cn.hutool + hutool-all + 5.8.0 + + + \ No newline at end of file diff --git a/java-advance/groovy/src/main/java/cn/cunchang/Client.java b/java-advance/groovy/src/main/java/cn/cunchang/Client.java new file mode 100644 index 00000000..6c67b14b --- /dev/null +++ b/java-advance/groovy/src/main/java/cn/cunchang/Client.java @@ -0,0 +1,48 @@ +package cn.cunchang; + +import cn.hutool.core.io.file.FileReader; +import com.alibaba.fastjson.JSONObject; +import groovy.lang.GroovyClassLoader; +import groovy.lang.GroovyObject; +import groovy.lang.GroovyShell; +import groovy.lang.Script; +import org.junit.Test; + +/** + * @author cunchang + * @date 2022/5/30 11:38 AM + */ +public class Client { + + + public static void main(String[] args) throws InstantiationException, IllegalAccessException { + FileReader jsonFileReader = new FileReader("rsp.json"); + String jsonStr = jsonFileReader.readString(); + JSONObject jsonObject = JSONObject.parseObject(jsonStr); + + FileReader groovyFileReader = new FileReader("Demo.groovy"); + String groovyStr = groovyFileReader.readString(); + + GroovyShell shell = new GroovyShell(); + Script script = shell.parse(groovyStr); + PaymentRequestOrderBO paymentRequestOrderBO = (PaymentRequestOrderBO) script.invokeMethod("extract", jsonObject); + + System.out.println(JSONObject.toJSONString(paymentRequestOrderBO)); + } + + @Test + public void test() throws InstantiationException, IllegalAccessException { + GroovyClassLoader groovyClassLoader = new GroovyClassLoader(); + String helloScript = "package cn.cunchang;" + // 可以是纯Java代码 + "class Hello {" + + "String say(String name) {" + + "System.out.println(\"hello, \" + name);" + + " return name;" + + "}" + + "}"; + Class helloClass = groovyClassLoader.parseClass(helloScript); + GroovyObject object = (GroovyObject) helloClass.newInstance(); + Object ret = object.invokeMethod("say", "vivo"); + System.out.println(helloClass.getName()); + } +} diff --git a/java-advance/groovy/src/main/java/cn/cunchang/Constants.java b/java-advance/groovy/src/main/java/cn/cunchang/Constants.java new file mode 100644 index 00000000..e229fc05 --- /dev/null +++ b/java-advance/groovy/src/main/java/cn/cunchang/Constants.java @@ -0,0 +1,47 @@ +package cn.cunchang; + +/** + * @author cunchang + * @date 2022/5/30 4:14 PM + */ +public class Constants { + + // 详情的form节点 + public static final String VALUE = "value"; + public static final String FORM = "form"; + /** + * 单据模板唯一ID + * 同一个单据模板,除非删除重建,不然不会改变 + */ + public static final String TEMPLATE_ID = "specificationId"; + // 单据编码 + public static final String CODE = "code"; + // 收款人id,用于获取收款人信息 + public static final String PAYEE_ID = "payeeId"; + // 证件类型 + public static final String CERTIFICATE_TYPE_1 = "居民身份证"; + // 提交人id + public static final String SUBMITTER_ID = "submitterId"; + // 提交日期 + public static final String SUBMITTER_DATE = "submitDate"; + public static final String CONTRACT_ID = "u_合同ID"; + public static final String SHOP_ID = "u_商户ID"; + public static final String SHOP_NAME = "u_商户名称"; + public static final String SHOP_TYPE = "u_商户类型1"; + public static final String INVOICE_METHOD = "u_票款顺序"; + public static final String AREA_DEPARTMENT = "u_大区事业部"; + public static final String REMARK = "description"; + public static final String CITY = "u_所属城市"; + public static final String PAYMENT_COMPANY = "法人实体"; + public static final String PAYMENT_COMPANY_2 = "u_我方公司名称"; + public static final String u_所属主体 = "u_所属主体"; + public static final String PAY_MONEY = "payMoney"; + public static final String PRE_TAX_MONEY = "u_税前金额"; + public static final String PAY_MONEY_STANDARD = "standard"; + + public static final String u_代理商名称 = "u_代理商名称"; + + public static final String 个人账户 = "个人账户"; + public static final String 对公账户 = "对公账户"; + +} diff --git a/java-advance/groovy/src/main/java/cn/cunchang/PaymentRequestOrderBO.java b/java-advance/groovy/src/main/java/cn/cunchang/PaymentRequestOrderBO.java new file mode 100644 index 00000000..48e96486 --- /dev/null +++ b/java-advance/groovy/src/main/java/cn/cunchang/PaymentRequestOrderBO.java @@ -0,0 +1,179 @@ +package cn.cunchang; + +import lombok.Data; + +@Data +public class PaymentRequestOrderBO { + + /** + * 主键 + */ + private Long id; + + /** + * 业务单号
+ * 1. 易快报单据编码 + */ + private String bizNo; + + /** + * 易快报单据id + */ + private String flowId; + + /** + * 付款单流水号 + */ + private String payBillNo; + + /** + * 单据类型 + */ + private Integer bizType; + + /** + * 业务类型,对应付款单的业务类型 + */ + private Integer payBizType; + + /** + * 单据类型名称 + */ + private String bizTypeStr; + + /** + * 业务类型名称 + */ + private String payBizTypeStr; + + /** + * 付款金额,单位分 + */ + private Long payAmount; + + /** + * 税前金额,单位分 + */ + private Long preTaxAmount; + + /** + * 付款主体 + */ + private Integer paymentCompany; + + /** + * 合同id + */ + private Long contractId; + + /** + * 商家id + */ + private Long shopId; + + /** + * 商家名称 + */ + private String shopName; + + /** + * 主体名称 + */ + private String subjectName; + + /** + * 账户所属主体 + */ + private String accountSubject; + + /** + * 结算方id + */ + private Long settleSubjectId; + + /** + * 大区/事业部 + */ + private String areaDepartment; + + /** + * 所属城市 + */ + private String city; + + /** + * 申请单说明 + */ + private String remark; + + /** + * 附件信息 + */ + private String attachment; + + /** + * 提交人ID + */ + private String submitterId; + + /** + * 提交人 + */ + private String submitter; + + /** + * 单据提交时间 + */ + protected Long submitTime; + + // --------------- 收款人信息 ----------------- + + /** + * 收款人 + */ + private String revAccName; + + /** + * 收款账号 + */ + private String revAccNo; + + /** + * 开户银行名称 + */ + private String revBankName; + + /** + * 开户银行支行名称 + */ + private String revBankBranch; + + /** + * 银行联行号,直接支付需要 + */ + private String revBankNo; + + /** + * 收款人身份证号,第三方支付身份证必传 + */ + private String revCardId; + + /** + * 收款人手机号 + */ + private String revMobile; + + /** + * 收方开户银行省份 + */ + private String revBankProvince; + + /** + * 收方开户银行城市 + */ + private String revBankCity; + /** + * 付款主体在易快报code + */ + private String ykbCompanyCode; +} diff --git a/java-advance/groovy/src/main/resources/Demo.groovy b/java-advance/groovy/src/main/resources/Demo.groovy new file mode 100644 index 00000000..dfeac409 --- /dev/null +++ b/java-advance/groovy/src/main/resources/Demo.groovy @@ -0,0 +1,18 @@ +import cn.cunchang.Constants +import cn.cunchang.PaymentRequestOrderBO +import com.alibaba.fastjson.JSONObject + +PaymentRequestOrderBO extract(JSONObject jsonObject) throws Exception { + PaymentRequestOrderBO paymentRequestOrderBO = new PaymentRequestOrderBO() + + // value节点 + JSONObject value = jsonObject.getJSONObject(Constants.VALUE) + // form节点 + JSONObject form = value.getJSONObject(Constants.FORM) + + // 合同ID + String agentName = form.getString(Constants.u_代理商名称); + paymentRequestOrderBO.setShopName(agentName); + + return paymentRequestOrderBO; +} diff --git a/java-advance/groovy/src/main/resources/rsp.json b/java-advance/groovy/src/main/resources/rsp.json new file mode 100644 index 00000000..0fff182b --- /dev/null +++ b/java-advance/groovy/src/main/resources/rsp.json @@ -0,0 +1,242 @@ + +{ + "value":{ + "pipeline":1, + "grayver":"9.30.0.0:A", + "version":5, + "active":true, + "createTime":1653564772443, + "updateTime":1653566242498, + "corporationId":"aOc9TH-dmo0c00", + "sourceCorporationId":null, + "dataCorporationId":null, + "form":{ + "code":"B22004119", + "title":"代理商", + "details":[ + { + "feeTypeId":"Z0gc6-zLKosQ00", + "feeTypeForm":{ + "amount":{ + "standard":"1", + "standardUnit":"元", + "standardScale":2, + "standardSymbol":"¥", + "standardNumCode":"156", + "standardStrCode":"CNY" + }, + "feeDate":1653494400000, + "detailId":"ID_3GZvaW6cp30", + "attachments":[ + + ], + "invoiceForm":{ + "type":"noWrite" + }, + "consumptionReasons":"1" + }, + "specificationId":"Z0gc6-zLKosQ00:expense:c3d95ed2347bf65b3ffda07e0a460a742c846454", + "feeType":{ + "id":"Z0gc6-zLKosQ00", + "name":"商家分成相关-有票", + "parentId":"", + "active":true, + "code":"016" + } + } + ], + "payeeId":"ID_3GZu7TEgjDg", + "payMoney":{ + "standard":"1.00", + "standardUnit":"元", + "standardScale":2, + "standardSymbol":"¥", + "standardNumCode":"156", + "standardStrCode":"CNY" + }, + "voucherNo":"", + "printCount":"0", + "printState":"noPrint", + "submitDate":1653566109520, + "attachments":[ + { + "key":"2-1653564645311-142.webp", + "fileId":"ID_3GZthA$IIPw", + "fileName":"2.webp" + } + ], + "description":"1", + "expenseDate":1653494400000, + "submitterId":"aOc9TH-dmo0c00:2167475407768135", + "expenseMoney":{ + "standard":"1.00", + "standardUnit":"元", + "standardScale":2, + "standardSymbol":"¥", + "standardNumCode":"156", + "standardStrCode":"CNY" + }, + "u_代理商ID":"1", + "voucherStatus":"未生成", + "companyRealPay":{ + "standard":"0.00", + "standardUnit":"元", + "standardScale":2, + "standardSymbol":"¥", + "standardNumCode":"156", + "standardStrCode":"CNY" + }, + "onlyOwnerPrint":false, + "u_所属主体":"ID_3gv0rVL4has", + "u_所属城市":"[{\"key\":\"858\",\"label\":\"上海市/上海市区\"}]", + "u_打款金额":{ + "standard":"1", + "standardUnit":"元", + "standardScale":2, + "standardSymbol":"¥", + "standardNumCode":"156", + "standardStrCode":"CNY" + }, + "specificationId":"ID_3GTiWkHZSDM:2521411b6b88ac1fdc2bddc949208018932e67ea", + "writtenOffMoney":{ + "standard":"0.00", + "standardUnit":"元", + "standardScale":2, + "standardSymbol":"¥", + "standardNumCode":"156", + "standardStrCode":"CNY" + }, + "expenseDepartment":"aOc9TH-dmo0c00:476694398", + "u_代理商名称":"寸长代理商", + "u_第几次付款":"1", + "voucherCreateTime":0, + "preNodeApprovedTime":1653566242488, + "u_分成账户余额":{ + "standard":"10", + "standardUnit":"元", + "standardScale":2, + "standardSymbol":"¥", + "standardNumCode":"156", + "standardStrCode":"CNY" + }, + "u_我方公司名称":"gi0cghrKAAOk00", + "u_渠道所属大区":"ID_3GsSytCFJZM", + "u_线下付款原因":"线下付款原因", + "timeToEnterPendingPayment":1653566242498, + "ownerAndApproverPrintNodeFlag":false + }, + "ownerId":"aOc9TH-dmo0c00:2167475407768135", + "ownerDefaultDepartment":"aOc9TH-dmo0c00:476694398", + "state":"paying", + "flowType":"freeflow", + "formType":"expense", + "logs":[ + { + "action":"freeflow.submit", + "state":"approving", + "operatorId":"aOc9TH-dmo0c00:2167475407768135", + "byDelegateId":null, + "operatorDefaultDepartment":"aOc9TH-dmo0c00:476694398", + "nextOperatorId":"ebot", + "nextOperatorIds":[ + + ], + "time":1653566113650, + "attributes":{ + "nextId":"FLOW:1337089428:1774981071", + "nodeId":"SUBMIT", + "comment":"", + "isUrgent":false, + "nextName":"费用标准检查", + "urgentReason":null, + "resubmitMethod":"FROM_START", + "nextCounterSign":false, + "sensitiveContent":null, + "resubmitOperatorIds":[ + + ] + }, + "modifyFlowLog":null, + "attachments":[ + + ] + }, + { + "action":"freeflow.agree", + "state":"approving", + "operatorId":"aOc9TH-dmo0c00:2167475407768135", + "byDelegateId":null, + "operatorDefaultDepartment":"aOc9TH-dmo0c00:476694398", + "nextOperatorId":"ebot", + "nextOperatorIds":[ + + ], + "time":1653566241843, + "attributes":{ + "nextId":"FLOW:194583488:1595867343", + "nodeId":"FLOW:1489097468:862917124", + "comment":"同意", + "complete":true, + "nextName":"对接CBS", + "nodeName":"审批节点1", + "expressNum":null, + "isEbotNode":false, + "counterSign":false, + "isRecalNode":false, + "oldFlowPlanId":null, + "nextCounterSign":false, + "autographImageId":null + }, + "modifyFlowLog":null, + "attachments":[ + + ] + }, + { + "action":"freeflow.agree", + "state":"paying", + "operatorId":"ebot", + "byDelegateId":null, + "operatorDefaultDepartment":null, + "nextOperatorId":"aOc9TH-dmo0c00:2167475407768135", + "nextOperatorIds":[ + + ], + "time":1653566242498, + "attributes":{ + "nextId":"FLOW:1374256138:1133323930", + "nodeId":"FLOW:194583488:1595867343", + "comment":"", + "complete":true, + "nextName":"出纳支付", + "nodeName":"对接CBS", + "expressNum":null, + "isEbotNode":true, + "counterSign":false, + "isRecalNode":false, + "oldFlowPlanId":null, + "nextCounterSign":false, + "autographImageId":null + }, + "modifyFlowLog":null, + "attachments":[ + + ] + } + ], + "actions":{ + "aOc9TH-dmo0c00:2167475407768135":[ + "freeflow.urge", + "freeflow.copy", + "freeflow.print", + "freeflow.reject", + "freeflow.pay", + "freeflow.addnode", + "freeflow.remind", + "freeflow.printed" + ] + }, + "invoiceRemind":false, + "id":"ID_3GZvaW6cc30" + } +} diff --git a/java-advance/javaagent/pom.xml b/java-advance/javaagent/pom.xml new file mode 100644 index 00000000..2711850d --- /dev/null +++ b/java-advance/javaagent/pom.xml @@ -0,0 +1,52 @@ + + + + apm + cn.lastwhisper + 1.0-SNAPSHOT + + 4.0.0 + + javaagent + + + + + org.apache.maven.plugins + maven-jar-plugin + 2.2 + + + + ${project.name} + ${project.version} + cn.lastwhisper.Agent + javassist-3.18.1-GA.jar + false + + + true + + + + + + + org.javassist + javassist + 3.18.1-GA + + + org.springframework + spring-webmvc + 4.0.4.RELEASE + + + javax.servlet + javax.servlet-api + 3.1.0 + + + \ No newline at end of file diff --git a/java-advance/javaagent/src/main/java/cn/lastwhisper/Agent.java b/java-advance/javaagent/src/main/java/cn/lastwhisper/Agent.java new file mode 100644 index 00000000..2e8bee50 --- /dev/null +++ b/java-advance/javaagent/src/main/java/cn/lastwhisper/Agent.java @@ -0,0 +1,28 @@ +package cn.lastwhisper; + +import java.lang.instrument.Instrumentation; + +/** + * https://www.cnblogs.com/aspirant/p/8796974.html + * @author lastwhisper + */ +public class Agent { + /** + * 该方法在main方法之前运行,与main方法运行在同一个JVM中 + * 并被同一个System ClassLoader装载 + * 被统一的安全策略(security policy)和上下文(context)管理 + */ + public static void premain(String agentOps, Instrumentation inst) { + System.out.println("=========premain方法执行========"); + System.out.println("agentOps:"+agentOps); + } + + /** + * 如果不存在 premain(String agentOps, Instrumentation inst) + * 则会执行 premain(String agentOps) + */ + public static void premain(String agentOps) { + System.out.println("=========premain方法执行2========"); + System.out.println("agentOps:"+agentOps); + } +} diff --git a/java-advance/javaagent/src/main/java/cn/lastwhisper/AgentTest.java b/java-advance/javaagent/src/main/java/cn/lastwhisper/AgentTest.java new file mode 100644 index 00000000..56779a07 --- /dev/null +++ b/java-advance/javaagent/src/main/java/cn/lastwhisper/AgentTest.java @@ -0,0 +1,15 @@ +package cn.lastwhisper; + +/** + * 该main方法用于测试Agent + * @author lastwhisper + */ +public class AgentTest { + + /** + * 启动参数:-javaagent:$HOME\Projects\Github\code\java-advance\apm\javaagent\target\javaagent-1.0-SNAPSHOT.jar + */ + public static void main(String[] args){ + System.out.println("=========main方法执行========"); + } +} diff --git a/java-advance/javassist/pom.xml b/java-advance/javassist/pom.xml new file mode 100644 index 00000000..c0e11173 --- /dev/null +++ b/java-advance/javassist/pom.xml @@ -0,0 +1,44 @@ + + + + apm + cn.lastwhisper + 1.0-SNAPSHOT + + 4.0.0 + + cn.lastwhisper + javassist + + + + org.apache.maven.plugins + maven-compiler-plugin + + 6 + 6 + + + + + + + + org.javassist + javassist + 3.18.1-GA + + + org.springframework + spring-webmvc + 4.0.4.RELEASE + + + javax.servlet + javax.servlet-api + 3.1.0 + + + \ No newline at end of file diff --git a/java-advance/javassist/src/main/java/cn/lastwhisper/javassist/DispatcherServletCollect.java b/java-advance/javassist/src/main/java/cn/lastwhisper/javassist/DispatcherServletCollect.java new file mode 100644 index 00000000..5c90e873 --- /dev/null +++ b/java-advance/javassist/src/main/java/cn/lastwhisper/javassist/DispatcherServletCollect.java @@ -0,0 +1,36 @@ +package cn.lastwhisper.javassist; + + +import javax.servlet.ServletInputStream; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * @author Administrator + */ +public class DispatcherServletCollect { + + public static void begin(Object[] params) { + HttpServletRequest request = (HttpServletRequest) params[0]; + try { + ServletInputStream is = request.getInputStream(); + + } catch (IOException e) { + e.printStackTrace(); + } + System.out.println("APM 远程地址是:" + request.getRequestURI()); + } + + public static void end(Object[] params) { + HttpServletResponse response = (HttpServletResponse) params[1]; + try { + ServletOutputStream os = response.getOutputStream(); + + } catch (IOException e) { + e.printStackTrace(); + } + } + +} diff --git a/java-advance/javassist/src/main/java/cn/lastwhisper/javassist/Error1.java b/java-advance/javassist/src/main/java/cn/lastwhisper/javassist/Error1.java new file mode 100644 index 00000000..eb4d361b --- /dev/null +++ b/java-advance/javassist/src/main/java/cn/lastwhisper/javassist/Error1.java @@ -0,0 +1,59 @@ +package cn.lastwhisper.javassist; + +import javassist.*; + + +/** + * 测试 + * @author lastwhisper + */ +public class Error1 { + + public interface IHello { + public void sayHello(String name); + } + /** + * 错误示范: + * 不会对类型进行强制检查:如 int i=System.nanoTime(); 或 int i="abc"; + */ + public static void main(String[] args) { + // true表示根据当前类去搜索 + ClassPool pool = new ClassPool(true); + try { + // 构建CtClass对象 + CtClass targetClass = pool.makeClass("cn.lastwhisper.javassist.IHello"); + // 实现接口 + targetClass.addInterface(pool.get(IHello.class.getName())); + // 实现方法,方法名 + String mName = "sayHello"; + // 实现方法,获取方法返回类型的CtClass + CtClass returnType = pool.get(void.class.getName()); + // 实现方法,获取方法入参的CtClass + CtClass[] parameters = new CtClass[]{pool.get(String.class.getName())}; + // 根据方法名、返回类型、入参类型实现方法 + CtMethod ctMethod = new CtMethod(returnType, mName, parameters, targetClass); + + // 设置实现方法的方法体 + String body = "{" + + "System.out.println(\"$1:\t\"+$1);" + + "int i=System.nanoTime();" + + //"int k =\"abc\";"+ //在clazz.newInstance()时才能发现错误 + "System.out.println(i);" + + "System.out.println(\"$args:\t\"+$args);" + + "System.out.println(\"$type:\t\"+$type);" + + "System.out.println(\"$class:\t\"+$class);" + + "System.out.println(\"hello:\t\"+$1);" + + "}"; + ctMethod.setBody(body); + targetClass.addMethod(ctMethod); + // 装载Class + Class clazz = targetClass.toClass(); + // 使用反射创建对象 + IHello hello = (IHello) clazz.newInstance(); + hello.sayHello("tom"); + } catch (NotFoundException | CannotCompileException | IllegalAccessException | InstantiationException e) { + e.printStackTrace(); + } + + } +} \ No newline at end of file diff --git a/java-advance/javassist/src/main/java/cn/lastwhisper/javassist/Error2.java b/java-advance/javassist/src/main/java/cn/lastwhisper/javassist/Error2.java new file mode 100644 index 00000000..b75c3852 --- /dev/null +++ b/java-advance/javassist/src/main/java/cn/lastwhisper/javassist/Error2.java @@ -0,0 +1,44 @@ +package cn.lastwhisper.javassist; + +import javassist.*; + +/** + * 计算方法用时 + * @author lastwhisper + */ +public class Error2 { + /** + * 错误示范:不能引用在方法中其它地方定义的局部变量 + */ + public static void main(String[] args) { + ClassPool pool = new ClassPool(true); + pool.insertClassPath(new LoaderClassPath(Error2.class.getClassLoader())); + try { + CtClass targetClass = pool.get("cn.lastwhisper.javassist.StringUtil"); + CtMethod ctMethod = targetClass.getDeclaredMethod("addString"); + ctMethod.insertBefore( + "{ " + + "System.out.println(\"====before====\");" + + "long begin = System.nanoTime();" + + "System.out.println(begin);" + + "}"); + // insertBefore代码块中的局部变量,insertAfter中访问不到 + ctMethod.insertAfter("{ " + + "System.out.println(\"====after====\");" + + "long end = System.nanoTime();" + + "System.out.println(end);" + + "}"); + //ctMethod.insertAfter("{ " + + // "System.out.println(\"====after====\");" + + // "long end = System.nanoTime();" + + // "System.out.println(\"耗时:\"+(end-begin));" + + // "}"); + Class clazz = targetClass.toClass(); + StringUtil util = (StringUtil) clazz.newInstance(); + System.out.println(util.addString(100)); + } catch (NotFoundException | CannotCompileException | IllegalAccessException | InstantiationException e) { + e.printStackTrace(); + } + + } +} diff --git a/java-advance/javassist/src/main/java/cn/lastwhisper/javassist/JavassistDynamicProxyClass.java b/java-advance/javassist/src/main/java/cn/lastwhisper/javassist/JavassistDynamicProxyClass.java new file mode 100644 index 00000000..fdc2ba99 --- /dev/null +++ b/java-advance/javassist/src/main/java/cn/lastwhisper/javassist/JavassistDynamicProxyClass.java @@ -0,0 +1,130 @@ +package cn.lastwhisper.javassist; + +import javassist.*; +import javassist.bytecode.AccessFlag; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +/** + * @author Administrator + */ +public class JavassistDynamicProxyClass { + + static class UserServiceImpl { + + public void getName(String userId) { + System.out.println("UserServiceImpl————getName————代理方法中"); + } + + public String createUser(String name, int id) { + System.out.println("UserServiceImpl————createUser————代理方法中"); + return name + id; + } + + } + + /** + * 代理类回调方法 + */ + public static Method getMethod(Class cla, String name, Class... types) { + try { + return cla.getMethod(name, types); + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } + } + + /** + * 动态代理对象构建 + */ + public void newProxyInstance(ClassLoader loader, Class proxyTarget, + InvocationHandler invocationHandler) throws NotFoundException, + CannotCompileException, IllegalAccessException, + InstantiationException, NoSuchMethodException, + InvocationTargetException { + ClassPool pool = new ClassPool(); + pool.insertClassPath(new LoaderClassPath(proxyTarget.getClassLoader())); + CtClass targetClass = pool.get(proxyTarget.getName()); + // 构建代理类,父类是targetClass + CtClass proxyClass = pool.makeClass(proxyTarget.getName() + "$proxy", + targetClass); + // 构建代理类的成员变量,添加到代理类 + CtField handlerField = new CtField(pool.get(InvocationHandler.class.getName()), "h", proxyClass); + proxyClass.addField(handlerField); + + int methodIndex = 0; + for (CtMethod ctMethod : targetClass.getDeclaredMethods()) { + // 满足非public,native、static、final直接跳过 + if (!AccessFlag.isPublic(ctMethod.getModifiers())) { + continue; + } else if ((ctMethod.getModifiers() & AccessFlag.NATIVE) != 0) { + continue; + } else if ((ctMethod.getModifiers() & AccessFlag.STATIC) != 0) { + continue; + } else if ((ctMethod.getModifiers() & AccessFlag.FINAL) != 0) { + continue; + } + String methodName = ctMethod.getName() + methodIndex; + CtField methodField = new CtField(pool.get(Method.class.getName()), + methodName, proxyClass); + StringBuilder paramTypeSrc = new StringBuilder("new Class[]{"); + for (int i = 0; i < ctMethod.getParameterTypes().length; i++) { + if (i != 0) { + paramTypeSrc.append(","); + } + paramTypeSrc.append(ctMethod.getParameterTypes()[i].getName()).append(".class"); + } + paramTypeSrc.append("}"); + String d = proxyTarget.getName() + ".class"; + String initSrc = getClass().getName() + ".getMethod(" + d + ",\"" + + ctMethod.getName() + "\"," + paramTypeSrc.toString() + ")"; + + proxyClass.addField(methodField, initSrc); + + CtMethod copyMethod = CtNewMethod.copy(ctMethod, proxyClass, null); + + String bodySrc = "{"; + bodySrc += "Object result=h.invoke($0," + methodName + ",$args);"; + + if (!"void".equals(copyMethod.getReturnType().getName())) { + bodySrc += "return ($r)result;"; + } + bodySrc += "}"; + + copyMethod.setBody(bodySrc); + proxyClass.addMethod(copyMethod); + methodIndex++; + } + // 构建代理类的构造器 + CtConstructor constructor = new CtConstructor( + new CtClass[]{pool.get(InvocationHandler.class.getName())}, + proxyClass); + constructor.setBody("h=$1;"); + proxyClass.addConstructor(constructor); + // 生成代理类字节码文件 + proxyClass.debugWriteFile("D:\\code\\GitRepository\\Apm\\apm\\javassist\\target"); + Class clazz = proxyClass.toClass(); + + UserServiceImpl userService = (UserServiceImpl) clazz.getConstructor( + InvocationHandler.class).newInstance(invocationHandler); + userService.getName("11"); + } + + public static void main(String[] args) throws Exception { + new JavassistDynamicProxyClass().newProxyInstance(JavassistDynamicProxyClass.class.getClassLoader(), + UserServiceImpl.class, new InvocationHandler() { + UserServiceImpl target = new UserServiceImpl(); + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + System.out.println("代理前"); + Object r = method.invoke(target, args); + System.out.println("代理后"); + return r; + } + }); + } +} + + diff --git a/java-advance/javassist/src/main/java/cn/lastwhisper/javassist/JavassistDynamicProxyInterface.java b/java-advance/javassist/src/main/java/cn/lastwhisper/javassist/JavassistDynamicProxyInterface.java new file mode 100644 index 00000000..2e3e743e --- /dev/null +++ b/java-advance/javassist/src/main/java/cn/lastwhisper/javassist/JavassistDynamicProxyInterface.java @@ -0,0 +1,50 @@ +package cn.lastwhisper.javassist; + +import javassist.*; + + +/** + * 使用Javassist运行时创建接口实现类 + * @author lastwhisper + */ +public class JavassistDynamicProxyInterface { + + public interface IHello { + public void sayHello(String name); + } + + public static void main(String[] args) { + // true表示根据当前类去搜索 + ClassPool pool = new ClassPool(true); + // 插入类路径,通过类路径去搜索类 + pool.insertClassPath(new LoaderClassPath(JavassistDynamicProxyInterface.class.getClassLoader())); + try { + // 构建CtClass对象 + CtClass targetClass = pool.makeClass("cn.lastwhisper.javassist.IHello"); + // 实现接口 + targetClass.addInterface(pool.get(IHello.class.getName())); + // 实现方法,方法名 + String mName = "sayHello"; + // 实现方法,获取方法返回类型的CtClass + CtClass returnType = pool.get(void.class.getName()); + // 实现方法,获取方法入参的CtClass + CtClass[] parameters = new CtClass[]{pool.get(String.class.getName())}; + // 根据方法名、返回类型、入参类型实现方法 + CtMethod ctMethod = new CtMethod(returnType, mName, parameters, targetClass); + // 设置实现方法的方法体 + String body = "{" + + "System.out.println(\"hello\"+$1);" + + "}"; + ctMethod.setBody(body); + targetClass.addMethod(ctMethod); + // 装载Class + Class clazz = targetClass.toClass(); + // 使用反射创建对象 + IHello hello = (IHello) clazz.newInstance(); + hello.sayHello("tom"); + } catch (NotFoundException | CannotCompileException | InstantiationException | IllegalAccessException e) { + e.printStackTrace(); + } + + } +} \ No newline at end of file diff --git a/java-advance/javassist/src/main/java/cn/lastwhisper/javassist/JavassistMonitorMethod.java b/java-advance/javassist/src/main/java/cn/lastwhisper/javassist/JavassistMonitorMethod.java new file mode 100644 index 00000000..61bf3685 --- /dev/null +++ b/java-advance/javassist/src/main/java/cn/lastwhisper/javassist/JavassistMonitorMethod.java @@ -0,0 +1,33 @@ +package cn.lastwhisper.javassist; + +import javassist.*; + +/** + * 新建一个方法,将被调用方法copy到新方法 + * 再被调用方法中进行监控新方法。 + * @author lastwhisper + */ +public class JavassistMonitorMethod { + public static void main(String[] args) throws NotFoundException, CannotCompileException { + + ClassPool pool = new ClassPool(true); + String targetClassName = "cn.lastwhisper.javassist.StringUtil"; + //String targetClassName = StringUtil.class.getName(); //导致类加载器提前加载StringUtil + CtClass targetClass = pool.get(targetClassName); + CtMethod method = targetClass.getDeclaredMethod("addString"); + CtMethod agentMethod = CtNewMethod.copy(method, method.getName() + "$agent", targetClass, null); + targetClass.addMethod(agentMethod); + String src = "{" + + "long begin = System.nanoTime();" + + "Object result=" + method.getName() + "$agent($$);" + + "long end = System.nanoTime();" + + "System.out.println(\"耗时:\"+(end-begin));" + + "return ($r)result;" + + "}"; + method.setBody(src); + // 载入至当前ClassLoader + targetClass.toClass(); + StringUtil util = new StringUtil();//此时类加载器还未加载StringUtil,StringUtil已经被修改 + util.addString(1000); + } +} diff --git a/java-advance/javassist/src/main/java/cn/lastwhisper/javassist/JavassistMonitorServlet.java b/java-advance/javassist/src/main/java/cn/lastwhisper/javassist/JavassistMonitorServlet.java new file mode 100644 index 00000000..7add0845 --- /dev/null +++ b/java-advance/javassist/src/main/java/cn/lastwhisper/javassist/JavassistMonitorServlet.java @@ -0,0 +1,59 @@ +package cn.lastwhisper.javassist; + +import java.io.IOException; +import java.lang.instrument.ClassFileTransformer; +import java.lang.instrument.IllegalClassFormatException; +import java.lang.instrument.Instrumentation; +import java.security.ProtectionDomain; + +import javassist.CannotCompileException; +import javassist.ClassPool; +import javassist.CtClass; +import javassist.CtMethod; +import javassist.LoaderClassPath; +import javassist.NotFoundException; +/** + * 一个代理实现ClassFileTransformer接口用于改变运行时的字节码(class File), + * 这个改变发生在jvm加载这个类之前。对所有的类加载器有效。 + */ +public class JavassistMonitorServlet implements ClassFileTransformer { + // 在应用启动前调用 + public static void premain(String agentArgs, Instrumentation inst) { + inst.addTransformer(new JavassistMonitorServlet()); + } + + @Override + public byte[] transform(ClassLoader loader, String className, + Class classBeingRedefined, ProtectionDomain protectionDomain, + byte[] classfileBuffer) throws IllegalClassFormatException { + // 屏蔽 + String target = "javax.servlet.http.HttpServlet"; + if (target.equals(className)) { + try { + return buildClass(target, loader); + } catch (Exception e) { + e.printStackTrace(); + } + } + return null; + } + + public byte[] buildClass(String target, ClassLoader loader) + throws NotFoundException, IOException, CannotCompileException { + ClassPool pool = new ClassPool(); + pool.insertClassPath(new LoaderClassPath(loader)); + CtClass cla = pool.get(target); + CtClass[] params = new CtClass[] { + pool.get("javax.servlet.http.HttpServletRequest"), + pool.get("javax.servlet.http.HttpServletResponse") + }; + CtMethod method = cla.getDeclaredMethod("service", params); + + method.insertBefore("cn.lastwhisper.javassist.DispatcherServletCollect.begin($args"); + // 解决ClassNotFound,AppClassLoader与CommonClassLoader不同层级 + // 同时tomcat的类加载机制打破了双亲委派机制是从下往上找 + pool.get("cn.lastwhisper.javassist.DispatcherServletCollect").toClass(loader,null); + return cla.toBytecode(); + + } +} diff --git a/java-advance/javassist/src/main/java/cn/lastwhisper/javassist/StringUtil.java b/java-advance/javassist/src/main/java/cn/lastwhisper/javassist/StringUtil.java new file mode 100644 index 00000000..115ea6a9 --- /dev/null +++ b/java-advance/javassist/src/main/java/cn/lastwhisper/javassist/StringUtil.java @@ -0,0 +1,36 @@ +package cn.lastwhisper.javassist; + +public class StringUtil { + /** + * 以添拼接的方式添加字符串 + */ + public String addString(int length) { + String result = ""; + for (int i = 0; i < length; i++) { + result += (char) (i % 26 + 'a'); + } + return result; + } + + /** + * 以追加的方式添加字符串 + */ + public String buildString(int length) { + StringBuilder inst = new StringBuilder(); + for (int i = 0; i < length; i++) { + inst.append((char) (i % 26 + 'a')); + } + return inst.toString(); + } + + public static void main(String[] args) { + StringUtil util = new StringUtil(); + util.addString(1000); + long begin = System.nanoTime(); + util.addString(10000); + System.out.println(System.nanoTime() - begin); + begin = System.nanoTime(); + util.buildString(10000); + System.out.println(System.nanoTime() - begin); + } +} diff --git a/java-advance/network/socketproxy/pom.xml b/java-advance/network/socketproxy/pom.xml new file mode 100644 index 00000000..95115404 --- /dev/null +++ b/java-advance/network/socketproxy/pom.xml @@ -0,0 +1,16 @@ + + + 4.0.0 + + cn.cunchang + socketproxy + 1.0-SNAPSHOT + + + 8 + 8 + + + \ No newline at end of file diff --git a/java-advance/network/socketproxy/src/main/java/cn/cunchang/CreateSecretKey.java b/java-advance/network/socketproxy/src/main/java/cn/cunchang/CreateSecretKey.java new file mode 100644 index 00000000..0763d4c9 --- /dev/null +++ b/java-advance/network/socketproxy/src/main/java/cn/cunchang/CreateSecretKey.java @@ -0,0 +1,286 @@ +package cn.cunchang; + +import sun.misc.BASE64Decoder; +import sun.misc.BASE64Encoder; + +import javax.crypto.Cipher; +import java.io.ByteArrayOutputStream; +import java.security.*; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; +import java.util.HashMap; +import java.util.Map; + +/** + * @Auther: + * @Date: 2021-03-26 11:35 + * @Since + * @Description: + */ +public class CreateSecretKey { + public static final String KEY_ALGORITHM = "RSA"; + private static final String PUBLIC_KEY = "RSAPublicKey"; + private static final String PRIVATE_KEY = "RSAPrivateKey"; + public static final String SIGNATURE_ALGORITHM="MD5withRSA"; + /** + * RSA最大加密明文大小 + */ + private static final int MAX_ENCRYPT_BLOCK = 117; + + /** + * RSA最大解密密文大小 + */ + private static final int MAX_DECRYPT_BLOCK = 128; + //获得公钥字符串 + public static String getPublicKeyStr(Map keyMap) throws Exception { + //获得map中的公钥对象 转为key对象 + Key key = (Key) keyMap.get(PUBLIC_KEY); + //编码返回字符串 + return encryptBASE64(key.getEncoded()); + } + + + //获得私钥字符串 + public static String getPrivateKeyStr(Map keyMap) throws Exception { + //获得map中的私钥对象 转为key对象 + Key key = (Key) keyMap.get(PRIVATE_KEY); + //编码返回字符串 + return encryptBASE64(key.getEncoded()); + } + + //获取公钥 + public static PublicKey getPublicKey(String key) throws Exception { + byte[] keyBytes; + keyBytes = (new BASE64Decoder()).decodeBuffer(key); + X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes); + KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); + PublicKey publicKey = keyFactory.generatePublic(keySpec); + return publicKey; + } + + //获取私钥 + public static PrivateKey getPrivateKey(String key) throws Exception { + byte[] keyBytes; + keyBytes = (new BASE64Decoder()).decodeBuffer(key); + PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes); + KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); + PrivateKey privateKey = keyFactory.generatePrivate(keySpec); + return privateKey; + } + + //解码返回byte + public static byte[] decryptBASE64(String key) throws Exception { + return (new BASE64Decoder()).decodeBuffer(key); + } + + + //编码返回字符串 + public static String encryptBASE64(byte[] key) throws Exception { + return (new BASE64Encoder()).encodeBuffer(key); + } + + //***************************签名和验证******************************* + public static byte[] sign(byte[] data,String privateKeyStr) throws Exception{ + PrivateKey priK = getPrivateKey(privateKeyStr); + Signature sig = Signature.getInstance(SIGNATURE_ALGORITHM); + sig.initSign(priK); + sig.update(data); + return sig.sign(); + } + + public static boolean verify(byte[] data,byte[] sign,String publicKeyStr) throws Exception{ + PublicKey pubK = getPublicKey(publicKeyStr); + Signature sig = Signature.getInstance(SIGNATURE_ALGORITHM); + sig.initVerify(pubK); + sig.update(data); + return sig.verify(sign); + } + + //************************公钥加密************************** + public static byte[] encryptByPublic(byte[] plainText,String publicKeyStr)throws Exception{ + PublicKey publicKey = getPublicKey(publicKeyStr); + Cipher cipher = Cipher.getInstance(KEY_ALGORITHM); + cipher.init(Cipher.ENCRYPT_MODE, publicKey); + int inputLen = plainText.length; + ByteArrayOutputStream out = new ByteArrayOutputStream(); + int offSet = 0; + int i = 0; + byte[] cache; + while (inputLen - offSet > 0) { + if (inputLen - offSet > MAX_ENCRYPT_BLOCK) { + cache = cipher.doFinal(plainText, offSet, MAX_ENCRYPT_BLOCK); + } else { + cache = cipher.doFinal(plainText, offSet, inputLen - offSet); + } + out.write(cache, 0, cache.length); + i++; + offSet = i * MAX_ENCRYPT_BLOCK; + } + byte[] encryptText = out.toByteArray(); + out.close(); + return encryptText; + } + + //************************私钥加密************************** + public static byte[] encryptByPrivate(byte[] plainText,String privateKeyStr)throws Exception{ + PrivateKey privateKey = getPrivateKey(privateKeyStr); + Cipher cipher = Cipher.getInstance(KEY_ALGORITHM); + cipher.init(Cipher.ENCRYPT_MODE, privateKey); + int inputLen = plainText.length; + ByteArrayOutputStream out = new ByteArrayOutputStream(); + int offSet = 0; + int i = 0; + byte[] cache; + while (inputLen - offSet > 0) { + if (inputLen - offSet > MAX_ENCRYPT_BLOCK) { + cache = cipher.doFinal(plainText, offSet, MAX_ENCRYPT_BLOCK); + } else { + cache = cipher.doFinal(plainText, offSet, inputLen - offSet); + } + out.write(cache, 0, cache.length); + i++; + offSet = i * MAX_ENCRYPT_BLOCK; + } + byte[] encryptText = out.toByteArray(); + out.close(); + return encryptText; + } + + //************************私钥解密************************** + public static byte[] decryptByPrivate(byte[] encryptText,String privateKeyStr)throws Exception{ + PrivateKey privateKey = getPrivateKey(privateKeyStr); + Cipher cipher = Cipher.getInstance(KEY_ALGORITHM); + cipher.init(Cipher.DECRYPT_MODE, privateKey); + int inputLen = encryptText.length; + ByteArrayOutputStream out = new ByteArrayOutputStream(); + int offSet = 0; + byte[] cache; + int i = 0; + // 对数据分段解密 + while (inputLen - offSet > 0) { + if (inputLen - offSet > MAX_DECRYPT_BLOCK) { + cache = cipher.doFinal(encryptText, offSet, MAX_DECRYPT_BLOCK); + } else { + cache = cipher.doFinal(encryptText, offSet, inputLen - offSet); + } + out.write(cache, 0, cache.length); + i++; + offSet = i * MAX_DECRYPT_BLOCK; + } + byte[] plainText = out.toByteArray(); + out.close(); + return plainText; + } + + //************************公钥解密************************** + public static byte[] decryptByPublic(byte[] encryptText,String publicKeyStr)throws Exception{ + PublicKey publicKey = getPublicKey(publicKeyStr); + Cipher cipher = Cipher.getInstance(KEY_ALGORITHM); + cipher.init(Cipher.DECRYPT_MODE, publicKey); + int inputLen = encryptText.length; + ByteArrayOutputStream out = new ByteArrayOutputStream(); + int offSet = 0; + byte[] cache; + int i = 0; + // 对数据分段解密 + while (inputLen - offSet > 0) { + if (inputLen - offSet > MAX_DECRYPT_BLOCK) { + cache = cipher.doFinal(encryptText, offSet, MAX_DECRYPT_BLOCK); + } else { + cache = cipher.doFinal(encryptText, offSet, inputLen - offSet); + } + out.write(cache, 0, cache.length); + i++; + offSet = i * MAX_DECRYPT_BLOCK; + } + byte[] plainText = out.toByteArray(); + out.close(); + return plainText; + } + + public static Map initKey() throws Exception { + KeyPairGenerator keyPairGen = KeyPairGenerator + .getInstance(KEY_ALGORITHM); + keyPairGen.initialize(1024); + KeyPair keyPair = keyPairGen.generateKeyPair(); + RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); + RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); + Map keyMap = new HashMap(2); + keyMap.put(PUBLIC_KEY, publicKey); + keyMap.put(PRIVATE_KEY, privateKey); + return keyMap; + } + + + public static void main(String[] args) { + Map keyMap; + byte[] cipherText; + String input = "晚上10点203等我!"; + try { + keyMap = initKey(); + String publicKey = getPublicKeyStr(keyMap); + System.out.println("公钥------------------"); + System.out.println(publicKey); + String privateKey = getPrivateKeyStr(keyMap); + System.out.println("私钥------------------"); + System.out.println(privateKey); + + + /*System.out.println("测试 公钥加密 私钥解密-------------------"); + System.out.println("明文======="+input); + + cipherText = encryptByPublic(input.getBytes(),publicKey); + //加密后的东西 + System.out.println("公钥加密密文======="+new String(cipherText)); + //开始解密 + byte[] plainText = decryptByPrivate(cipherText,privateKey); + System.out.println("私钥解密后明文===== " + new String(plainText));*/ + + + /*System.out.println("测试 私钥加密 公钥解密-------------------"); + System.out.println("明文======="+input); + + cipherText = encryptByPrivate(input.getBytes(),privateKey); + //加密后的东西 + System.out.println("私钥加密密文======="+new String(cipherText)); + //开始解密 + byte[] plainText = decryptByPublic(cipherText,publicKey); + System.out.println("公钥解密后明文===== " + new String(plainText));*/ + + + /*System.out.println("测试 私钥加密 私钥解密-------------------"); + System.out.println("明文======="+input); + + cipherText = encryptByPrivate(input.getBytes(),privateKey); + //加密后的东西 + System.out.println("私钥加密密文======="+new String(cipherText)); + //开始解密 + byte[] plainText = decryptByPrivate(cipherText,privateKey); + System.out.println("私钥解密后明文===== " + new String(plainText));*/ + + /*System.out.println("测试 公钥加密 公钥解密-------------------"); + System.out.println("明文======="+input); + + cipherText = encryptByPublic(input.getBytes(),publicKey); + //加密后的东西 + System.out.println("公钥加密密文======="+new String(cipherText)); + //开始解密 + byte[] plainText = decryptByPublic(cipherText,publicKey); + System.out.println("公钥解密后明文===== " + new String(plainText));*/ + + System.out.println("验证签名-----------"); + + /*String str="被签名的内容"; + System.out.println("\n原文:"+str); + byte[] signature=sign(str.getBytes(),privateKey); + boolean status=verify(str.getBytes(), signature,publicKey); + System.out.println("验证情况:"+status);*/ + } catch (Exception e) { + e.printStackTrace(); + } + } + + +} diff --git a/java-advance/network/socketproxy/src/main/java/cn/cunchang/LineBuffer.java b/java-advance/network/socketproxy/src/main/java/cn/cunchang/LineBuffer.java new file mode 100644 index 00000000..d63babab --- /dev/null +++ b/java-advance/network/socketproxy/src/main/java/cn/cunchang/LineBuffer.java @@ -0,0 +1,46 @@ +package cn.cunchang; + +import java.io.IOException; +import java.io.InputStream; + +/** + * @Auther: + * @Date: 2021-03-22 15:52 + * @Since + * @Description: + */ +public class LineBuffer { + private int size; + + public LineBuffer(int size) { + this.size = size; + } + + public String readLine(InputStream input) throws IOException { + int flag = 0; + int index = 0; + byte[] bts = new byte[this.size]; + int b; + while(flag!=2&&(b= input.read())!=-1){ + bts[index++] = (byte) b; + if(b=='\r'&&flag%2==0){ + flag++; + }else if(b=='\n'&&flag%2==1){ + flag++; + if(flag==2){ + return new String(bts,0,index-2); + } + }else{ + flag = 0; + } + if(index==bts.length){ + //满了扩容 + byte[] newBts = new byte[bts.length*2]; + System.arraycopy(bts,0,newBts,0,bts.length); + bts = null; + bts = newBts; + } + } + return null; + } +} diff --git a/java-advance/network/socketproxy/src/main/java/cn/cunchang/ProxyHandleThread.java b/java-advance/network/socketproxy/src/main/java/cn/cunchang/ProxyHandleThread.java new file mode 100644 index 00000000..ba1fa3d6 --- /dev/null +++ b/java-advance/network/socketproxy/src/main/java/cn/cunchang/ProxyHandleThread.java @@ -0,0 +1,33 @@ +package cn.cunchang; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.concurrent.CountDownLatch; + +/** + * @Auther: + * @Date: 2021-03-22 15:51 + * @Since + * @Description: + */ +public class ProxyHandleThread extends Thread{ + private InputStream input; + private OutputStream output; + + public ProxyHandleThread(InputStream input, OutputStream output, CountDownLatch cdl) { + this.input = input; + this.output = output; + } + + @Override + public void run() { + try { + while (true) { + output.write(input.read()); + } + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/java-advance/network/socketproxy/src/main/java/cn/cunchang/ProxyServer.java b/java-advance/network/socketproxy/src/main/java/cn/cunchang/ProxyServer.java new file mode 100644 index 00000000..2924ba2c --- /dev/null +++ b/java-advance/network/socketproxy/src/main/java/cn/cunchang/ProxyServer.java @@ -0,0 +1,100 @@ +package cn.cunchang; + +import javax.swing.*; +import java.awt.*; +import java.io.*; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.URL; +import java.util.Date; + +/** + * @Auther: + * @Date: 2021-03-22 16:22 + * @Since + * @Description: + */ +public class ProxyServer extends JFrame { + private JTextArea jta =new JTextArea();//create an JTextArea to output some information + + public static void main(String[] args){ + new ProxyServer(); + } + + public ProxyServer() { + setLayout(new BorderLayout()); + add(new JScrollPane(jta), BorderLayout.CENTER); + + setTitle("Proxy Server by Li Zhaoji"); + setSize(500, 300); + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + setVisible(true); + try{ + ServerSocket serverSocket = new ServerSocket(8081);//Listening port 8081 + jta.append("Proxy Server started at " + new Date() + '\n'); + jta.append("Proxy Server is listening on port "+serverSocket.getLocalPort() + '\n' + '\n'); + + int clientNo = 1; + + while (true) { + + Socket socket = serverSocket.accept(); + + jta.append("1****************************************************************************1" + '\n'); + jta.append("Starting thread for client " + clientNo + " at " + new Date() + '\n'); + + InetAddress inetAddress = socket.getInetAddress();//get the host PC's information + jta.append("Client " + clientNo + "'s host name is " + inetAddress.getHostName() + '\n'); + jta.append("Client " + clientNo + "'s IP Address is " + inetAddress.getHostAddress() + '\n'); + + HandleClient task = new HandleClient(socket); + + new Thread(task).start();//start a new thread to handle the require of the host + + clientNo++; + } + } + catch(IOException ex) { + System.err.println(ex); + } + } + + class HandleClient implements Runnable { + private Socket socket; + + public HandleClient(Socket socket){ + this.socket = socket; + } + + @Override + public void run() { + try{ + BufferedReader inputFromClient = new BufferedReader(new InputStreamReader(socket.getInputStream())); + PrintStream outputToClient = new PrintStream(socket.getOutputStream()); + String str = inputFromClient.readLine();//read the GET require string from Host + jta.append("The require from Client:" + str + '\n'); + String inurl = str.substring(4, str.indexOf("HTTP/")-1);//get the URL string from GET + jta.append("The require URL:" + inurl + '\n'); + URL url = new URL(inurl); + InputStream infile = url.openStream();//the input stream that get the data from Web Server + int n = infile.available();//the number of bytes that accept from Web Server + byte buf[] = new byte[1024]; + while((n = infile.read(buf)) >= 0){ + outputToClient.write(buf, 0, n);//start send with buf[0], send n bytes + } + outputToClient.close(); + socket.close(); + inputFromClient.close(); + + jta.append("socket has been closed!!!" + '\n'); + jta.append("2****************************************************************************2" + '\n' + '\n'); + } + catch(IOException e) { + System.err.println(e); + jta.append("Sorry! There is no require file??? :(" + '\n'); + } + } + } + +} diff --git a/java-advance/network/socketproxy/src/main/java/cn/cunchang/SocketHandle.java b/java-advance/network/socketproxy/src/main/java/cn/cunchang/SocketHandle.java new file mode 100644 index 00000000..c5084980 --- /dev/null +++ b/java-advance/network/socketproxy/src/main/java/cn/cunchang/SocketHandle.java @@ -0,0 +1,136 @@ +package cn.cunchang; + +import java.io.*; +import java.net.Socket; + +/** + * @Auther: + * @Date: 2021-03-22 15:49 + * @Since + * @Description: + */ +public class SocketHandle extends Thread{ + + private Socket socket; + + public SocketHandle(Socket socket) { + this.socket = socket; + } + + @Override + public void run() { + OutputStream clientOutput = null; + InputStream clientInput = null; + Socket proxySocket = null; + InputStream proxyInput = null; + OutputStream proxyOutput = null; + try { + clientInput = socket.getInputStream(); + clientOutput = socket.getOutputStream(); + String line; + String host = ""; + LineBuffer lineBuffer = new LineBuffer(1024); + StringBuilder headStr = new StringBuilder(); + //读取HTTP请求头,并拿到HOST请求头和method + while (null != (line = lineBuffer.readLine(clientInput))) { + System.out.println(line); + headStr.append(line + "\r\n"); + if (line.length() == 0) { + break; + } else { + String[] temp = line.split(" "); + if (temp[0].contains("Host")) { + host = temp[1]; + } + } + } + String type = headStr.substring(0, headStr.indexOf(" ")); + //根据host头解析出目标服务器的host和port + String[] hostTemp = host.split(":"); + host = hostTemp[0]; + int port = 80; + if (hostTemp.length > 1) { + port = Integer.valueOf(hostTemp[1]); + } + //连接到目标服务器 + proxySocket = new Socket(host, port); + proxyInput = proxySocket.getInputStream(); + proxyOutput = proxySocket.getOutputStream(); + //根据HTTP method来判断是https还是http请求 + if ("CONNECT".equalsIgnoreCase(type)) {//https先建立隧道 + clientOutput.write("HTTP/1.1 200 Connection Established\r\n\r\n".getBytes()); + clientOutput.flush(); + } else {//http直接将请求头转发 + proxyOutput.write(headStr.toString().getBytes()); + } + //新开线程转发客户端请求至目标服务器 + new ProxyHandleThread(clientInput, proxyOutput,null).start(); + //转发目标服务器响应至客户端 + while (true) { + clientOutput.write(proxyInput.read()); + print(proxyInput); + /*String url ="https://image.baidu.com/search/detail?ct=503316480&z=0&ipn=false&word=%E6%9E%97%E5%BF%97%E7%8E%B2&step_word=&hs=2&pn=8&spn=0&di=7150&pi=0&rn=1&tn=baiduimagedetail&is=0%2C0&istype=0&ie=utf-8&oe=utf-8&in=&cl=2&lm=-1&st=undefined&cs=2732989282%2C3677770873&os=2359571368%2C569377150&simid=55908706%2C799425763&adpicid=0&lpn=0&ln=2666&fr=&fmq=1616661848576_R&fm=&ic=undefined&s=undefined&hd=undefined&latest=undefined©right=undefined&se=&sme=&tab=0&width=undefined&height=undefined&face=undefined&ist=&jit=&cg=star&bdtype=0&oriquery=&objurl=https%3A%2F%2Fgimg2.baidu.com%2Fimage_search%2Fsrc%3Dhttp%3A%2F%2Fup.enterdesk.com%2Fedpic_source%2Fc3%2F28%2F51%2Fc328516d6a64807408f0180f8e7e9032.jpg%26refer%3Dhttp%3A%2F%2Fup.enterdesk.com%26app%3D2002%26size%3Df9999%2C10000%26q%3Da80%26n%3D0%26g%3D0n%26fmt%3Djpeg%3Fsec%3D1619253875%26t%3D1dae7d851056b4b20dde8c9749192719&fromurl=ippr_z2C%24qAzdH3FAzdH3Fp7_z%26e3Bjgpj61jfh_z%26e3Bv54AzdH3F15ogs5w1AzdH3F8888cAzdH3F&gsm=9&rpstart=0&rpnum=0&islist=&querylist=&force=undefined"; + clientOutput.write(url.getBytes());*/ + } + } catch (IOException e) { + e.printStackTrace(); + } finally { + if (proxyInput != null) { + try { + proxyOutput.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + if (proxyOutput != null) { + try { + proxyOutput.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + if (proxySocket != null) { + try { + proxySocket.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + if (clientInput != null) { + try { + clientInput.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + if (clientOutput != null) { + try { + clientOutput.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + if (socket != null) { + try { + socket.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + } + + public static void print (InputStream is) throws UnsupportedEncodingException { + InputStreamReader isr =new InputStreamReader(is,"utf-8"); + BufferedReader br =new BufferedReader(isr); + try { + while ((br.read())!=-1) { + System.out.println(br.readLine()); + } + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } +} diff --git a/java-advance/network/socketproxy/src/main/java/cn/cunchang/SocketProxy.java b/java-advance/network/socketproxy/src/main/java/cn/cunchang/SocketProxy.java new file mode 100644 index 00000000..7a10b207 --- /dev/null +++ b/java-advance/network/socketproxy/src/main/java/cn/cunchang/SocketProxy.java @@ -0,0 +1,21 @@ +package cn.cunchang; + +import java.net.ServerSocket; + +/** + * @Auther: + * @Date: 2021-03-22 15:56 + * @Since + * @Description: + */ +public class SocketProxy { + + public static void main(String[] args) throws Exception { + //监听端口 + ServerSocket serverSocket = new ServerSocket(8001); + System.out.println("8001正在监听.........."); + for (; ; ) { + new SocketHandle(serverSocket.accept()).start(); + } + } +} diff --git a/java-advance/proxy/README.md b/java-advance/proxy/README.md new file mode 100644 index 00000000..f05d236d --- /dev/null +++ b/java-advance/proxy/README.md @@ -0,0 +1,49 @@ +# 代理 + +代理的优点 + + +## 静态代理 + +**继承实现** + +缺点: + +- 继承关系决定了代理顺序,代理顺序改变,需要新增继承类。 + +**组合实现** + +优点: + +- 组合关系决定了代理顺序,类可以任意组合,不会新增类 + + + +虽然静态代理侵入性很小,但是增强的代码无法复用。比如接口再加一个 stop 方法,需要复制耗时记录的代码 + + + + + +## 动态代理 + +需要一个代理类,可以给所有的类做代理。 + + + + + +**优点:** + +- 代理模式能将代理对象与真实被调用的目标对象分离 +- 一定程度上降低了系统的耦合度,扩展性好 +- 增强目标对象 + +**缺点:** + +- 代理模式会造成系统设计中类的数目增加 +- 在客户端和目标对象增加一个代理对象,会造成请求处理速度变慢 +- 增加系统的复杂度 + + + diff --git a/java-advance/proxy/com/sun/proxy/$Proxy0.class b/java-advance/proxy/com/sun/proxy/$Proxy0.class new file mode 100644 index 00000000..2168a4ca Binary files /dev/null and b/java-advance/proxy/com/sun/proxy/$Proxy0.class differ diff --git a/java-advance/proxy/jdk-proxy/README.md b/java-advance/proxy/jdk-proxy/README.md new file mode 100644 index 00000000..c887afe9 --- /dev/null +++ b/java-advance/proxy/jdk-proxy/README.md @@ -0,0 +1,6 @@ + +v1 jdk动态代理常规用法 +v1.equal jdk动态代理生成的类,等价调用 + +v2 jdk动态代理接口 +v3 jdk动态代理无法代理抽象类 diff --git a/java-advance/proxy/jdk-proxy/pom.xml b/java-advance/proxy/jdk-proxy/pom.xml new file mode 100644 index 00000000..a6919d4a --- /dev/null +++ b/java-advance/proxy/jdk-proxy/pom.xml @@ -0,0 +1,19 @@ + + + + proxy + cn.cunchang + 1.0-SNAPSHOT + + 4.0.0 + + jdk-proxy + + + 11 + 11 + + + \ No newline at end of file diff --git a/java-advance/proxy/jdk-proxy/src/main/java/cn/cunchang/v1/ProxyInvocationHandler.java b/java-advance/proxy/jdk-proxy/src/main/java/cn/cunchang/v1/ProxyInvocationHandler.java new file mode 100644 index 00000000..bac76061 --- /dev/null +++ b/java-advance/proxy/jdk-proxy/src/main/java/cn/cunchang/v1/ProxyInvocationHandler.java @@ -0,0 +1,34 @@ +package cn.cunchang.v1; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; + +/** + * 定义动态代理调用处理器 + */ +public class ProxyInvocationHandler implements InvocationHandler { + /** + * 被代理类,我们自己定义的成员变量,不要也可以 + */ + private Object target; + + public ProxyInvocationHandler(Object target) { + this.target = target; + } + + /** + * @param proxy 代理对象,jdk给你生成的对象 + * @param method 被代理类的方法 + * @param args 被代理类方法的参数 + * @return + * @throws Throwable + */ + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + System.out.println("进入代理调用处理器 before"); + Object obj = method.invoke(target, args); + System.out.println("进入代理调用处理器 fater"); + return obj; + } + +} \ No newline at end of file diff --git a/java-advance/proxy/jdk-proxy/src/main/java/cn/cunchang/v1/ProxyTest.java b/java-advance/proxy/jdk-proxy/src/main/java/cn/cunchang/v1/ProxyTest.java new file mode 100644 index 00000000..96a7518f --- /dev/null +++ b/java-advance/proxy/jdk-proxy/src/main/java/cn/cunchang/v1/ProxyTest.java @@ -0,0 +1,20 @@ + +package cn.cunchang.v1; + +import java.lang.reflect.Proxy; + +public class ProxyTest { + public static void main(String[] args) { + + System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true"); + + Subject subject = new SubjectImpl(); + Subject proxy = (Subject) Proxy + .newProxyInstance( + subject.getClass().getClassLoader(), + subject.getClass().getInterfaces(), + new ProxyInvocationHandler(subject)); + + proxy.sayHello(); + } +} \ No newline at end of file diff --git a/java-advance/proxy/jdk-proxy/src/main/java/cn/cunchang/v1/Subject.java b/java-advance/proxy/jdk-proxy/src/main/java/cn/cunchang/v1/Subject.java new file mode 100644 index 00000000..dc4fef32 --- /dev/null +++ b/java-advance/proxy/jdk-proxy/src/main/java/cn/cunchang/v1/Subject.java @@ -0,0 +1,5 @@ +package cn.cunchang.v1; + +public interface Subject { // 定义代理接口 + String sayHello(); +} diff --git a/java-advance/proxy/jdk-proxy/src/main/java/cn/cunchang/v1/SubjectImpl.java b/java-advance/proxy/jdk-proxy/src/main/java/cn/cunchang/v1/SubjectImpl.java new file mode 100644 index 00000000..6dc0d06b --- /dev/null +++ b/java-advance/proxy/jdk-proxy/src/main/java/cn/cunchang/v1/SubjectImpl.java @@ -0,0 +1,9 @@ +package cn.cunchang.v1; + +public class SubjectImpl implements Subject { // 定义代理接口实现类 + @Override + public String sayHello() { + System.out.println(" Hello World"); + return "success"; + } +} \ No newline at end of file diff --git a/java-advance/proxy/jdk-proxy/src/main/java/cn/cunchang/v1/equal/$Proxy0.java b/java-advance/proxy/jdk-proxy/src/main/java/cn/cunchang/v1/equal/$Proxy0.java new file mode 100644 index 00000000..546e880c --- /dev/null +++ b/java-advance/proxy/jdk-proxy/src/main/java/cn/cunchang/v1/equal/$Proxy0.java @@ -0,0 +1,98 @@ +// +// Source code recreated from a .class file by IntelliJ IDEA +// (powered by FernFlower decompiler) +// + +package cn.cunchang.v1.equal; + +import cn.cunchang.v2.Subject; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.lang.reflect.UndeclaredThrowableException; + +/** + * 继承jdk的Proxy,作用之一:直接使用handler成员变量 + * 副作用:由于Java只能单继承,所以jdk动态代理只能代理有接口实现的类 + */ +public final class $Proxy0 extends Proxy implements Subject { + private static Method m1; + private static Method m3; + private static Method m2; + private static Method m0; + + /** + * InvocationHandler 是代理对象的调用被代理对象的接口。 + * 也就是说代理对象为什么能调用被代理对象,是因为有这个handler在中间做桥梁 + * @param var1 + */ + public $Proxy0(InvocationHandler var1) { + super(var1); + } + + static { + try { + /** + * 获取代理对象接口的所有方法,用于代理方法回调 + */ + m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object")); + m3 = Class.forName("cn.cunchang.v1.equal.Subject").getMethod("sayHello"); + m2 = Class.forName("java.lang.Object").getMethod("toString"); + m0 = Class.forName("java.lang.Object").getMethod("hashCode"); + } catch (NoSuchMethodException var2) { + throw new NoSuchMethodError(var2.getMessage()); + } catch (ClassNotFoundException var3) { + throw new NoClassDefFoundError(var3.getMessage()); + } + } + + public final String sayHello() { + try { + /** + * 代理类调用handler,handler.invoke()方法,把方法的执行链交给用户 + * + * InvocationHandler.invoke(Object proxy, Method method, Object[] args) + * proxy – jdk给你生成的代理对象 + * method – 被代理类的方法 + * args – 被代理类方法的参数 + */ + return (String)super.h.invoke(this, m3, (Object[])null); + } catch (RuntimeException | Error var2) { + throw var2; + } catch (Throwable var3) { + throw new UndeclaredThrowableException(var3); + } + } + + public final boolean equals(Object var1) { + try { + return (Boolean)super.h.invoke(this, m1, new Object[]{var1}); + } catch (RuntimeException | Error var3) { + throw var3; + } catch (Throwable var4) { + throw new UndeclaredThrowableException(var4); + } + } + + public final String toString() { + try { + return (String)super.h.invoke(this, m2, (Object[])null); + } catch (RuntimeException | Error var2) { + throw var2; + } catch (Throwable var3) { + throw new UndeclaredThrowableException(var3); + } + } + + public final int hashCode() { + try { + return (Integer)super.h.invoke(this, m0, (Object[])null); + } catch (RuntimeException | Error var2) { + throw var2; + } catch (Throwable var3) { + throw new UndeclaredThrowableException(var3); + } + } + + +} diff --git a/java-advance/proxy/jdk-proxy/src/main/java/cn/cunchang/v1/equal/ProxyInvocationHandler.java b/java-advance/proxy/jdk-proxy/src/main/java/cn/cunchang/v1/equal/ProxyInvocationHandler.java new file mode 100644 index 00000000..3d253e35 --- /dev/null +++ b/java-advance/proxy/jdk-proxy/src/main/java/cn/cunchang/v1/equal/ProxyInvocationHandler.java @@ -0,0 +1,34 @@ +package cn.cunchang.v1.equal; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; + +/** + * 定义动态代理调用处理器 + */ +public class ProxyInvocationHandler implements InvocationHandler { + /** + * 被代理类,我们自己定义的成员变量,不要也可以 + */ + private Object target; + + public ProxyInvocationHandler(Object target) { + this.target = target; + } + + /** + * @param proxy 代理对象,jdk给你生成的对象 + * @param method 被代理类的方法 + * @param args 被代理类方法的参数 + * @return + * @throws Throwable + */ + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + System.out.println("进入代理调用处理器 before"); + Object obj = method.invoke(target, args); + System.out.println("进入代理调用处理器 fater"); + return obj; + } + +} \ No newline at end of file diff --git a/java-advance/proxy/jdk-proxy/src/main/java/cn/cunchang/v1/equal/ProxyTest.java b/java-advance/proxy/jdk-proxy/src/main/java/cn/cunchang/v1/equal/ProxyTest.java new file mode 100644 index 00000000..6c98f724 --- /dev/null +++ b/java-advance/proxy/jdk-proxy/src/main/java/cn/cunchang/v1/equal/ProxyTest.java @@ -0,0 +1,20 @@ + +package cn.cunchang.v1.equal; + +public class ProxyTest { + public static void main(String[] args) { + + System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true"); + + Subject subject = new SubjectImpl(); +// Subject proxy = (Subject) Proxy +// .newProxyInstance( +// subject.getClass().getClassLoader(), +// subject.getClass().getInterfaces(), +// new ProxyInvocationHandler(subject)); + + $Proxy0 $Proxy0 = new $Proxy0(new ProxyInvocationHandler(subject)); + $Proxy0.sayHello(); + + } +} \ No newline at end of file diff --git a/java-advance/proxy/jdk-proxy/src/main/java/cn/cunchang/v1/equal/Subject.java b/java-advance/proxy/jdk-proxy/src/main/java/cn/cunchang/v1/equal/Subject.java new file mode 100644 index 00000000..af71b97e --- /dev/null +++ b/java-advance/proxy/jdk-proxy/src/main/java/cn/cunchang/v1/equal/Subject.java @@ -0,0 +1,5 @@ +package cn.cunchang.v1.equal; + +public interface Subject { // 定义代理接口 + String sayHello(); +} diff --git a/java-advance/proxy/jdk-proxy/src/main/java/cn/cunchang/v1/equal/SubjectImpl.java b/java-advance/proxy/jdk-proxy/src/main/java/cn/cunchang/v1/equal/SubjectImpl.java new file mode 100644 index 00000000..ea8a4553 --- /dev/null +++ b/java-advance/proxy/jdk-proxy/src/main/java/cn/cunchang/v1/equal/SubjectImpl.java @@ -0,0 +1,9 @@ +package cn.cunchang.v1.equal; + +public class SubjectImpl implements Subject { // 定义代理接口实现类 + @Override + public String sayHello() { + System.out.println(" Hello World"); + return "success"; + } +} \ No newline at end of file diff --git a/java-advance/proxy/jdk-proxy/src/main/java/cn/cunchang/v2/ProxyInvocationHandler.java b/java-advance/proxy/jdk-proxy/src/main/java/cn/cunchang/v2/ProxyInvocationHandler.java new file mode 100644 index 00000000..c4946ad9 --- /dev/null +++ b/java-advance/proxy/jdk-proxy/src/main/java/cn/cunchang/v2/ProxyInvocationHandler.java @@ -0,0 +1,22 @@ +package cn.cunchang.v2; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; + +public class ProxyInvocationHandler implements InvocationHandler { + + /** + * + * @param proxy + * @param method + * @param args + * @return + * @throws Throwable + */ + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + System.out.println("进入代理调用处理器"); + return "success"; + } + +} \ No newline at end of file diff --git a/java-advance/proxy/jdk-proxy/src/main/java/cn/cunchang/v2/ProxyTest.java b/java-advance/proxy/jdk-proxy/src/main/java/cn/cunchang/v2/ProxyTest.java new file mode 100644 index 00000000..fb5b9043 --- /dev/null +++ b/java-advance/proxy/jdk-proxy/src/main/java/cn/cunchang/v2/ProxyTest.java @@ -0,0 +1,19 @@ +package cn.cunchang.v2; + +import java.lang.reflect.Proxy; + +public class ProxyTest { + public static void main(String[] args) { + + System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true"); + + Subject proxy = (Subject) Proxy + .newProxyInstance( + ProxyTest.class.getClassLoader(), + new Class[]{Subject.class}, + new ProxyInvocationHandler()); + + proxy.sayHello(); + + } +} \ No newline at end of file diff --git a/java-advance/proxy/jdk-proxy/src/main/java/cn/cunchang/v2/Subject.java b/java-advance/proxy/jdk-proxy/src/main/java/cn/cunchang/v2/Subject.java new file mode 100644 index 00000000..22226a81 --- /dev/null +++ b/java-advance/proxy/jdk-proxy/src/main/java/cn/cunchang/v2/Subject.java @@ -0,0 +1,6 @@ +package cn.cunchang.v2; + +public interface Subject { + String sayHello(); +} + diff --git a/java-advance/proxy/jdk-proxy/src/main/java/cn/cunchang/v3/AbstractProxy.java b/java-advance/proxy/jdk-proxy/src/main/java/cn/cunchang/v3/AbstractProxy.java new file mode 100644 index 00000000..d7d445d9 --- /dev/null +++ b/java-advance/proxy/jdk-proxy/src/main/java/cn/cunchang/v3/AbstractProxy.java @@ -0,0 +1,5 @@ +package cn.cunchang.v3; + +public abstract class AbstractProxy { + abstract void sayHello(); +} diff --git a/java-advance/proxy/jdk-proxy/src/main/java/cn/cunchang/v3/ProxyInvocationHandler.java b/java-advance/proxy/jdk-proxy/src/main/java/cn/cunchang/v3/ProxyInvocationHandler.java new file mode 100644 index 00000000..59c9ab61 --- /dev/null +++ b/java-advance/proxy/jdk-proxy/src/main/java/cn/cunchang/v3/ProxyInvocationHandler.java @@ -0,0 +1,14 @@ +package cn.cunchang.v3; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; + +public class ProxyInvocationHandler implements InvocationHandler { + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + System.out.println("进入代理调用处理器"); + return "success"; + } + +} \ No newline at end of file diff --git a/java-advance/proxy/jdk-proxy/src/main/java/cn/cunchang/v3/ProxyTest.java b/java-advance/proxy/jdk-proxy/src/main/java/cn/cunchang/v3/ProxyTest.java new file mode 100644 index 00000000..60e091d2 --- /dev/null +++ b/java-advance/proxy/jdk-proxy/src/main/java/cn/cunchang/v3/ProxyTest.java @@ -0,0 +1,16 @@ +package cn.cunchang.v3; + +import java.lang.reflect.Proxy; + +public class ProxyTest { + public static void main(String[] args) { + + AbstractProxy proxyInterface = (AbstractProxy) Proxy + .newProxyInstance( + ProxyTest.class.getClassLoader(), + new Class[]{AbstractProxy.class}, + new ProxyInvocationHandler()); + proxyInterface.sayHello(); + + } +} \ No newline at end of file diff --git a/java-advance/proxy/mybatis-mapper/pom.xml b/java-advance/proxy/mybatis-mapper/pom.xml new file mode 100644 index 00000000..71653055 --- /dev/null +++ b/java-advance/proxy/mybatis-mapper/pom.xml @@ -0,0 +1,19 @@ + + + + proxy + cn.cunchang + 1.0-SNAPSHOT + + 4.0.0 + + mybatis-mapper + + + 11 + 11 + + + \ No newline at end of file diff --git a/java-advance/proxy/mybatis-mapper/src/main/java/cn/cunchang/Main.java b/java-advance/proxy/mybatis-mapper/src/main/java/cn/cunchang/Main.java new file mode 100644 index 00000000..4f2cc064 --- /dev/null +++ b/java-advance/proxy/mybatis-mapper/src/main/java/cn/cunchang/Main.java @@ -0,0 +1,28 @@ +package cn.cunchang; + +import java.lang.reflect.Proxy; +import java.util.List; + +/** + * @author cunchang + * @date 2021/11/25 12:53 上午 + */ +public class Main { + + public static void main(String[] args) { + // 获取SqlSession + SqlSession sqlSession = new SqlSession() { + @Override + public List selectList(String statementId) { + System.out.println(statementId); + return null; + } + }; + // 获取UserMapper接口 + MyMapperProxy userMapperProxy = new MyMapperProxy<>(UserMapper.class, sqlSession); + UserMapper userMapper = (UserMapper) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), + new Class[] { UserMapper.class }, userMapperProxy); + // 调用selectAll方法 + List user = userMapper.selectAll(); + } +} diff --git a/java-advance/proxy/mybatis-mapper/src/main/java/cn/cunchang/MyMapperProxy.java b/java-advance/proxy/mybatis-mapper/src/main/java/cn/cunchang/MyMapperProxy.java new file mode 100644 index 00000000..97786dbc --- /dev/null +++ b/java-advance/proxy/mybatis-mapper/src/main/java/cn/cunchang/MyMapperProxy.java @@ -0,0 +1,29 @@ +package cn.cunchang; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.util.List; + +/** + * @author cunchang + * @date 2021/11/25 12:48 上午 + */ +public class MyMapperProxy implements InvocationHandler { + private Class mapperInterface; + private SqlSession sqlSession; + + public MyMapperProxy(Class mapperInterface, SqlSession sqlSession) { + this.mapperInterface = mapperInterface; + this.sqlSession = sqlSession; + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + // 针对不同的sql类型,需要调用sqlSession不同的方法 + // 接口方法中的参数也有很多情况,这里只考虑没有参数的情况 + List list = sqlSession.selectList(mapperInterface.getCanonicalName() + "." + method.getName()); + // 返回值也有很多情况,这里不做处理直接返回 + return list; + } + +} \ No newline at end of file diff --git a/java-advance/proxy/mybatis-mapper/src/main/java/cn/cunchang/SqlSession.java b/java-advance/proxy/mybatis-mapper/src/main/java/cn/cunchang/SqlSession.java new file mode 100644 index 00000000..e36a0c22 --- /dev/null +++ b/java-advance/proxy/mybatis-mapper/src/main/java/cn/cunchang/SqlSession.java @@ -0,0 +1,13 @@ +package cn.cunchang; + +import java.util.List; + +/** + * @author cunchang + * @date 2021/11/25 12:46 上午 + */ +public interface SqlSession { + + List selectList(String statementId); + +} diff --git a/java-advance/proxy/mybatis-mapper/src/main/java/cn/cunchang/SysUser.java b/java-advance/proxy/mybatis-mapper/src/main/java/cn/cunchang/SysUser.java new file mode 100644 index 00000000..1e4b7a71 --- /dev/null +++ b/java-advance/proxy/mybatis-mapper/src/main/java/cn/cunchang/SysUser.java @@ -0,0 +1,8 @@ +package cn.cunchang; + +/** + * @author cunchang + * @date 2021/11/25 12:48 上午 + */ +public class SysUser { +} diff --git a/java-advance/proxy/mybatis-mapper/src/main/java/cn/cunchang/UserMapper.java b/java-advance/proxy/mybatis-mapper/src/main/java/cn/cunchang/UserMapper.java new file mode 100644 index 00000000..e4e3477c --- /dev/null +++ b/java-advance/proxy/mybatis-mapper/src/main/java/cn/cunchang/UserMapper.java @@ -0,0 +1,7 @@ +package cn.cunchang; + +import java.util.List; + +public interface UserMapper{ + List selectAll(); +} \ No newline at end of file diff --git a/java-advance/proxy/pom.xml b/java-advance/proxy/pom.xml new file mode 100644 index 00000000..e8e329fe --- /dev/null +++ b/java-advance/proxy/pom.xml @@ -0,0 +1,59 @@ + + + 4.0.0 + + cn.cunchang + proxy + pom + 1.0-SNAPSHOT + + mybatis-mapper + jdk-proxy + + + + 8 + 8 + + + + + junit + junit + 4.13 + + + + cglib + cglib + 3.1 + + + + org.ow2.asm + asm-util + 8.0.1 + + + org.ow2.asm + asm + 8.0.1 + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 8 + 8 + + + + + \ No newline at end of file diff --git a/java-advance/proxy/src/main/java/cn/cunchang/Client.java b/java-advance/proxy/src/main/java/cn/cunchang/Client.java new file mode 100644 index 00000000..5bb29576 --- /dev/null +++ b/java-advance/proxy/src/main/java/cn/cunchang/Client.java @@ -0,0 +1,191 @@ +package cn.cunchang; + +import cn.cunchang.cglib.RunMethodIntercepot; +import cn.cunchang.myjdkdynamic.*; +import cn.cunchang.jdkdynamic.JdkTimeHandler; +import cn.cunchang.staticproxy.combination.TankLogProxy1; +import cn.cunchang.staticproxy.combination.TankTimeProxy1; +import cn.cunchang.staticproxy.inherit.TankLogTimeProxy; +import net.sf.cglib.core.DebuggingClassWriter; +import net.sf.cglib.proxy.Enhancer; +import org.junit.Test; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.ArrayList; +import java.util.Collection; + +/** + * @author cunchang + * @date 2021/5/9 10:11 上午 + */ +public class Client { + + @Test + public void test继承代理() { + Moveable tank = new TankLogTimeProxy(); + tank.move(); + } + + @Test + public void test组合代理() { + Tank tank = new Tank(); + // 先时间后日志 +// TankTimeProxy1 ttp = new TankTimeProxy1(tank); +// TankLogProxy1 tlp = new TankLogProxy1(ttp); +// tlp.move(); + // 先日志后时间 + TankLogProxy1 tlp = new TankLogProxy1(tank); + TankTimeProxy1 ttp = new TankTimeProxy1(tlp); + ttp.move(); + } + + /** + * 动态代理原理 + * 1、动态生成代理类java源码 + * 2、通过java编译器将源码编译成字节码 + * 3、通过类加载器加载字节码,获取Class对象 + * 4、有了Class对象就可以通过反射获取代理对象 + * + * @throws Exception + */ + @Test + public void test手写动态代理1() throws Exception { + String path = System.getProperty("user.dir") + "/src/main/java/cn/cunchang/dynamic/"; + String pkg = "cn.cunchang.dynamic"; + MyClassLoader classLoader = new MyClassLoader(path, pkg); + + Moveable proxyObj = (Moveable) Proxy1.newProxyInstance(classLoader); + proxyObj.move(); + } + + /** + * 需要代理的方法,通过Class获取 + * @throws Exception + */ + @Test + public void test手写动态代理2() throws Exception { + String path = System.getProperty("user.dir") + "/src/main/java/cn/cunchang/dynamic/"; + String pkg = "cn.cunchang.dynamic"; + MyClassLoader classLoader = new MyClassLoader(path, pkg); + + Moveable proxyObj = (Moveable) Proxy2.newProxyInstance(classLoader, Moveable.class); + proxyObj.move(); + } + + /** + * 代理的逻辑,通过InvocationHandler封装 + * @throws Exception + */ + @Test + public void test手写动态代理3() throws Exception { + String path = System.getProperty("user.dir") + "/src/main/java/cn/cunchang/dynamic/"; + String pkg = "cn.cunchang.dynamic"; + MyClassLoader classLoader = new MyClassLoader(path, pkg); + + Tank tank = new Tank(); + InvocationHandler timeHandler = new TimeHandler(tank); + Moveable proxyObj = (Moveable) Proxy3.newProxyInstance(classLoader, Moveable.class, timeHandler); + proxyObj.move(); + } + + /** + * newProxyInstance + * |-- getProxyClass0 + * |--proxyClassCache.get(loader, interfaces); + * |--ProxyClassFactory + * |--apply + * |--代理类的名称 String proxyName = proxyPkg + proxyClassNamePrefix + num; + * |--生成字节码 byte[] proxyClassFile = ProxyGenerator.generateProxyClass( + * proxyName, interfaces, accessFlags);通过类加载器defineClass0加载 + * |--生成符合Java规范的代码 generateProxyClass + * 在动态生成的对象中,使用h.invoke(this, m3, (Object[])null)这种形式执行方法 + * 这个h就是Proxy的InvocationHandler成员变量,而这个成员变量是在 + * Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this)传入this时赋值的 + */ + public void testJdk动态代理1() throws Exception { + // 查看jdk生成的代理类,必须在main方法中才能生成 + System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true"); + + ClassLoader classLoader = Client.class.getClassLoader(); + Tank tank = new Tank(); + // 第二种方法、创建代理对象;使用Proxy提供的静态方法newProxyInstance + // 参数一:目标增强类的类加载器(用于加载代理类); + // 参数二:目标增强类的接口(代理类实现接口); + // 参数三:InvocationHandler执行增强代码和目标对象 + Moveable proxyObj = (Moveable) Proxy.newProxyInstance(classLoader, Tank.class.getInterfaces(), new JdkTimeHandler(tank)); + proxyObj.move(); + + } + + public static void main(String[] args) throws Exception { +// new Client().testJdk动态代理1(); + new Client().testCglib动态代理1(); + } + + public void testCglib动态代理1() throws Exception { + // 查看Cglib生成的代理类 + System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, System.getProperty("user.dir")); + Enhancer enhancer = new Enhancer(); + enhancer.setSuperclass(Tank.class); + enhancer.setCallback(new RunMethodIntercepot()); + Moveable tank = (Moveable) enhancer.create(); + tank.move(); + } + + /** + * 代理jdk集合 + * @throws Exception + */ + @Test + public void testJdk动态代理2() throws Exception { + // 第一种方法、创建代理对象;使用有参构造 + Class proxyClass = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class); + Constructor constructor = proxyClass.getConstructor(java.lang.reflect.InvocationHandler.class); + Collection proxy1 = (Collection) constructor.newInstance(new java.lang.reflect.InvocationHandler() { +// List target = new ArrayList(); + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + Object retVal = null; +// retVal = method.invoke(target, args); + return retVal; + } + + }); + proxy1.clear(); + // 为什么待返回值的方法会报错? + // 因为InvocationHandler的invoke方法返回值为null + proxy1.size(); + + // 第二种方法、创建代理对象;使用Proxy提供的静态方法newProxyInstance + // 参数一:目标增强类的类加载器(用于加载代理类); + // 参数二:目标增强类的接口(代理类实现接口); + // 参数三:InvocationHandler执行增强代码和目标方法 + Collection proxy2 = (Collection) Proxy.newProxyInstance(Collection.class.getClassLoader(), + new Class[]{Collection.class}, + new java.lang.reflect.InvocationHandler() { + ArrayList target = new ArrayList(); + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + long start = System.currentTimeMillis(); + // 使用反射调用目标对象的方法 + Object retVal = method.invoke(target, args); + long end = System.currentTimeMillis(); + System.out.println("性能监控:" + method.getName() + "方法耗时 " + (end - start)); + // 修改代理类的返回值(过滤器) + // retVal = false; + return retVal; + } + }); + boolean retVal = proxy2.add("普通代理"); + proxy2.add("静态代理"); + proxy2.add("动态代理"); + proxy2.add("CGLIB代理"); + System.out.println(retVal); + System.out.println(proxy2.size()); + } + + +} diff --git a/java-advance/proxy/src/main/java/cn/cunchang/Moveable.java b/java-advance/proxy/src/main/java/cn/cunchang/Moveable.java new file mode 100644 index 00000000..330ca6af --- /dev/null +++ b/java-advance/proxy/src/main/java/cn/cunchang/Moveable.java @@ -0,0 +1,10 @@ +package cn.cunchang; + +/** + * @author cunchang + * @date 2021/5/9 9:57 上午 + */ +public interface Moveable { + void move(); +// void stop(); +} diff --git a/java-advance/proxy/src/main/java/cn/cunchang/Tank.java b/java-advance/proxy/src/main/java/cn/cunchang/Tank.java new file mode 100644 index 00000000..5b83e2e8 --- /dev/null +++ b/java-advance/proxy/src/main/java/cn/cunchang/Tank.java @@ -0,0 +1,39 @@ +package cn.cunchang; + +import java.util.Random; + +/** + * @author cunchang + * @date 2021/5/9 9:57 上午 + */ +public class Tank implements Moveable { + + @Override + public void move() { + try { + Thread.sleep(new Random().nextInt(1000)); + } catch (InterruptedException e) { + e.printStackTrace(); + } + System.out.println("Tank Moving..."); + } + + /** + * 直接修改源码 + */ +// @Override +// public void move() { +// //计算方法运行了多长时间 +// long start = System.currentTimeMillis(); +// +// try { +// Thread.sleep(new Random().nextInt(1000)); +// } catch (InterruptedException e) { +// e.printStackTrace(); +// } +// System.out.println("Tank Moving..."); +// long end = System.currentTimeMillis(); +// System.out.println("耗时:"+(end-start)); +// } + +} \ No newline at end of file diff --git a/java-advance/proxy/src/main/java/cn/cunchang/cglib/RunMethodIntercepot.java b/java-advance/proxy/src/main/java/cn/cunchang/cglib/RunMethodIntercepot.java new file mode 100644 index 00000000..7c54b442 --- /dev/null +++ b/java-advance/proxy/src/main/java/cn/cunchang/cglib/RunMethodIntercepot.java @@ -0,0 +1,25 @@ +package cn.cunchang.cglib; + +import net.sf.cglib.proxy.MethodInterceptor; +import net.sf.cglib.proxy.MethodProxy; + +import java.lang.reflect.Method; + +public class RunMethodIntercepot implements MethodInterceptor { + + @Override + public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { + long start = System.currentTimeMillis(); + Object result = null; + try { + result = methodProxy.invokeSuper(o, objects); + } catch (Exception e) { + e.printStackTrace(); + throw e; + } + long end = System.currentTimeMillis(); + System.out.println("耗时:" + (end - start)); + return result; + } + +} \ No newline at end of file diff --git a/java-advance/proxy/src/main/java/cn/cunchang/jdkdynamic/JdkTimeHandler.java b/java-advance/proxy/src/main/java/cn/cunchang/jdkdynamic/JdkTimeHandler.java new file mode 100644 index 00000000..af2b12d3 --- /dev/null +++ b/java-advance/proxy/src/main/java/cn/cunchang/jdkdynamic/JdkTimeHandler.java @@ -0,0 +1,42 @@ +package cn.cunchang.jdkdynamic; + +import cn.cunchang.Moveable; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; + +/** + * @author cunchang + * @date 2021/5/9 4:23 下午 + */ +public class JdkTimeHandler implements InvocationHandler { + + private Moveable moveable; + + public JdkTimeHandler(Moveable moveable) { + this.moveable = moveable; + } + + /** + * @param proxy 代理类 + * @param method 执行的方法 + * @param args 参数 + * @return + * @throws Throwable + */ + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + long start = System.currentTimeMillis(); + Object result = null; + try { + result = method.invoke(moveable, new Object[]{}); + } catch (Exception e) { + e.printStackTrace(); + throw e; + } + long end = System.currentTimeMillis(); + System.out.println("耗时:" + (end - start)); + return result; + } + +} diff --git a/java-advance/proxy/src/main/java/cn/cunchang/myjdkdynamic/InvocationHandler.java b/java-advance/proxy/src/main/java/cn/cunchang/myjdkdynamic/InvocationHandler.java new file mode 100644 index 00000000..bf753eb0 --- /dev/null +++ b/java-advance/proxy/src/main/java/cn/cunchang/myjdkdynamic/InvocationHandler.java @@ -0,0 +1,12 @@ +package cn.cunchang.myjdkdynamic; + +import java.lang.reflect.Method; +public interface InvocationHandler { + + /** + * 代理执行的逻辑 + * @param o 代理类 + * @param m 要执行的方法 + */ + public void invoke(Object o,Method m); +} \ No newline at end of file diff --git a/java-advance/proxy/src/main/java/cn/cunchang/myjdkdynamic/MyClassLoader.java b/java-advance/proxy/src/main/java/cn/cunchang/myjdkdynamic/MyClassLoader.java new file mode 100644 index 00000000..530d8852 --- /dev/null +++ b/java-advance/proxy/src/main/java/cn/cunchang/myjdkdynamic/MyClassLoader.java @@ -0,0 +1,42 @@ +package cn.cunchang.myjdkdynamic; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; + +public class MyClassLoader extends ClassLoader { + private File dir; + private String proxyClassPackage; + + public File getDir() { + return dir; + } + + public String getProxyClassPackage() { + return proxyClassPackage; + } + + public MyClassLoader(String path, String proxyClassPackage) { + this.dir = new File(path); + this.proxyClassPackage = proxyClassPackage; + } + + @Override + protected Class findClass(String name) throws ClassNotFoundException { + if (null != dir) { + File classFile = new File(dir, name + ".class"); + if (classFile.exists()) { + try { + // Since JDK 7 + byte[] classBytes = Files.readAllBytes(classFile.toPath()); + return defineClass(proxyClassPackage + "." + name, classBytes, 0, classBytes.length); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + throw new ClassNotFoundException("class:" + name + " 找不到"); + } + + +} diff --git a/java-advance/proxy/src/main/java/cn/cunchang/myjdkdynamic/Proxy1.java b/java-advance/proxy/src/main/java/cn/cunchang/myjdkdynamic/Proxy1.java new file mode 100644 index 00000000..3b2fdef3 --- /dev/null +++ b/java-advance/proxy/src/main/java/cn/cunchang/myjdkdynamic/Proxy1.java @@ -0,0 +1,65 @@ +package cn.cunchang.myjdkdynamic; + +import cn.cunchang.Moveable; +import cn.cunchang.Tank; + +import javax.tools.JavaCompiler; +import javax.tools.JavaCompiler.CompilationTask; +import javax.tools.StandardJavaFileManager; +import javax.tools.ToolProvider; +import java.io.File; +import java.io.FileWriter; +import java.lang.reflect.Constructor; + +public class Proxy1 { + + public static Object newProxyInstance(MyClassLoader classLoader) throws Exception { + String rt = "\r\n"; + String src = + "package "+classLoader.getProxyClassPackage()+";" + rt + + + "import cn.cunchang.Moveable;" + rt + + + "public class $Proxy0 implements Moveable{" + rt + + + " Moveable m;" + rt + + + " public $Proxy0(Moveable m) {" + rt + + " super();" + rt + + " this.m = m;" + rt + + " }" + rt + + + " @Override" + rt + + " public void move() {" + rt + + " long start = System.currentTimeMillis();" + rt + + " m.move();" + rt + + " long end = System.currentTimeMillis();" + rt + + " System.out.println(\"耗时:\"+(end-start));" + rt + + " }" + rt + + "}"; + + //1,生成代理类 + String fileName = classLoader.getDir() + File.separator + "$Proxy0.java"; + File file = new File(fileName); + FileWriter fw = new FileWriter(file); + fw.write(src); + fw.flush(); + fw.close(); + + //2,将生成的类进行编译成class文件 + JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();//拿到系统默认的编译器(其实就是javac) + StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null, null, null);//诊断监听器;语言;编码 + Iterable units = fileMgr.getJavaFileObjects(fileName); + CompilationTask task = compiler.getTask(null, fileMgr, null, null, null, units); + task.call(); + fileMgr.close(); + + //3,将class load到内存 + Class clazz = classLoader.findClass("$Proxy0"); + //4,,创建一个对象 + //不能用 clazz.newInstance();创建对象因为它会调用空构造方法 + Constructor constructor = clazz.getConstructor(Moveable.class);//获取某个类型参数的构造器 + return constructor.newInstance(new Tank()); + } + +} \ No newline at end of file diff --git a/java-advance/proxy/src/main/java/cn/cunchang/myjdkdynamic/Proxy2.java b/java-advance/proxy/src/main/java/cn/cunchang/myjdkdynamic/Proxy2.java new file mode 100644 index 00000000..02ca324b --- /dev/null +++ b/java-advance/proxy/src/main/java/cn/cunchang/myjdkdynamic/Proxy2.java @@ -0,0 +1,91 @@ +package cn.cunchang.myjdkdynamic; + +import cn.cunchang.Moveable; +import cn.cunchang.Tank; + +import java.io.File; +import java.io.FileWriter; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; + +import javax.tools.JavaCompiler; +import javax.tools.JavaCompiler.CompilationTask; +import javax.tools.StandardJavaFileManager; +import javax.tools.ToolProvider; + +/** + * 产生代理的类 + * + */ +public class Proxy2 { + + /** + * 动态传入接口,其实jdk可以传多个接口 + * + * @param interfaces + * @return + * @throws Exception + */ + public static Object newProxyInstance(MyClassLoader classLoader,Class interfaces) throws Exception{ + //换行字符串 + String rt = "\r\n"; + String methodStr = ""; + //反射拿到接口的所有的方法 + Method[] methods = interfaces.getMethods(); + for(Method m : methods){ + methodStr += "@Override"+rt + + "public void "+ m.getName()+ "() {" +rt + + //计算方法运行了多长时间 + " long start = System.currentTimeMillis();" +rt + + " m."+m.getName() +"();" +rt + + " long end = System.currentTimeMillis();"+rt + + " System.out.println(\"耗时:\"+(end-start));"+rt + + "}"; + } + + //只要能动态的 编译这段代码,就能动态的产生代理类!类的名字无所谓 + //动态编译的技术:JDK6 Compiler API,CGLib(用到了ASM) ,ASM + //(CGLib、ASM不用源码来编译,能直接生成二进制文件,因为java的二进制文件格式是公开的) + //Spring内部,如果是实现接口就是用的JDK本身的API产生代理,否则就用CGLib + + String src = + "package "+classLoader.getProxyClassPackage()+";"+ rt + + + "import cn.cunchang.Moveable;" + rt + + + "public class $Proxy0 implements "+ interfaces.getName() +"{"+rt + + + " Moveable m;"+rt + + + " public $Proxy0(Moveable m) {"+rt + + " super();"+rt + + " this.m = m;"+rt + + " }"+rt + + + methodStr + + "}"; + + //1,生成代理类 + String fileName = classLoader.getDir() + File.separator + "$Proxy0.java"; + File file = new File(fileName); + FileWriter fw = new FileWriter(file); + fw.write(src); + fw.flush(); + fw.close(); + + //2,将生成的类进行编译成class文件 + JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();//拿到系统默认的编译器(其实就是javac) + StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null, null, null);//诊断监听器;语言;编码 + Iterable units = fileMgr.getJavaFileObjects(fileName); + CompilationTask task = compiler.getTask(null, fileMgr, null, null, null, units); + task.call(); + fileMgr.close(); + + //3,将class load到内存 + Class clazz = classLoader.findClass("$Proxy0"); + //4,,创建一个对象 + //不能用 clazz.newInstance();创建对象因为它会调用空构造方法 + Constructor constructor = clazz.getConstructor(Moveable.class);//获取某个类型参数的构造器 + return constructor.newInstance(new Tank()); + } +} \ No newline at end of file diff --git a/java-advance/proxy/src/main/java/cn/cunchang/myjdkdynamic/Proxy3.java b/java-advance/proxy/src/main/java/cn/cunchang/myjdkdynamic/Proxy3.java new file mode 100644 index 00000000..e72bf298 --- /dev/null +++ b/java-advance/proxy/src/main/java/cn/cunchang/myjdkdynamic/Proxy3.java @@ -0,0 +1,88 @@ +package cn.cunchang.myjdkdynamic; + +import javax.tools.JavaCompiler; +import javax.tools.JavaCompiler.CompilationTask; +import javax.tools.StandardJavaFileManager; +import javax.tools.ToolProvider; +import java.io.File; +import java.io.FileWriter; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; + +/** + * 产生代理的类 + * @author dev + * + */ +public class Proxy3 { + /** + * + * @param interfaces 代理实现的接口 + * @param h 代理处理逻辑 + * @return + * @throws Exception + */ + public static Object newProxyInstance(MyClassLoader classLoader,Class interfaces, InvocationHandler h) throws Exception{//动态传入接口,其实jdk可以传多个接口 + //换行字符串 + String rt = "\r\n"; + String methodStr = ""; + //反射拿到接口的所有的方法 + Method[] methods = interfaces.getMethods(); + for(Method m : methods){ + methodStr += "@Override"+rt + + "public void "+ m.getName()+ "() {"+ + " try{"+rt+ + " Method md = "+ interfaces.getName()+".class.getMethod(\""+m.getName()+"\");"+rt+ + " h.invoke(this,md);"+rt+ //this->代理对象 + " }catch(Exception e){e.printStackTrace();}"+ + "}"; + } + + //只要能动态的 编译这段代码,就能动态的产生代理类!类的名字无所谓 + //动态编译的技术:JDK6 Compiler API,CGLib(用到了ASM) ,ASM + //(CGLib、ASM不用源码来编译,能直接生成二进制文件,因为java的二进制文件格式是公开的) + //Spring内部,如果是实现接口就是用的JDK本身的API产生代理,否则就用CGLib + + String src = + "package "+classLoader.getProxyClassPackage()+";"+ rt + + + "import java.lang.reflect.Method;"+rt+ + "import cn.cunchang.Moveable;" + rt + + "import cn.cunchang.dynamic.InvocationHandler;"+rt+ + + "public class $Proxy0 implements "+ interfaces.getName() +"{"+rt + + + " InvocationHandler h;"+rt+ + " public $Proxy0(InvocationHandler h) {"+rt + + " this.h = h;"+rt + + " }"+rt + + + methodStr + + "}"; + + //1,生成代理类 + String fileName = classLoader.getDir() + File.separator + "$Proxy0.java"; + File file = new File(fileName); + FileWriter fw = new FileWriter(file); + fw.write(src); + fw.flush(); + fw.close(); + + //2,将生成的类进行编译成class文件 + JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();//拿到系统默认的编译器(其实就是javac) + StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null, null, null);//诊断监听器;语言;编码 + Iterable units = fileMgr.getJavaFileObjects(fileName); + CompilationTask task = compiler.getTask(null, fileMgr, null, null, null, units); + task.call(); + fileMgr.close(); + + //3,将class load到内存 + Class clazz = classLoader.findClass("$Proxy0"); + //4,,创建一个对象 + //不能用 clazz.newInstance();创建对象因为它会调用空构造方法 + Constructor constructor = clazz.getConstructor(InvocationHandler.class);//获取某个类型参数的构造器 + Object obj = constructor.newInstance(h);// + + return obj; + } +} \ No newline at end of file diff --git a/java-advance/proxy/src/main/java/cn/cunchang/myjdkdynamic/TimeHandler.java b/java-advance/proxy/src/main/java/cn/cunchang/myjdkdynamic/TimeHandler.java new file mode 100644 index 00000000..a9cd1f8c --- /dev/null +++ b/java-advance/proxy/src/main/java/cn/cunchang/myjdkdynamic/TimeHandler.java @@ -0,0 +1,28 @@ +package cn.cunchang.myjdkdynamic; + +import java.lang.reflect.Method; + +public class TimeHandler implements InvocationHandler{ + + //被代理类 + private Object target; + + + public TimeHandler(Object target) { + super(); + this.target = target; + } + + @Override + public void invoke(Object o,Method m) { + long start = System.currentTimeMillis(); + try { + m.invoke(target, new Object[]{}); + } catch (Exception e) { + e.printStackTrace(); + } + long end = System.currentTimeMillis(); + System.out.println("耗时:" + (end - start)); + + } +} \ No newline at end of file diff --git a/java-advance/proxy/src/main/java/cn/cunchang/staticproxy/combination/TankLogProxy1.java b/java-advance/proxy/src/main/java/cn/cunchang/staticproxy/combination/TankLogProxy1.java new file mode 100644 index 00000000..2a02cca2 --- /dev/null +++ b/java-advance/proxy/src/main/java/cn/cunchang/staticproxy/combination/TankLogProxy1.java @@ -0,0 +1,24 @@ +package cn.cunchang.staticproxy.combination; + +import cn.cunchang.Moveable; + +/** + * @author cunchang + * @date 2021/5/9 9:57 上午 + */ +public class TankLogProxy1 implements Moveable { + + Moveable m; + public TankLogProxy1(Moveable m) { + super(); + this.m = m; + } + + @Override + public void move() { + System.out.println("Tank start...."); + m.move(); + System.out.println("Tank end...."); + } + +} \ No newline at end of file diff --git a/java-advance/proxy/src/main/java/cn/cunchang/staticproxy/combination/TankTimeProxy1.java b/java-advance/proxy/src/main/java/cn/cunchang/staticproxy/combination/TankTimeProxy1.java new file mode 100644 index 00000000..24a15a1f --- /dev/null +++ b/java-advance/proxy/src/main/java/cn/cunchang/staticproxy/combination/TankTimeProxy1.java @@ -0,0 +1,34 @@ +package cn.cunchang.staticproxy.combination; + +import cn.cunchang.Moveable; + +/** + * @author cunchang + * @date 2021/5/9 9:57 上午 + */ +public class TankTimeProxy1 implements Moveable { + + Moveable m; + public TankTimeProxy1(Moveable m) { + super(); + this.m = m; + } + @Override + public void move() { + //计算方法运行了多长时间 + long start = System.currentTimeMillis(); + m.move(); + long end = System.currentTimeMillis(); + System.out.println("耗时:"+(end-start)); + } + +// @Override +// public void stop() { +// //计算方法运行了多长时间 +// long start = System.currentTimeMillis(); +// System.out.println("start:"+start); +// m.stop(); +// long end = System.currentTimeMillis(); +// System.out.println("耗时:"+(end-start)); +// } +} \ No newline at end of file diff --git a/java-advance/proxy/src/main/java/cn/cunchang/staticproxy/inherit/TankLogTimeProxy.java b/java-advance/proxy/src/main/java/cn/cunchang/staticproxy/inherit/TankLogTimeProxy.java new file mode 100644 index 00000000..4130a607 --- /dev/null +++ b/java-advance/proxy/src/main/java/cn/cunchang/staticproxy/inherit/TankLogTimeProxy.java @@ -0,0 +1,14 @@ +package cn.cunchang.staticproxy.inherit; + +public class TankLogTimeProxy extends TankTimeProxy { + + @Override + public void move() { + //记录日志 + System.out.println("Tank start...."); + super.move(); + System.out.println("Tank end...."); + } + + +} \ No newline at end of file diff --git a/java-advance/proxy/src/main/java/cn/cunchang/staticproxy/inherit/TankTimeProxy.java b/java-advance/proxy/src/main/java/cn/cunchang/staticproxy/inherit/TankTimeProxy.java new file mode 100644 index 00000000..37144847 --- /dev/null +++ b/java-advance/proxy/src/main/java/cn/cunchang/staticproxy/inherit/TankTimeProxy.java @@ -0,0 +1,20 @@ +package cn.cunchang.staticproxy.inherit; + +import cn.cunchang.Tank; + +/** + * @author cunchang + * @date 2021/5/9 9:57 上午 + */ +public class TankTimeProxy extends Tank { + + @Override + public void move() { + //计算方法运行了多长时间 + long start = System.currentTimeMillis(); + super.move(); + long end = System.currentTimeMillis(); + System.out.println("耗时:"+(end-start)); + } + +} \ No newline at end of file diff --git a/java-advance/spi/README.md b/java-advance/spi/README.md new file mode 100644 index 00000000..260eecb1 --- /dev/null +++ b/java-advance/spi/README.md @@ -0,0 +1,21 @@ + +https://www.jianshu.com/p/46b42f7f593c + + +比如,我们日常使用是数据库驱动,会提供统一的规范(java.sql.Driver),各数据库服务商提供对应数据库的逻辑实现。当使用到该数据库时,直接引入不同的SPI服务实现即可。 + +常见场景: + +Spring框架中有大量实现,如上图中Spring对servlet3.0规范的ServletContainerInitializer的实现。 +数据库驱动程序加载不同数据库的实现,如上图中java.sql.Driver接口的实现。 +日志框架log4j中的实现。 +Dubbo中实现框架扩展的实现。 + +使用规范,下面了解一下使用SPI的基本规范步骤: + +服务提供者定义对外接口及方法,比如数据库驱动会提供一个java.sql.Driver的接口。 +针对定义的接口,提供一个实现类。 +在项目或jar包的META-INF/services目录下,创建一个文本文件:名称为接口的“全限定名”,内容为实现类的全限定名(包+实现类名)。上面的截图中其实已经可以发现,统一都是如此。 +服务调用者引入该项目的jar包,并将其放置于classpath下。 +服务调用者通过核心API java.util.ServiceLoader来动态加载该实现,主要就是扫描classpath下所有jar包内META-INF/services目录下,按照指定格式定义的文件,并把其中类进行加载。 +由于SPI机制使用的过程中无法进行传递构造参数,因此需提供一个无参的构造方法。 diff --git a/java-advance/spi/pom.xml b/java-advance/spi/pom.xml new file mode 100644 index 00000000..5f6216be --- /dev/null +++ b/java-advance/spi/pom.xml @@ -0,0 +1,23 @@ + + + 4.0.0 + + cn.cunchang + spi + pom + 1.0-SNAPSHOT + + spi-jdbc-interface + spi-mysql + spi-oracle + web-client + + + + 8 + 8 + + + \ No newline at end of file diff --git a/java-advance/spi/spi-jdbc-interface/pom.xml b/java-advance/spi/spi-jdbc-interface/pom.xml new file mode 100644 index 00000000..257f4ee6 --- /dev/null +++ b/java-advance/spi/spi-jdbc-interface/pom.xml @@ -0,0 +1,19 @@ + + + + spi + cn.cunchang + 1.0-SNAPSHOT + + 4.0.0 + + spi-jdbc-interface + + + 8 + 8 + + + \ No newline at end of file diff --git a/java-advance/spi/spi-jdbc-interface/src/main/java/cn/jdbc/Driver.java b/java-advance/spi/spi-jdbc-interface/src/main/java/cn/jdbc/Driver.java new file mode 100644 index 00000000..765f35b4 --- /dev/null +++ b/java-advance/spi/spi-jdbc-interface/src/main/java/cn/jdbc/Driver.java @@ -0,0 +1,22 @@ +package cn.jdbc; + +import java.sql.Connection; +import java.sql.SQLException; + +/** + * spi-interface: 是针对厂商定义的接口项目,只提供接口,不提供实现 + *

+ * 服务接口 (Service Interface),这是提供者实现的 + * Connection口就是其服务接口 + * + * @author lastwhisper + */ +public interface Driver { + + public boolean available(String url, + String user, String password); + + + public Connection getConnection() throws SQLException; + +} diff --git a/java-advance/spi/spi-jdbc-interface/src/main/java/cn/jdbc/DriverManager.java b/java-advance/spi/spi-jdbc-interface/src/main/java/cn/jdbc/DriverManager.java new file mode 100644 index 00000000..3c088e3e --- /dev/null +++ b/java-advance/spi/spi-jdbc-interface/src/main/java/cn/jdbc/DriverManager.java @@ -0,0 +1,52 @@ +package cn.jdbc; + + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.ServiceLoader; + +/** + * spi-core: 是提供给用户使用的核心jar文件, + * 同样依赖于interface项目, 用户使用时需要引入spi-core.jar和厂商具体实现的jar + *

+ * 提供者注册 API ( Provider Registration API),这是提供者用来注册实现的 + * DriverManager.registerDriver是提供者注册API + *

+ * 服务访问 API (Service Access API),这是客户端用来获取服务的实例 + * DriverManager.getConnection 是服务访问 API + * + * @author lastwhisper + */ +public class DriverManager { + + public static List driverList; + + static { + registerDriver(); + } + + private static void registerDriver() { + ServiceLoader services = ServiceLoader.load(Driver.class); + driverList = new ArrayList<>(); + for (Driver driver : services) { + driverList.add(driver); + } + } + + + public static Driver getDriver(String url, + String user, String password) { + if (Objects.isNull(driverList)) { + throw new IllegalStateException("未找到 Driver 的实现"); + } + System.out.println("找到" + driverList.size() + "个jdbc实现驱动"); + for (Driver driver : driverList) { + if (driver.available(url, user, password)) { + return driver; + } + } + throw new IllegalStateException("未找到 Driver 的实现"); + } + +} diff --git a/java-advance/spi/spi-mysql/pom.xml b/java-advance/spi/spi-mysql/pom.xml new file mode 100644 index 00000000..7ee7a542 --- /dev/null +++ b/java-advance/spi/spi-mysql/pom.xml @@ -0,0 +1,26 @@ + + + + spi + cn.cunchang + 1.0-SNAPSHOT + + 4.0.0 + + spi-mysql + + + 8 + 8 + + + + + cn.cunchang + spi-jdbc-interface + 1.0-SNAPSHOT + + + \ No newline at end of file diff --git a/java-advance/spi/spi-mysql/src/main/java/cn/mysql/MysqlDriver.java b/java-advance/spi/spi-mysql/src/main/java/cn/mysql/MysqlDriver.java new file mode 100644 index 00000000..cbb5f792 --- /dev/null +++ b/java-advance/spi/spi-mysql/src/main/java/cn/mysql/MysqlDriver.java @@ -0,0 +1,34 @@ +package cn.mysql; + + +import cn.jdbc.Driver; + +import java.sql.Connection; +import java.sql.SQLException; + +/** + * MysqlDriver/OracleDriver: 分别是两个厂商对interface的不同实现,所以他们会依赖于interface项目 + * + * @author lastwhisper + */ +public class MysqlDriver implements Driver { + + static { + System.out.println("加载mysql driver"); + } + + @Override + public boolean available(String url, String user, String password) { + if (url != null && url.contains("mysql")) { + System.out.println("成功注册mysql驱动"); + return true; + } + return false; + } + + @Override + public Connection getConnection() throws SQLException { + // return new MysqlConnection(); + return null; + } +} diff --git a/java-advance/spi/spi-mysql/src/main/resources/META-INF/services/cn.jdbc.Driver b/java-advance/spi/spi-mysql/src/main/resources/META-INF/services/cn.jdbc.Driver new file mode 100644 index 00000000..8ff7ab24 --- /dev/null +++ b/java-advance/spi/spi-mysql/src/main/resources/META-INF/services/cn.jdbc.Driver @@ -0,0 +1 @@ +cn.mysql.MysqlDriver \ No newline at end of file diff --git a/java-advance/spi/spi-oracle/pom.xml b/java-advance/spi/spi-oracle/pom.xml new file mode 100644 index 00000000..b79f1a95 --- /dev/null +++ b/java-advance/spi/spi-oracle/pom.xml @@ -0,0 +1,26 @@ + + + + spi + cn.cunchang + 1.0-SNAPSHOT + + 4.0.0 + + spi-oracle + + + 8 + 8 + + + + + cn.cunchang + spi-jdbc-interface + 1.0-SNAPSHOT + + + \ No newline at end of file diff --git a/java-advance/spi/spi-oracle/src/main/java/cn/oracle/OracleDriver.java b/java-advance/spi/spi-oracle/src/main/java/cn/oracle/OracleDriver.java new file mode 100644 index 00000000..ffaed4be --- /dev/null +++ b/java-advance/spi/spi-oracle/src/main/java/cn/oracle/OracleDriver.java @@ -0,0 +1,34 @@ +package cn.oracle; + + +import cn.jdbc.Driver; + +import java.sql.Connection; +import java.sql.SQLException; + +/** + * spi-boy/spi-gril: 分别是两个厂商对interface的不同实现,所以他们会依赖于interface项目 + * + * @author lastwhisper + */ +public class OracleDriver implements Driver { + + static { + System.out.println("加载oracle driver"); + } + + @Override + public boolean available(String url, String user, String password) { + if (url != null && url.contains("oracle")) { + System.out.println("成功注册oracle驱动"); + return true; + } + return false; + } + + @Override + public Connection getConnection() throws SQLException { + // return new OracleConnection(); + return null; + } +} diff --git a/java-advance/spi/spi-oracle/src/main/resources/META-INF/services/cn.jdbc.Driver b/java-advance/spi/spi-oracle/src/main/resources/META-INF/services/cn.jdbc.Driver new file mode 100644 index 00000000..50ae9acc --- /dev/null +++ b/java-advance/spi/spi-oracle/src/main/resources/META-INF/services/cn.jdbc.Driver @@ -0,0 +1 @@ +cn.oracle.OracleDriver \ No newline at end of file diff --git a/java-advance/spi/web-client/pom.xml b/java-advance/spi/web-client/pom.xml new file mode 100644 index 00000000..75130634 --- /dev/null +++ b/java-advance/spi/web-client/pom.xml @@ -0,0 +1,32 @@ + + + + spi + cn.cunchang + 1.0-SNAPSHOT + + 4.0.0 + + web-client + + + 8 + 8 + + + + + cn.cunchang + spi-mysql + 1.0-SNAPSHOT + + + + cn.cunchang + spi-oracle + 1.0-SNAPSHOT + + + \ No newline at end of file diff --git a/java-advance/spi/web-client/src/main/java/cn/lastwhisper/JdbcUtil.java b/java-advance/spi/web-client/src/main/java/cn/lastwhisper/JdbcUtil.java new file mode 100644 index 00000000..1501aa8d --- /dev/null +++ b/java-advance/spi/web-client/src/main/java/cn/lastwhisper/JdbcUtil.java @@ -0,0 +1,27 @@ +package cn.lastwhisper; + + +import cn.jdbc.Driver; +import cn.jdbc.DriverManager; + +import java.sql.Connection; +import java.sql.SQLException; + +/** + * @author cunchang + * @date 2022/5/8 7:17 PM + */ +public class JdbcUtil { + + public static void main(String[] args) throws SQLException { + String user = "root"; + String password = "12456"; + String url = "jdbc:mysql://47.100.54.177:3637/mysqlstudy?characterEnconding=UTF-8"; + + // 拿到jdbc链接搞事情 + Driver driver = DriverManager.getDriver(url, user, password); + System.out.println("客户端获取driver:" + driver); + Connection connection = driver.getConnection(); + } + +} diff --git a/java-advance/spi/web-client/src/main/resources/META-INF/services/cn.jdbc.Driver b/java-advance/spi/web-client/src/main/resources/META-INF/services/cn.jdbc.Driver new file mode 100644 index 00000000..9ab433f5 --- /dev/null +++ b/java-advance/spi/web-client/src/main/resources/META-INF/services/cn.jdbc.Driver @@ -0,0 +1 @@ +#cn.mysql.MysqlDriver \ No newline at end of file diff --git a/java-basic/README.MD b/java-basic/README.MD new file mode 100644 index 00000000..6b2926c5 --- /dev/null +++ b/java-basic/README.MD @@ -0,0 +1,5 @@ +java基础学习 +1. jdk特性 +2. jvm代码 +3. 并发 +4. 设计模式 \ No newline at end of file diff --git a/java-basic/basic/pom.xml b/java-basic/basic/pom.xml new file mode 100644 index 00000000..e2243446 --- /dev/null +++ b/java-basic/basic/pom.xml @@ -0,0 +1,114 @@ + + + + 4.0.0 + basic + cn.lastwhisper + 0.0.1-SNAPSHOT + + + + + junit + junit + 4.13 + + + + + org.slf4j + slf4j-api + 1.7.26 + + + + + org.apache.logging.log4j + log4j-slf4j-impl + 2.9.1 + + + + + org.apache.logging.log4j + log4j-api + 2.11.1 + + + + + org.apache.logging.log4j + log4j-core + 2.11.1 + + + + + com.alibaba + fastjson + 1.2.80 + + + + + org.projectlombok + lombok + 1.18.22 + + + + + com.google.guava + guava + 30.1.1-jre + + + + + cn.hutool + hutool-all + 5.8.0 + + + + + com.belerweb + pinyin4j + 2.5.0 + + + + + org.springframework + spring-expression + 5.2.7.RELEASE + + + + org.apache.commons + commons-lang3 + 3.11 + + + + commons-collections + commons-collections + 3.2.2 + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.6.1 + + 1.8 + 1.8 + + + + + \ No newline at end of file diff --git a/java-basic/basic/src/main/java/cn/cunchang/Jsq.java b/java-basic/basic/src/main/java/cn/cunchang/Jsq.java new file mode 100644 index 00000000..e0258ac2 --- /dev/null +++ b/java-basic/basic/src/main/java/cn/cunchang/Jsq.java @@ -0,0 +1,162 @@ +package cn.cunchang; + + + +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JTextField; + +public class Jsq extends JFrame implements ActionListener{ + private final String[] KEYS = {"7","8","9","/","4","5","6","*","1","2","3","-","0",".","=","+"}; + + private JTextField resultText = new JTextField("hello world");//文本框 + private JButton Clear = new JButton("C"); + private JButton keys[] = new JButton[KEYS.length];//定义数组 + + // 标志用户按的是否是整个表达式的第一个数字,或者是运算符后的第一个数字 + private boolean firstDigit = true; + // 计算的中间结果。 + private double resultNum = 0.0; + // 当前运算的运算符 + private String operator = "="; + // 操作是否合法 + private boolean operateValidFlag = true; + + public Jsq() { + super("计算器");//设置窗体标题 + this.setSize(300, 300); + this.setLocationRelativeTo(null);//设置窗体的相对位置(屏幕中间) + this.setResizable(true);// 修改计算器的大小,默认是true.如果是false,则不能拉伸。 + init(); + + } + + + private void init() { + // 建立一个画板放文本框和清空按钮。 + JPanel top = new JPanel(); + top.setLayout(new BorderLayout());//边框的布局管理器,设置样式 + resultText.setHorizontalAlignment(JTextField.RIGHT);// Java文本框左右对齐属性;文本框中的内容采用右对齐方式。 + resultText.setEditable(false);// 不允许修改结果文本框,使调用这个函数的控件不能被编辑。 + resultText.setBackground(Color.white); + top.add("Center", resultText);//文本框位于top画板中间。 + Clear.setForeground(Color.red); + Clear.setBackground(Color.black);//黑色 + top.add("East",Clear); + + JPanel calckeysPanel = new JPanel(); // 建立另一个画板放按键 + calckeysPanel.setLayout(new GridLayout(4, 4, 5, 5)); + // 用网格布局器,4行,4列的网格,网格之间的水平方向间隔为5个象素,垂直方向间隔为5个象素 + for (int i = 0; i < KEYS.length; i++) { //从keys0开始数。 + keys[i] = new JButton(KEYS[i]); + keys[i].setForeground(Color.blue); + keys[i].setFont(new Font("alias", Font.PLAIN, 6)); + calckeysPanel.add(keys[i]); + } + keys[3].setForeground(Color.red); + keys[7].setForeground(Color.red); + keys[11].setForeground(Color.red); + keys[14].setForeground(Color.red); + keys[15].setForeground(Color.red); + + // 整体布局 + getContentPane().setLayout(new BorderLayout());//布局管理器 + getContentPane().add("North", top); + getContentPane().add("Center", calckeysPanel); + +// 为各按钮添加事件侦听器,都使用同一个事件侦听器,即本对象。 本类的声明中有implements ActionListener(能点击按钮) + for (int i = 0; i < KEYS.length; i++) { + keys[i].addActionListener(this);//this表示当前类的对象 + } + Clear.addActionListener(this); + + } + + public void actionPerformed(ActionEvent e) { + // 获取事件源的标签 + String label = e.getActionCommand();//返回的是当前动作指向对象的名称 + + if (label.equals("C")) {// 用户按了"C"键 + resultText.setText("0"); + firstDigit = true; + operator = "="; + } else if ("0123456789.".indexOf(label) >= 0) { // 用户按了数字键或者小数点键(按下任何一个数字进行运算) + handleNumber(label); + } else { + handleOperator(label);// 用户按了运算符键 + } + } + + //处理数字键被按下的事件 + private void handleNumber(String key) { + if (firstDigit) { + // 输入的第一个数字 + resultText.setText(key);//向text中放置数值 + } + else { + resultText.setText(resultText.getText() + key);//获取text的值 + } + firstDigit = false; + } + + //处理运算符键被按下的事件 + private void handleOperator(String key) { + if (operator.equals("/")) { + // 除法运算 + // 如果当前结果文本框中的值等于0 + if (getNumberFromText() == 0.0) { + operateValidFlag = false;// 操作不合法 + resultText.setText("除数不能为0"); + } else { + resultNum /= getNumberFromText(); + } + } else if (operator.equals("+")) { // 加法运算 + resultNum += getNumberFromText(); + } else if (operator.equals("-")) {// 减法运算 + resultNum -= getNumberFromText(); + } else if (operator.equals("*")) {// 乘法运算 + resultNum *=getNumberFromText(); + } + if (operator.equals("+/-")) {// 正负数运算 + resultNum = resultNum * (-1); + } else if (operator.equals("=")) { // 赋值运算 + resultNum = getNumberFromText(); + } + + if (operateValidFlag) { // 双精度浮点数的运算 + long t1; + double t2; + t1 = (long) resultNum; + t2 = resultNum - t1; + if (t2 == 0) { + resultText.setText(String.valueOf(t1)); + } else { + resultText.setText(String.valueOf(resultNum)); + } + } + // 运算符等于用户按的按钮 + operator = key; + firstDigit = true; + operateValidFlag = true; + } + //从结果文本框中获取数字 + private double getNumberFromText() { //得到结果 + double result = 0; + try { + result = Double.valueOf(resultText.getText()).doubleValue(); + } catch (NumberFormatException e) { + } + return result; + } + + public static void main(String args[]) { + Jsq jsq = new Jsq(); + jsq.setVisible(true);//窗口是否可见 + jsq.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//设置点击窗体右上角的关闭图标后,结束应用。 + } +} diff --git a/java-basic/basic/src/main/java/cn/cunchang/Main.java b/java-basic/basic/src/main/java/cn/cunchang/Main.java new file mode 100644 index 00000000..15d95195 --- /dev/null +++ b/java-basic/basic/src/main/java/cn/cunchang/Main.java @@ -0,0 +1,60 @@ +package cn.cunchang; + +import com.alibaba.fastjson.JSON; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author kaisui + * @description + * @date 2022/12/26 + */ +public class Main { + static Map map = new HashMap<>(); + + /** + * 判断数组中的数是否可以组成另一个数 + * a*n+b*m=c + */ + public static void main(String[] args) { + // a*n+b*m=c + //1、n=1、m=1 || n=0||m==0 + Integer[] arr = {50, 10}; + int c = 60; + //2、n>1,m=1 || n=1,m>1 +// Integer[] arr = {50, 10}; +// int c = 110; + // + //3、n>1,m>1 +// Integer[] arr = {50, 90}; +// Integer[] arr = {50, 80}; +// int c = 260; + boolean xxxx = xxxx(arr, c); + if (xxxx) { + System.out.println("找到了:" + JSON.toJSONString(map)); + } else { + System.out.println("没找到"); + } + } + + private static boolean xxxx(Integer[] arr, int c) { + if (c == 0) { + return true; + } + if (c < 0) { + return false; + } + for (int i = 0; i < arr.length; i++) { + map.put(arr[i], map.getOrDefault(arr[i], 0) + 1); + c = c - arr[i]; + if (xxxx(arr, c)) { + return true; + } + // 回溯 + c = c + arr[i]; + map.put(arr[i], map.get(arr[i]) - 1); + } + return false; + } +} diff --git a/java-basic/basic/src/main/java/cn/cunchang/README.md b/java-basic/basic/src/main/java/cn/cunchang/README.md new file mode 100644 index 00000000..637c7a4d --- /dev/null +++ b/java-basic/basic/src/main/java/cn/cunchang/README.md @@ -0,0 +1,9 @@ + +- collection 集合相关操作 +- cpu 控制cpu的利用率 +- decimal decimal相关操作 +- packagesacn 扫包 +- regex 正则表达式 +- sugar java语法糖 +- sysproperty 系统变量 +- trycatch trycatch相关操作 \ No newline at end of file diff --git a/java-basic/basic/src/main/java/cn/cunchang/RandomTest.java b/java-basic/basic/src/main/java/cn/cunchang/RandomTest.java new file mode 100644 index 00000000..1351be61 --- /dev/null +++ b/java-basic/basic/src/main/java/cn/cunchang/RandomTest.java @@ -0,0 +1,36 @@ +package cn.cunchang; + +import java.util.Random; + +/** + * @author cunchang + * @date 2022/6/16 1:51 PM + */ +public class RandomTest { + + static int stock = 10000; + + public static void main(String[] args) { + Random random = new Random(); + + for (int i = 0; i < 1000000; i++) { + int nextInt = random.nextInt(100); + if (nextInt == 1) { + if (!deduct()) { + break; + } + System.out.println("用户" + i + "抢到了"); + } + } + } + + public static boolean deduct() { + if (stock < 0) { + System.out.println("抢完了"); + return false; + } + stock--; + return true; + } + +} diff --git a/java-basic/basic/src/main/java/cn/cunchang/collection/ArraysTest.java b/java-basic/basic/src/main/java/cn/cunchang/collection/ArraysTest.java new file mode 100644 index 00000000..dceda74b --- /dev/null +++ b/java-basic/basic/src/main/java/cn/cunchang/collection/ArraysTest.java @@ -0,0 +1,48 @@ +package cn.cunchang.collection; + +import org.junit.Test; + +import java.util.Arrays; +import java.util.List; + +/** + * + * @author cunchang + * @date 2021/6/23 2:37 下午 + */ +public class ArraysTest { + + @Test + public void test1Arrays的坑(){ + // 一个参数 + int[] arr = {1,2,3}; + List list = Arrays.asList(arr); + System.out.println(list); + System.out.println(list.size()); + // 三个参数 + list = Arrays.asList(1,2,3); + System.out.println(list); + System.out.println(list.size()); + } + + @Test + public void test2Arrays的坑(){ + String[] arr = {"欢迎","关注","Java"}; + List list = Arrays.asList(arr); + System.out.println("arr="+Arrays.toString(arr)); + arr[1] = "爱上"; + list.set(2,"我"); + System.out.println("修改list,arr也会被修改="+Arrays.toString(arr)); + System.out.println("修改arr,list也会被修改="+list); + } + + @Test + public void test3Arrays的坑(){ + String[] arr = {"欢迎","关注","Java"}; + List list = Arrays.asList(arr); + System.out.println("arr="+Arrays.toString(arr)); + list.add("新增"); + list.remove("关注"); + } + +} diff --git a/java-basic/basic/src/main/java/cn/cunchang/collection/Intersection.java b/java-basic/basic/src/main/java/cn/cunchang/collection/Intersection.java new file mode 100644 index 00000000..da13c826 --- /dev/null +++ b/java-basic/basic/src/main/java/cn/cunchang/collection/Intersection.java @@ -0,0 +1,59 @@ +package cn.cunchang.collection; + +import org.junit.Test; + +import java.util.HashSet; +import java.util.Set; + +/** + * 集合运算 - Java实现集合的交、并、差 + * @author cunchang + * @date 2020/7/22 11:43 + */ +public class Intersection { + + @Test + public void test1(){ + + } + + public static void main(String[] args) { + + HashSet set1 = new HashSet() { + private static final long serialVersionUID = 1L; + { + add(1); + add(2); + }}; + + HashSet set2 = new HashSet(){ + private static final long serialVersionUID = 1L; + { + add(2); + add(3); + }}; + System.out.println("set1:"+set1); + System.out.println("set2:"+set2); + + HashSet result = new HashSet(); + + //交集 + result.addAll(set1); + result.retainAll(set2); + System.out.println("交集:"+result);//交集:[2] + + //差集 + result.clear(); + result.addAll(set1); + result.removeAll(set2); + System.out.println("set1-set2,差集:"+result);//差集:[1] + + //并集 + result.clear(); + result.addAll(set1); + result.addAll(set2); + System.out.println("并集:"+result);//并集:[1, 2, 3] + + } + +} diff --git a/java-basic/basic/src/main/java/cn/cunchang/collection/README.md b/java-basic/basic/src/main/java/cn/cunchang/collection/README.md new file mode 100644 index 00000000..b65e0c5d --- /dev/null +++ b/java-basic/basic/src/main/java/cn/cunchang/collection/README.md @@ -0,0 +1,3 @@ + +- Arrays https://blog.csdn.net/AlbenXie/article/details/103051176 + diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/cpu/ControlCpu.java b/java-basic/basic/src/main/java/cn/cunchang/cpu/ControlCpu.java similarity index 93% rename from java-basic/interview/src/main/java/cn/lastwhisper/interview/cpu/ControlCpu.java rename to java-basic/basic/src/main/java/cn/cunchang/cpu/ControlCpu.java index 34dfc6d6..9af7cbba 100644 --- a/java-basic/interview/src/main/java/cn/lastwhisper/interview/cpu/ControlCpu.java +++ b/java-basic/basic/src/main/java/cn/cunchang/cpu/ControlCpu.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.interview.cpu; +package cn.cunchang.cpu; /** * 控制cpu利用率 diff --git a/java-basic/basic/src/main/java/cn/cunchang/date/AggregateTypeEnum.java b/java-basic/basic/src/main/java/cn/cunchang/date/AggregateTypeEnum.java new file mode 100644 index 00000000..ad59cebf --- /dev/null +++ b/java-basic/basic/src/main/java/cn/cunchang/date/AggregateTypeEnum.java @@ -0,0 +1,66 @@ +package cn.cunchang.date; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.time.LocalDate; +import java.time.temporal.IsoFields; + +/** + * 聚合类型 + * + * @author cunchang + * @date 2020/11/4 17:10 + */ +@Getter +@AllArgsConstructor +public enum AggregateTypeEnum { + + 月(1, "月", 1), + 季(2, "季", 3), + 半年(3, "半年", 6), + 年(4, "年", 12), + + ; + private Integer code; + private String desc; + /** + * 步长 + */ + private Integer step; + + + /** + * 输出格式化日期 + * + * @param localDate + * @return + */ + public String format(LocalDate localDate) { + String topCategoryName = null; + switch (this) { + case 月: + topCategoryName = localDate.getYear() + "年" + localDate.getMonthValue() + "月"; + break; + case 季: + int quarter = localDate.get(IsoFields.QUARTER_OF_YEAR); + topCategoryName = localDate.getYear() + "年" + "Q" + quarter; + break; + case 半年: + quarter = localDate.get(IsoFields.QUARTER_OF_YEAR); + if (quarter <= 2) { + topCategoryName = localDate.getYear() + "年" + "上半年"; + } + if (quarter >= 3) { + topCategoryName = localDate.getYear() + "年" + "下半年"; + } + break; + case 年: + topCategoryName = localDate.getYear() + "年"; + break; + default: + + } + return topCategoryName; + } +} \ No newline at end of file diff --git a/java-basic/basic/src/main/java/cn/cunchang/date/LocalDateTest.java b/java-basic/basic/src/main/java/cn/cunchang/date/LocalDateTest.java new file mode 100644 index 00000000..12675870 --- /dev/null +++ b/java-basic/basic/src/main/java/cn/cunchang/date/LocalDateTest.java @@ -0,0 +1,83 @@ +package cn.cunchang.date; + +import com.alibaba.fastjson.JSONObject; +import lombok.extern.slf4j.Slf4j; +import org.junit.Test; + +import java.time.LocalDate; +import java.time.Period; +import java.util.List; + +/** + * @author cunchang + * @date 2021/7/14 11:31 上午 + */ +@Slf4j +public class LocalDateTest { + + /** + * 日期循环 + */ + @Test + public void test1() { + LocalDate startDate = LocalDateUtil.parse4YYYYMMdd("20210601"); + LocalDate endDate = LocalDateUtil.parse4YYYYMMdd("20210610"); + + // [20210601,20210610) +// while (startDate.isBefore(endDate)) { +// System.out.println(startDate); +// startDate = startDate.plusDays(1L); +// } + + // (20210601,20210610] +// while (endDate.isAfter(startDate)) { +// System.out.println(endDate); +// endDate = endDate.plusDays(-1L); +// } + + // [20210601,20210610] + while (!startDate.isAfter(endDate)) { + System.out.println(startDate); + startDate = startDate.plusDays(1L); + } + + // [20210601,20210610] +// while (!endDate.isBefore(startDate)) { +// System.out.println(endDate); +// endDate = endDate.plusDays(-1L); +// } + } + + /** + * 日期格式化 + */ + @Test + public void test2() { + log.info(AggregateTypeEnum.月.format(LocalDate.now())); + } + + /** + * 日期分割 + */ + @Test + public void test3() { + LocalDate startDate = LocalDateUtil.parseStr("20210101", LocalDateUtil.yyyyMMdd); + LocalDate endDate = LocalDateUtil.parseStr("20210630", LocalDateUtil.yyyyMMdd); + + AggregateTypeEnum aggregateTypeEnum = AggregateTypeEnum.月; + + // 分割日期 + List> regionDates = LocalDateUtil.splitByStep(startDate, endDate, aggregateTypeEnum.getStep()); + + log.info(JSONObject.toJSONString(regionDates)); + } + + @Test + public void test4() { + LocalDate startDate=LocalDate.now().plusDays(-1), endDate=LocalDate.now(); + // 日期之差 + Long dayDiv = endDate.toEpochDay() - startDate.toEpochDay(); + System.out.println("startDate:"+startDate+" endDate:"+endDate +" dayDiv:"+dayDiv); + } + +} diff --git a/java-basic/basic/src/main/java/cn/cunchang/date/LocalDateUtil.java b/java-basic/basic/src/main/java/cn/cunchang/date/LocalDateUtil.java new file mode 100644 index 00000000..a0fb3b71 --- /dev/null +++ b/java-basic/basic/src/main/java/cn/cunchang/date/LocalDateUtil.java @@ -0,0 +1,287 @@ +package cn.cunchang.date; + + +import java.time.*; +import java.time.format.DateTimeFormatter; +import java.time.temporal.IsoFields; +import java.time.temporal.TemporalAdjusters; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Objects; + +public class LocalDateUtil { + /** + * yyyy-MM-dd HH:MM:ss + */ + public final static String yyyyMMddHHMMss = "yyyy-MM-dd HH:MM:ss"; + + /** + * yyyy-MM-dd HH:MM:ss + */ + public final static String yyyyMMddHHMMssTime = "yyyyMMddHHMMss"; + + /** + * yyyyMMdd + */ + public final static String yyyyMMdd = "yyyyMMdd"; + + /** + * yyyyMM + */ + public final static String yyyyMM = "yyyyMM"; + + /** + * yyyyMM + */ + public final static String yyMM = "yyMM"; + + public final static DateTimeFormatter YYYYMMDD_FORMATTER = DateTimeFormatter.ofPattern(yyyyMMdd); + + + /** + * 字符串转日期 + */ + public static LocalDate parseStr(String date, String pattern) { + if (Objects.isNull(pattern) || Objects.isNull(date)) { + return null; + } + return LocalDate.parse(date, DateTimeFormatter.ofPattern(pattern)); + } + + /** + * 获取日期对应的月份数字, + * + * @param billDate 格式20200405 + */ + public static Integer getMonth(Integer billDate) { + if (Objects.isNull(billDate)) { + return null; + } + //月账单时间格式202010 + String billMonth = String.valueOf(billDate).substring(0, 6); + return Integer.valueOf(billMonth); + } + + /** + * 字符串转日期 -yyyyMMdd + */ + public static LocalDate parse4YYYYMMdd(String date) { + if (Objects.isNull(date)) { + return null; + } + return LocalDate.parse(date, DateTimeFormatter.ofPattern(yyyyMMdd)); + } + + /** + * Date转换为LocalDateTime + */ + + public static LocalDateTime convertDateToLDT(Date date) { + if (Objects.isNull(date)) { + return null; + } + return LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault()); + } + + /** + * Date转换为LocalDateTime + */ + + public static LocalDate convertDateToLD(Date date) { + if (Objects.isNull(date)) { + return null; + } + return LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault()).toLocalDate(); + } + + /** + * LocalDateTime转换为Date + */ + public static Date convertLDTToDate(LocalDateTime time) { + if (Objects.isNull(time)) { + return null; + } + + return Date.from(time.atZone(ZoneId.systemDefault()).toInstant()); + } + + /** + * 获取指定日期的毫秒 + */ + public static Long getMilliByTime(LocalDateTime time) { + if (Objects.isNull(time)) { + return null; + } + return time.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli(); + } + + /** + * 获取指定日期的毫秒 + */ + public static Long getMilliByDate(LocalDate date) { + if (Objects.isNull(date)) { + return null; + } + return getMilliByTime(date.atStartOfDay()); + } + + /** + * 获取指定时间的指定格式 + */ + public static String formatTime(LocalDateTime time, String pattern) { + if (Objects.isNull(time) || Objects.isNull(pattern)) { + return null; + } + return time.format(DateTimeFormatter.ofPattern(pattern)); + } + + /** + * 获取指定时间的指定格式,返回格式20201112 + */ + public static Integer formatIntTime(LocalDate time) { + if (Objects.isNull(time)) { + return null; + } + String date = time.format(YYYYMMDD_FORMATTER); + return Integer.valueOf(date); + } + + /** + * 获取指定时间的指定格式 + */ + public static String formatTime(LocalDate time, String pattern) { + if (Objects.isNull(time) || Objects.isNull(pattern)) { + return null; + } + return time.format(DateTimeFormatter.ofPattern(pattern)); + } + + + /** + * 获取指定时间的指定格式 + */ + public static String formatTimeYYYYMMDD(LocalDate time) { + if (Objects.isNull(time)) { + return null; + } + return time.format(YYYYMMDD_FORMATTER); + } + + /** + * 获取当前时间的指定格式 + */ + public static String formatNow(String pattern) { + if (Objects.isNull(pattern)) { + return null; + } + return formatTime(LocalDateTime.now(), pattern); + } + + /** + * 获取一天的开始时间,2017,7,22 00:00 + */ + public static LocalDateTime getDayStart(LocalDateTime time) { + if (Objects.isNull(time)) { + return null; + } + return time.withHour(0) + .withMinute(0) + .withSecond(0); + } + + //获取一天的结束时间,2017,7,22 23:59:59.999999999 + public static LocalDateTime getDayEnd(LocalDateTime time) { + if (Objects.isNull(time)) { + return null; + } + return time.withHour(23) + .withMinute(59) + .withSecond(59); + } + + + /** + * 按步长分割日期 + *

+ * 20210101~20210630 =》 + * [2021-01-01=2021-01-31, 2021-02-01=2021-02-28, 2021-03-01=2021-03-31, + * 2021-04-01=2021-04-30, 2021-05-01=2021-05-31, 2021-06-01=2021-06-30, + * 2021-07-01=2021-07-31, 2021-08-01=2021-08-31, 2021-09-01=2021-09-30, + * 2021-10-01=2021-10-31, 2021-11-01=2021-11-30, 2021-12-01=2021-12-31, + * 2022-01-01=2022-01-31, 2022-02-01=2022-02-28, 2022-03-01=2022-03-31, + * 2022-04-01=2022-04-30, 2022-05-01=2022-05-31, 2022-06-01=2022-06-30, + * 2022-07-01=2022-07-31, 2022-08-01=2022-08-31, 2022-09-01=2022-09-30, + * 2022-10-01=2022-10-31, 2022-11-01=2022-11-30, 2022-12-01=2022-12-31] + * --------------- + * 20210101~20210630 =》 + * [2021-01-01=2021-03-31, 2021-04-01=2021-06-30, 2021-07-01=2021-09-30, 2021-10-01=2021-12-31, + * 2022-01-01=2022-03-31, 2022-04-01=2022-06-30, 2022-07-01=2022-09-30, 2022-10-01=2022-12-31] + * --------------- + * 20210101~20210630 =》 + * [2021-01-01=2021-06-30, 2021-07-01=2021-12-31, + * 2022-01-01=2022-06-30, 2022-07-01=2022-12-31] + * --------------- + * 20210101~20210630 =》 + * [2021-01-01=2021-12-31, 2022-01-01=2022-12-31] + * + * @param startDate 20210101 + * @param endDate 20210630 + * @param step 步长 {@link AggregateTypeEnum} + * @return <起始日期,结束日期> + */ + public static List> splitByStep(LocalDate startDate, LocalDate endDate, int step) { + LocalDate firstDayOfMonth = startDate.with(TemporalAdjusters.firstDayOfMonth()); + if(!Objects.equals(startDate, firstDayOfMonth)){ + throw new IllegalArgumentException(String.format("起始日期必须是月份第一天,startDate:%s", startDate)); + } + + LocalDate lastDayOfMonth = endDate.with(TemporalAdjusters.lastDayOfMonth()); + if(!Objects.equals(endDate, lastDayOfMonth)){ + throw new IllegalArgumentException(String.format("结束日期必须是月份最后一天,endDate:%s", endDate)); + } + + List> list = new ArrayList<>(); + + while (startDate.isBefore(endDate)) { + // 下一个步长减1的末尾日期 + LocalDate nextStartDate = startDate.plusMonths(step - 1).with(TemporalAdjusters.lastDayOfMonth()); + list.add(new Pair<>(startDate, nextStartDate)); + // 下一个月的起始日期 + startDate = nextStartDate.plusDays(1L); + } + + return list; + } + + public static String format(LocalDate localDate, AggregateTypeEnum aggregateTypeEnum) { + String topCategoryName = null; + switch (aggregateTypeEnum) { + case 月: + topCategoryName = localDate.getYear() + "年" + localDate.getMonthValue() + "月"; + break; + case 季: + int quarter = localDate.get(IsoFields.QUARTER_OF_YEAR); + topCategoryName = localDate.getYear() + "年" + "Q" + quarter; + break; + case 半年: + quarter = localDate.get(IsoFields.QUARTER_OF_YEAR); + if (quarter <= 2) { + topCategoryName = localDate.getYear() + "年" + "上半年"; + } + if (quarter >= 3) { + topCategoryName = localDate.getYear() + "年" + "下半年"; + } + break; + case 年: + topCategoryName = localDate.getYear() + "年"; + break; + default: + + } + return topCategoryName; + } + + + +} diff --git a/java-basic/basic/src/main/java/cn/cunchang/date/Pair.java b/java-basic/basic/src/main/java/cn/cunchang/date/Pair.java new file mode 100644 index 00000000..736b6495 --- /dev/null +++ b/java-basic/basic/src/main/java/cn/cunchang/date/Pair.java @@ -0,0 +1,42 @@ +package cn.cunchang.date; + +import java.io.Serializable; +import java.util.Objects; + +public class Pair implements Serializable { + private static final long serialVersionUID = 1L; + private final K key; + private final V value; + + public Pair(K key, V value) { + this.key = key; + this.value = value; + } + + public K getKey() { + return this.key; + } + + public V getValue() { + return this.value; + } + + public String toString() { + return "Pair [key=" + this.key + ", value=" + this.value + "]"; + } + + public boolean equals(Object o) { + if (this == o) { + return true; + } else if (!(o instanceof Pair)) { + return false; + } else { + Pair pair = (Pair)o; + return Objects.equals(this.getKey(), pair.getKey()) && Objects.equals(this.getValue(), pair.getValue()); + } + } + + public int hashCode() { + return Objects.hashCode(this.key) ^ Objects.hashCode(this.value); + } +} diff --git a/java-basic/basic/src/main/java/cn/cunchang/decimal/BigDecimalTest.java b/java-basic/basic/src/main/java/cn/cunchang/decimal/BigDecimalTest.java new file mode 100644 index 00000000..29b643dc --- /dev/null +++ b/java-basic/basic/src/main/java/cn/cunchang/decimal/BigDecimalTest.java @@ -0,0 +1,83 @@ +package cn.cunchang.decimal; + +import org.junit.Test; + +import java.math.BigDecimal; +import java.math.RoundingMode; + +/** + * @author cunchang + * @date 2021/3/11 4:00 下午 + */ +public class BigDecimalTest { + + @Test + public void testBigDecimal格式化输出() { + // 浮点数的打印 + System.out.println(String.valueOf(new BigDecimal("1234567891231234.1234"))); + // 普通的数字字符串 + // 100.000 + System.out.println(new BigDecimal("100.000").toString()); + // 去除末尾多余的0 + System.out.println(new BigDecimal("100.000").stripTrailingZeros().toString()); + // 避免输出科学计数法 + System.out.println(new BigDecimal("100.000").stripTrailingZeros().toPlainString()); + } + + /** + * 一定要用字符串形式的构造函数,否则会出现精度问题 + */ + @Test + public void test构造BigDecimal的坑() { + BigDecimal bigDecimal1 = new BigDecimal(1.23); + String str1 = bigDecimal1.toString(); + System.out.println(str1);// 1.229999999999999982236431605997495353221893310546875 + BigDecimal bigDecimal2 = new BigDecimal("1.23"); + String str2 = bigDecimal2.toString(); + System.out.println(str2);// 1.23 + } + + /** + * BigDecimal.setScale()方法用于格式化小数点 + * setScale(1)表示保留一位小数,默认用四舍五入方式 + * setScale(1,BigDecimal.ROUND_DOWN)直接删除多余的小数位,如2.35会变成2.3 + * setScale(1,BigDecimal.ROUND_UP)进位处理,2.35变成2.4 + * setScale(1,BigDecimal.ROUND_HALF_UP)四舍五入,2.35变成2.4 + * setScaler(1,BigDecimal.ROUND_HALF_DOWN)四舍五入,2.35变成2.3,如果是5则向下舍 + * setScaler(1,BigDecimal.ROUND_CEILING)接近正无穷大的舍入 + * setScaler(1,BigDecimal.ROUND_FLOOR)接近负无穷大的舍入,数字>0和ROUND_UP作用一样,数字<0和ROUND_DOWN作用一样 + * setScaler(1,BigDecimal.ROUND_HALF_EVEN)向最接近的数字舍入,如果与两个相邻数字的距离相等,则向相邻的偶数舍入。 + */ + @Test + public void test格式化小数点() { + BigDecimal bigDecimal = new BigDecimal("3.1415926572358452"); + + BigDecimal bigDecimal1 = bigDecimal.setScale(4, RoundingMode.DOWN); + // 保留四位,不会四舍五入 + System.out.println(bigDecimal1);// 3.1415 + + BigDecimal bigDecimal2 = bigDecimal.setScale(4, RoundingMode.HALF_UP); + // 保留四位,会四舍五入 + System.out.println(bigDecimal2);// 3.1416 + } + + /** + * 一定要使用compareTo + */ + @Test + public void test比较大小() { + System.out.println(new BigDecimal("0").compareTo(new BigDecimal("0")) <= 0); + System.out.println(new BigDecimal("1").compareTo(new BigDecimal("0")) <= 0); + } + + @Test + public void test3() { + BigDecimal taxAmount = new BigDecimal("0.001"); + BigDecimal originTaxAmount = new BigDecimal("0.001"); + BigDecimal exchangeRate = new BigDecimal("1"); + BigDecimal calOriginTaxAmount = taxAmount.divide(exchangeRate, + 5, BigDecimal.ROUND_HALF_UP); + System.out.println(calOriginTaxAmount.compareTo(originTaxAmount) != 0); + } + +} diff --git a/java-basic/basic/src/main/java/cn/cunchang/guava/bloomfilter/TestBloomFilter.java b/java-basic/basic/src/main/java/cn/cunchang/guava/bloomfilter/TestBloomFilter.java new file mode 100644 index 00000000..c99178c4 --- /dev/null +++ b/java-basic/basic/src/main/java/cn/cunchang/guava/bloomfilter/TestBloomFilter.java @@ -0,0 +1,23 @@ +package cn.cunchang.guava.bloomfilter; + +import com.google.common.hash.BloomFilter; +import com.google.common.hash.Funnel; +import com.google.common.hash.Funnels; + +public class TestBloomFilter { + + public static void main(String[] args) { + Funnel funnel = Funnels.integerFunnel(); + int size = 1000_000; + double errorChance = 0.001; //错误率 + BloomFilter filter = BloomFilter.create(funnel, size, errorChance); + for (int i = 0; i < size; i++) { + filter.put(i); + } + for (int i = 0; i < size; i++) { + if (!filter.mightContain(i)) { + System.out.println("发现不存在的数据 : " + i); + } + } + } +} \ No newline at end of file diff --git a/java-basic/basic/src/main/java/cn/cunchang/guava/cache/TestCache.java b/java-basic/basic/src/main/java/cn/cunchang/guava/cache/TestCache.java new file mode 100644 index 00000000..04db32ca --- /dev/null +++ b/java-basic/basic/src/main/java/cn/cunchang/guava/cache/TestCache.java @@ -0,0 +1,40 @@ +package cn.cunchang.guava.cache; + +import com.google.common.cache.*; +import org.junit.Test; + +import java.util.concurrent.TimeUnit; + +/** + * Guava的Cache + * @author lastwhisper + * @date 2020/6/2 + */ +public class TestCache { + + // https://github.com/zhuzhenke/common-caches + @Test + public void testCacheUse() throws Exception{ + + LoadingCache loadingCache = CacheBuilder.newBuilder() + .expireAfterAccess(10, TimeUnit.SECONDS) + .maximumSize(1000) + .removalListener(new RemovalListener() { + @Override + public void onRemoval(RemovalNotification notification) { + + } + }) + .build(new CacheLoader() { + @Override + public String load(String key) throws Exception { + return key; + } + }); + + System.out.println(loadingCache.get("key")); + + + } + +} diff --git a/java-basic/basic/src/main/java/cn/cunchang/guava/collection/MapTest.java b/java-basic/basic/src/main/java/cn/cunchang/guava/collection/MapTest.java new file mode 100644 index 00000000..0ea90360 --- /dev/null +++ b/java-basic/basic/src/main/java/cn/cunchang/guava/collection/MapTest.java @@ -0,0 +1,282 @@ +package cn.cunchang.guava.collection; + +import com.google.common.collect.*; +import org.junit.Test; + +import java.util.*; + +/** + * 参考:https://mp.weixin.qq.com/s/LOZ-p6divRjO9ZTcus101A + * + * @author cunchang + * @date 2022/3/17 1:54 PM + */ +public class MapTest { + + /** + *

+ * 案例:记录员工每个月工作的天数 + * 使用hashmap的话,得两个嵌套 + */ + @Test + public void test双键Map() { + // java中的Map只允许有一个key和一个value存在。 + // guava中的Table允许一个value存在两个key。Table中的两个key分别被称为rowKey和columnKey,也就是行和列。 + Table table = HashBasedTable.create(); + //存放元素 + table.put("Hydra", "Jan", 20); + table.put("Hydra", "Feb", 28); + + table.put("Trunks", "Jan", 28); + table.put("Trunks", "Feb", 16); + + //取出元素 + Integer dayCount = table.get("Hydra", "Feb"); + System.out.println("取出元素:" + dayCount); + +// 1、获得key或value的集合 + //rowKey或columnKey的集合 + System.out.println("---rowKey或columnKey的集合"); + Set rowKeys = table.rowKeySet(); + Set columnKeys = table.columnKeySet(); + //value集合 + Collection values = table.values(); + System.out.println("rowKeys:" + rowKeys); + System.out.println("columnKeys:" + columnKeys); + System.out.println("values:" + values); + +// 2、计算key对应的所有value的和 + // 以统计所有rowKey对应的value之和为例: + System.out.println("---统计所有rowKey对应的value之和"); + for (String key : table.rowKeySet()) { + Set> rows = table.row(key).entrySet(); + int total = 0; + for (Map.Entry row : rows) { + total += row.getValue(); + } + System.out.println(key + ": " + total); + } +// 3、转换rowKey和columnKey + // 行和列的转置,直接调用Tables的静态方法transpose + System.out.println("---行和列的转置"); + Table table2 = Tables.transpose(table); + Set> cells = table2.cellSet(); + cells.forEach(cell -> + System.out.println(cell.getRowKey() + "," + cell.getColumnKey() + ":" + cell.getValue()) + ); + +// 4、转为嵌套的Map + // 将数据还原成嵌套Map的那种形式,使用Table的rowMap或columnMap方法就可以实现了 + System.out.println("---转为嵌套的Map"); + Map> rowMap = table.rowMap(); + Map> columnMap = table.columnMap(); + System.out.println("rowMap: " + rowMap); + System.out.println("columnMap: " + columnMap); + } + + /** + * 在普通Map中,如果要想根据value查找对应的key,没什么简便的办法,无论是使用for循环还是迭代器,都需要遍历整个Map。 + */ + @Test + public void test双向Map() { + HashBiMap biMap = HashBiMap.create(); + biMap.put("Hydra", "Programmer"); + biMap.put("Tony", "IronMan"); + biMap.put("Thanos", "Titan"); + //使用key获取value + System.out.println("使用key获取value:" + biMap.get("Tony")); + + BiMap inverse = biMap.inverse(); + //使用value获取key + System.out.println("使用value获取key:" + inverse.get("Titan")); + } + + /** + * 上面我们用inverse方法反转了原来BiMap的键值映射,但是这个反转后的BiMap并不是一个新的对象, + * 它实现了一种视图的关联,所以对反转后的BiMap执行的所有操作会作用于原先的BiMap上。 + */ + @Test + public void test双向Map_坑_反转后操作的影响() { + HashBiMap biMap = HashBiMap.create(); + biMap.put("Hydra", "Programmer"); + biMap.put("Tony", "IronMan"); + biMap.put("Thanos", "Titan"); + BiMap inverse = biMap.inverse(); + + // 原先值为IronMan时对应的键是Tony,虽然没有直接修改,但是现在键变成了Stark + inverse.put("IronMan", "Stark"); + System.out.println(biMap); + } + + @Test + public void test双向Map_坑_value不可重复() { + // 双向的BiMap,key和value都不允许重复 + HashBiMap biMap = HashBiMap.create(); + biMap.put("Tony", "IronMan"); + // java.lang.IllegalArgumentException: value already present: IronMan + biMap.put("Stark", "IronMan"); + } + + @Test + public void test双向Map_坑_value不可重复2() { + // 把新的key映射到已有的value上,使用forcePut方法强制替换掉原有的key + HashBiMap biMap = HashBiMap.create(); + biMap.put("Tony", "IronMan"); + biMap.forcePut("Stark", "IronMan"); + // 由于BiMap的value是不允许重复的,因此它的values方法返回的是没有重复的Set,而不是普通Collection: + Set values = biMap.values(); + } + + /** + * 将一个键映射到多个值 + */ + @Test + public void test多值Map() { + Multimap multimap = ArrayListMultimap.create(); + multimap.put("day", 1); + multimap.put("day", 2); + multimap.put("day", 8); + multimap.put("month", 3); + // {month=[3], day=[1, 2, 8]} + System.out.println(multimap); + + // 1、获取值的集合 + System.out.println("---获取值的集合"); + Collection day = multimap.get("day"); + // 如果在创建时指定为ArrayListMultimap类型,那么get方法将返回一个List: + // 同理,你还可以创建HashMultimap、TreeMultimap等类型的Multimap。 + ArrayListMultimap multimap2 = ArrayListMultimap.create(); + List day2 = multimap2.get("day"); + // Multimap的get方法会返回一个非null的集合,但是这个集合的内容可能是空,看一下下面的例子: + List day22 = multimap2.get("day"); + List year2 = multimap2.get("year"); + System.out.println(day22); + System.out.println(year2); + + } + + /** + * 和BiMap的使用类似,使用get方法返回的集合也不是一个独立的对象, + * 可以理解为集合视图的关联,对这个新集合的操作仍然会作用于原始的Multimap上 + */ + @Test + public void test多值Map_操作get后的集合() { + ArrayListMultimap multimap = ArrayListMultimap.create(); + multimap.put("day", 1); + multimap.put("day", 2); + multimap.put("day", 8); + multimap.put("month", 3); + + List day = multimap.get("day"); + List month = multimap.get("month"); + + System.out.println("before:" + multimap); + day.remove(0);//这个0是下标 + month.add(12); + System.out.println("after:" + multimap); + } + + /** + * 使用asMap方法,可以将Multimap转换为Map的形式, + * 同样这个Map也可以看做一个关联的视图,在这个Map上的操作会作用于原始的Multimap + */ + @Test + public void test多值Map_转换为Map() { + Multimap multimap = ArrayListMultimap.create(); + multimap.put("day", 1); + multimap.put("day", 2); + multimap.put("day", 8); + multimap.put("month", 3); + + Map> map = multimap.asMap(); + for (String key : map.keySet()) { + System.out.println(key + " : " + map.get(key)); + } + map.get("day").add(20); + System.out.println(multimap); + } + + @Test + public void test多值Map_坑_数量问题() { + Multimap multimap = ArrayListMultimap.create(); + multimap.put("day", 1); + multimap.put("day", 2); + multimap.put("day", 8); + multimap.put("month", 3); + + for (Map.Entry entry : multimap.entries()) { + System.out.println(entry.getKey() + "," + entry.getValue()); + } + + // size()方法返回的是所有key到单个value的映射,因此结果为4,entries()方法同理 + System.out.println(multimap.size()); + System.out.println(multimap.entries().size()); + // 但是它的keySet中保存的是不同的key的个数,例如下面这行代码打印的结果就会是2 + System.out.println(multimap.keySet().size()); + } + + public static String getRank(int score) { + if (0 <= score && score < 60) + return "fail"; + else if (60 <= score && score <= 90) + return "satisfactory"; + else if (90 < score && score <= 100) + return "excellent"; + return null; + } + + /** + * 要根据分数对考试成绩进行分类 + * guava中的RangeMap描述了一种从区间到特定值的映射关系,让我们能够以更为优雅的方法来书写代码 + */ + @Test + public void test范围Map() { + RangeMap rangeMap = TreeRangeMap.create(); + rangeMap.put(Range.closedOpen(0, 60), "fail"); + rangeMap.put(Range.closed(60, 90), "satisfactory"); + rangeMap.put(Range.openClosed(90, 100), "excellent"); + + System.out.println(rangeMap.get(59)); + System.out.println(rangeMap.get(60)); + System.out.println(rangeMap.get(90)); + System.out.println(rangeMap.get(91)); + + rangeMap.remove(Range.closed(70, 80)); + System.out.println(rangeMap.get(75)); + } + + /** + * ClassToInstanceMap相对普通Map + * 1、取出对象时省去了复杂的强制类型转换 + * 2、通过泛型保证value要符合key所对应的类型 + */ + @Test + public void test实例Map() { + ClassToInstanceMap instanceMap = MutableClassToInstanceMap.create(); + HashMap hashMap = new HashMap<>(); + TreeMap treeMap = new TreeMap<>(); + ArrayList list = new ArrayList<>(); + + instanceMap.putInstance(HashMap.class, hashMap); + instanceMap.putInstance(TreeMap.class, treeMap); + // HashMap和TreeMap都集成了Map父类,但是如果想放入其他类型,就会编译报错 +// instanceMap.putInstance(ArrayList.class,list); + } + + @Test + public void test实例Map对比普通Map() { + Map map = new HashMap<>(); + + HashMap hashMap = new HashMap<>(); + TreeMap treeMap = new TreeMap<>(); + ArrayList list = new ArrayList<>(); + + map.put(HashMap.class, hashMap); + map.put(TreeMap.class, treeMap); + // 1、类型转换 + treeMap = (TreeMap) map.get(TreeMap.class); + // 2、无法限制只存某些Class + map.put(ArrayList.class, list); + } + +} diff --git a/java-basic/basic/src/main/java/cn/cunchang/guava/limit/TestRateLimiter.java b/java-basic/basic/src/main/java/cn/cunchang/guava/limit/TestRateLimiter.java new file mode 100644 index 00000000..f23faf1c --- /dev/null +++ b/java-basic/basic/src/main/java/cn/cunchang/guava/limit/TestRateLimiter.java @@ -0,0 +1,39 @@ +package cn.cunchang.guava.limit; + +import com.google.common.util.concurrent.RateLimiter; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +/** + * Guava的RateLimiter限流基于令牌桶算法 + * @author lastwhisper + */ +public class TestRateLimiter { + + /** + * 单机全局限流器(限制QPS为1)(放入拦截器,对HTTP接口限流) + */ + private static RateLimiter limiter = RateLimiter.create(1.0); + + /** + * 固定10个线程,模拟十个用户并发 + */ + private static ExecutorService pool = Executors.newFixedThreadPool(10); + + static class Task implements Runnable { + @Override + public void run() { + limiter.acquire(); // 对应web项目,就是在业务代码之前执行(拦截器、AOP) + System.out.println(System.currentTimeMillis()); + } + } + + public static void main(String[] args) { + for (int i = 0; i < 50; i++) { + pool.submit(new Task()); + } + } + + +} diff --git a/java-basic/basic/src/main/java/cn/cunchang/guava/limit/TokenBucket.java b/java-basic/basic/src/main/java/cn/cunchang/guava/limit/TokenBucket.java new file mode 100644 index 00000000..aff3dee6 --- /dev/null +++ b/java-basic/basic/src/main/java/cn/cunchang/guava/limit/TokenBucket.java @@ -0,0 +1,39 @@ +package cn.cunchang.guava.limit; + +// 因为令牌桶对业务有一定的容忍度 +public class TokenBucket { + + private int bucketNums = 100; // 桶的容量 + private int rate = 1; // 流入速度 + private int nowTokens; // 当前令牌数量 + private long timestamp = getNowTime(); // 时间 + + private long getNowTime() { + return System.currentTimeMillis(); + } + + private int min(int tokens) { + return Math.min(bucketNums, tokens); + } + + public boolean getToken() { + // 记录来拿令牌的时间 + long nowTime = getNowTime(); + // 添加令牌【判断该有多少个令牌】 + nowTokens = nowTokens + (int) ((nowTime - timestamp) * rate); + // 添加以后的令牌数量与桶的容量那个小 + nowTokens = min(nowTokens); + System.out.println("当前令牌数量" + nowTokens); + // 修改拿令牌的时间 + timestamp = nowTime; + // 判断令牌是否足够 + if (nowTokens < 1) { + return false; + } else { + nowTokens -= 1; + return true; + } + } + + +} \ No newline at end of file diff --git a/java-basic/basic/src/main/java/cn/cunchang/hutool/IDUtilTest.java b/java-basic/basic/src/main/java/cn/cunchang/hutool/IDUtilTest.java new file mode 100644 index 00000000..16714272 --- /dev/null +++ b/java-basic/basic/src/main/java/cn/cunchang/hutool/IDUtilTest.java @@ -0,0 +1,17 @@ +package cn.cunchang.hutool; + +import cn.hutool.core.util.IdUtil; + +/** + * @author cunchang + * @date 2022/5/15 11:43 PM + */ +public class IDUtilTest { + + public static void main(String[] args) { + System.out.println(IdUtil.getSnowflakeNextId()); +// System.out.println(IdUtil.objectId()); + + + } +} diff --git a/java-basic/basic/src/main/java/cn/cunchang/hutool/ZipUtilTest.java b/java-basic/basic/src/main/java/cn/cunchang/hutool/ZipUtilTest.java new file mode 100644 index 00000000..8f1df9a0 --- /dev/null +++ b/java-basic/basic/src/main/java/cn/cunchang/hutool/ZipUtilTest.java @@ -0,0 +1,24 @@ +package cn.cunchang.hutool; + +import cn.hutool.core.util.ZipUtil; + +import java.io.File; + +/** + * 解压文件 + * @author cunchang + * @date 2022/5/9 2:51 PM + */ +public class ZipUtilTest { + + public static void main(String[] args) { + //将test.zip解压到e:\\aaa目录下,返回解压到的目录 + File unzip = ZipUtil.unzip("/Users/cunchang/Downloads/1.zip", "/Users/cunchang/Downloads/receipt"); + System.out.println(unzip.getAbsoluteFile()); + String[] filePaths = unzip.list(); + for (String filePath : filePaths) { + System.out.println(unzip.getAbsoluteFile()+"/"+filePath); + } + } + +} diff --git a/java-basic/basic/src/main/java/cn/cunchang/json/FeatureComment.java b/java-basic/basic/src/main/java/cn/cunchang/json/FeatureComment.java new file mode 100644 index 00000000..60edd3cc --- /dev/null +++ b/java-basic/basic/src/main/java/cn/cunchang/json/FeatureComment.java @@ -0,0 +1,77 @@ +package cn.cunchang.json; + +public enum FeatureComment { + + /** + * 这个特性,决定了解析器是否将自动关闭那些不属于parser自己的输入源。 如果禁止,则调用应用不得不分别去关闭那些被用来创建parser的基础输入流InputStream和reader;如果允许,parser只要自己需要获取closed方法(当遇到输入流结束,或者parser自己调用 JsonParder#close方法),就会处理流关闭。 + * 注意:这个属性默认是true,即允许自动关闭流 + */ + AutoCloseSource, + + /** + * 该特性决定parser将是否允许解析使用Java/C++ 样式的注释(包括'/'+'*' 和'//' 变量)。 由于JSON标准说明书上面没有提到注释是否是合法的组成,所以这是一个非标准的特性;尽管如此,这个特性还是被广泛地使用。 + * 注意:该属性默认是false,因此必须显式允许,即通过JsonParser.Feature.ALLOW_COMMENTS 配置为true。 + */ + AllowComment, + + /** + * 这个特性决定parser是否将允许使用非双引号属性名字, (这种形式在Javascript中被允许,但是JSON标准说明书中没有)。 + * 注意:由于JSON标准上需要为属性名称使用双引号,所以这也是一个非标准特性,默认是false的。 + * 同样,需要设置JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES为true,打开该特性。 + */ + AllowUnQuotedFieldNames, + + /** + * 该特性决定parser是否允许单引号来包住属性名称和字符串值。 + * 注意:默认下,该属性也是关闭的。需要设置JsonParser.Feature.ALLOW_SINGLE_QUOTES为true + */ + AllowSingleQuotes, + + /** + * 该特性决定JSON对象属性名称是否可以被String#intern 规范化表示。如果允许,则JSON所有的属性名将会 intern() ;如果不设置,则不会规范化,默认下,该属性是开放的。此外,必须设置CANONICALIZE_FIELD_NAMES为true + * 关于intern方法作用:当调用 intern 方法时,如果池已经包含一个等于此 String 对象的字符串 (该对象由 equals(Object) 方法确定),则返回池中的字符串。否则,将此 String + * 对象添加到池中, 并且返回此 String 对象的引用。 + */ + InternFieldNames, + + //这个设置为true则遇到字符串符合ISO8601格式的日期时,会直接转换成日期类。 + AllowISO8601DateFormat, + + //允许多重逗号,如果设为true,则遇到多个逗号会直接跳过; + AllowArbitraryCommas, + + //这个设置为true则用BigDecimal类来装载数字,否则用的是double; + UseBigDecimal, + + //忽略不匹配 + IgnoreNotMatch, + + //如果你用fastjson序列化的文本,输出的结果是按照fieldName排序输出的,parser时也能利用这个顺序进行优化读取。这种情况下,parser能够获得非常好的性能 + SortFeidFastMatch, + + //禁用ASM + DisableASM, + + //禁用循环引用检测 + DisableCircularReferenceDetect, + + //对于没有值得字符串属性设置为空串 + InitStringFieldAsEmpty, + + //支持数组to对象 + SupportArrayToBean, + + //属性保持原来的顺序 + OrderedField, + + //禁用特殊字符检查 + DisableSpecialKeyDetect, + + //使用对象数组 + UseObjectArray, + + + ; + + +} diff --git a/java-basic/basic/src/main/java/cn/cunchang/json/JSONObjectTest.java b/java-basic/basic/src/main/java/cn/cunchang/json/JSONObjectTest.java new file mode 100644 index 00000000..4f4120de --- /dev/null +++ b/java-basic/basic/src/main/java/cn/cunchang/json/JSONObjectTest.java @@ -0,0 +1,48 @@ +package cn.cunchang.json; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.TypeReference; +import com.alibaba.fastjson.parser.Feature; +import org.junit.Test; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * @author cunchang + * @date 2021/6/24 10:37 上午 + */ +public class JSONObjectTest { + + + @Test + public void testOrder() { + String str = "{\"S0209\":\"#S0201#+#S0203#+#S0205#+#S0207#\",\"S0210\":\"#S0202#+#S0204#+#S0206#+#S0208#\",\"S0212\":\"#S0211#/#S0210#\",\"S0213\":\"#S0210#+#S0211#\",\"S0214\":\"#S0213#/#S0209#\"}"; + JSONObject jsonObject = JSONObject.parseObject(str, Feature.OrderedField); +// JSONObject jsonObject = JSONObject.parseObject(str); + for (Map.Entry entry : jsonObject.entrySet()) { + System.out.println(entry); + } + } + + @Test + public void test2() { + Map> map2 = new HashMap<>(); + String jsonMap2 = "{\"BUSINESS_CONTACT\":[{\"sourceTypes\":[\"XXX1\",\"XXX2\"],\"supplierList\":[\"1\",\"2\"]},{\"sourceTypes\":[\"AAA1\",\"AAA2\"],\"supplierList\":[\"4\",\"5\"]}]}"; + JSONObject jsonObject = JSONObject.parseObject(jsonMap2); + String jsonArrStr = jsonObject.getString("BUSINESS_CONTACT"); + List>> list1 = JSONObject.parseObject(jsonArrStr, new TypeReference>>>() { + }); + for (Map> kvList : list1) { + List sourceTypes = kvList.get("sourceTypes"); + for (String sourceType : sourceTypes) { + map2.put(sourceType, kvList.get("supplierList")); + } + } + System.out.println(JSON.toJSONString(map2)); + } + + +} \ No newline at end of file diff --git a/java-basic/basic/src/main/java/cn/cunchang/json/biz/Biz.java b/java-basic/basic/src/main/java/cn/cunchang/json/biz/Biz.java new file mode 100644 index 00000000..9271782b --- /dev/null +++ b/java-basic/basic/src/main/java/cn/cunchang/json/biz/Biz.java @@ -0,0 +1,99 @@ +package cn.cunchang.json.biz; + +import cn.cunchang.json.dto.ContractExceedDTO; +import cn.cunchang.json.dto.ContractRiskApproveRuleDTO; +import com.alibaba.fastjson.JSON; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.expression.ExpressionParser; +import org.springframework.expression.spel.standard.SpelExpressionParser; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * @author kaisui + * @description + * @date 2022/12/8 + */ +@Slf4j +public class Biz { + + static String jsonConfig="{\"isDeleted\":\"n\",\"conditions\":[{\"order\":0,\"isDeleted\":\"n\",\"approveType\":\"TYPE_LEVEL_BY_LEVEL_TO_PRESIDENT_DD\",\"ruleType\":\"overdue\",\"approveNodeTip\":\"OVER_DUE_STEP_BY_STEP\",\"detailTip\":\"CONTRACT_OVERDUE\",\"desc\":\"合同过期,采购经理逐级封顶到总裁DD。\"},{\"ratioExpression\":\"ratio>1\",\"contractTypeSet\":[\"common_frame\"],\"order\":1,\"isDeleted\":\"n\",\"approveType\":\"TYPE_LEVEL_BY_LEVEL_TO_PRESIDENT_DD\",\"ruleType\":\"overratio\",\"approveNodeTip\":\"OVERRATIO_STEP_BY_STEP_100\",\"detailTip\":\"CONTRACT_OVERRATIO_100\",\"desc\":\"单项目合同超框,采购经理逐级封顶到总裁DD。\"},{\"ratioExpression\":\"ratio>1.2\",\"contractTypeSet\":[\"price_frame\"],\"purchaseCategoryNotContainSet\":[\"OXM\"],\"order\":2,\"isDeleted\":\"n\",\"approveType\":\"TYPE_LEVEL_BY_LEVEL_TO_PRESIDENT_DD\",\"ruleType\":\"overratio\",\"approveNodeTip\":\"OVERRATIO_STEP_BY_STEP_120\",\"detailTip\":\"CONTRACT_OVERRATIO_120\",\"desc\":\"框架合同超框120%(大于)且非OXM类目,采购经理逐级封顶到总裁DD。\"},{\"ratioExpression\":\"ratio>1.5\",\"contractTypeSet\":[\"price_frame\"],\"purchaseCategorySet\":[\"OXM\"],\"order\":3,\"isDeleted\":\"n\",\"approveType\":\"TYPE_LEVEL_BY_LEVEL_TO_PRESIDENT_DD\",\"ruleType\":\"overratio\",\"approveNodeTip\":\"OVERRATIO_STEP_BY_STEP_150\",\"detailTip\":\"CONTRACT_OVERRATIO_150\",\"desc\":\"框架合同超框150%(大于)且为OXM类目,采购经理逐级封顶到总裁DD。\"},{\"ratioExpression\":\"1 matchRule(ContractExceedDTO contractExceedDTO) { + Map result = new HashMap<>(); + ContractRiskApproveRuleDTO contractRiskApproveRule = JSON.parseObject(jsonConfig,ContractRiskApproveRuleDTO.class); + List conditions = contractRiskApproveRule.getConditions(); + if (CollectionUtils.isEmpty(conditions)) { + log.warn("matchRule() 合同过期超框规则为空 => 【contractRiskApproveRule = {}】", JSON.toJSONString(contractRiskApproveRule)); + return result; + } + for (ContractRiskApproveRuleDTO.Condition condition : conditions) { + if (condition.getRuleType().equals(RuleTypeEnum.OVER_DUE.getCode())) { + if (!contractExceedDTO.getOverdue()) { + log.info("matchRule() 合同过期规则未匹配上,因为当前合同未过期 => 【contractExceedVO = {}】,【condition ={}】", + JSON.toJSONString(contractExceedDTO), JSON.toJSONString(condition)); + continue; + } + } else if (condition.getRuleType().equals(RuleTypeEnum.OVER_RATIO.getCode())) { + if(StringUtils.isNotBlank(condition.getRatioExpression())){ + String ratioExpression = condition.getRatioExpression().replaceAll("ratio", contractExceedDTO.getRatio().toString()); + if(Boolean.FALSE.equals(expressionParser.parseExpression(ratioExpression).getValue(Boolean.class))){ + log.info("matchRule() 合同超框规则未匹配上,因为当前比率:{}不满足规则比率:{} => 【contractExceedVO = {}】,【condition ={}】", contractExceedDTO.getRatio(),condition.getRatioExpression(), + JSON.toJSONString(contractExceedDTO), JSON.toJSONString(condition)); + continue; + } + } + if(!condition.getContractTypeSet().contains(contractExceedDTO.getContractType())){ + log.info("matchRule() 合同超框规则未匹配上,因为当前合同类型:{}不满足规则合同类型:{} => 【contractExceedVO = {}】,【condition ={}】", contractExceedDTO.getContractType(),JSON.toJSONString(condition.getContractTypeSet()), + JSON.toJSONString(contractExceedDTO), JSON.toJSONString(condition)); + continue; + } + if (CollectionUtils.isNotEmpty(condition.getPurchaseCategorySet())) { + // po 1、2、4;规则 4、5、6 + Set rulePurchaseCategorySet = new HashSet<>(condition.getPurchaseCategorySet()); + rulePurchaseCategorySet.removeAll(contractExceedDTO.getCurrentPoPurchaseCategory()); + if (rulePurchaseCategorySet.size() == condition.getPurchaseCategorySet().size()) { + log.info("matchRule() 合同超框规则未匹配上,因为当前po的采购类目:{}不匹配规则采购类目:{} => 【contractExceedVO = {}】,【condition ={}】", JSON.toJSONString(contractExceedDTO.getCurrentPoPurchaseCategory()), JSON.toJSONString(condition.getPurchaseCategorySet()), + JSON.toJSONString(contractExceedDTO), JSON.toJSONString(condition)); + continue; + } + } + if (CollectionUtils.isNotEmpty(condition.getPurchaseCategoryNotContainSet())) { + // po 1、2、4;not Contain 规则 4、5、6 + Set rulePurchaseCategoryNotContainSet = new HashSet<>(condition.getPurchaseCategoryNotContainSet()); + rulePurchaseCategoryNotContainSet.removeAll(contractExceedDTO.getCurrentPoPurchaseCategory()); + if (rulePurchaseCategoryNotContainSet.size() != condition.getPurchaseCategoryNotContainSet().size()) { + log.info("matchRule() 合同超框规则未匹配上,因为当前po的采购类目:{}不匹配规则采购类目:{} => 【contractExceedVO = {}】,【condition ={}】", JSON.toJSONString(contractExceedDTO.getCurrentPoPurchaseCategory()), JSON.toJSONString(condition.getPurchaseCategorySet()), + JSON.toJSONString(contractExceedDTO), JSON.toJSONString(condition)); + continue; + } + } + } + log.info("matchRule() 合同超框规则匹配成功 => 【contractExceedVO = {}】,【condition ={}】", + JSON.toJSONString(contractExceedDTO), JSON.toJSONString(condition)); + ContractRiskApproveRuleDTO.Condition existCondition = result.get(condition.getRuleType()); + if(existCondition!=null){ + log.error("matchRule() 合同超框规则匹配异常,匹配到了两个相同类型的规则 => 【contractExceedVO = {}】,【existCondition ={}】,【newCondition ={}】", + JSON.toJSONString(contractExceedDTO), JSON.toJSONString(existCondition), JSON.toJSONString(condition)); + } + result.put(condition.getRuleType(),condition); + } + return result; + } + + public static void main(String[] args) { + ContractRiskApproveRuleDTO contractRiskApproveRule = JSON.parseObject(jsonConfig,ContractRiskApproveRuleDTO.class); + List conditions = contractRiskApproveRule.getConditions().stream() + .filter(condition -> Objects.equals(condition.getIsDeleted(), "n")) + +// .sorted(Comparator.comparingInt(ContractRiskApproveRuleDTO.Condition::getOrder)).collect(Collectors.toList()); + + .sorted().collect(Collectors.toList()); + + } +} diff --git a/java-basic/basic/src/main/java/cn/cunchang/json/biz/BizTest.java b/java-basic/basic/src/main/java/cn/cunchang/json/biz/BizTest.java new file mode 100644 index 00000000..7dc53aa1 --- /dev/null +++ b/java-basic/basic/src/main/java/cn/cunchang/json/biz/BizTest.java @@ -0,0 +1,113 @@ +package cn.cunchang.json.biz; + +import cn.cunchang.json.dto.ContractExceedDTO; +import cn.cunchang.json.dto.ContractRiskApproveRuleDTO; +import com.google.common.collect.Sets; +import org.apache.commons.collections.MapUtils; +import org.junit.Assert; +import org.junit.Test; + +import java.math.BigDecimal; +import java.util.Map; + +/** + * @author kaisui + * @description + * @date 2022/12/8 + */ +public class BizTest { + + Biz biz = new Biz(); + + // 单项目未过期 + @Test + public void test1(){ + ContractExceedDTO contractExceedDTO = new ContractExceedDTO(); + contractExceedDTO.setContractCode("1"); + contractExceedDTO.setContractType("common_frame"); + contractExceedDTO.setPoNumber("1"); + contractExceedDTO.setCurrentPoPurchaseCategory(Sets.newHashSet("PS1")); + contractExceedDTO.setOverdue(false); + contractExceedDTO.setRatio(new BigDecimal("1")); + + Map matchRuleMap = biz.matchRule(contractExceedDTO); + Assert.assertTrue(MapUtils.isEmpty(matchRuleMap)); + } + // 单项目过期 + @Test + public void test2(){ + ContractExceedDTO contractExceedDTO = new ContractExceedDTO(); + contractExceedDTO.setContractCode("1"); + contractExceedDTO.setContractType("common_frame"); + contractExceedDTO.setPoNumber("1"); + contractExceedDTO.setCurrentPoPurchaseCategory(Sets.newHashSet("PS1")); + contractExceedDTO.setOverdue(true); + contractExceedDTO.setRatio(new BigDecimal("1")); + + Map matchRuleMap = biz.matchRule(contractExceedDTO); + Assert.assertEquals(0, (int) matchRuleMap.get(RuleTypeEnum.OVER_DUE.getCode()).getOrder()); + Assert.assertNull(matchRuleMap.get(RuleTypeEnum.OVER_RATIO.getCode())); + } + + // 单项目超框 + @Test + public void test3(){ + ContractExceedDTO contractExceedDTO = new ContractExceedDTO(); + contractExceedDTO.setContractCode("1"); + contractExceedDTO.setContractType("common_frame"); + contractExceedDTO.setPoNumber("1"); + contractExceedDTO.setCurrentPoPurchaseCategory(Sets.newHashSet("PS1")); + contractExceedDTO.setOverdue(false); + contractExceedDTO.setRatio(new BigDecimal("1.0000001")); + + Map matchRuleMap = biz.matchRule(contractExceedDTO); + Assert.assertEquals(1, (int) matchRuleMap.get(RuleTypeEnum.OVER_RATIO.getCode()).getOrder()); + Assert.assertNull(matchRuleMap.get(RuleTypeEnum.OVER_DUE.getCode())); + } + + // 单项目过期+超框1.0000001 + @Test + public void test4(){ + ContractExceedDTO contractExceedDTO = new ContractExceedDTO(); + contractExceedDTO.setContractCode("1"); + contractExceedDTO.setContractType("common_frame"); + contractExceedDTO.setPoNumber("1"); + contractExceedDTO.setCurrentPoPurchaseCategory(Sets.newHashSet("PS1")); + contractExceedDTO.setOverdue(true); + contractExceedDTO.setRatio(new BigDecimal("1.0000001")); + + Map matchRuleMap = biz.matchRule(contractExceedDTO); + Assert.assertEquals(0, (int) matchRuleMap.get(RuleTypeEnum.OVER_DUE.getCode()).getOrder()); + Assert.assertEquals(1, (int) matchRuleMap.get(RuleTypeEnum.OVER_RATIO.getCode()).getOrder()); + } + // 框架合同过期 + @Test + public void test5(){ + ContractExceedDTO contractExceedDTO = new ContractExceedDTO(); + contractExceedDTO.setContractCode("1"); + contractExceedDTO.setContractType("price_frame"); + contractExceedDTO.setPoNumber("1"); + contractExceedDTO.setCurrentPoPurchaseCategory(Sets.newHashSet("PS1")); + contractExceedDTO.setOverdue(true); + contractExceedDTO.setRatio(new BigDecimal("1.0000000")); + + Map matchRuleMap = biz.matchRule(contractExceedDTO); + Assert.assertEquals(0, (int) matchRuleMap.get(RuleTypeEnum.OVER_DUE.getCode()).getOrder()); + Assert.assertNull(matchRuleMap.get(RuleTypeEnum.OVER_RATIO.getCode())); + } + // 框架合同过期+超框1.0000001 + @Test + public void test6(){ + ContractExceedDTO contractExceedDTO = new ContractExceedDTO(); + contractExceedDTO.setContractCode("1"); + contractExceedDTO.setContractType("price_frame"); + contractExceedDTO.setPoNumber("1"); + contractExceedDTO.setCurrentPoPurchaseCategory(Sets.newHashSet("PS1")); + contractExceedDTO.setOverdue(true); + contractExceedDTO.setRatio(new BigDecimal("1.0000001")); + + Map matchRuleMap = biz.matchRule(contractExceedDTO); + Assert.assertEquals(0, (int) matchRuleMap.get(RuleTypeEnum.OVER_DUE.getCode()).getOrder()); + Assert.assertNull(matchRuleMap.get(RuleTypeEnum.OVER_RATIO.getCode())); + } +} diff --git a/java-basic/basic/src/main/java/cn/cunchang/json/biz/RuleTypeEnum.java b/java-basic/basic/src/main/java/cn/cunchang/json/biz/RuleTypeEnum.java new file mode 100644 index 00000000..c43634e1 --- /dev/null +++ b/java-basic/basic/src/main/java/cn/cunchang/json/biz/RuleTypeEnum.java @@ -0,0 +1,33 @@ +package cn.cunchang.json.biz; +/** + * + * @author kaisui + * @date 2022/11/24 + **/ +public enum RuleTypeEnum { + /** + * + */ + OVER_DUE("overdue", "超期"), + /** + * + */ + OVER_RATIO("overratio", "超框"), + + ; + private String code; + private String desc; + + RuleTypeEnum(String code, String desc) { + this.code = code; + this.desc = desc; + } + + public String getCode() { + return code; + } + + public String getDesc() { + return desc; + } + } diff --git a/java-basic/basic/src/main/java/cn/cunchang/packagesacn/ClasspathPackageScanner.java b/java-basic/basic/src/main/java/cn/cunchang/packagesacn/ClasspathPackageScanner.java new file mode 100644 index 00000000..b36dafcc --- /dev/null +++ b/java-basic/basic/src/main/java/cn/cunchang/packagesacn/ClasspathPackageScanner.java @@ -0,0 +1,131 @@ +package cn.cunchang.packagesacn; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.jar.JarEntry; +import java.util.jar.JarInputStream; + +public class ClasspathPackageScanner implements PackageScanner { + private Logger log = LoggerFactory.getLogger(ClasspathPackageScanner.class); + private String basePackage; + private ClassLoader cl; + + /** + * 初始化 + * + * @param basePackage + */ + public ClasspathPackageScanner(String basePackage) { + this.basePackage = basePackage; + this.cl = getClass().getClassLoader(); + } + + public ClasspathPackageScanner(String basePackage, ClassLoader cl) { + this.basePackage = basePackage; + this.cl = cl; + } + + /** + * 获取指定包下的所有字节码文件的全类名 + */ + @Override + public List getFullyQualifiedClassNameList() throws IOException { + log.info("开始扫描包{}下的所有类", basePackage); + return doScan(basePackage, new ArrayList()); + } + + /** + * doScan函数 + * + * @param basePackage + * @param nameList + * @return + * @throws IOException + */ + private List doScan(String basePackage, List nameList) throws IOException { + String splashPath = StringUtil.dotToSplash(basePackage); + URL url = cl.getResource(splashPath); //file:/D:/WorkSpace/java/ScanTest/target/classes/com/scan + String filePath = StringUtil.getRootPath(url); + List names = null; // contains the name of the class file. e.g., Apple.class will be stored as "Apple" + if (isJarFile(filePath)) {// 先判断是否是jar包,如果是jar包,通过JarInputStream产生的JarEntity去递归查询所有类 + log.debug("{} 是一个JAR包", filePath); + names = readFromJarFile(filePath, splashPath); + } else { + log.debug("{} 是一个目录", filePath); + names = readFromDirectory(filePath); + } + for (String name : names) { + if (isClassFile(name)) { + nameList.add(toFullyQualifiedName(name, basePackage)); + } else { + doScan(basePackage + "." + name, nameList); + } + } + for (String n : nameList) { + log.debug("找到{}", n); + } + return nameList; + } + + private String toFullyQualifiedName(String shortName, String basePackage) { + StringBuilder sb = new StringBuilder(basePackage); + sb.append('.'); + sb.append(StringUtil.trimExtension(shortName)); + //打印出结果 + System.out.println(sb.toString()); + return sb.toString(); + } + + private List readFromJarFile(String jarPath, String splashedPackageName) throws IOException { + log.debug("从JAR包中读取类: {}", jarPath); + JarInputStream jarIn = new JarInputStream(new FileInputStream(jarPath)); + JarEntry entry = jarIn.getNextJarEntry(); + List nameList = new ArrayList(); + while (null != entry) { + String name = entry.getName(); + if (name.startsWith(splashedPackageName) && isClassFile(name)) { + nameList.add(name); + } + + entry = jarIn.getNextJarEntry(); + } + + return nameList; + } + + private List readFromDirectory(String path) { + File file = new File(path); + String[] names = file.list(); + + if (null == names) { + return null; + } + + return Arrays.asList(names); + } + + private boolean isClassFile(String name) { + return name.endsWith(".class"); + } + + private boolean isJarFile(String name) { + return name.endsWith(".jar"); + } + + /** + * For test purpose. + */ + public static void main(String[] args) throws Exception { + // https://www.cnblogs.com/juncaoit/p/7591778.html + PackageScanner scan = new ClasspathPackageScanner("cn.cunchang"); + scan.getFullyQualifiedClassNameList(); + } +} \ No newline at end of file diff --git a/java-basic/basic/src/main/java/cn/cunchang/packagesacn/PackageScanner.java b/java-basic/basic/src/main/java/cn/cunchang/packagesacn/PackageScanner.java new file mode 100644 index 00000000..151df0f4 --- /dev/null +++ b/java-basic/basic/src/main/java/cn/cunchang/packagesacn/PackageScanner.java @@ -0,0 +1,10 @@ +package cn.cunchang.packagesacn; + +import java.io.IOException; +import java.util.List; + +public interface PackageScanner { + + List getFullyQualifiedClassNameList() throws IOException; + +} \ No newline at end of file diff --git a/java-basic/basic/src/main/java/cn/cunchang/packagesacn/StringUtil.java b/java-basic/basic/src/main/java/cn/cunchang/packagesacn/StringUtil.java new file mode 100644 index 00000000..6a676848 --- /dev/null +++ b/java-basic/basic/src/main/java/cn/cunchang/packagesacn/StringUtil.java @@ -0,0 +1,59 @@ +package cn.cunchang.packagesacn; + +import java.net.URL; + +public class StringUtil { + private StringUtil() { + + } + + /** + * "file:/home/whf/cn/fh" -> "/home/whf/cn/fh" + * "jar:file:/home/whf/foo.jar!cn/fh" -> "/home/whf/foo.jar" + */ + public static String getRootPath(URL url) { + String fileUrl = url.getFile(); + int pos = fileUrl.indexOf('!'); + + if (-1 == pos) { + return fileUrl; + } + + return fileUrl.substring(5, pos); + } + + /** + * "cn.fh.lightning" -> "cn/fh/lightning" + * + * @param name + * @return + */ + public static String dotToSplash(String name) { + return name.replaceAll("\\.", "/"); + } + + /** + * "Apple.class" -> "Apple" + */ + public static String trimExtension(String name) { + int pos = name.indexOf('.'); + if (-1 != pos) { + return name.substring(0, pos); + } + + return name; + } + + /** + * /application/home -> /home + * + * @param uri + * @return + */ + public static String trimURI(String uri) { + String trimmed = uri.substring(1); + int splashIndex = trimmed.indexOf('/'); + + return trimmed.substring(splashIndex); + } +} \ No newline at end of file diff --git a/java-basic/basic/src/main/java/cn/cunchang/pinyin4j/DeCode.java b/java-basic/basic/src/main/java/cn/cunchang/pinyin4j/DeCode.java new file mode 100644 index 00000000..ae9c02ea --- /dev/null +++ b/java-basic/basic/src/main/java/cn/cunchang/pinyin4j/DeCode.java @@ -0,0 +1,20 @@ +package cn.cunchang.pinyin4j; + +/** + * + * @author lastwhisper + * @date 2020/6/8 + */ +public class DeCode { + + public static void main(String[] args) { + final String words = "原谅女儿离开父亲 昨日看到急报提示 " + + "阴祸氏突袭数据库 然后立刻离开城门 " + + "发现事情并不单纯 于是就跟随他来此 " + + "如果我没法再找寻 根据这追踪器书信 " + + "一定就会发现原因 "; + String binary = PinYinUtil.word2Tonal(words); + System.out.println(PinYinUtil.binary2Ascii(binary)); + } + +} diff --git a/java-basic/basic/src/main/java/cn/cunchang/pinyin4j/PinYinUtil.java b/java-basic/basic/src/main/java/cn/cunchang/pinyin4j/PinYinUtil.java new file mode 100644 index 00000000..c6c80146 --- /dev/null +++ b/java-basic/basic/src/main/java/cn/cunchang/pinyin4j/PinYinUtil.java @@ -0,0 +1,171 @@ +package cn.cunchang.pinyin4j; + +import net.sourceforge.pinyin4j.PinyinHelper; +import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType; +import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat; +import net.sourceforge.pinyin4j.format.HanyuPinyinToneType; +import net.sourceforge.pinyin4j.format.HanyuPinyinVCharType; +import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination; + +import static net.sourceforge.pinyin4j.format.HanyuPinyinCaseType.LOWERCASE; +import static net.sourceforge.pinyin4j.format.HanyuPinyinToneType.WITHOUT_TONE; +import static net.sourceforge.pinyin4j.format.HanyuPinyinToneType.WITH_TONE_NUMBER; +import static net.sourceforge.pinyin4j.format.HanyuPinyinVCharType.WITH_V; + +/** + * @author lastwhisper + */ +public class PinYinUtil { + + /** + * @param words 汉字字符串 + */ + public static String words2Pinyin(String words) { + return words2Pinyin(words, getDefaultPinyinFormat()); + } + + /** + * @param words 汉字字符串 + * @param pinyinFormat 汉字转拼音格式化模式 + */ + public static String words2Pinyin(String words, HanyuPinyinOutputFormat pinyinFormat) { + return words2Pinyin(words.toCharArray(), pinyinFormat); + } + + /** + * @param chars 汉字字符数组 + * @param pinyinFormat 汉字转拼音格式化模式 + */ + public static String words2Pinyin(char[] chars, HanyuPinyinOutputFormat pinyinFormat) { + StringBuilder pinyinBuilder = new StringBuilder(); + try { + for (char word : chars) { + //是否为汉字字符 + if (Character.toString(word).matches("[\\u4E00-\\u9FA5]+")) { + // 多音字 + String[] py = PinyinHelper.toHanyuPinyinStringArray(word, pinyinFormat); + pinyinBuilder.append(py[0]); + } else { + pinyinBuilder.append(word); + } + } + } catch (BadHanyuPinyinOutputFormatCombination e) { + e.printStackTrace(); + } + return pinyinBuilder.toString(); + } + + /** + * 小写、音标无声调无音符、v表示ü + * @return net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat + */ + public static HanyuPinyinOutputFormat getDefaultPinyinFormat() { + return getPinyinFormat(LOWERCASE, WITHOUT_TONE, WITH_V); + } + + /** + * 小写、音标有声调无音符、v表示ü + * @return net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat + */ + public static HanyuPinyinOutputFormat getToneNumberPinyinFormat() { + return getPinyinFormat(LOWERCASE, WITH_TONE_NUMBER, WITH_V); + } + + /** + * 获取汉语拼音格式化器 + * @param caseType 大小写 + * @see HanyuPinyinCaseType + * UPPERCASE:大写 (ZHONG) + * LOWERCASE:小写 (zhong) + * @param toneType 音标格式 + * @see HanyuPinyinToneType + * WITHOUT_TONE:无音标 (zhong) + * WITH_TONE_NUMBER:1-4数字表示英标 (zhong4) + * WITH_TONE_MARK:直接用音标符(必须WITH_U_UNICODE否则异常) (zhòng) + * @param charType charType + * @see HanyuPinyinVCharType + * WITH_V:用v表示ü (nv) + * WITH_U_AND_COLON:用"u:"表示ü (nu:) + * WITH_U_UNICODE:直接用ü (nü) + * @return net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat + */ + public static HanyuPinyinOutputFormat getPinyinFormat(HanyuPinyinCaseType caseType, HanyuPinyinToneType toneType, HanyuPinyinVCharType charType) { + HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat(); + format.setCaseType(caseType); + format.setToneType(toneType); + format.setVCharType(charType); + return format; + } + + /** + * 汉字串转声调 + * @param words 字符串 + * @return java.lang.String 声调串 + * 1,2,3,4 + */ + public static String word2ToneNumber(String words) { + String tones = words2Pinyin(words, getToneNumberPinyinFormat()); + StringBuilder toneNumBuilder = new StringBuilder(); + for (int i = 0; i < tones.length(); i++) { + char c = tones.charAt(i); + if (isTonal(c)) { + toneNumBuilder.append(c); + } + } + return toneNumBuilder.toString(); + } + + private static boolean isTonal(char c) { + return isLow(c) || isHeight(c); + } + + private static boolean isLow(char c) { + return c == 49 || c == 50; + } + + private static boolean isHeight(char c) { + return c == 51 || c == 52; + } + + /** + * 汉字串转平仄 + * @param words 字符串 + * @return java.lang.String 平仄 + * 1,2:平、3,4:仄 + * 平:0、仄:1 + */ + public static String word2Tonal(String words) { + String tones = words2Pinyin(words, getToneNumberPinyinFormat()); + StringBuilder tonalNumBuilder = new StringBuilder(); + for (int i = 0; i < tones.length(); i++) { + char c = tones.charAt(i); + if (isLow(c)) { + tonalNumBuilder.append(0); + } else if (isHeight(c)) { + tonalNumBuilder.append(1); + } + } + return tonalNumBuilder.toString(); + } + + /** + * @param binary 二进制串 + * @return java.lang.String 对应的ASCII + */ + public static String binary2Ascii(String binary) { + StringBuilder asciiBuilder = new StringBuilder(); + for (int i = 0; i < binary.length(); i += 8) { + asciiBuilder.append((char) Integer.parseInt(binary.substring(i, i + 8), 2)); + } + return asciiBuilder.toString(); + } + + public static void main(String[] args) { + String words = "原谅女儿离开父亲 昨日看到急报提示 "; + String tonal = word2Tonal(words); + System.out.println(tonal); + String str = binary2Ascii(tonal); + System.out.println(str); + } + +} \ No newline at end of file diff --git a/java-basic/basic/src/main/java/cn/cunchang/regex/RegExTest.java b/java-basic/basic/src/main/java/cn/cunchang/regex/RegExTest.java new file mode 100644 index 00000000..c3bcc629 --- /dev/null +++ b/java-basic/basic/src/main/java/cn/cunchang/regex/RegExTest.java @@ -0,0 +1,143 @@ +package cn.cunchang.regex; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Java 正则表达式 + * + * @author lastwhisper + * @date 2020/5/29 + */ +public class RegExTest { + + @Test + public void testPhone() { + // 按指定模式在字符串查找 + String[] lines = {"13812345678"}; + // 138、166、198、199 + String regEx = "^1([38][0-9]|4[579]|5[0-3,5-9]|6[6]|7[0135678]|9[89])\\d{8}$"; + match(regEx, lines); + } + + @Test + public void testLetter() { + String[] lines = {"13812345abc", "13812345ABC", "13812345;", "13812345】"}; + String regEx = "[a-zA-Z]"; + match(regEx, lines); + } + + @Test + public void testRegExSplit() { + String[] lines = {"pop-upu*123214/asd44"}; + String regEx = "[^a-zA-Z0-9]"; + match(regEx, lines); + } + + @Test + public void testIllegal() { + // 按指定模式在字符串查找 + String[] lines = {"13812345abc", "13812345哈哈", "aaa13812345;", "13812345】"}; + String regEx = "[^0-9]"; + match(regEx, lines); + } + + /** + * 名称允许汉字、字母、数字,域名只允许英文域名 + */ + @Test + public void testEmail1() { + // 按指定模式在字符串查找 + String[] lines = {"杨元庆001Abc@lenovo.com.cn"}; + // 138、166、198、199 + String regEx = "^[A-Za-z0-9\\u4e00-\\u9fa5]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$"; + match(regEx, lines); + } + + /** + * 只允许英文字母、数字、下划线、英文句号、以及中划线组成 + */ + @Test + public void testEmail2() { + // 按指定模式在字符串查找 + String[] lines = {"zhangsan-001@gmail.com"}; + String regEx = "^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$"; + match(regEx, lines); + } + + @Test + public void test1() { + String[] lines = {"${asdasdasd}"}; + String regEx = "\\$\\{(.*?)\\}"; + match(regEx, lines); + } + + private void match(String regEx, String[] lines) { + // 创建 Pattern 对象,这个类的实例是不可变的,可以安全地被多个并发线程使用。 + Pattern pattern = Pattern.compile(regEx); + for (String line : lines) { + Matcher m = pattern.matcher(line); + // matches()是全部匹配 + if (m.matches()) { + System.out.println("Found value:" + m.group(0)); + } else { + System.out.println("NO MATCH"); + } + } + } + + + /** + * 学习正则api + */ + @Test + public void test正则api() { + Pattern p = Pattern.compile("\\d+"); + Matcher m = p.matcher("aaa2223bb"); + System.out.println(m.find());//匹配2223,返回true + System.out.println(m.start());//返回3,返回的是2223起始的索引号 + System.out.println(m.end());//返回7,返回的是2223结束的索引号 + System.out.println(m.group());//返回2223 + Matcher m2 = p.matcher("2223bb"); + System.out.println(m2.lookingAt()); //匹配2223,返回true + System.out.println(m2.start()); //返回0,由于lookingAt()只能匹配前面的字符串,所以当使用lookingAt()匹配时,start()方法总是返回0 + System.out.println(m2.end()); //返回4 + System.out.println(m2.group()); //返回2223 + Matcher m3 = p.matcher("2223"); //如果Matcher m3=p.matcher("2223bb"); 那么下面的方法出错,因为不匹配返回false + System.out.println(m3.matches()); //匹配整个字符串,返回true + System.out.println(m3.start()); //返回0 + System.out.println(m3.end()); //返回3,原因相信大家也清楚了,因为matches()需要匹配所有字符串 + System.out.println(m3.group()); //返回2223 + } + + @Test + public void test匹配所有数字() { + Pattern p = Pattern.compile("\\d+"); +// Matcher matcher = p.matcher("请问奥所,啊啊啊12356789101,999956789101阿萨德");// 2个12位数字 + Matcher matcher = p.matcher("请问奥所,啊啊啊123567891011,999956789101阿萨德");// 13 12 +// Matcher matcher = p.matcher("请问奥所,啊啊啊123567891011阿萨德");// 13位数字 +// Matcher matcher = p.matcher("请问奥所,啊啊啊 阿萨德"); + List list = new ArrayList<>(); + while (matcher.find()) { + list.add(matcher.group()); + } + System.out.println(list); + } + + @Test + public void test匹配表达式() { + String str = "#10110#+#10120#+#10130#+#10140#+#10150#"; + Pattern p = Pattern.compile("\\d+"); + Matcher matcher = p.matcher(str); + List list = new ArrayList<>(); + while (matcher.find()) { + list.add(matcher.group()); + } + System.out.println(list); + } + +} diff --git a/java-basic/basic/src/main/java/cn/cunchang/spring/SpringELTest.java b/java-basic/basic/src/main/java/cn/cunchang/spring/SpringELTest.java new file mode 100644 index 00000000..611b6773 --- /dev/null +++ b/java-basic/basic/src/main/java/cn/cunchang/spring/SpringELTest.java @@ -0,0 +1,37 @@ +package cn.cunchang.spring; + +import org.junit.Test; +import org.springframework.expression.ExpressionParser; +import org.springframework.expression.spel.standard.SpelExpressionParser; + +import java.math.BigDecimal; + +/** + * + * org.springframework + * spring-expression + * 5.2.7.RELEASE + * + * + * @author kaisui + * @description + * @date 2022/11/16 + */ +public class SpringELTest { + + // spring el解析表达式 + @Test + public void test1() { + ExpressionParser parser = new SpelExpressionParser(); + BigDecimal ratio = new BigDecimal("1.1"); + String compareExpression = "1 + System.out.println("TaskInfo:"+sw.getTaskName()+" TimeMillis:"+ + sw.getTimeMillis()+" TimeSeconds:"+sw.getTimeSeconds())); + // 在start()方法和stop()方法间时,isRunning()返回true + System.out.println("isRunning:"+stopWatch.isRunning()); + System.out.println("prettyPrint:\n"+stopWatch.prettyPrint());//打印详细信息 + System.out.println("shortSummary:\n"+stopWatch.shortSummary());//打印简要信息 + } +} + + diff --git a/java-basic/basic/src/main/java/cn/cunchang/str/StringTest.java b/java-basic/basic/src/main/java/cn/cunchang/str/StringTest.java new file mode 100644 index 00000000..8cb7f245 --- /dev/null +++ b/java-basic/basic/src/main/java/cn/cunchang/str/StringTest.java @@ -0,0 +1,26 @@ +package cn.cunchang.str; + +import org.junit.Test; + +/** + * @author cunchang + * @date 2022/5/9 3:23 PM + */ +public class StringTest { + + public static void main(String[] args) { +// String fileName = "819882007410001_20200309-20200309_0010387011560_KV691300131099C.pdf"; +// String REFNBR = fileName.substring(fileName.lastIndexOf("_") + 1, fileName.lastIndexOf(".")); +// System.out.println(REFNBR); + String srts = "1,"; + String[] arrs = srts.split(","); + for (String arr : arrs) { + System.out.println(arr); + } + } + + @Test + public void formatTest() { + System.out.println(String.format("百分百%s%",111)); + } +} diff --git a/java-basic/basic/src/main/java/cn/cunchang/sugar/type/A.java b/java-basic/basic/src/main/java/cn/cunchang/sugar/type/A.java new file mode 100644 index 00000000..9f985b81 --- /dev/null +++ b/java-basic/basic/src/main/java/cn/cunchang/sugar/type/A.java @@ -0,0 +1,11 @@ +package cn.cunchang.sugar.type; + +// A.jar +//A.java有类A,A调了B的方法add(int i),这时传的是个原始类型, 完美匹配 +public class A { + public static void main(String[] args) { + // add(int i) ,1不会进行拆装箱 + // add(Integer i),1会进行拆装箱 + B.add(1); + } +} diff --git a/java-basic/basic/src/main/java/cn/cunchang/sugar/type/B.java b/java-basic/basic/src/main/java/cn/cunchang/sugar/type/B.java new file mode 100644 index 00000000..c613dd13 --- /dev/null +++ b/java-basic/basic/src/main/java/cn/cunchang/sugar/type/B.java @@ -0,0 +1,13 @@ +package cn.cunchang.sugar.type; + +// B.jar +//B.java +public class B { +// public static void add(int i) { +// System.out.println(i); +// } + + public static void add(Integer i) { + System.out.println(i); + } +} \ No newline at end of file diff --git a/java-basic/basic/src/main/java/cn/cunchang/sugar/type/README.md b/java-basic/basic/src/main/java/cn/cunchang/sugar/type/README.md new file mode 100644 index 00000000..f6cf4ace --- /dev/null +++ b/java-basic/basic/src/main/java/cn/cunchang/sugar/type/README.md @@ -0,0 +1,6 @@ + +自动拆装箱的坑 + +Java自动拆装箱为什么不起作用了 - 鸿缘的文章 - 知乎 +https://zhuanlan.zhihu.com/p/26650204 + diff --git a/java-basic/basic/src/main/java/cn/cunchang/sysproperty/SystemProperty.java b/java-basic/basic/src/main/java/cn/cunchang/sysproperty/SystemProperty.java new file mode 100644 index 00000000..d9a47e38 --- /dev/null +++ b/java-basic/basic/src/main/java/cn/cunchang/sysproperty/SystemProperty.java @@ -0,0 +1,56 @@ +package cn.cunchang.sysproperty; + +import org.junit.Test; + +import java.util.Properties; + +public class SystemProperty { + + @Test + public void properties() { + Properties props = System.getProperties(); + System.out.println("Java的执行环境版本号:" + props.getProperty("java.version")); + System.out.println("Java的执行环境供应商:" + props.getProperty("java.vendor")); + System.out.println("Java供应商的URL:" + props.getProperty("java.vendor.url")); + System.out.println("Java的安装路径:" + props.getProperty("java.home")); + System.out.println("Java的虚拟机规范版本号:" + props.getProperty("java.vm.specification.version")); + System.out.println("Java的虚拟机规范供应商:" + props.getProperty("java.vm.specification.vendor")); + System.out.println("Java的虚拟机规范名称:" + props.getProperty("java.vm.specification.name")); + System.out.println("Java的虚拟机实现版本号:" + props.getProperty("java.vm.version")); + System.out.println("Java的虚拟机实现供应商:" + props.getProperty("java.vm.vendor")); + System.out.println("Java的虚拟机实现名称:" + props.getProperty("java.vm.name")); + System.out.println("Java执行时环境规范版本号:" + props.getProperty("java.specification.version")); + System.out.println("Java执行时环境规范供应商:" + props.getProperty("java.specification.vender")); + System.out.println("Java执行时环境规范名称:" + props.getProperty("java.specification.name")); + System.out.println("Java的类格式版本号号:" + props.getProperty("java.class.version")); + System.out.println("Java的类路径:" + props.getProperty("java.class.path")); + System.out.println("载入库时搜索的路径列表:" + props.getProperty("java.library.path")); + System.out.println("默认的暂时文件路径:" + props.getProperty("java.io.tmpdir")); + System.out.println("一个或多个扩展文件夹的路径:" + props.getProperty("java.ext.dirs")); + // 操作系统 输出 + // linux Linux + // windows Windows XP + // mac Mac OS X + System.out.println("操作系统的名称:" + props.getProperty("os.name")); + System.out.println("操作系统的构架:" + props.getProperty("os.arch")); + System.out.println("操作系统的版本号:" + props.getProperty("os.version")); + System.out.println("文件分隔符:" + props.getProperty("file.separator")); + //在 unix 系统中是"/" + System.out.println("路径分隔符:" + props.getProperty("path.separator")); + //在 unix 系统中是":" + System.out.println("行分隔符:" + props.getProperty("line.separator")); + //在 unix 系统中是"/n" + System.out.println("用户的账户名称:" + props.getProperty("user.name")); + System.out.println("用户的主文件夹:" + props.getProperty("user.home")); + System.out.println("用户的当前工作文件夹:" + props.getProperty("user.dir")); + } + + @Test + public void dynamicPath() { + String userHome = System.getProperty("user.home"); + System.out.println(userHome+"/upload"); + } + + + +} \ No newline at end of file diff --git a/java-basic/basic/src/main/java/cn/cunchang/trycatch/ForTryFinallyTest.java b/java-basic/basic/src/main/java/cn/cunchang/trycatch/ForTryFinallyTest.java new file mode 100644 index 00000000..65342d70 --- /dev/null +++ b/java-basic/basic/src/main/java/cn/cunchang/trycatch/ForTryFinallyTest.java @@ -0,0 +1,39 @@ +package cn.cunchang.trycatch; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author cunchang + * @date 2020/12/29 3:06 下午 + */ +public class ForTryFinallyTest { + + public static void main(String[] args) { + List list = new ArrayList<>(); + list.add(1); + list.add(2); + list.add(3); + list.add(4); + for (Integer num : list) { + try { + if (num == 2) { + continue; + } + if (num == 3) { + break; + } + System.out.println("正常执行 " + num); + } finally { + if (num == 2) { + System.out.println("for循环,try里面continue会执行finally " + num); + } + if (num == 3) { + System.out.println("for循环,try里面break会执行finally " + num); + } + } + } + } + + +} diff --git a/java-basic/basic/src/main/resources/log4j2.xml b/java-basic/basic/src/main/resources/log4j2.xml new file mode 100644 index 00000000..0fed87ee --- /dev/null +++ b/java-basic/basic/src/main/resources/log4j2.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/java-basic/concurrent/README.md b/java-basic/concurrent/README.md new file mode 100644 index 00000000..19b37306 --- /dev/null +++ b/java-basic/concurrent/README.md @@ -0,0 +1,4 @@ +1. jmm-specification +2. thread-syncronized +3. thread-current +4. \ No newline at end of file diff --git a/java-basic/concurrent/jmm-specification/README.md b/java-basic/concurrent/jmm-specification/README.md new file mode 100644 index 00000000..0b33e62e --- /dev/null +++ b/java-basic/concurrent/jmm-specification/README.md @@ -0,0 +1,7 @@ + + +AsIfSerialSample AsIfSerial语义 +Jmm01_HappensBefore HappensBefore +Jmm05_CodeReorder 指令重排序 +Jmm06_MemoryBarrier 内存屏障 + diff --git a/java-basic/concurrent/jmm-specification/pom.xml b/java-basic/concurrent/jmm-specification/pom.xml new file mode 100644 index 00000000..825ba9af --- /dev/null +++ b/java-basic/concurrent/jmm-specification/pom.xml @@ -0,0 +1,19 @@ + + + + concurrent + cn.lastwhisper + 1.0-SNAPSHOT + + 4.0.0 + + jmm-specification + + + 11 + 11 + + + \ No newline at end of file diff --git a/java-basic/concurrent/jmm-specification/src/main/java/cn/lastwhisper/AsIfSerialSample.java b/java-basic/concurrent/jmm-specification/src/main/java/cn/lastwhisper/AsIfSerialSample.java new file mode 100644 index 00000000..ca36ab8e --- /dev/null +++ b/java-basic/concurrent/jmm-specification/src/main/java/cn/lastwhisper/AsIfSerialSample.java @@ -0,0 +1,25 @@ +package cn.lastwhisper; + +/** + * @author : + * @date:2019/7/18 + * @version: V1.0 + * @slogan: 天下风云出我辈,一入代码岁月催 + * @description : + */ +public class AsIfSerialSample { + + public static void main(String[] args) { + /** + * as-if-serial语义的意思是:不管怎么重排序(编译器和处理器为了提高并行度),(单线程) + * 程序的执行结果不能被改变。编译器、runtime和处理器都必须遵守as-if-serial语义。 + * + * 以下例子当中1、2步存在指令重排行为,但是1、2不能与第三步指令重排 + * 也就是第3步不可能先于1、2步执行,否则将改变程序的执行结果 + */ + double p = 3.14; //1 + double r = 1.0; //2 + double area = p * r * r; //3计算面积 + } + +} diff --git a/java-basic/concurrent/jmm-specification/src/main/java/cn/lastwhisper/Jmm01_HappensBefore.java b/java-basic/concurrent/jmm-specification/src/main/java/cn/lastwhisper/Jmm01_HappensBefore.java new file mode 100644 index 00000000..3313e95c --- /dev/null +++ b/java-basic/concurrent/jmm-specification/src/main/java/cn/lastwhisper/Jmm01_HappensBefore.java @@ -0,0 +1,27 @@ +package cn.lastwhisper; + +/** + * @date :Created in 2020/4/29 13:58 + * @version: V1.0 + * @slogan: 天下风云出我辈,一入代码岁月催 + * @description: + **/ +public class Jmm01_HappensBefore { + public static volatile int r = 3; + + public static int g=6; + + public static volatile double pai = 3.14; + + public static volatile double area; + + public static void caculate(){ + int a = r; + int b = g; + area = a * b * pai; + } + + public static void main(String[] args) { + caculate(); + } +} diff --git a/java-basic/concurrent/jmm-specification/src/main/java/cn/lastwhisper/Jmm02_CpuCache.java b/java-basic/concurrent/jmm-specification/src/main/java/cn/lastwhisper/Jmm02_CpuCache.java new file mode 100644 index 00000000..f7bc3229 --- /dev/null +++ b/java-basic/concurrent/jmm-specification/src/main/java/cn/lastwhisper/Jmm02_CpuCache.java @@ -0,0 +1,64 @@ +package cn.lastwhisper; + +/** + * ,;,,; + * ,;;'( 社 + * __ ,;;' ' \ 会 + * /' '\'~~'~' \ /'\.) 主 + * ,;( ) / |. 义 + *,;' \ /-.,,( ) \ 码 + * ) / ) / )| 农 + * || || \) + * (_\ (_\ + * + * @date :Created in 2020/4/29 14:00 + * @version: V1.0 + * @slogan: 天下风云出我辈,一入代码岁月催 + * @description: + **/ +public class Jmm02_CpuCache { + private static final int RUNS = 10; + private static final int DIMENSION_1 = 1024 * 1024; + private static final int DIMENSION_2 = 6; + + private static long[][] longs; + + public static void main(String[] args) throws Exception { + /* + * 初始化数组 + */ + longs = new long[DIMENSION_1][]; + for (int i = 0; i < DIMENSION_1; i++) { + longs[i] = new long[DIMENSION_2]; + for (int j = 0; j < DIMENSION_2; j++) { + longs[i][j] = 1L; + } + } + System.out.println("初始化完毕...."); + + long sum = 0L; + long start = System.currentTimeMillis(); + for (int r = 0; r < RUNS; r++) { + for (int i = 0; i < DIMENSION_1; i++) {//DIMENSION_1=1024*1024 + for (int j=0;j{ + while (!initFlag){ + //System.out.println("runing"); + counter++; + } + log.info("线程:" + Thread.currentThread().getName() + + "当前线程嗅探到initFlag的状态的改变"); + },"threadA"); + threadA.start(); + + try { + Thread.sleep(500); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + Thread threadB = new Thread(()->{ + refresh(); + },"threadB"); + threadB.start(); + } +} diff --git a/java-basic/concurrent/jmm-specification/src/main/java/cn/lastwhisper/Jmm04_CodeAtomic.java b/java-basic/concurrent/jmm-specification/src/main/java/cn/lastwhisper/Jmm04_CodeAtomic.java new file mode 100644 index 00000000..700f3bad --- /dev/null +++ b/java-basic/concurrent/jmm-specification/src/main/java/cn/lastwhisper/Jmm04_CodeAtomic.java @@ -0,0 +1,51 @@ +package cn.lastwhisper; + +import com.sun.xml.internal.ws.developer.MemberSubmissionAddressingFeature; + +import javax.security.sasl.SaslServer; + +/** + * ,;,,; + * ,;;'( 社 + * __ ,;;' ' \ 会 + * /' '\'~~'~' \ /'\.) 主 + * ,;( ) / |. 义 + * ,;' \ /-.,,( ) \ 码 + * ) / ) / )| 农 + * || || \) + * (_\ (_\ + * + * + * @date :Created in 2020/4/29 + * @version: V1.0 + * @slogan: 天下风云出我辈,一入代码岁月催 + * @description: + **/ +public class Jmm04_CodeAtomic { + + private volatile static int counter = 0; + static Object object = new Object(); + + public static void main(String[] args) { + + for (int i = 0; i < 10; i++) { + Thread thread = new Thread(()->{ + for (int j = 0; j < 1000; j++) { + synchronized (object){ + counter++;//分三步- 读,自加,写回 + } + } + }); + thread.start(); + } + + try { + Thread.sleep(3000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + System.out.println(counter); + + } +} diff --git a/java-basic/concurrent/jmm-specification/src/main/java/cn/lastwhisper/Jmm05_CodeReorder.java b/java-basic/concurrent/jmm-specification/src/main/java/cn/lastwhisper/Jmm05_CodeReorder.java new file mode 100644 index 00000000..9da86070 --- /dev/null +++ b/java-basic/concurrent/jmm-specification/src/main/java/cn/lastwhisper/Jmm05_CodeReorder.java @@ -0,0 +1,50 @@ +package cn.lastwhisper; + +public class Jmm05_CodeReorder { + private static int x = 0, y = 0; + private static int a = 0, b = 0; + + public static void main(String[] args) throws InterruptedException { + int i = 0; + for (; ; ) { + i++; + x = 0; + y = 0; + a = 0; + b = 0; + Thread t1 = new Thread(new Runnable() { + @Override + public void run() { + a = 1; + x = b; + } + }); + + Thread t2 = new Thread(new Runnable() { + @Override + public void run() { + b = 1; + y = a; + } + }); + + t1.start(); + t2.start(); + // 阻塞主线程,直到t1执行完 + t1.join(); + // 阻塞主线程,直到t2执行完 + t2.join(); + // 第12627次 (0,0) + // 第951620次 (0,0) + // 出现指令重排: 第22648505次 (0,0) + String result = "第" + i + "次 (" + x + "," + y + ")"; + if (x == 0 && y == 0) { + System.out.println("出现指令重排: " + result); + break; + } else { + System.out.println(result); + } + } + + } +} diff --git a/java-basic/concurrent/jmm-specification/src/main/java/cn/lastwhisper/Jmm06_MemoryBarrier.java b/java-basic/concurrent/jmm-specification/src/main/java/cn/lastwhisper/Jmm06_MemoryBarrier.java new file mode 100644 index 00000000..76416a50 --- /dev/null +++ b/java-basic/concurrent/jmm-specification/src/main/java/cn/lastwhisper/Jmm06_MemoryBarrier.java @@ -0,0 +1,35 @@ +package cn.lastwhisper; + +/** + * ,;,,; + * ,;;'( 社 + * __ ,;;' ' \ 会 + * /' '\'~~'~' \ /'\.) 主 + * ,;( ) / |. 义 + * ,;' \ /-.,,( ) \ 码 + * ) / ) / )| 农 + * || || \) + * (_\ (_\ + * + * + * @date :Created in 2020/4/29 + * @version: V1.0 + * @slogan: 天下风云出我辈,一入代码岁月催 + * @description: + **/ +public class Jmm06_MemoryBarrier { + int a; + public volatile int m1 = 1; + public volatile int m2 = 2; + + public void readAndWrite() { + int i = m1; // 第一个volatile读 + int j = m2; // 第二个volatile读 + + a = i + j; // i,j普通读,a普通写 + + m1 = i + 1; // 第一个volatile写 + m2 = j * 2; // 第二个 volatile写 + } + +} diff --git a/java-basic/concurrent/jmm-specification/src/main/java/cn/lastwhisper/Jmm07_ByteCodeJitDump.java b/java-basic/concurrent/jmm-specification/src/main/java/cn/lastwhisper/Jmm07_ByteCodeJitDump.java new file mode 100644 index 00000000..5907c948 --- /dev/null +++ b/java-basic/concurrent/jmm-specification/src/main/java/cn/lastwhisper/Jmm07_ByteCodeJitDump.java @@ -0,0 +1,43 @@ +package cn.lastwhisper; + +/** + * ,;,,; + * ,;;'( 社 + * __ ,;;' ' \ 会 + * /' '\'~~'~' \ /'\.) 主 + * ,;( ) / |. 义 + *,;' \ /-.,,( ) \ 码 + * ) / ) / )| 农 + * || || \) + * (_\ (_\ + * + * @date :Created in 2020/4/29 14:12 + * @version: V1.0 + * @slogan: 天下风云出我辈,一入代码岁月催 + * @description: -server -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly -XX:CompileCommand=compileonly,*Jmm07_ByteCodeJitDump.refresh + **/ +public class Jmm07_ByteCodeJitDump { + private volatile static int c = 1; + + public static int refresh(){ + int a = 0; + int b = 1; + int sub = a + b + c; + return sub; + } + + public static void main(String[] args) throws InterruptedException { + + Thread thread0 = new Thread(()->{ + System.out.println(String.format("sub0:%d",refresh())); + }); + + thread0.start(); + + Thread thread1 = new Thread(()->{ + System.out.println(String.format("sub1:%d",refresh())); + }); + + thread1.start(); + } +} diff --git a/java-basic/concurrent/jmm-specification/src/main/java/cn/lastwhisper/JmmCausalityCase16Test.java b/java-basic/concurrent/jmm-specification/src/main/java/cn/lastwhisper/JmmCausalityCase16Test.java new file mode 100644 index 00000000..8317bbbb --- /dev/null +++ b/java-basic/concurrent/jmm-specification/src/main/java/cn/lastwhisper/JmmCausalityCase16Test.java @@ -0,0 +1,51 @@ +package cn.lastwhisper; + +public class JmmCausalityCase16Test { + private static int x = 0; + private static int r1 = 0, r2 = 0; + + public static void main(String[] args) throws InterruptedException { + int i = 0; + for (; ; ) { + i++; + x = 0; + r1 = 0; + r2 = 0; + Thread t1 = new Thread(new Runnable() { + @Override + public void run() { + r1 = x; + x = 1; + } + }); + + Thread t2 = new Thread(new Runnable() { + @Override + public void run() { + r2 = x; + x = 2; + } + }); + + t1.start(); + t2.start(); + // 阻塞主线程,直到t1执行完 + t1.join(); + // 阻塞主线程,直到t2执行完 + t2.join(); + String result = "第" + i + "次 (" + r1 + "," + r2 + ")"; + // t1/t2 => r1=0;r2=1——(0,1) + // t2/t1 => r1=2;r2=0——(2,0) + + // x=2,r1=x(2);x=1,r2=x(1) => r1=2;r2=1——(2,1)概率极小 + // 第23339610次 (0,1) + if (r1 == 2 && r2 == 1) { + System.out.println("出现指令重排: " + result); + break; + } else { + System.out.println(result); + } + } + + } +} diff --git a/java-basic/concurrent/jmm-specification/src/main/java/cn/lastwhisper/dcl/Singleton.java b/java-basic/concurrent/jmm-specification/src/main/java/cn/lastwhisper/dcl/Singleton.java new file mode 100644 index 00000000..45ae9a41 --- /dev/null +++ b/java-basic/concurrent/jmm-specification/src/main/java/cn/lastwhisper/dcl/Singleton.java @@ -0,0 +1,36 @@ +package cn.lastwhisper.dcl; + +/** + * @author : + * @date:2019/7/10 + * @version: V1.0 + * @slogan:天下风云出我辈,一入代码岁月催 + * @description + */ +public class Singleton { + + /** + * 查看汇编指令 + * -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly + */ + private volatile static Singleton myinstance; + + /** + * 双重锁机制保证单例安全 + * @return + */ + public static Singleton getInstance() { + if (myinstance == null) { + synchronized (Singleton.class) { + if (myinstance == null) { + myinstance = new Singleton(); + } + } + } + return myinstance; + } + + public static void main(String[] args) { + Singleton.getInstance(); + } +} diff --git a/java-basic/concurrent/jmm-specification/src/main/java/cn/lastwhisper/tmodel/ThreadModel.java b/java-basic/concurrent/jmm-specification/src/main/java/cn/lastwhisper/tmodel/ThreadModel.java new file mode 100644 index 00000000..c0e47997 --- /dev/null +++ b/java-basic/concurrent/jmm-specification/src/main/java/cn/lastwhisper/tmodel/ThreadModel.java @@ -0,0 +1,30 @@ +package cn.lastwhisper.tmodel; + +/** + * + * @date :Created in 2020/8/2 + * @version: V1.0 + * @slogan: 天下风云出我辈,一入代码岁月催 + * @description: + **/ +public class ThreadModel { + + public static void main(String[] args) { + + for (int i=0;i<200;i++){ + new Thread(new Runnable() { + @Override + public void run() { + while(true){ + try { + Thread.sleep(100); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + }).start(); + } + } + +} diff --git a/java-basic/concurrent/jmm-specification/src/main/java/cn/lastwhisper/util/UnsafeInstance.java b/java-basic/concurrent/jmm-specification/src/main/java/cn/lastwhisper/util/UnsafeInstance.java new file mode 100644 index 00000000..1996ed15 --- /dev/null +++ b/java-basic/concurrent/jmm-specification/src/main/java/cn/lastwhisper/util/UnsafeInstance.java @@ -0,0 +1,27 @@ +package cn.lastwhisper.util; + +import sun.misc.Unsafe; + +import java.lang.reflect.Field; + +/** + * @author : + * @date:2019/7/14 + * @version: V1.0 + * @slogan: 天下风云出我辈,一入代码岁月催 + * @description : + */ +public class UnsafeInstance { + + public static Unsafe reflectGetUnsafe() { + try { + Field field = Unsafe.class.getDeclaredField("theUnsafe"); + field.setAccessible(true); + return (Unsafe) field.get(null); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + +} diff --git a/java-basic/concurrent/pom.xml b/java-basic/concurrent/pom.xml index ef8a3f9f..fc832c9f 100644 --- a/java-basic/concurrent/pom.xml +++ b/java-basic/concurrent/pom.xml @@ -2,27 +2,46 @@ - - java-basic - cn.lastwhisper - 1.0-SNAPSHOT - + 4.0.0 cn.lastwhisper concurrent + pom + 1.0-SNAPSHOT + + jmm-specification + + - - com.google.guava - guava - 27.0.1-jre + org.springframework.boot + spring-boot-starter-web + 2.1.7.RELEASE org.projectlombok lombok 1.18.8 + + junit + junit + 4.13 + + + + org.openjdk.jol + jol-core + 0.10 + + + + com.alibaba + transmittable-thread-local + 2.12.6 + + \ No newline at end of file diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/UncaughtExceptionHandler/ExecuteCaught.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/UncaughtExceptionHandler/ExecuteCaught.java new file mode 100644 index 00000000..1c53072e --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/UncaughtExceptionHandler/ExecuteCaught.java @@ -0,0 +1,14 @@ +package cn.lastwhisper.concurrent.UncaughtExceptionHandler; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +public class ExecuteCaught { + public static void main(String[] args) { + ExecutorService exec = Executors.newCachedThreadPool(); + Thread thread = new Thread(new Task()); + thread.setUncaughtExceptionHandler(new ExceptionHandler()); + exec.execute(thread); + exec.shutdown(); + } +} \ No newline at end of file diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/UncaughtExceptionHandler/ExecuteCaught2.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/UncaughtExceptionHandler/ExecuteCaught2.java new file mode 100644 index 00000000..1c44db12 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/UncaughtExceptionHandler/ExecuteCaught2.java @@ -0,0 +1,22 @@ +package cn.lastwhisper.concurrent.UncaughtExceptionHandler; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +public class ExecuteCaught2 { + public static void main(String[] args) { + ExecutorService exec = Executors.newCachedThreadPool(); + exec.execute(new ThreadPoolTask()); + exec.shutdown(); + } +} + +class ThreadPoolTask implements Runnable { + @Override + public void run() { + Thread.currentThread().setUncaughtExceptionHandler(new ExceptionHandler()); + System.out.println(3 / 2); + System.out.println(3 / 0); + System.out.println(3 / 1); + } +} \ No newline at end of file diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/UncaughtExceptionHandler/InitiativeCaught.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/UncaughtExceptionHandler/InitiativeCaught.java new file mode 100644 index 00000000..2936b077 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/UncaughtExceptionHandler/InitiativeCaught.java @@ -0,0 +1,33 @@ +package cn.lastwhisper.concurrent.UncaughtExceptionHandler; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +public class InitiativeCaught { + public void threadDeal(Runnable r, Throwable t) { + System.out.println("==Exception: " + t.getMessage()); + } + + class InitialtiveThread implements Runnable { + @Override + public void run() { + Throwable thrown = null; + try { + System.out.println(3 / 2); + System.out.println(3 / 0); + System.out.println(3 / 1); + } catch (Throwable e) { + thrown = e; + } finally { + threadDeal(this, thrown); + } + } + } + + public static void main(String[] args) { + ExecutorService exec = Executors.newCachedThreadPool(); + exec.execute(new InitiativeCaught().new InitialtiveThread()); + exec.shutdown(); + } + +} \ No newline at end of file diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/UncaughtExceptionHandler/NoCaughtThread.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/UncaughtExceptionHandler/NoCaughtThread.java new file mode 100644 index 00000000..d0301798 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/UncaughtExceptionHandler/NoCaughtThread.java @@ -0,0 +1,14 @@ +package cn.lastwhisper.concurrent.UncaughtExceptionHandler; + +public class NoCaughtThread { + public static void main(String[] args) { + try { + Thread thread = new Thread(new Task()); + thread.start(); + } catch (Exception e) { + System.out.println("==Exception: " + e.getMessage()); + } + } + +} + diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/UncaughtExceptionHandler/README.md b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/UncaughtExceptionHandler/README.md new file mode 100644 index 00000000..a1adad8d --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/UncaughtExceptionHandler/README.md @@ -0,0 +1,3 @@ + +JAVA多线程之UncaughtExceptionHandler——处理非正常的线程中止 +https://blog.csdn.net/u013256816/article/details/50417822 diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/UncaughtExceptionHandler/Task.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/UncaughtExceptionHandler/Task.java new file mode 100644 index 00000000..a6f3b917 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/UncaughtExceptionHandler/Task.java @@ -0,0 +1,10 @@ +package cn.lastwhisper.concurrent.UncaughtExceptionHandler; + +public class Task implements Runnable { + @Override + public void run() { + System.out.println(3 / 2); + System.out.println(3 / 0); + System.out.println(3 / 1); + } + } \ No newline at end of file diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/UncaughtExceptionHandler/WitchCaughtThread.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/UncaughtExceptionHandler/WitchCaughtThread.java new file mode 100644 index 00000000..b12127fe --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/UncaughtExceptionHandler/WitchCaughtThread.java @@ -0,0 +1,18 @@ +package cn.lastwhisper.concurrent.UncaughtExceptionHandler; + +import java.lang.Thread.UncaughtExceptionHandler; + +public class WitchCaughtThread { + public static void main(String args[]) { + Thread thread = new Thread(new Task()); + thread.setUncaughtExceptionHandler(new ExceptionHandler()); + thread.start(); + } +} + +class ExceptionHandler implements UncaughtExceptionHandler { + @Override + public void uncaughtException(Thread t, Throwable e) { + System.out.println("==Exception: " + e.getMessage()); + } +} \ No newline at end of file diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/Daemon.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/Daemon.java new file mode 100644 index 00000000..21fd8394 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/Daemon.java @@ -0,0 +1,30 @@ +package cn.lastwhisper.concurrent.basic; + +public class Daemon { + /** + * Daemon线程是一种支持型线程,因为它主要被用作程序中后台调度以及支持性工作。这 + * 意味着,当一个Java虚拟机中不存在非Daemon线程的时候,Java虚拟机将会退出。可以通过调 + * 用Thread.setDaemon(true)将线程设置为Daemon线程。 + * + * 虚拟机没有非Daemon线程,虚拟机需要退出,此时所有Daemon线程都需要立即终止, + * 因此DaemonRunner立即终止,但是DaemonRunner中的finally块并没有执行。 + * @param args + */ + public static void main(String[] args) { + Thread thread = new Thread(new DaemonRunner(), + "DaemonRunner"); + thread.setDaemon(true); + thread.start(); + } + + static class DaemonRunner implements Runnable { + @Override + public void run() { + try { + SleepUtils.second(10); + } finally { + System.out.println("DaemonThread finally run."); + } + } + } +} \ No newline at end of file diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/DeadLockDemo.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/DeadLockDemo.java index 9e297586..a8c89314 100644 --- a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/DeadLockDemo.java +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/DeadLockDemo.java @@ -21,8 +21,8 @@ public static void main(String[] args) { class HoldLock implements Runnable { - private String lockA; - private String lockB; + private final String lockA; + private final String lockB; public HoldLock(String lockA, String lockB) { this.lockA = lockA; diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/Deprecated.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/Deprecated.java new file mode 100644 index 00000000..e08b3f42 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/Deprecated.java @@ -0,0 +1,41 @@ +package cn.lastwhisper.concurrent.basic; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.concurrent.TimeUnit; + +public class Deprecated { + public static void main(String[] args) throws Exception { + DateFormat format = new SimpleDateFormat("HH:mm:ss"); + Thread printThread = new Thread(new Runner(), + "PrintThread"); + printThread.setDaemon(true); + printThread.start(); + TimeUnit.SECONDS.sleep(3); + // 将PrintThread进行暂停,输出内容工作停止 + printThread.suspend(); + System.out.println("main suspend PrintThread at " + format.format(new Date())); + TimeUnit.SECONDS.sleep(3); + // 将PrintThread进行恢复,输出内容继续 + printThread.resume(); + System.out.println("main resume PrintThread at " + format.format(new Date())); + TimeUnit.SECONDS.sleep(3); + // 将PrintThread进行终止,输出内容停止 + printThread.stop(); + System.out.println("main stop PrintThread at " + format.format(new Date())); + TimeUnit.SECONDS.sleep(3); + } + + static class Runner implements Runnable { + @Override + public void run() { + DateFormat format = new SimpleDateFormat("HH:mm:ss"); + while (true) { + System.out.println(Thread.currentThread().getName() + " Run at " + + format.format(new Date())); + SleepUtils.second(1); + } + } + } +} \ No newline at end of file diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/Interrupted/InterruptLockSupportDemo.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/Interrupted/InterruptLockSupportDemo.java new file mode 100644 index 00000000..f7bfcc90 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/Interrupted/InterruptLockSupportDemo.java @@ -0,0 +1,18 @@ +package cn.lastwhisper.concurrent.basic.Interrupted; + +import java.util.concurrent.locks.LockSupport; + +public class InterruptLockSupportDemo { + public static void main(String[] args) throws InterruptedException { + Thread t1 = new Thread(() -> { + System.out.println("t1 come in"); + LockSupport.park(); + System.out.println("t1 go out"); + }, "t1"); + t1.start(); + + Thread.sleep(1000); + t1.interrupt(); + Thread.sleep(1000); + } +} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/Interrupted/InterruptNotAliveDemo.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/Interrupted/InterruptNotAliveDemo.java new file mode 100644 index 00000000..75378fc7 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/Interrupted/InterruptNotAliveDemo.java @@ -0,0 +1,24 @@ +package cn.lastwhisper.concurrent.basic.Interrupted; + +public class InterruptNotAliveDemo { + private static class A extends Thread { + @Override + public void run() { + } + } + + public static void test() throws InterruptedException { + A a = new A(); + a.interrupt(); + System.out.println(a.isInterrupted()); + + a.start(); + Thread.sleep(100); + a.interrupt(); + System.out.println(a.isInterrupted()); + } + + public static void main(String[] args) throws InterruptedException { + test(); + } +} \ No newline at end of file diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/Interrupted/InterruptReadCancelDemo.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/Interrupted/InterruptReadCancelDemo.java new file mode 100644 index 00000000..da20d31c --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/Interrupted/InterruptReadCancelDemo.java @@ -0,0 +1,36 @@ +package cn.lastwhisper.concurrent.basic.Interrupted; + +import java.io.IOException; + +public class InterruptReadCancelDemo { + private static class A extends Thread { + @Override + public void run() { + while (!Thread.currentThread().isInterrupted()) { + try { + System.out.println("a线程等待输入:"); + System.out.println(System.in.read());//wait input + } catch (IOException e) { + e.printStackTrace(); + } + } + System.out.println("a线程 exit"); + } + + public void cancel() { + try { + System.in.close(); + } catch (IOException e) { + } + interrupt(); + } + } + + public static void main(String[] args) throws InterruptedException { + A t = new A(); + t.start(); + Thread.sleep(100); + System.out.println("main线程对a线程input进行close"); + t.cancel(); + } +} \ No newline at end of file diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/Interrupted/InterruptReadDemo.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/Interrupted/InterruptReadDemo.java new file mode 100644 index 00000000..ab690710 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/Interrupted/InterruptReadDemo.java @@ -0,0 +1,28 @@ +package cn.lastwhisper.concurrent.basic.Interrupted; + +import java.io.IOException; + +public class InterruptReadDemo { + private static class A extends Thread { + @Override + public void run() { + while (!Thread.currentThread().isInterrupted()) { + try { + System.out.println("a线程等待输入:"); + System.out.println(System.in.read());//wait input + } catch (IOException e) { + e.printStackTrace(); + } + } + System.out.println("a线程 exit"); + } + } + + public static void main(String[] args) throws InterruptedException { + A a = new A(); + a.start(); + Thread.sleep(100); + System.out.println("main线程对a线程发起中断信号"); + a.interrupt(); + } +} \ No newline at end of file diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/Interrupted/InterruptRunnableDemo.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/Interrupted/InterruptRunnableDemo.java new file mode 100644 index 00000000..f74134ac --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/Interrupted/InterruptRunnableDemo.java @@ -0,0 +1,23 @@ +package cn.lastwhisper.concurrent.basic.Interrupted; + +public class InterruptRunnableDemo extends Thread { + @Override + public void run() { + while (!Thread.currentThread().isInterrupted()) { + // ... 单次循环代码 + System.out.println("loop..."); + } + System.out.println("done "); + } + + /** + * 如果线程在运行中,interrupt()只是会设置线程的中断标志位,没有任何其它作用。 + * 线程应该在运行过程中合适的位置检查中断标志位,比如说,如果主体代码是一个循环,可以在循环开始处进行检查 + */ + public static void main(String[] args) throws InterruptedException { + Thread thread = new InterruptRunnableDemo(); + thread.start(); + Thread.sleep(1000); + thread.interrupt(); + } +} \ No newline at end of file diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/Interrupted/InterruptSynchronizedDemo.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/Interrupted/InterruptSynchronizedDemo.java new file mode 100644 index 00000000..0c155cd8 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/Interrupted/InterruptSynchronizedDemo.java @@ -0,0 +1,32 @@ + +package cn.lastwhisper.concurrent.basic.Interrupted; + +public class InterruptSynchronizedDemo { + private static final Object lock = new Object();//monitor + private static class BlockedThread extends Thread { + @Override + public void run() { + //等待lock锁 + synchronized (lock) { + //等待标志位被置为true + while (!Thread.currentThread().isInterrupted()) { + } + } + System.out.println("exit"); + } + } + public static void test() throws InterruptedException { + synchronized (lock) {//获取锁 + BlockedThread blockedThread = new BlockedThread(); + blockedThread.start(); + Thread.sleep(1000); + //blockedThread在等待lock锁,interrupt 无法中断 + blockedThread.interrupt(); + //blockedThread线程加入当前线程,main线程等待blockedThread执行完毕,才会继续往下执行 + blockedThread.join(); + } + } + public static void main(String[] args) throws InterruptedException { + test(); + } +} \ No newline at end of file diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/Interrupted/InterruptWaitingDemo.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/Interrupted/InterruptWaitingDemo.java new file mode 100644 index 00000000..959e5ad3 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/Interrupted/InterruptWaitingDemo.java @@ -0,0 +1,37 @@ +package cn.lastwhisper.concurrent.basic.Interrupted; + +public class InterruptWaitingDemo extends Thread { + + //抛出中断异常,由调用者捕获 + public void interruptibleMethod() throws InterruptedException{ + // ... 包含wait, join 或 sleep 方法 + Thread.sleep(1000); + } + + // 中断异常,由自己捕获,自己处理 + @Override + public void run() { + while (!Thread.currentThread().isInterrupted()) { + try { + // 模拟任务代码 + Thread.sleep(2000); + } catch (InterruptedException e) { + // ... 清理操作 + System.out.println("当前线程执行中,发生中断异常,当前Interrupted:"+ isInterrupted());//false + // 重设中断标志位为true + Thread.currentThread().interrupt(); + } + } + System.out.println("当前线程执行即将结束,当前Interrupted:"+isInterrupted());//true + } + + public static void main(String[] args) { + InterruptWaitingDemo thread = new InterruptWaitingDemo(); + thread.start(); + try { + Thread.sleep(100); + } catch (InterruptedException e) { + } + thread.interrupt(); + } +} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/Interrupted/README.md b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/Interrupted/README.md new file mode 100644 index 00000000..aba045c6 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/Interrupted/README.md @@ -0,0 +1,45 @@ +# 线程不同状态对中断的反应 + +## RUNNABLE + +线程在运行或具备运行条件只是在等待操作系统调度 +案例:InterruptRunnableDemo; +如果线程在RUNNABLE,interrupt()只是会设置线程的中断标志位,没有任何其它作用。 + +## WAITING/TIMED_WAITING: + +线程在等待某个条件或超时 +1、案例:InterruptWaitingDemo + +在这些状态时,对线程对象调用interrupt()会使得该线程抛出InterruptedException,抛出异常后,中断标志位会被清空(线程的中断标志位会由true重置为false,因为线程为了处理异常已经重新处于就绪状态。 + +捕获到InterruptedException,通常表示希望结束该线程,线程大概有两种处理方式: +(1)向上传递该异常,这使得该方法也变成了一个可中断的方法,需要调用者进行处理 +(2)有些情况,不能向上传递异常,比如Thread的run方法,它的声明是固定的,不能抛出任何受检异常,这时,应该捕获异常,进行合适的清理操作,清理后,一般应该调用Thread的interrupt方法再次设置中断标志位,使得当前线程知道自己发生了中断。 + +2、案例:InterruptLockSupportDemo +LockSupport的线程被中断后直接唤醒放行 + +## BLOCKED + +线程在等待锁,试图进入同步块 +案例:InterruptSynchronizedDemo +如果线程在等待锁,对线程对象调用interrupt()只是会设置线程的中断标志位,线程依然会处于BLOCKED状态,也就是说,interrupt()并不能使一个在等待锁的线程真正”中断”。 + +## NEW/TERMINATED + +线程还未启动或已结束 +如果线程尚未启动(NEW),或者已经结束(TERMINATED),则调用interrupt()对它没有任何效果,中断标志位也不会被设置。 + +## 特殊的RUNNABLE +案例: +- InterruptReadDemo 无法通过中断取消 +- InterruptReadCancelDemo +Java线程在进行io操作时,在java中的状态也是RUNNABLE + +1. 实现java.nio.channels.InterruptibleChannel接口的通道是可中断的:如果某个线程在可中断通道上因调用某个阻塞的 I/O 操作(常见的操作一般有这些:serverSocketChannel. accept()、socketChannel.connect、socketChannel.open、socketChannel.read、socketChannel.write、fileChannel.read、fileChannel.write)而进入阻塞状态,而另一个线程又调用了该阻塞线程的 interrupt 方法,这将导致该通道被关闭,并且已阻塞线程接将会收到ClosedByInterruptException,并且设置已阻塞线程的中断状态。另外,如果已设置某个线程的中断状态并且它在通道上调用某个阻塞的 I/O 操作,则该通道将关闭并且该线程立即接收到 ClosedByInterruptException;并仍然设置其中断状态。 +2. 如果线程阻塞于Selector调用,则线程的中断标志位会被设置,同时,阻塞的调用会立即返回。 +3. InputStream的read调用,该操作是不可中断的,如果流中没有数据,read会阻塞 (但线程状态依然是RUNNABLE),且不响应interrupt(),与synchronized类似,调用interrupt()只会设置线程的中断标志,同时由于read阻塞,当前线程也无法检测中断标志。 + + + diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/Interrupted/Shutdown.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/Interrupted/Shutdown.java new file mode 100644 index 00000000..48e7d1c0 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/Interrupted/Shutdown.java @@ -0,0 +1,32 @@ +package cn.lastwhisper.concurrent.basic.Interrupted; + +public class Shutdown { + + public static void main(String[] args) throws InterruptedException { + Thread t1 = new Thread(new Runnable() { + @Override + public void run() { + while (true) { + // 中断的比stop更为强劲。如果在循环体中,出现了类似于wait()方法或者sleep(方法这样的操作,则只能通过中断来识别了。 + if (Thread.currentThread().isInterrupted()) { + System.out.println("Interrupted!"); + break; + } + try { + // 当线程在waiting、time_waiting时,如果被中断,就会产生InterruptedException + Thread.sleep(2000); + } catch (InterruptedException e) { + System.out.println("Interrupted When Sleep"); + // 设置中断状态 + Thread.currentThread().interrupt(); + } + } + } + }, "Shutdown"); + + t1.start(); + Thread.sleep(2000); + t1.interrupt(); + } + +} \ No newline at end of file diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/JoinDemo.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/JoinDemo.java deleted file mode 100644 index 638e8362..00000000 --- a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/JoinDemo.java +++ /dev/null @@ -1,40 +0,0 @@ -package cn.lastwhisper.concurrent.basic; - -public class JoinDemo { - private class A extends Thread { - @Override - public void run() { - System.out.println("A"); - } - } - - private class B extends Thread { - private A a; - - B(A a) { - this.a = a; - } - - @Override - public void run() { - try { - a.join(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - System.out.println("B"); - } - } - - public void test() { - A a = new A(); - B b = new B(a); - b.start(); - a.start(); - } - - public static void main(String[] args) { - JoinDemo example = new JoinDemo(); - example.test(); - } -} \ No newline at end of file diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/README.md b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/README.md new file mode 100644 index 00000000..ad215bfa --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/README.md @@ -0,0 +1,10 @@ +# basic +1. communicate ;线程通信相关 +2. createthread;线程创建相关 +3. Interrupted ;线程中断相关 +4. state ;线程状态相关 +5. syncronized ;线程锁、锁升级相关 +6. threadlocal ; +7. DeadLockDemo;死锁 demo +8. Daemon;守护线程 +9. Deprecated;线程暂停、恢复和停止对应线程Thread的API就是suspend()、resume()和stop(),这些方法已经被废弃 \ No newline at end of file diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/SleepUtils.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/SleepUtils.java new file mode 100644 index 00000000..1c37fb47 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/SleepUtils.java @@ -0,0 +1,13 @@ +package cn.lastwhisper.concurrent.basic; + +import java.util.concurrent.TimeUnit; + +public class SleepUtils { + public static void second(long seconds) { + try { + TimeUnit.SECONDS.sleep(seconds); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } +} \ No newline at end of file diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/TestThread8Monitor.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/TestThread8Monitor.java deleted file mode 100644 index bcfdfd6e..00000000 --- a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/TestThread8Monitor.java +++ /dev/null @@ -1,61 +0,0 @@ -package cn.lastwhisper.concurrent.basic; - -/** - * 前置知识: - * 对象锁: - * 1)对象锁也叫方法锁,是针对一个对象实例的,它只在该对象的某个内存位置声明一个标识该对象是否拥有锁,所有它只会锁住当前的对象,而并不会对其他对象实例的锁产生任何影响,不同对象访问同一个被synchronized修饰的方法的时候不会阻塞 - * 2)synchronized修饰的非静态方法,即非静态同步方法 - * 3)synchronized(this),即非静态同步代码块 - * 类锁: - * 1)synchronized static 修饰的静态方法,即静态同步方法 - * 2)synchronized(类名.class),即静态同步代码块 - * 题目:判断打印的 1 or 2 or 3? - * 1. 两个普通同步方法,两个线程,打印? //one two - * 2. 新增 Thread.sleep() 给 getOne() ,打印? //one two - * 3. 新增普通方法 getThree() , 打印? //three one two - * 4. 两个普通同步方法,两个 Number 对象,打印? //two one - * 5. 修改 getOne() 为静态同步方法,打印? //two one - * 6. 修改两个方法均为静态同步方法,一个 Number 对象? //one two - * 7. 一个静态同步方法,一个非静态同步方法,两个 Number 对象? //two one - * 8. 两个静态同步方法,两个 Number 对象? //one two - * @author lastwhisper - */ -public class TestThread8Monitor { - public static void main(String[] args) { - Number number1 = new Number(); - Number number2 = new Number(); - - new Thread(new Runnable() { - @Override - public void run() { - number1.getOne(); - } - }).start(); - - new Thread(new Runnable() { - @Override - public void run() { - number2.getTwo(); - } - }).start(); - } -} - -class Number { - public static synchronized void getOne(){ - try { - Thread.sleep(50); - } catch (InterruptedException e) { - e.printStackTrace(); - } - System.out.println("one"); - } - - public void getTwo() { - System.out.println("two"); - } - - public void getThree() { - System.out.println("three"); - } -} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/ThreadDemo.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/ThreadDemo.java deleted file mode 100644 index 2cdc5fec..00000000 --- a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/ThreadDemo.java +++ /dev/null @@ -1,14 +0,0 @@ -package cn.lastwhisper.concurrent.basic; - -/** - * @author lastwhisper - */ -public class ThreadDemo { - public static void main(String[] args){ - // 继承Thread - // 实现Runnable - // 实现Callable - // - System.out.println(Runtime.getRuntime().availableProcessors()); - } -} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/communicate/Join.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/communicate/Join.java new file mode 100644 index 00000000..3cbd2128 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/communicate/Join.java @@ -0,0 +1,32 @@ +package cn.lastwhisper.concurrent.basic.communicate; + +public class Join { + public static void main(String[] args){ + System.out.println("MainThread run start."); + + //启动一个子线程 + Thread lock = new Thread(new Runnable() { + @Override + public void run() { + System.out.println("threadA run start."); + try { + Thread.sleep(1000); + } catch (Exception e) { + e.printStackTrace(); + } + System.out.println("threadA run finished."); + } + }); + lock.start(); + + System.out.println("MainThread join before"); + try { + // main持有lock线程的锁,lock.wait() 阻塞main线程 + // lock线程执行完了,会调用lock.notify_all(thread),唤醒main线程 + lock.join(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + System.out.println("MainThread run finished."); + } +} \ No newline at end of file diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/communicate/Piped.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/communicate/Piped.java new file mode 100644 index 00000000..129d1eef --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/communicate/Piped.java @@ -0,0 +1,44 @@ +package cn.lastwhisper.concurrent.basic.communicate; + +import java.io.IOException; +import java.io.PipedReader; +import java.io.PipedWriter; + +public class Piped { + + public static void main(String[] args) throws Exception { + PipedWriter out = new PipedWriter(); + PipedReader in = new PipedReader(); + // 将输出流和输入流进行连接,否则在使用时会抛出IOException + out.connect(in); + + Thread printThread = new Thread(new Print(in), "PrintThread"); + printThread.start(); + int receive = 0; + try { + while ((receive = System.in.read()) != -1) { + out.write(receive); + } + } finally { + out.close(); + } + } + + static class Print implements Runnable { + private PipedReader in; + + public Print(PipedReader in) { + this.in = in; + } + + public void run() { + int receive = 0; + try { + while ((receive = in.read()) != -1) { + System.out.print((char) receive); + } + } catch (IOException ex) { + } + } + } +} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/communicate/README.md b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/communicate/README.md new file mode 100644 index 00000000..b27131a7 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/communicate/README.md @@ -0,0 +1,5 @@ +# 线程间通信 +1. WaitNotify +2. Join +3. Piped;管道输入/输出流和普通的文件输入/输出流或者网络输入/输出流不同之处在于,它主要 + 用于线程之间的数据传输,而传输的媒介为内存。 diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/communicate/WaitNotify.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/communicate/WaitNotify.java new file mode 100644 index 00000000..38a6dd1e --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/communicate/WaitNotify.java @@ -0,0 +1,61 @@ +package cn.lastwhisper.concurrent.basic.communicate; + +import cn.lastwhisper.concurrent.basic.SleepUtils; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.concurrent.TimeUnit; + +public class WaitNotify { + static boolean flag = true; + static final Object lock = new Object(); + + public static void main(String[] args) throws Exception { + Thread waitThread = new Thread(new Wait(), "WaitThread"); + waitThread.start(); + TimeUnit.SECONDS.sleep(1); + + Thread notifyThread = new Thread(new Notify(), "NotifyThread"); + notifyThread.start(); + } + + static class Wait implements Runnable { + public void run() { + // 加锁,拥有lock的Monitor + synchronized (lock) { + // 当条件不满足时,继续wait,同时释放了lock的锁 + while (flag) { + try { + System.out.println(Thread.currentThread() + " flag is true. wait @ " + + new SimpleDateFormat("HH:mm:ss").format(new Date())); + lock.wait(); + } catch (InterruptedException e) { + } + } + // 条件满足时,完成工作 + System.out.println(Thread.currentThread() + " flag is false. running @ " + + new SimpleDateFormat("HH:mm:ss").format(new Date())); + } + } + } + + static class Notify implements Runnable { + public void run() { + // 加锁,拥有lock的Monitor + synchronized (lock) { + // 获取lock的锁,然后进行通知,通知时不会释放lock的锁, + // 直到当前线程释放了lock后,WaitThread才能从wait方法中返回 + System.out.println(Thread.currentThread() + " hold lock. notify @ " + new SimpleDateFormat("HH:mm:ss").format(new Date())); + lock.notifyAll(); + flag = false; + SleepUtils.second(5); + } + // 再次加锁 + synchronized (lock) { + System.out.println(Thread.currentThread() + " hold lock again. sleep @ " + + new SimpleDateFormat("HH:mm:ss").format(new Date())); + SleepUtils.second(5); + } + } + } +} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/executor/TestCallable.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/createthread/TestCallable.java similarity index 86% rename from java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/executor/TestCallable.java rename to java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/createthread/TestCallable.java index ddc0821d..2ffa2e07 100644 --- a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/executor/TestCallable.java +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/createthread/TestCallable.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.concurrent.juc.executor; +package cn.lastwhisper.concurrent.basic.createthread; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; @@ -19,9 +19,7 @@ public static void main(String[] args) { Integer result = futureTask.get();// FutureTask可以用于闭锁 System.out.println(result); System.out.println("主线程拿到返回值"); - } catch (InterruptedException e) { - e.printStackTrace(); - } catch (ExecutionException e) { + } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/state/ThreadState.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/state/ThreadState.java new file mode 100644 index 00000000..28399a08 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/state/ThreadState.java @@ -0,0 +1,107 @@ +package cn.lastwhisper.concurrent.basic.state; + +import cn.lastwhisper.concurrent.basic.SleepUtils; +import org.apache.tomcat.util.http.fileupload.IOUtils; + +import java.io.IOException; +import java.net.ServerSocket; +import java.net.Socket; +import java.util.Scanner; + +/** + * 线程状态 + * + * @author cunchang + * @date 2022/4/4 10:26 PM + */ +public class ThreadState { + + public static void main(String[] args) { + new Thread(new TimeWaiting(), "TimeWaitingThread-TIMED_WAITING").start(); + new Thread(new Waiting(), "WaitingThread-WAITING").start(); + // 使用两个Blocked线程,一个获取锁成功,另一个被阻塞 + new Thread(new Blocked(), "BlockedThread-1").start(); + new Thread(new Blocked(), "BlockedThread-2").start(); + new Thread(new IOBlockedState(), "IOBlockedThread-RUNNABLE").start(); + new Thread(new SocketBlockedState(), "SocketBlockedThread-RUNNABLE").start(); + } + + // 该线程不断地进行睡眠 + static class TimeWaiting implements Runnable { + @Override + public void run() { + while (true) { + SleepUtils.second(100); + } + } + } + + // 该线程在Waiting.class实例上等待 + static class Waiting implements Runnable { + @Override + public void run() { + while (true) { + synchronized (Waiting.class) { + try { + Waiting.class.wait(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + } + + } + + // 该线程在Blocked.class实例上加锁后,不会释放该锁 + static class Blocked implements Runnable { + @Override + public void run() { + synchronized (Blocked.class) { + while (true) { + SleepUtils.second(100); + } + } + } + } + + // os io阻塞 + static class IOBlockedState implements Runnable { + Scanner in = new Scanner(System.in); + @Override + public void run() { + try { + // 命令行中的阻塞读 + String input = in.nextLine(); + System.out.println(input); + } catch (Exception e) { + e.printStackTrace(); + } finally { + IOUtils.closeQuietly(in); + } + } + } + + static class SocketBlockedState implements Runnable { + @Override + public void run() { + ServerSocket serverSocket = null; + try { + serverSocket = new ServerSocket(10086); + while (true) { + // 阻塞的accept方法 + Socket socket = serverSocket.accept(); + } + } catch (IOException e) { + e.printStackTrace(); + } finally { + try { + serverSocket.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + } + +} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/state/jstack.txt b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/state/jstack.txt new file mode 100644 index 00000000..87c6875b --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/state/jstack.txt @@ -0,0 +1,62 @@ + +"SocketBlockedThread-RUNNABLE" #15 prio=5 os_prio=31 tid=0x00007f86ae0c4000 nid=0x9a13 runnable [0x0000000305f92000] + java.lang.Thread.State: RUNNABLE + at java.net.PlainSocketImpl.socketAccept(Native Method) + at java.net.AbstractPlainSocketImpl.accept(AbstractPlainSocketImpl.java:409) + at java.net.ServerSocket.implAccept(ServerSocket.java:545) + at java.net.ServerSocket.accept(ServerSocket.java:513) + at cn.lastwhisper.concurrent.basic.state.ThreadState$SocketBlockedState.run(ThreadState.java:92) + at java.lang.Thread.run(Thread.java:748) + +"IOBlockedThread-RUNNABLE" #14 prio=5 os_prio=31 tid=0x00007f86ae0c3000 nid=0x9c1f runnable [0x0000000305e8f000] + java.lang.Thread.State: RUNNABLE + at java.io.FileInputStream.readBytes(Native Method) + at java.io.FileInputStream.read(FileInputStream.java:255) + at java.io.BufferedInputStream.read1(BufferedInputStream.java:284) + at java.io.BufferedInputStream.read(BufferedInputStream.java:345) + - locked <0x000000076ab21a38> (a java.io.BufferedInputStream) + at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284) + at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326) + at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178) + - locked <0x000000076abde010> (a java.io.InputStreamReader) + at java.io.InputStreamReader.read(InputStreamReader.java:184) + at java.io.Reader.read(Reader.java:100) + at java.util.Scanner.readInput(Scanner.java:804) + at java.util.Scanner.findWithinHorizon(Scanner.java:1685) + at java.util.Scanner.nextLine(Scanner.java:1538) + at cn.lastwhisper.concurrent.basic.state.ThreadState$IOBlockedState.run(ThreadState.java:74) + at java.lang.Thread.run(Thread.java:748) + +"BlockedThread-2" #13 prio=5 os_prio=31 tid=0x00007f86ae0b5800 nid=0x6303 waiting for monitor entry [0x0000000305d8c000] + java.lang.Thread.State: BLOCKED (on object monitor) + at cn.lastwhisper.concurrent.basic.state.ThreadState$Blocked.run(ThreadState.java:61) + - waiting to lock <0x000000076abd3f90> (a java.lang.Class for cn.lastwhisper.concurrent.basic.state.ThreadState$Blocked) + at java.lang.Thread.run(Thread.java:748) + +"BlockedThread-1" #12 prio=5 os_prio=31 tid=0x00007f86ae0b4800 nid=0x6203 waiting on condition [0x0000000305c89000] + java.lang.Thread.State: TIMED_WAITING (sleeping) + at java.lang.Thread.sleep(Native Method) + at java.lang.Thread.sleep(Thread.java:340) + at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386) + at cn.lastwhisper.concurrent.basic.state.SleepUtils.second(SleepUtils.java:8) + at cn.lastwhisper.concurrent.basic.state.ThreadState$Blocked.run(ThreadState.java:61) + - locked <0x000000076abd3f90> (a java.lang.Class for cn.lastwhisper.concurrent.basic.state.ThreadState$Blocked) + at java.lang.Thread.run(Thread.java:748) + +"WaitingThread" #11 prio=5 os_prio=31 tid=0x00007f86be835000 nid=0x9f23 in Object.wait() [0x0000000305b86000] + java.lang.Thread.State: WAITING (on object monitor) + at java.lang.Object.wait(Native Method) + - waiting on <0x000000076abcf4d8> (a java.lang.Class for cn.lastwhisper.concurrent.basic.state.ThreadState$Waiting) + at java.lang.Object.wait(Object.java:502) + at cn.lastwhisper.concurrent.basic.state.ThreadState$Waiting.run(ThreadState.java:45) + - locked <0x000000076abcf4d8> (a java.lang.Class for cn.lastwhisper.concurrent.basic.state.ThreadState$Waiting) + at java.lang.Thread.run(Thread.java:748) + +"TimeWaitingThread" #10 prio=5 os_prio=31 tid=0x00007f86be0bf800 nid=0xa05f waiting on condition [0x0000000305a83000] + java.lang.Thread.State: TIMED_WAITING (sleeping) + at java.lang.Thread.sleep(Native Method) + at java.lang.Thread.sleep(Thread.java:340) + at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386) + at cn.lastwhisper.concurrent.basic.state.SleepUtils.second(SleepUtils.java:8) + at cn.lastwhisper.concurrent.basic.state.ThreadState$TimeWaiting.run(ThreadState.java:33) + at java.lang.Thread.run(Thread.java:748) diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/synchronized1/Juc_PrintMarkWord.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/synchronized1/Juc_PrintMarkWord.java new file mode 100644 index 00000000..b714be92 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/synchronized1/Juc_PrintMarkWord.java @@ -0,0 +1,38 @@ +package cn.lastwhisper.concurrent.basic.synchronized1; + +import org.openjdk.jol.info.ClassLayout; + +/** + * + * @author cunchang + * @date 2022/3/2 8:26 PM + */ +public class Juc_PrintMarkWord { + + public static void main(String[] args) throws InterruptedException { + // 需要sleep一段时间,因为java对于偏向锁的启动是在启动几秒之后才激活。 + // 因为jvm启动的过程中会有大量的同步块,且这些同步块都有竞争,如果一启动就启动 + // 偏向锁,会出现很多没有必要的锁撤销 + Thread.sleep(5000); + T t = new T(); + //未出现任何获取锁的时候 + System.out.println(ClassLayout.parseInstance(t).toPrintable()); + synchronized (t){ + // 获取一次锁之后 + System.out.println(ClassLayout.parseInstance(t).toPrintable()); + } + // 输出hashcode + System.out.println("hashCode:"+t.hashCode()); + // 计算了hashcode之后,将导致锁的升级 + // 锁已经释放了,输出无锁markword + System.out.println(ClassLayout.parseInstance(t).toPrintable()); + synchronized (t){ + // 再次获取锁,锁升级,轻量级锁 + System.out.println(ClassLayout.parseInstance(t).toPrintable()); + } + } +} + +class T{ + int i = 0; +} \ No newline at end of file diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/synchronized1/README.md b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/synchronized1/README.md new file mode 100644 index 00000000..ac8baff2 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/synchronized1/README.md @@ -0,0 +1,8 @@ +# synchronize原理 + +使用jol-core + +1. T0_ObjectSize;无锁、可偏向锁 +2. T0_BasicLock;偏向锁-》轻量级锁 +3. T0_heavyWeightMonitor;自旋锁后未获得到锁,升级重量级锁, +4. Juc_PrintMarkWord;对象处在偏向锁,调用hashcode,会升级为轻量级锁,因为偏向锁无法记录hashcode。 diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/synchronized1/T0_BasicLock.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/synchronized1/T0_BasicLock.java new file mode 100644 index 00000000..41dde330 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/synchronized1/T0_BasicLock.java @@ -0,0 +1,37 @@ +package cn.lastwhisper.concurrent.basic.synchronized1; + +import lombok.extern.slf4j.Slf4j; +import org.openjdk.jol.info.ClassLayout; + + +@Slf4j +public class T0_BasicLock { + public static void main(String[] args) { + try { + Thread.sleep(5000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + Object o = new Object(); + log.info(ClassLayout.parseInstance(o).toPrintable()); + + new Thread(()->{ + synchronized (o){ + log.info(ClassLayout.parseInstance(o).toPrintable()); + } + }).start(); + + try { + Thread.sleep(2000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + log.info(ClassLayout.parseInstance(o).toPrintable()); + new Thread(()->{ + synchronized (o){ + log.info(ClassLayout.parseInstance(o).toPrintable()); + } + }).start(); + } +} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/synchronized1/T0_ObjectSize.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/synchronized1/T0_ObjectSize.java new file mode 100644 index 00000000..a32c3d8c --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/synchronized1/T0_ObjectSize.java @@ -0,0 +1,37 @@ +package cn.lastwhisper.concurrent.basic.synchronized1; + +import org.openjdk.jol.info.ClassLayout; + +import java.util.concurrent.TimeUnit; + +/** + * 打印object信息 + * + * @author cunchang + * @date 2022/3/2 8:26 PM + */ +public class T0_ObjectSize { + + public static void main(String[] args) throws InterruptedException { + // 1、无锁;未启用偏向锁 +// Object o = new Object(); +// System.out.println(ClassLayout.parseInstance(o).toPrintable()); + // 2、有锁;未启用偏向锁 + // 偏向锁会延迟使用,所以无锁直接升级为轻量级锁 +// Object o = new Object(); +// System.out.println(ClassLayout.parseInstance(o).toPrintable()); +// synchronized (o) { +// System.out.println(ClassLayout.parseInstance(o).toPrintable()); +// } + // 3、有锁;启用偏向锁 + // 延迟执行,让jvm启动偏向锁 + TimeUnit.SECONDS.sleep(5); + Object object = new Object(); + object.notify(); + object.notifyAll(); + System.out.println(ClassLayout.parseInstance(object).toPrintable()); + synchronized (object){ + System.out.println(ClassLayout.parseInstance(object).toPrintable()); + } + } +} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/synchronized1/T0_ObjectStackAlloc.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/synchronized1/T0_ObjectStackAlloc.java new file mode 100644 index 00000000..30aaf532 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/synchronized1/T0_ObjectStackAlloc.java @@ -0,0 +1,44 @@ +package cn.lastwhisper.concurrent.basic.synchronized1; + + +public class T0_ObjectStackAlloc { + + /** + * 进行两种测试 + * 关闭逃逸分析,同时调大堆空间,避免堆内GC的发生,如果有GC信息将会被打印出来 + * VM运行参数:-Xmx4G -Xms4G -XX:-DoEscapeAnalysis -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError + * + * 开启逃逸分析 + * VM运行参数:-Xmx4G -Xms4G -XX:+DoEscapeAnalysis -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError + * + * 执行main方法后 + * jps 查看进程 + * jmap -histo 进程ID + */ + public static void main(String[] args) { + long start = System.currentTimeMillis(); + for (int i = 0; i < 500000; i++) { + alloc(); + } + long end = System.currentTimeMillis(); + //查看执行时间 + System.out.println("cost-time " + (end - start) + " ms"); + try { + Thread.sleep(100000); + } catch (InterruptedException e1) { + e1.printStackTrace(); + } + } + + private static TulingStudent alloc() { + //Jit对编译时会对代码进行 逃逸分析 + //并不是所有对象存放在堆区,有的一部分存在线程栈空间 + TulingStudent student = new TulingStudent(); + return student; + } + + static class TulingStudent { + private String name; + private int age; + } +} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/synchronized1/T0_heavyWeightMonitor.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/synchronized1/T0_heavyWeightMonitor.java new file mode 100644 index 00000000..27470c8d --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/synchronized1/T0_heavyWeightMonitor.java @@ -0,0 +1,45 @@ +package cn.lastwhisper.concurrent.basic.synchronized1; + +import org.openjdk.jol.info.ClassLayout; + + +public class T0_heavyWeightMonitor { + + public static void main(String[] args) throws InterruptedException { + Thread.sleep(5000); + Object a = new Object(); + + Thread thread1 = new Thread(){ + @Override + public void run() { + synchronized (a){ + System.out.println("thread1 locking"); + System.out.println(ClassLayout.parseInstance(a).toPrintable()); + try { + //让线程晚点儿死亡,造成锁的竞争 + Thread.sleep(2000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + }; + Thread thread2 = new Thread(){ + @Override + public void run() { + synchronized (a){ + System.out.println("thread2 locking"); + System.out.println(ClassLayout.parseInstance(a).toPrintable()); + try { + Thread.sleep(2000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + }; + thread1.start(); + thread2.start(); + } + +} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/threadlocal/AlibabaThreadLocalDemo.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/threadlocal/AlibabaThreadLocalDemo.java new file mode 100644 index 00000000..faa2e44f --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/threadlocal/AlibabaThreadLocalDemo.java @@ -0,0 +1,62 @@ +package cn.lastwhisper.concurrent.basic.threadlocal; + +import com.alibaba.ttl.TransmittableThreadLocal; +import com.alibaba.ttl.TtlRunnable; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +/** + * @author cunchang + * @date 2022/4/28 7:54 PM + */ +public class AlibabaThreadLocalDemo { + public static void main(String[] args) throws InterruptedException { + final TransmittableThreadLocal context = new TransmittableThreadLocal<>(); + context.set(new Span("xiexiexie")); + //输出 xiexiexie + Object o = context.get(); + System.out.println("main get Span:"+o); + Runnable runnable = new Runnable() { + @Override + public void run() { + System.out.println("========"); + Object o = context.get(); + System.out.println("t get Span:"+o); + context.set(new Span("zhangzhangzhang")); + o = context.get(); + System.out.println("t update Span:"+o); + } + }; + + ExecutorService executorService = Executors.newFixedThreadPool(1); + executorService.submit(TtlRunnable.get(runnable)); + TimeUnit.SECONDS.sleep(1); + executorService.submit(TtlRunnable.get(runnable)); + TimeUnit.SECONDS.sleep(1); + System.out.println("========"); + Span span = context.get(); + System.out.println("main last again get Span:"+o); + + + executorService.shutdown(); + } + + static class Span { + public String name; + public int age; + + public Span(String name) { + this.name = name; + } + + @Override + public String toString() { + return "Span{" + + "name='" + name + '\'' + + ", age=" + age + + '}'; + } + } +} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/threadlocal/InheritableThreadLocalDemo.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/threadlocal/InheritableThreadLocalDemo.java new file mode 100644 index 00000000..bf0f72ec --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/threadlocal/InheritableThreadLocalDemo.java @@ -0,0 +1,49 @@ +package cn.lastwhisper.concurrent.basic.threadlocal; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +/** + * @author cunchang + * @date 2022/4/28 7:54 PM + */ +public class InheritableThreadLocalDemo { + public static void main(String[] args) throws InterruptedException { + final InheritableThreadLocal inheritableThreadLocal = new InheritableThreadLocal(); + inheritableThreadLocal.set(new Span("xiexiexie")); + //输出 xiexiexie + Object o = inheritableThreadLocal.get(); + System.out.println("main get Span:"+o); + Thread thread = new Thread() { + @Override + public void run() { + System.out.println("========"); + Object o = inheritableThreadLocal.get(); + System.out.println("t get Span:"+o); + inheritableThreadLocal.set(new Span("zhangzhangzhang")); + o = inheritableThreadLocal.get(); + System.out.println("t update Span:"+o); + } + }; + thread.start(); + thread.join(); + } + + static class Span { + public String name; + public int age; + + public Span(String name) { + this.name = name; + } + + @Override + public String toString() { + return "Span{" + + "name='" + name + '\'' + + ", age=" + age + + '}'; + } + } +} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/threadlocal/InheritableThreadLocalDemo2.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/threadlocal/InheritableThreadLocalDemo2.java new file mode 100644 index 00000000..11e71889 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/threadlocal/InheritableThreadLocalDemo2.java @@ -0,0 +1,59 @@ +package cn.lastwhisper.concurrent.basic.threadlocal; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +/** + * @author cunchang + * @date 2022/4/28 7:54 PM + */ +public class InheritableThreadLocalDemo2 { + public static void main(String[] args) throws InterruptedException { + final InheritableThreadLocal inheritableThreadLocal = new InheritableThreadLocal(); + inheritableThreadLocal.set(new Span("xiexiexie")); + //输出 xiexiexie + Object o = inheritableThreadLocal.get(); + System.out.println("main get Span:"+o); + Runnable runnable = new Runnable() { + @Override + public void run() { + System.out.println("========"); + Object o = inheritableThreadLocal.get(); + System.out.println("t get Span:"+o); + inheritableThreadLocal.set(new Span("zhangzhangzhang")); + o = inheritableThreadLocal.get(); + System.out.println("t update Span:"+o); + } + }; + + ExecutorService executorService = Executors.newFixedThreadPool(1); + executorService.submit(runnable); + TimeUnit.SECONDS.sleep(1); + executorService.submit(runnable); + TimeUnit.SECONDS.sleep(1); + System.out.println("========"); + Span span = inheritableThreadLocal.get(); + System.out.println("main last again get Span:"+o); + + + executorService.shutdown(); + } + + static class Span { + public String name; + public int age; + + public Span(String name) { + this.name = name; + } + + @Override + public String toString() { + return "Span{" + + "name='" + name + '\'' + + ", age=" + age + + '}'; + } + } +} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/threadlocal/README.md b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/threadlocal/README.md new file mode 100644 index 00000000..9b994f20 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/threadlocal/README.md @@ -0,0 +1,7 @@ + + +1. ThreadLocalDemo;的用法 +2. ThreadLocalDemo2;一个线程多个local +3. InheritableThreadLocalDemo;InheritableThreadLocal解决父子线程local传递问题 +4. InheritableThreadLocalDemo2;InheritableThreadLocal在线程池中的窘境 +5. AlibabaThreadLocalDemo;通过修饰runnable解决InheritableThreadLocal的问题 diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/threadlocal/ThreadLocalDemo.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/threadlocal/ThreadLocalDemo.java index 67cc4549..6db17541 100644 --- a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/threadlocal/ThreadLocalDemo.java +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/threadlocal/ThreadLocalDemo.java @@ -11,7 +11,7 @@ * @author lastwhisper */ public class ThreadLocalDemo { - //private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); static ThreadLocal tl = new ThreadLocal<>(); public static class ParseDate implements Runnable{ @@ -23,10 +23,10 @@ public ParseDate(int i) { @Override public void run() { try { - //Date t = sdf.parse("2015-03-28 19:15:" + i % 60); if(tl.get()==null){ tl.set(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")); } +// Date t = sdf.parse("2015-03-28 19:15:" + i % 60); Date t = tl.get().parse("2015-03-28 19:15:" + i % 60); System.out.println(i+"\t"+t); } catch (ParseException e) { @@ -40,6 +40,6 @@ public static void main(String[] args){ for (int i = 0; i < 10; i++) { pool.execute(new ParseDate(i)); } - + pool.shutdown(); } } diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/threadlocal/ThreadLocalDemo2.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/threadlocal/ThreadLocalDemo2.java new file mode 100644 index 00000000..f92b9e27 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/threadlocal/ThreadLocalDemo2.java @@ -0,0 +1,22 @@ +package cn.lastwhisper.concurrent.basic.threadlocal; + +/** + * ThreadLocal原理 + * + * @author lastwhisper + */ +public class ThreadLocalDemo2 { + + static ThreadLocal tl1 = new ThreadLocal<>(); + static ThreadLocal tl2 = new ThreadLocal<>(); + + public static void main(String[] args){ + tl1.set(1); + System.out.println(tl1.get()); + System.out.println(tl2.get()); + tl2.set(2); + System.out.println(tl1.get()); + System.out.println(tl2.get()); + } + +} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/threadlocal/ThreadLocalNotSafe.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/threadlocal/ThreadLocalNotSafe.java deleted file mode 100644 index b28c41c1..00000000 --- a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/threadlocal/ThreadLocalNotSafe.java +++ /dev/null @@ -1,32 +0,0 @@ -package cn.lastwhisper.concurrent.basic.threadlocal; - -/** - * @author lastwhisper - */ -public class ThreadLocalNotSafe { - static class Container { - int num; - } - - public static void main(String[] args) throws InterruptedException { - ThreadLocal tl = new ThreadLocal<>(); - tl.set(new Container()); // 先set下ThreadLocal - - Container container = tl.get(); - Runnable task = () -> { - for (int i = 0; i < 10000; i++) { - container.num++; - } - }; - - //Thread t1 = new Thread(task); - Thread t2 = new Thread(task); - - //t1.start(); - t2.start(); - //t1.join(); - t2.join(); - - System.out.println(tl.get().num); - } -} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/threadlocal/ThreadLocal_GC_Demo.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/threadlocal/ThreadLocal_GC_Demo.java index 58b2eada..02639424 100644 --- a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/threadlocal/ThreadLocal_GC_Demo.java +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/threadlocal/ThreadLocal_GC_Demo.java @@ -38,12 +38,12 @@ protected void finalize() throws Throwable { System.out.println(this.toString() + " is GC"); } }); - System.out.println(Thread.currentThread().getId()+":create SimpleDataFormat"); + System.out.println(Thread.currentThread().getId() + ":create SimpleDataFormat"); } Date t = tl.get().parse("2015-03-28 19:15:" + i % 60); } catch (ParseException e) { e.printStackTrace(); - }finally { + } finally { latch.countDown(); } } diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/volatileDemo/VolatileDemo.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/volatileDemo/VolatileDemo.java index 82b308bb..1fcd5094 100644 --- a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/volatileDemo/VolatileDemo.java +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/basic/volatileDemo/VolatileDemo.java @@ -5,6 +5,10 @@ */ public class VolatileDemo implements Runnable { + /** + * 无volatile程序不会结束,主线程无法感知update线程修改的值 + * + */ private volatile boolean[] flag = {false}; @Override @@ -24,7 +28,7 @@ public boolean isFlag() { public static void main(String[] args) throws InterruptedException { VolatileDemo runnable = new VolatileDemo(); - new Thread(runnable).start(); + new Thread(runnable,"update thread").start(); while (true) { if (runnable.isFlag()) { System.out.println("-----------------"); diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/example/README.md b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/example/README.md new file mode 100644 index 00000000..e9d4f929 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/example/README.md @@ -0,0 +1,5 @@ +# 线程的一些案例 +1. future;手写future +2. alternate;线程交替打印ABCABC +3. productconsumer;生产者消费者 + diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/example/alternate/TestABCAlternateForLock.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/example/alternate/TestABCAlternateForLock.java index 6e615167..23555e51 100644 --- a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/example/alternate/TestABCAlternateForLock.java +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/example/alternate/TestABCAlternateForLock.java @@ -17,32 +17,23 @@ public class TestABCAlternateForLock { public static void main(String[] args) { ABCAlternateDemo ad = new ABCAlternateDemo(); - new Thread(new Runnable() { - @Override - public void run() { - for (int i = 1; i <= 10; i++) { - ad.loopA(i); - } + new Thread(() -> { + for (int i = 1; i <= 10; i++) { + ad.loopA(i); } }, "A").start(); - new Thread(new Runnable() { - @Override - public void run() { - for (int i = 1; i <= 10; i++) { - ad.loopB(i); - } + new Thread(() -> { + for (int i = 1; i <= 10; i++) { + ad.loopB(i); } }, "B").start(); - new Thread(new Runnable() { - @Override - public void run() { - for (int i = 1; i <= 10; i++) { - ad.loopC(i); + new Thread(() -> { + for (int i = 1; i <= 10; i++) { + ad.loopC(i); - System.out.println("-----------------------------------"); - } + System.out.println("-----------------------------------"); } }, "C").start(); } diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/example/future/Data.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/example/future/Data.java new file mode 100644 index 00000000..e0cce301 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/example/future/Data.java @@ -0,0 +1,7 @@ +package cn.lastwhisper.concurrent.example.future; + +//公共data数据接口 +public abstract class Data { + //方法作用 返回线程执行结果 + public abstract String getRequest(); +} \ No newline at end of file diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/example/future/FutureClient.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/example/future/FutureClient.java new file mode 100644 index 00000000..ab37f889 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/example/future/FutureClient.java @@ -0,0 +1,18 @@ +package cn.lastwhisper.concurrent.example.future; + +public class FutureClient { + //用户请求时候就会调用这个方法 + public Data request(String requestData) { + FutureData futureData = new FutureData(); + //开启一个线程 + new Thread(() -> { + //会有阻塞 但是不影响到主线程 + RealData realData = new RealData("toov5"); //执行业务逻辑 然后返回结果 + futureData.setRealData(realData); //把加载到的值(返回结果)设置给他 + + }).start(); + + return futureData; + } + +} \ No newline at end of file diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/example/future/FutureData.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/example/future/FutureData.java new file mode 100644 index 00000000..a85f622e --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/example/future/FutureData.java @@ -0,0 +1,35 @@ +package cn.lastwhisper.concurrent.example.future; + +//当有线程想要获取RealData时候,程序会被阻塞。等到RealData被注入才会使用getReal()方法 +public class FutureData extends Data { + + private boolean isReady = false; + private RealData realData; + + //读取data数据 + public synchronized void setRealData(RealData realData) { + //读取结果 + if (isReady) { //true 说明已经获取到结果了 如果获取到则直接返回结果 + System.out.println("FLAG:" + isReady); + } + //如果flag是false,没有获取到数据,传递realData对象 + this.realData = realData; + isReady = true; //获取到执行结果 改为true + notifyAll();//唤醒 + } + + + @Override + public synchronized String getRequest() { + while (!isReady) { //如果false 一直等待 + try { + wait(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + return realData.getRequest(); + } + + +} \ No newline at end of file diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/example/future/Main.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/example/future/Main.java new file mode 100644 index 00000000..5c017a0f --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/example/future/Main.java @@ -0,0 +1,12 @@ +package cn.lastwhisper.concurrent.example.future; + +public class Main { + public static void main(String[] args) { + FutureClient futureClient = new FutureClient(); + Data request = futureClient.request("cone on"); + System.out.println("数据发送成功"); //主线程 + System.out.println("主线程继续干自己的"); + String result = request.getRequest(); + System.out.println("主线程去获取结果" + result); + } +} \ No newline at end of file diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/example/future/README.md b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/example/future/README.md new file mode 100644 index 00000000..4e106898 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/example/future/README.md @@ -0,0 +1 @@ +手写future diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/example/future/RealData.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/example/future/RealData.java new file mode 100644 index 00000000..03a59f95 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/example/future/RealData.java @@ -0,0 +1,26 @@ +package cn.lastwhisper.concurrent.example.future; + +//获取真实数据 +public class RealData extends Data { + + private String requestData; + + public RealData(String requestData) { + System.out.println("RealData——————正在使用requestData进行网络请求,requestData:[" + requestData + "],开始"); + try { + //模拟执行业务逻辑耗时时间 + Thread.sleep(3000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + System.out.println("RealData——————操作执行完毕...获取结果"); + //获取返回结果 + this.requestData = "结果"; + } + + @Override + public String getRequest() { + return requestData; + } + +} \ No newline at end of file diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/example/productconsumer/v3/ProdConsumer_BlockQueueDemo.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/example/productconsumer/blockqueue/ProdConsumer_BlockQueueDemo.java similarity index 97% rename from java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/example/productconsumer/v3/ProdConsumer_BlockQueueDemo.java rename to java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/example/productconsumer/blockqueue/ProdConsumer_BlockQueueDemo.java index 7b669b41..cb630ee6 100644 --- a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/example/productconsumer/v3/ProdConsumer_BlockQueueDemo.java +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/example/productconsumer/blockqueue/ProdConsumer_BlockQueueDemo.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.concurrent.example.productconsumer.v3; +package cn.lastwhisper.concurrent.example.productconsumer.blockqueue; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/example/productconsumer/v2/TestProductAndConsumerForLock.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/example/productconsumer/lockcondition/TestProductAndConsumerForLock.java similarity index 97% rename from java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/example/productconsumer/v2/TestProductAndConsumerForLock.java rename to java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/example/productconsumer/lockcondition/TestProductAndConsumerForLock.java index 7e50c76f..93d97fdf 100644 --- a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/example/productconsumer/v2/TestProductAndConsumerForLock.java +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/example/productconsumer/lockcondition/TestProductAndConsumerForLock.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.concurrent.example.productconsumer.v2; +package cn.lastwhisper.concurrent.example.productconsumer.lockcondition; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/example/productconsumer/v1/TestProductAndConsumer.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/example/productconsumer/waitnotify/TestProductAndConsumer.java similarity index 85% rename from java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/example/productconsumer/v1/TestProductAndConsumer.java rename to java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/example/productconsumer/waitnotify/TestProductAndConsumer.java index c465b731..ce518640 100644 --- a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/example/productconsumer/v1/TestProductAndConsumer.java +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/example/productconsumer/waitnotify/TestProductAndConsumer.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.concurrent.example.productconsumer.v1; +package cn.lastwhisper.concurrent.example.productconsumer.waitnotify; /** * 生产者消费者案例(等待唤醒机制),使用synchronize+Object的wait和notify; @@ -17,8 +17,8 @@ public class TestProductAndConsumer { public static void main(String[] args) { Clerk clerk = new Clerk(); - new Thread(new Product(clerk), "生产者").start(); - new Thread(new Consumer(clerk), "消费者").start(); + new Thread(new Product(clerk), "生产者A").start(); + new Thread(new Consumer(clerk), "消费者B").start(); } } @@ -27,9 +27,9 @@ class Clerk { private int product = 0; //进货(生产者线程调用) - public synchronized void get() {//循环次数:2——》1 + public synchronized void stock() {//循环次数:2——》1 if (product >= 1) { - System.out.println("货物已满!"); +// System.out.println("货物已满!"); try { //货物满了之后生产者等待 this.wait(); @@ -37,7 +37,7 @@ public synchronized void get() {//循环次数:2——》1 e.printStackTrace(); } } else { - System.out.println(Thread.currentThread().getName() + " : " + ++product); + System.out.println(Thread.currentThread().getName() + "添加商品,剩余数量" + ++product); //生产货物之后唤醒消费者 this.notifyAll(); } @@ -46,7 +46,7 @@ public synchronized void get() {//循环次数:2——》1 //销售(消费者线程调用) public synchronized void sale() {//product:0——》1,循环次数:1——》0 if (product <= 0) { - System.out.println("货物为空!"); +// System.out.println("货物为空!"); try { //货物为空之后消费者等待 this.wait(); @@ -54,7 +54,7 @@ public synchronized void sale() {//product:0——》1,循环次数:1— e.printStackTrace(); } } else { - System.out.println(Thread.currentThread().getName() + " : " + --product); + System.out.println(Thread.currentThread().getName() + "销售商品,剩余数量" + --product); //消费货物之后唤醒生产者 this.notifyAll(); } @@ -77,7 +77,7 @@ public void run() { } catch (InterruptedException e) { e.printStackTrace(); } - clerk.get(); + clerk.stock(); } } } diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/example/productconsumer/v1/TestProductAndConsumer2.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/example/productconsumer/waitnotify/TestProductAndConsumer2.java similarity index 89% rename from java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/example/productconsumer/v1/TestProductAndConsumer2.java rename to java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/example/productconsumer/waitnotify/TestProductAndConsumer2.java index 6d5bdd6e..c9898d19 100644 --- a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/example/productconsumer/v1/TestProductAndConsumer2.java +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/example/productconsumer/waitnotify/TestProductAndConsumer2.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.concurrent.example.productconsumer.v1; +package cn.lastwhisper.concurrent.example.productconsumer.waitnotify; /** * 生产者消费者案例(等待唤醒机制),使用synchronize+Object的wait和notify; @@ -38,7 +38,7 @@ class Clerk2 { //进货(生产者线程调用) public synchronized void get() { while (product >= 1) { - System.out.println("货物已满!"); +// System.out.println("货物已满!"); try { //货物满了之后生产者等待 this.wait(); @@ -46,7 +46,7 @@ public synchronized void get() { e.printStackTrace(); } } - System.out.println(Thread.currentThread().getName() + " : " + ++product); + System.out.println(Thread.currentThread().getName() + "添加商品,剩余数量" + ++product); //生产货物之后唤醒消费者 this.notifyAll(); } @@ -54,7 +54,7 @@ public synchronized void get() { //销售(消费者线程调用) public synchronized void sale() { while (product <= 0) { - System.out.println("货物为空!"); +// System.out.println("货物为空!"); try { //货物为空之后消费者等待 this.wait(); @@ -62,7 +62,7 @@ public synchronized void sale() { e.printStackTrace(); } } - System.out.println(Thread.currentThread().getName() + " : " + --product); + System.out.println(Thread.currentThread().getName() + "销售商品,剩余数量" + --product); //消费货物之后唤醒生产者 this.notifyAll(); diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/guava/TestRateLimiter.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/guava/TestRateLimiter.java deleted file mode 100644 index 460ab5a8..00000000 --- a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/guava/TestRateLimiter.java +++ /dev/null @@ -1,25 +0,0 @@ -package cn.lastwhisper.concurrent.guava; - -import com.google.common.util.concurrent.RateLimiter; - -/** - * Guava的RateLimiter限流基于令牌桶算法 - * @author lastwhisper - */ -public class TestRateLimiter { - private static RateLimiter limiter = RateLimiter.create(3); - - public static class Task implements Runnable { - @Override - public void run() { - System.out.println(System.currentTimeMillis()); - } - } - - public static void main(String[] args) { - for (int i = 0; i < 50; i++) { - limiter.acquire(); - new Thread(new Task()).start(); - } - } -} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/guava/TokenBucket.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/guava/TokenBucket.java deleted file mode 100644 index 4157d5ae..00000000 --- a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/guava/TokenBucket.java +++ /dev/null @@ -1,45 +0,0 @@ -package cn.lastwhisper.concurrent.guava; - -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -// 因为令牌桶对业务有一定的容忍度 -public class TokenBucket { - - private int bucketNums = 100; // 桶的容量 - private int rate = 1; // 流入速度 - private int nowTokens; // 当前令牌数量 - private long timestamp = getNowTime(); // 时间 - - private long getNowTime() { - return System.currentTimeMillis(); - } - - private int min(int tokens) { - if (bucketNums > tokens) { - return tokens; - } else { - return bucketNums; - } - } - - public boolean getToken() { - // 记录来拿令牌的时间 - long nowTime = getNowTime(); - // 添加令牌【判断该有多少个令牌】 - nowTokens = nowTokens + (int) ((nowTime - timestamp) * rate); - // 添加以后的令牌数量与桶的容量那个小 - nowTokens = min(nowTokens); - System.out.println("当前令牌数量" + nowTokens); - // 修改拿令牌的时间 - timestamp = nowTime; - // 判断令牌是否足够 - if (nowTokens < 1) { - return false; - } else { - nowTokens -= 1; - return true; - } - } - -} \ No newline at end of file diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/README.md b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/README.md new file mode 100644 index 00000000..b2a51333 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/README.md @@ -0,0 +1,13 @@ +# locks 锁相关 +# aqs aqs相关 +# tools +# executor +# blockingqueue +# lockfree 无锁 + + +locksupport waiting当前线程 +future 获取异步执行的结果 +completefuture 获取异步执行的结果 + + diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/aqs/AQSDemo.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/aqs/AQSDemo.java new file mode 100644 index 00000000..7ed60546 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/aqs/AQSDemo.java @@ -0,0 +1,59 @@ +package cn.lastwhisper.concurrent.juc.aqs; + +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.ReentrantLock; + +/** + * + * on 2020/11/11 18:08 + */ +public class AQSDemo { + + public static void main(String[] args) { + + ReentrantLock lock = new ReentrantLock(); + + //带入一个银行办理业务的案例来模拟我们的AQS如何进行线程的管理和通知唤醒机制 + + // 3个线程模拟3个银行网点,受理窗口办理业务的客户 + + // A 顾客就是每一个顾客,此时受理窗口没有任何人,A可以直接办理 + new Thread(() -> { + try { + lock.lock(); + System.out.println("----------A thread come in"); + //暂停几秒钟线程 + try { + TimeUnit.MINUTES.sleep(20); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } finally { + lock.unlock(); + } + }, "A").start(); + + //第二个顾客,第2个线程 ---》,由于受理业务的窗口只有一个(只能一个线程持有锁),些时B只能等待 + //进入候客区 + new Thread(() -> { + try { + lock.lock(); + System.out.println("----------B thread come in"); + } finally { + lock.unlock(); + } + }, "B").start(); + + //第三个顾客,第3个线程 ---》,由于受理业务的窗口只有一个(只能一个线程持有锁),些时C只能等待 + //进入候客区 + new Thread(() -> { + try { + lock.lock(); + System.out.println("----------C thread come in"); + } finally { + lock.unlock(); + } + }, "C").start(); + + } +} \ No newline at end of file diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/aqs/README.md b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/aqs/README.md new file mode 100644 index 00000000..f125cd53 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/aqs/README.md @@ -0,0 +1,4 @@ +1. ThreadNoSafe 线程不安全 +2. ThreadSafe 通过互斥保证线程安全 +3. mylock1 手动实现Lock,通过synchronized和wait、notify +4. mylock2 手动实现Lock,通过aqs \ No newline at end of file diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/aqs/ThreadNoSafe.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/aqs/ThreadNoSafe.java new file mode 100644 index 00000000..8f2e8223 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/aqs/ThreadNoSafe.java @@ -0,0 +1,24 @@ +package cn.lastwhisper.concurrent.juc.aqs; + +/** + * @author lastwhisper + */ +public class ThreadNoSafe { + private static int m = 0; + + public static void main(String[] args) throws InterruptedException { + Thread[] threads = new Thread[100]; + for (int i = 0; i < threads.length; i++) { + threads[i] = new Thread(() -> { + for (int j = 0; j < 10000; j++) { + m++; + } + }); + } + + for (Thread t : threads) t.start(); + for (Thread t : threads) t.join();//等待所有线程运行结束 +// Thread.sleep(1000); + System.out.println(m); + } +} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/aqs/ThreadSafe.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/aqs/ThreadSafe.java new file mode 100644 index 00000000..a80302f2 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/aqs/ThreadSafe.java @@ -0,0 +1,36 @@ +package cn.lastwhisper.concurrent.juc.aqs; + +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +/** + * @author lastwhisper + */ +public class ThreadSafe { + private static int m = 0; + private static ReentrantLock lock = new ReentrantLock(); + + public static void main(String[] args) throws InterruptedException { + Thread[] threads = new Thread[100]; + for (int i = 0; i < threads.length; i++) { + threads[i] = new Thread(() -> { +// synchronized (Main.class) { +// for (int j = 0; j < 1000; j++) { +// m++; +// } +// } + try { + lock.lock(); + for (int j = 0; j < 1000; j++) m++; + } finally { + lock.unlock(); + } + }); + } + + for (Thread t : threads) t.start(); + for (Thread t : threads) t.join();//等待所有线程运行结束 + + System.out.println(m); + } +} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/aqs/mylock1/MLock.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/aqs/mylock1/MLock.java new file mode 100644 index 00000000..44e0b4db --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/aqs/mylock1/MLock.java @@ -0,0 +1,63 @@ +package cn.lastwhisper.concurrent.juc.aqs.mylock1; + +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.Lock; + +/** + * 正确 + * + * @author lastwhisper + */ +public class MLock implements Lock { + private volatile int i = 0; + + /** + * t1进来i=1; + * t2进来this.wait(); + * t3进来synchronized blocked + */ + @Override + public synchronized void lock() { + while (i != 0) { + try { + this.wait(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + i = 1; + } + + @Override + public synchronized void lockInterruptibly() throws InterruptedException { + while (i != 0) { + this.wait(); + } + i = 1; + } + + @Override + public boolean tryLock() { + return false; + } + + @Override + public boolean tryLock(long time, TimeUnit unit) throws InterruptedException { + return false; + } + + /** + * 这里用notify就够了,因为只有一个线程wait + */ + @Override + public synchronized void unlock() { + i = 0; + this.notify(); + } + + @Override + public Condition newCondition() { + return null; + } +} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/aqs/mylock1/Main.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/aqs/mylock1/Main.java new file mode 100644 index 00000000..f5608356 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/aqs/mylock1/Main.java @@ -0,0 +1,31 @@ +package cn.lastwhisper.concurrent.juc.aqs.mylock1; + +import java.util.concurrent.locks.Lock; + +/** + * @author lastwhisper + */ +public class Main { + private static int m = 0; + private static Lock lock = new MLock(); + + public static void main(String[] args) throws InterruptedException { + Thread[] threads = new Thread[100]; + for (int i = 0; i < threads.length; i++) { + threads[i] = new Thread(() -> { + try { + lock.lock(); + for (int j = 0; j < 10000; j++) m++; + } finally { + lock.unlock(); + } + + }); + } + + for (Thread t : threads) t.start(); + for (Thread t : threads) t.join();//等待所有线程运行结束 + + System.out.println(m); + } +} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/aqs/mylock2/MLock.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/aqs/mylock2/MLock.java new file mode 100644 index 00000000..c0b9dc1b --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/aqs/mylock2/MLock.java @@ -0,0 +1,75 @@ +package cn.lastwhisper.concurrent.juc.aqs.mylock2; + +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.AbstractQueuedSynchronizer; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.Lock; + +/** + * 正确 + * 独占锁 + * @author lastwhisper + */ +public class MLock implements Lock { + private Sync sync = new Sync(); + + // 静态内部类,自定义同步器 + private class Sync extends AbstractQueuedSynchronizer { + // 当状态为0的时候获取锁 + @Override + protected boolean tryAcquire(int arg) { + assert arg == 1; + if (compareAndSetState(0, 1)) { + setExclusiveOwnerThread(Thread.currentThread());// 设置互斥锁 + return true; + } + return false; + } + // 释放锁,将状态设置为0 + @Override + protected boolean tryRelease(int arg) { + assert arg == 1; + if (!isHeldExclusively()) throw new IllegalMonitorStateException(); + setExclusiveOwnerThread(null); + setState(0); + return true; + } + + @Override + protected boolean isHeldExclusively() { + // 拿到当前排他线程是不是和当前线程一样,如果一样才释放 + return getExclusiveOwnerThread() == Thread.currentThread(); + } + } + + @Override + public void lock() { + sync.acquire(1); + } + + @Override + public void lockInterruptibly() throws InterruptedException { + + } + + @Override + public boolean tryLock() { + return false; + } + + @Override + public boolean tryLock(long time, TimeUnit unit) throws InterruptedException { + return false; + } + + @Override + public void unlock() { + sync.release(1); + } + + @Override + public Condition newCondition() { + return null; + } + +} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/aqs/mylock2/Main.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/aqs/mylock2/Main.java new file mode 100644 index 00000000..5914b363 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/aqs/mylock2/Main.java @@ -0,0 +1,31 @@ +package cn.lastwhisper.concurrent.juc.aqs.mylock2; + +import java.util.concurrent.locks.Lock; + +/** + * @author lastwhisper + */ +public class Main { + private static int m = 0; + private static Lock lock = new MLock(); + + public static void main(String[] args) throws InterruptedException { + Thread[] threads = new Thread[100]; + for (int i = 0; i < threads.length; i++) { + threads[i] = new Thread(() -> { + try { + lock.lock(); + for (int j = 0; j < 100; j++) m++; + } finally { + lock.unlock(); + } + + }); + } + + for (Thread t : threads) t.start(); + for (Thread t : threads) t.join();//等待所有线程运行结束 + + System.out.println(m); + } +} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/aqs/s01/Main.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/aqs/s01/Main.java deleted file mode 100644 index 8ecde27b..00000000 --- a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/aqs/s01/Main.java +++ /dev/null @@ -1,24 +0,0 @@ -package cn.lastwhisper.concurrent.juc.aqs.s01; - -/** - * @author lastwhisper - */ -public class Main { - private static int m = 0; - - public static void main(String[] args) throws InterruptedException { - Thread[] threads = new Thread[100]; - for (int i = 0; i < threads.length; i++) { - threads[i] = new Thread(() -> { - for (int j = 0; j < 100; j++) { - m++; - } - }); - } - - for (Thread t : threads) t.start(); - for (Thread t : threads) t.join();//等待所有线程运行结束 - - System.out.println(m); - } -} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/aqs/s02/Main.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/aqs/s02/Main.java deleted file mode 100644 index f327dd8d..00000000 --- a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/aqs/s02/Main.java +++ /dev/null @@ -1,31 +0,0 @@ -package cn.lastwhisper.concurrent.juc.aqs.s02; - -import cn.lastwhisper.concurrent.juc.aqs.s04.MLock; - -import java.util.concurrent.locks.Lock; - -/** - * @author lastwhisper - */ -public class Main { - private static int m = 0; - private static Lock lock = new MLock(); - - public static void main(String[] args) throws InterruptedException { - Thread[] threads = new Thread[100]; - for (int i = 0; i < threads.length; i++) { - threads[i] = new Thread(() -> { - synchronized (Main.class) { - for (int j = 0; j < 100; j++) { - m++; - } - } - }); - } - - for (Thread t : threads) t.start(); - for (Thread t : threads) t.join();//等待所有线程运行结束 - - System.out.println(m); - } -} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/aqs/s03/Main.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/aqs/s03/Main.java deleted file mode 100644 index 99f5a245..00000000 --- a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/aqs/s03/Main.java +++ /dev/null @@ -1,32 +0,0 @@ -package cn.lastwhisper.concurrent.juc.aqs.s03; - -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; - -/** - * @author lastwhisper - */ -public class Main { - private static int m = 0; - private static Lock lock = new ReentrantLock(); - - public static void main(String[] args) throws InterruptedException { - Thread[] threads = new Thread[100]; - for (int i = 0; i < threads.length; i++) { - threads[i] = new Thread(() -> { - try { - lock.lock(); - for (int j = 0; j < 100; j++) m++; - } finally { - lock.unlock(); - } - - }); - } - - for (Thread t : threads) t.start(); - for (Thread t : threads) t.join();//等待所有线程运行结束 - - System.out.println(m); - } -} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/aqs/s04/MLock.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/aqs/s04/MLock.java deleted file mode 100644 index 6232ebff..00000000 --- a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/aqs/s04/MLock.java +++ /dev/null @@ -1,47 +0,0 @@ -package cn.lastwhisper.concurrent.juc.aqs.s04; - -import java.util.concurrent.TimeUnit; -import java.util.concurrent.locks.Condition; -import java.util.concurrent.locks.Lock; - -/** - * 错误 - * @author lastwhisper - */ -public class MLock implements Lock { - private volatile int i = 0; - - @Override - public void lock() { - synchronized (this) { - i = 1; - } - } - - @Override - public void lockInterruptibly() throws InterruptedException { - - } - - @Override - public boolean tryLock() { - return false; - } - - @Override - public boolean tryLock(long time, TimeUnit unit) throws InterruptedException { - return false; - } - - @Override - public void unlock() { - synchronized (this) { - i = 0; - } - } - - @Override - public Condition newCondition() { - return null; - } -} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/aqs/s04/Main.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/aqs/s04/Main.java deleted file mode 100644 index 948a91d2..00000000 --- a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/aqs/s04/Main.java +++ /dev/null @@ -1,31 +0,0 @@ -package cn.lastwhisper.concurrent.juc.aqs.s04; - -import java.util.concurrent.locks.Lock; - -/** - * @author lastwhisper - */ -public class Main { - private static int m = 0; - private static Lock lock = new MLock(); - - public static void main(String[] args) throws InterruptedException { - Thread[] threads = new Thread[100]; - for (int i = 0; i < threads.length; i++) { - threads[i] = new Thread(() -> { - try { - lock.lock(); - for (int j = 0; j < 100; j++) m++; - } finally { - lock.unlock(); - } - - }); - } - - for (Thread t : threads) t.start(); - for (Thread t : threads) t.join();//等待所有线程运行结束 - - System.out.println(m); - } -} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/aqs/s05/MLock.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/aqs/s05/MLock.java deleted file mode 100644 index 2e822b34..00000000 --- a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/aqs/s05/MLock.java +++ /dev/null @@ -1,55 +0,0 @@ -package cn.lastwhisper.concurrent.juc.aqs.s05; - -import java.util.concurrent.TimeUnit; -import java.util.concurrent.locks.Condition; -import java.util.concurrent.locks.Lock; - -/** - * 正确 - * @author lastwhisper - */ -public class MLock implements Lock { - private volatile int i = 0; - - @Override - public void lock() { - synchronized (this) { - while (i != 0) { - try { - this.wait(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - i = 1; - } - } - - @Override - public void lockInterruptibly() throws InterruptedException { - - } - - @Override - public boolean tryLock() { - return false; - } - - @Override - public boolean tryLock(long time, TimeUnit unit) throws InterruptedException { - return false; - } - - @Override - public void unlock() { - synchronized (this) { - i = 0; - this.notify(); - } - } - - @Override - public Condition newCondition() { - return null; - } -} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/aqs/s05/Main.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/aqs/s05/Main.java deleted file mode 100644 index f8912a78..00000000 --- a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/aqs/s05/Main.java +++ /dev/null @@ -1,31 +0,0 @@ -package cn.lastwhisper.concurrent.juc.aqs.s05; - -import java.util.concurrent.locks.Lock; - -/** - * @author lastwhisper - */ -public class Main { - private static int m = 0; - private static Lock lock = new MLock(); - - public static void main(String[] args) throws InterruptedException { - Thread[] threads = new Thread[100]; - for (int i = 0; i < threads.length; i++) { - threads[i] = new Thread(() -> { - try { - lock.lock(); - for (int j = 0; j < 100; j++) m++; - } finally { - lock.unlock(); - } - - }); - } - - for (Thread t : threads) t.start(); - for (Thread t : threads) t.join();//等待所有线程运行结束 - - System.out.println(m); - } -} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/aqs/s06/MLock.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/aqs/s06/MLock.java deleted file mode 100644 index 8aafadee..00000000 --- a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/aqs/s06/MLock.java +++ /dev/null @@ -1,41 +0,0 @@ -package cn.lastwhisper.concurrent.juc.aqs.s06; - -import java.util.concurrent.TimeUnit; -import java.util.concurrent.locks.Condition; -import java.util.concurrent.locks.Lock; - -/** - * 错误 - * @author lastwhisper - */ -public class MLock implements Lock { - private volatile int i = 0; - - @Override - public void lock() { - } - - @Override - public void lockInterruptibly() throws InterruptedException { - - } - - @Override - public boolean tryLock() { - return false; - } - - @Override - public boolean tryLock(long time, TimeUnit unit) throws InterruptedException { - return false; - } - - @Override - public void unlock() { - } - - @Override - public Condition newCondition() { - return null; - } -} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/aqs/s06/Main.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/aqs/s06/Main.java deleted file mode 100644 index 93508846..00000000 --- a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/aqs/s06/Main.java +++ /dev/null @@ -1,31 +0,0 @@ -package cn.lastwhisper.concurrent.juc.aqs.s06; - -import java.util.concurrent.locks.Lock; - -/** - * @author lastwhisper - */ -public class Main { - private static int m = 0; - private static Lock lock = new MLock(); - - public static void main(String[] args) throws InterruptedException { - Thread[] threads = new Thread[100]; - for (int i = 0; i < threads.length; i++) { - threads[i] = new Thread(() -> { - try { - lock.lock(); - for (int j = 0; j < 100; j++) m++; - } finally { - lock.unlock(); - } - - }); - } - - for (Thread t : threads) t.start(); - for (Thread t : threads) t.join();//等待所有线程运行结束 - - System.out.println(m); - } -} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/aqs/s06/Sync.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/aqs/s06/Sync.java deleted file mode 100644 index 526399c3..00000000 --- a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/aqs/s06/Sync.java +++ /dev/null @@ -1,33 +0,0 @@ -package cn.lastwhisper.concurrent.juc.aqs.s06; - -import java.util.concurrent.locks.AbstractQueuedSynchronizer; - -/** - * 错误 - * @author lastwhisper - */ -public class Sync extends AbstractQueuedSynchronizer { - - @Override - protected boolean tryAcquire(int arg) { - if (compareAndSetState(0, 1)) { - setExclusiveOwnerThread(Thread.currentThread());// 设置互斥锁 - return true; - } - return false; - } - - @Override - protected boolean tryRelease(int arg) { - setExclusiveOwnerThread(null); - setState(0); - return true; - } - - @Override - protected boolean isHeldExclusively() { - return getState()==1; - } - - -} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/aqs/s07/MLock.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/aqs/s07/MLock.java deleted file mode 100644 index b39dbea1..00000000 --- a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/aqs/s07/MLock.java +++ /dev/null @@ -1,69 +0,0 @@ -package cn.lastwhisper.concurrent.juc.aqs.s07; - -import java.util.concurrent.TimeUnit; -import java.util.concurrent.locks.AbstractQueuedSynchronizer; -import java.util.concurrent.locks.Condition; -import java.util.concurrent.locks.Lock; - -/** - * 错误 - * @author lastwhisper - */ -public class MLock implements Lock { - private volatile int i = 0; - - private class Sync extends AbstractQueuedSynchronizer { - @Override - protected boolean tryAcquire(int arg) { - if (compareAndSetState(0, 1)) { - setExclusiveOwnerThread(Thread.currentThread());// 设置互斥锁 - return true; - } - return false; - } - - @Override - protected boolean tryRelease(int arg) { - setExclusiveOwnerThread(null); - setState(0); - return true; - } - - @Override - protected boolean isHeldExclusively() { - return getState() == 1; - } - } - - - @Override - public void lock() { - - } - - @Override - public void lockInterruptibly() throws InterruptedException { - - } - - @Override - public boolean tryLock() { - return false; - } - - @Override - public boolean tryLock(long time, TimeUnit unit) throws InterruptedException { - return false; - } - - @Override - public void unlock() { - - } - - @Override - public Condition newCondition() { - return null; - } - -} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/aqs/s07/Main.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/aqs/s07/Main.java deleted file mode 100644 index 6ab8d435..00000000 --- a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/aqs/s07/Main.java +++ /dev/null @@ -1,31 +0,0 @@ -package cn.lastwhisper.concurrent.juc.aqs.s07; - -import java.util.concurrent.locks.Lock; - -/** - * @author lastwhisper - */ -public class Main { - private static int m = 0; - private static Lock lock = new MLock(); - - public static void main(String[] args) throws InterruptedException { - Thread[] threads = new Thread[100]; - for (int i = 0; i < threads.length; i++) { - threads[i] = new Thread(() -> { - try { - lock.lock(); - for (int j = 0; j < 100; j++) m++; - } finally { - lock.unlock(); - } - - }); - } - - for (Thread t : threads) t.start(); - for (Thread t : threads) t.join();//等待所有线程运行结束 - - System.out.println(m); - } -} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/aqs/s08/MLock.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/aqs/s08/MLock.java deleted file mode 100644 index 7fe43fbc..00000000 --- a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/aqs/s08/MLock.java +++ /dev/null @@ -1,74 +0,0 @@ -package cn.lastwhisper.concurrent.juc.aqs.s08; - -import java.util.concurrent.TimeUnit; -import java.util.concurrent.locks.AbstractQueuedSynchronizer; -import java.util.concurrent.locks.Condition; -import java.util.concurrent.locks.Lock; - -/** - * 正确 - * 独占锁 - * @author lastwhisper - */ -public class MLock implements Lock { - private Sync sync = new Sync(); - - private class Sync extends AbstractQueuedSynchronizer { - @Override - protected boolean tryAcquire(int arg) { - assert arg == 1; - if (compareAndSetState(0, 1)) { - setExclusiveOwnerThread(Thread.currentThread());// 设置互斥锁 - return true; - } - return false; - } - - @Override - protected boolean tryRelease(int arg) { - assert arg == 1; - if (!isHeldExclusively()) throw new IllegalMonitorStateException(); - setExclusiveOwnerThread(null); - setState(0); - return true; - } - - @Override - protected boolean isHeldExclusively() { - // 拿到当前排他线程是不是和当前线程一样,如果一样才释放 - return getExclusiveOwnerThread() == Thread.currentThread(); - - } - } - - @Override - public void lock() { - sync.acquire(1); - } - - @Override - public void lockInterruptibly() throws InterruptedException { - - } - - @Override - public boolean tryLock() { - return false; - } - - @Override - public boolean tryLock(long time, TimeUnit unit) throws InterruptedException { - return false; - } - - @Override - public void unlock() { - sync.release(1); - } - - @Override - public Condition newCondition() { - return null; - } - -} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/aqs/s08/Main.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/aqs/s08/Main.java deleted file mode 100644 index 7a7270ff..00000000 --- a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/aqs/s08/Main.java +++ /dev/null @@ -1,31 +0,0 @@ -package cn.lastwhisper.concurrent.juc.aqs.s08; - -import java.util.concurrent.locks.Lock; - -/** - * @author lastwhisper - */ -public class Main { - private static int m = 0; - private static Lock lock = new MLock(); - - public static void main(String[] args) throws InterruptedException { - Thread[] threads = new Thread[100]; - for (int i = 0; i < threads.length; i++) { - threads[i] = new Thread(() -> { - try { - lock.lock(); - for (int j = 0; j < 100; j++) m++; - } finally { - lock.unlock(); - } - - }); - } - - for (Thread t : threads) t.start(); - for (Thread t : threads) t.join();//等待所有线程运行结束 - - System.out.println(m); - } -} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/atomic/AtomicReferenceDemo.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/atomic/AtomicReferenceDemo.java deleted file mode 100644 index be937d77..00000000 --- a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/atomic/AtomicReferenceDemo.java +++ /dev/null @@ -1,26 +0,0 @@ -package cn.lastwhisper.concurrent.juc.atomic; - -import jdk.nashorn.internal.objects.annotations.Getter; -import jdk.nashorn.internal.objects.annotations.Setter; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.ToString; - -import java.util.concurrent.atomic.AtomicReference; -@Data -@AllArgsConstructor -@ToString -class User{ - private String name; - private int age; -} -public class AtomicReferenceDemo { - public static void main(String[] args) { - User zs = new User("zs", 22); - User ls = new User("ls", 22); - AtomicReference userAtomicReference = new AtomicReference<>(); - userAtomicReference.set(zs); - System.out.println(userAtomicReference.compareAndSet(zs, ls)+"\t"+userAtomicReference.get().toString()); - System.out.println(userAtomicReference.compareAndSet(zs, ls)+"\t"+userAtomicReference.get().toString()); - } -} \ No newline at end of file diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/atomic/CASDemo.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/atomic/CASDemo.java deleted file mode 100644 index 0fbacf47..00000000 --- a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/atomic/CASDemo.java +++ /dev/null @@ -1,12 +0,0 @@ -package cn.lastwhisper.concurrent.juc.atomic; - -import java.util.concurrent.atomic.AtomicInteger; - -public class CASDemo { - public static void main(String[] args) { - AtomicInteger atomicInteger = new AtomicInteger(5); - System.out.println(atomicInteger.compareAndSet(5, 2019) + "\t current" + atomicInteger.get()); - System.out.println(atomicInteger.compareAndSet(5, 2014) + "\t current" + atomicInteger.get()); - atomicInteger.getAndIncrement(); - } -} \ No newline at end of file diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/atomic/TestAtomic.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/atomic/TestAtomic.java deleted file mode 100644 index d377d57e..00000000 --- a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/atomic/TestAtomic.java +++ /dev/null @@ -1,52 +0,0 @@ -package cn.lastwhisper.concurrent.juc.atomic; - -import java.util.concurrent.atomic.AtomicInteger; - -/** - * 一、i++的原子性问题:i++并非原子操作,取值,修改,存储 - * int temp = i;//第一步:取值 - * i = i + 1;//第二步:修改 - * i = temp;//第三步:存储 - * 内存到寄存器 - * 寄存器自增 - * 写回内存 - * 二、原子变量:jdk5后java.util.concurrent.atomic 包下提供了常用的原子变量 - * AtomicInteger - * 1.volatile 保证可见性 - * 2.CAS(Compare-And-Swap) 保证原子性 - * CAS 算法是硬件对于并发操作共享数据的支持 - * CAS 算法的过程:包含三个参数CAS(V,E,N), - * V 表示要更新的变量 - * E 表示预期值 - * N 表示新值 - * 仅当V==E时,才会将V=N,如果V!=E说明有其他线程做了更新,则当前线程什么也不做。 - * - * @author lastwhisper - */ -public class TestAtomic { - public static void main(String[] args) { - AtomicDemo ad = new AtomicDemo(); - for (int i = 0; i < 10; i++) { - new Thread(ad).start(); - } - } -} - -class AtomicDemo implements Runnable { - private int i; - //private volatile int i; - private AtomicInteger serialNum = new AtomicInteger(); - @Override - public void run() { - try { - Thread.sleep(100); - } catch (InterruptedException e) { - e.printStackTrace(); - } - System.out.println(Thread.currentThread().getName() + " : " + increment()); - } - public int increment() { - //return serialNum.incrementAndGet(); - return i++; - } -} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/atomic/TestCompareAndSwap.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/atomic/TestCompareAndSwap.java deleted file mode 100644 index 543358db..00000000 --- a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/atomic/TestCompareAndSwap.java +++ /dev/null @@ -1,45 +0,0 @@ -package cn.lastwhisper.concurrent.juc.atomic; - -/** - * 模拟的CAS算法 - * @author lastwhisper - */ -public class TestCompareAndSwap { - public static void main(String[] args) { - final CompareAndSwap CAS = new CompareAndSwap(); - for (int i = 0; i < 10; i++) { - new Thread(new Runnable() { - @Override - public void run() { - int expectedValue = CAS.get(); - boolean flag = CAS.compareAndSet(expectedValue, (int) (Math.random() * 100)); - System.out.println(flag); - } - }).start(); - } - } -} - -class CompareAndSwap { - private int value; - - //获取当前内存的值 - public synchronized int get() { - return value; - } - - //比较当前内存的值与预期的值是否相同,相同则设置内存值为更新的值 - // 并返回当前内存值 - public synchronized int compareAndSwap(int expectedValue, int newValue) { - int oldValue = value; - if (oldValue == expectedValue) { - this.value = newValue; - } - return oldValue; - } - - //交换是否成功 - public synchronized boolean compareAndSet(int expectedValue, int newValue) { - return expectedValue == compareAndSwap(expectedValue, newValue); - } -} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/blockingqueue/ArrayBlockingQueueDemo.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/blockingqueue/ArrayBlockingQueueDemo.java new file mode 100644 index 00000000..ad5bfac6 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/blockingqueue/ArrayBlockingQueueDemo.java @@ -0,0 +1,81 @@ +package cn.lastwhisper.concurrent.juc.blockingqueue; + +import org.junit.Test; + +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.TimeUnit; + +/** + * 阻塞队列 + * + * @author lastwhisper + */ +public class ArrayBlockingQueueDemo { + ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(3); + + // 超时退出 + @Test + public void test4() throws InterruptedException { + blockingQueue.offer("a"); + blockingQueue.offer("b"); + blockingQueue.offer("c"); + // 当阻塞队列满时,队列会阻塞生产者线程一定时间,超过后限时后生产者线程就会退出 + blockingQueue.offer("x", 2L, TimeUnit.SECONDS); + + System.out.println(blockingQueue.poll()); + System.out.println(blockingQueue.poll()); + System.out.println(blockingQueue.poll()); + System.out.println(blockingQueue.poll(2L, TimeUnit.SECONDS)); + } + + // 一直阻塞 + @Test + public void test3() throws InterruptedException { + blockingQueue.put("a"); + blockingQueue.put("b"); + blockingQueue.put("c"); + // 当阻塞队列满时,生产者继续往队列里面put元素,队列会一直阻塞直到put数据or响应中断退出 + blockingQueue.offer("x"); + + System.out.println(blockingQueue.take()); + System.out.println(blockingQueue.take()); + System.out.println(blockingQueue.take()); + //当阻塞队列空时,消费者试图从队列take元素,队列会一直阻塞消费者线程直到队列可用. + System.out.println(blockingQueue.take()); + } + + // 特殊值 + @Test + public void test2() { + System.out.println(blockingQueue.offer("a")); + System.out.println(blockingQueue.offer("b")); + System.out.println(blockingQueue.offer("c")); + // 插入方法,成功返回true 失败返回false + System.out.println(blockingQueue.offer("x")); + + System.out.println(blockingQueue.poll()); + System.out.println(blockingQueue.poll()); + System.out.println(blockingQueue.poll()); + //移除方法,成功返回元素,队列里面没有就返回null + System.out.println(blockingQueue.poll()); + } + + // 抛异常 + @Test + public void test1() { + System.out.println(blockingQueue.add("a")); + System.out.println(blockingQueue.add("b")); + System.out.println(blockingQueue.add("c")); + //当阻塞队列满时,再往队列里面add插入元素会抛IllegalStateException: Queue full + //System.out.println(blockingQueue.add("x")); + + System.out.println(blockingQueue.element()); + System.out.println(blockingQueue.remove()); + System.out.println(blockingQueue.remove()); + System.out.println(blockingQueue.remove()); + //当阻塞队列空时,再往队列Remove元素时候回抛出NoSuchElementException + //System.out.println(blockingQueue.remove()); + } + + +} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/blockingqueue/DelayQueueDemo.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/blockingqueue/DelayQueueDemo.java new file mode 100644 index 00000000..0c3a1b50 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/blockingqueue/DelayQueueDemo.java @@ -0,0 +1,64 @@ +package cn.lastwhisper.concurrent.juc.blockingqueue; + +import java.util.concurrent.DelayQueue; +import java.util.concurrent.Delayed; +import java.util.concurrent.TimeUnit; + +/** + * @author cunchang + * @date 2022/6/18 11:01 AM + */ +public class DelayQueueDemo { + + public static void main(String[] args) throws InterruptedException { + DelayQueue queue = new DelayQueue<>(); + queue.add(new MyDelay<>(8, "第一次添加任务")); + queue.add(new MyDelay<>(3, "第二次添加任务")); + queue.add(new MyDelay<>(5, "第三次添加任务")); + + while (!queue.isEmpty()) { + Delayed delayed = queue.take(); + System.out.println(delayed); + } + } + + static class MyDelay implements Delayed { + long delayTime; // 延迟时间 + long expire; // 过期时间 + T data; + + public MyDelay(long delayTime, T t) { + this.delayTime = delayTime; + // 过期时间 = 当前时间 + 延迟时间 + this.expire = System.currentTimeMillis() + delayTime; + data = t; + } + + /** + * 剩余时间 = 到期时间 - 当前时间 + */ + @Override + public long getDelay(TimeUnit unit) { + return unit.convert(this.expire - System.currentTimeMillis(), TimeUnit.MILLISECONDS); + } + + /** + * 优先级规则:两个任务比较,时间短的优先执行 + */ + @Override + public int compareTo(Delayed o) { + long f = this.getDelay(TimeUnit.MILLISECONDS) - o.getDelay(TimeUnit.MILLISECONDS); + return (int) f; + } + + + @Override + public String toString() { + return "delayTime=" + delayTime + + ", expire=" + expire + + ", data=" + data; + } + } + +} + diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/blockingqueue/PriorityBlockingQueueDemo.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/blockingqueue/PriorityBlockingQueueDemo.java new file mode 100644 index 00000000..a6b700e8 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/blockingqueue/PriorityBlockingQueueDemo.java @@ -0,0 +1,80 @@ +package cn.lastwhisper.concurrent.juc.blockingqueue; + +import java.util.concurrent.PriorityBlockingQueue; + +/** + * @author cunchang + * @date 2022/6/18 11:11 AM + */ +public class PriorityBlockingQueueDemo { + + public static void main(String[] args) throws InterruptedException { + PriorityBlockingQueue pbq = new PriorityBlockingQueue<>(); + pbq.add(new Person(3,"person3")); + System.err.println("容器为:" + pbq); + pbq.add(new Person(2,"person2")); + System.err.println("容器为:" + pbq); + pbq.add(new Person(1,"person1")); + System.err.println("容器为:" + pbq); + pbq.add(new Person(4,"person4")); + System.err.println("容器为:" + pbq); + System.err.println("分割线----------------------------------------------------------------" ); + + + System.err.println("获取元素 " + pbq.take()); + System.err.println("当前容器为:" + pbq); + System.err.println("分割线----------------------------------------------------------------" ); + + System.err.println("获取元素 " + pbq.take()); + System.err.println("当前容器为:" + pbq); + System.err.println("分割线----------------------------------------------------------------" ); + + System.err.println("获取元素 " + pbq.take()); + System.err.println("当前容器为:" + pbq); + System.err.println("分割线----------------------------------------------------------------" ); + + System.err.println("获取元素 " + pbq.take()); + System.err.println("当前容器为:" + pbq); + System.err.println("分割线----------------------------------------------------------------" ); + } + + static class Person implements Comparable { + private int id; + private String name; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Person(int id, String name) { + super(); + this.id = id; + this.name = name; + } + + public Person() { + } + + @Override + public String toString() { + return this.id + ":" + this.name; + } + + @Override + public int compareTo(Person person) { + return Integer.compare(this.id, person.getId()); + } + } +} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/collections/SynchronousQueueDemo.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/blockingqueue/SynchronousQueueDemo.java similarity index 97% rename from java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/collections/SynchronousQueueDemo.java rename to java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/blockingqueue/SynchronousQueueDemo.java index 2113eae8..248a241f 100644 --- a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/collections/SynchronousQueueDemo.java +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/blockingqueue/SynchronousQueueDemo.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.concurrent.juc.collections; +package cn.lastwhisper.concurrent.juc.blockingqueue; import java.util.concurrent.BlockingQueue; import java.util.concurrent.SynchronousQueue; @@ -9,6 +9,7 @@ * @author lastwhisper */ public class SynchronousQueueDemo { + public static void main(String[] args) { BlockingQueue blockingQueue = new SynchronousQueue<>(); new Thread(() -> { diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/atomic/ABADemo.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/cas/ABADemo.java similarity index 98% rename from java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/atomic/ABADemo.java rename to java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/cas/ABADemo.java index 57220a5f..b4e1990a 100644 --- a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/atomic/ABADemo.java +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/cas/ABADemo.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.concurrent.juc.atomic; +package cn.lastwhisper.concurrent.juc.cas; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/cas/AtomicIntegerTest.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/cas/AtomicIntegerTest.java new file mode 100644 index 00000000..d9c82c28 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/cas/AtomicIntegerTest.java @@ -0,0 +1,54 @@ +package cn.lastwhisper.concurrent.juc.cas; + +import java.util.concurrent.atomic.AtomicInteger; + +/** + * 一、i++的原子性问题:i++并非原子操作,取值,修改,存储 + * int temp = i;//第一步:取值 + * i = i + 1;//第二步:修改 + * i = temp;//第三步:存储 + * 内存到寄存器 + * 寄存器自增 + * 写回内存 + * 二、原子变量:jdk5后java.util.concurrent.atomic 包下提供了常用的原子变量 + * AtomicInteger + * 1.volatile 保证可见性 + * 2.CAS(Compare-And-Swap) 保证原子性 + * CAS 算法是硬件对于并发操作共享数据的支持 + * CAS 算法的过程:包含三个参数CAS(V,E,N), + * V 表示要更新的变量 + * E 表示预期值 + * N 表示新值 + * 仅当V==E时,才会将V=N,如果V!=E说明有其他线程做了更新,则当前线程什么也不做。 + * + * @author lastwhisper + */ +public class AtomicIntegerTest { + public static void main(String[] args) { + AtomicDemo ad = new AtomicDemo(); + for (int i = 0; i < 10; i++) { + new Thread(ad).start(); + } + } +} + +class AtomicDemo implements Runnable { + private int i; + //private volatile int i; + private AtomicInteger serialNum = new AtomicInteger(); + + @Override + public void run() { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + e.printStackTrace(); + } + System.out.println(Thread.currentThread().getName() + " : " + increment()); + } + + public int increment() { + //return serialNum.incrementAndGet(); + return i++; + } +} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/cas/CASDemo.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/cas/CASDemo.java new file mode 100644 index 00000000..8aaddd8e --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/cas/CASDemo.java @@ -0,0 +1,45 @@ +package cn.lastwhisper.concurrent.juc.cas; + +/** + * 模拟的CAS算法 + * @author lastwhisper + */ +public class CASDemo { + public static void main(String[] args) { + final CompareAndSwap CAS = new CompareAndSwap(); + for (int i = 0; i < 10; i++) { + new Thread(new Runnable() { + @Override + public void run() { + int expectedValue = CAS.get(); + boolean flag = CAS.compareAndSet(expectedValue, (int) (Math.random() * 100)); + System.out.println(flag); + } + }).start(); + } + } +} + +class CompareAndSwap { + private int value; + + //获取当前内存的值 + public synchronized int get() { + return value; + } + + //比较当前内存的值与预期的值是否相同,相同则设置内存值为更新的值 + // 并返回当前内存值 + public synchronized int compareAndSwap(int expectedValue, int newValue) { + int oldValue = value; + if (oldValue == expectedValue) { + this.value = newValue; + } + return oldValue; + } + + //交换是否成功 + public synchronized boolean compareAndSet(int expectedValue, int newValue) { + return expectedValue == compareAndSwap(expectedValue, newValue); + } +} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/collections/BlockingQueueDemo.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/collections/BlockingQueueDemo.java deleted file mode 100644 index 7ad4bad0..00000000 --- a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/collections/BlockingQueueDemo.java +++ /dev/null @@ -1,80 +0,0 @@ -package cn.lastwhisper.concurrent.juc.collections; - -import org.junit.Test; - -import java.util.concurrent.ArrayBlockingQueue; -import java.util.concurrent.TimeUnit; - -/** - * 阻塞队列 - * @author lastwhisper - */ -public class BlockingQueueDemo { - ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(3); - - // 超时退出 - @Test - public void test4() throws InterruptedException { - blockingQueue.offer("a"); - blockingQueue.offer("b"); - blockingQueue.offer("c"); - // 当阻塞队列满时,队列会阻塞生产者线程一定时间,超过后限时后生产者线程就会退出 - blockingQueue.offer("x",2L, TimeUnit.SECONDS); - - System.out.println(blockingQueue.poll()); - System.out.println(blockingQueue.poll()); - System.out.println(blockingQueue.poll()); - System.out.println(blockingQueue.poll(2L, TimeUnit.SECONDS)); - } - - // 一直阻塞 - @Test - public void test3() throws InterruptedException { - blockingQueue.put("a"); - blockingQueue.put("b"); - blockingQueue.put("c"); - // 当阻塞队列满时,生产者继续往队列里面put元素,队列会一直阻塞直到put数据or响应中断退出 - blockingQueue.offer("x"); - - System.out.println(blockingQueue.take()); - System.out.println(blockingQueue.take()); - System.out.println(blockingQueue.take()); - //当阻塞队列空时,消费者试图从队列take元素,队列会一直阻塞消费者线程直到队列可用. - System.out.println(blockingQueue.take()); - } - - // 特殊值 - @Test - public void test2(){ - System.out.println(blockingQueue.offer("a")); - System.out.println(blockingQueue.offer("b")); - System.out.println(blockingQueue.offer("c")); - // 插入方法,成功返回true 失败返回false - System.out.println(blockingQueue.offer("x")); - - System.out.println(blockingQueue.poll()); - System.out.println(blockingQueue.poll()); - System.out.println(blockingQueue.poll()); - //移除方法,成功返回元素,队列里面没有就返回null - System.out.println(blockingQueue.poll()); - } - - // 抛异常 - @Test - public void test1(){ - System.out.println(blockingQueue.add("a")); - System.out.println(blockingQueue.add("b")); - System.out.println(blockingQueue.add("c")); - //当阻塞队列满时,再往队列里面add插入元素会抛IllegalStateException: Queue full - //System.out.println(blockingQueue.add("x")); - - System.out.println(blockingQueue.element()); - System.out.println(blockingQueue.remove()); - System.out.println(blockingQueue.remove()); - System.out.println(blockingQueue.remove()); - //当阻塞队列空时,再往队列Remove元素时候回抛出NoSuchElementException - //System.out.println(blockingQueue.remove()); - } - - -} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/collections/ContainerNotSafeDemo.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/collections/ContainerNotSafeDemo.java deleted file mode 100644 index 3692c78f..00000000 --- a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/collections/ContainerNotSafeDemo.java +++ /dev/null @@ -1,61 +0,0 @@ -package cn.lastwhisper.concurrent.juc.collections; - -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; - -/** - * 集合类不安全的问题 - * @author lastwhisper - */ -public class ContainerNotSafeDemo { - /** - * 读写分离的思想,读和写不同的容器. - * CopyOnWriteArrayList在add时,会先上锁,然后copy一个新arr - * 将add的元素放入新arr里面,再将arr替换 - */ - public static void main(String[] args) { - //listNotSafe(); - //setNotSafe(); - mapNotSafe(); - - } - - private static void mapNotSafe() { - //Map map = new HashMap<>(); - Map map = new ConcurrentHashMap<>(); - for (int i = 1; i <= 30; i++) { - new Thread(() -> { - map.put(generatorStr(), generatorStr()); - System.out.println(map); - }, String.valueOf(i)).start(); - } - - } - - private static void setNotSafe() { - //Set set= new CopyOnWriteArraySet<>(); - Set set = new HashSet<>(); - for (int i = 1; i <= 30; i++) { - new Thread(() -> { - set.add(generatorStr()); - System.out.println(set); - }, String.valueOf(i)).start(); - } - } - - private static void listNotSafe() { - //List list= new CopyOnWriteArrayList<>(); - List list = new ArrayList<>(); - for (int i = 1; i <= 30; i++) { - new Thread(() -> { - list.add(generatorStr()); - System.out.println(list);//toString里面使用了迭代器 - }, String.valueOf(i)).start(); - } - } - - public static String generatorStr() { - return UUID.randomUUID().toString().substring(1, 8); - } - -} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/collections/SkipListMapDemo.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/collections/SkipListMapDemo.java deleted file mode 100644 index 450bd96a..00000000 --- a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/collections/SkipListMapDemo.java +++ /dev/null @@ -1,22 +0,0 @@ -package cn.lastwhisper.concurrent.juc.collections; - -import java.util.Map; -import java.util.concurrent.ConcurrentSkipListMap; - -/** - * 跳表 - * @author lastwhisper - */ -public class SkipListMapDemo { - - public static void main(String[] args) { - ConcurrentSkipListMap skipListMap = new ConcurrentSkipListMap<>(); - for (int i = 0; i < 30; i++) { - skipListMap.put(i, i); - } - for (Map.Entry entry : skipListMap.entrySet()) { - System.out.println(entry.getKey()); - } - } - -} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/completefuture/CFutureMain1.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/completefuture/CFutureMain1.java new file mode 100644 index 00000000..7539874b --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/completefuture/CFutureMain1.java @@ -0,0 +1,38 @@ +package cn.lastwhisper.concurrent.juc.completefuture; + +import java.util.concurrent.CompletableFuture; + +/** + * 脱离线程池的使用,仅作为一个契约 + * + * @author Geym + * + */ +public class CFutureMain1 { + public static class AskThread implements Runnable { + CompletableFuture re = null; + + public AskThread(CompletableFuture re) { + this.re = re; + } + + @Override + public void run() { + int myRe = 0; + try { + myRe = re.get() * re.get(); + } catch (Exception e) { + } + System.out.println(myRe); + } + } + + public static void main(String[] args) throws InterruptedException { + final CompletableFuture future = new CompletableFuture<>(); + new Thread(new AskThread(future)).start(); + // 模拟长时间其他调用 + Thread.sleep(1000); + // 告知完成结果 + future.complete(60); + } +} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/completefuture/CFutureMain2.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/completefuture/CFutureMain2.java new file mode 100644 index 00000000..70d9c63e --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/completefuture/CFutureMain2.java @@ -0,0 +1,32 @@ +package cn.lastwhisper.concurrent.juc.completefuture; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + +/** + * 完成普通future的工作 + * + * 以下几个函数可以执行(创建)一个CompletableFuture任务 + * static CompletableFuture supplyAsync(Supplier supplier); + * static CompletableFuture supplyAsync(Supplier supplier, Executor executor); + * static CompletableFuture runAsync(Runnable runnable); + * static CompletableFuture runAsync(Runnable runnable, Executor executor); + * @author Geym + * + */ +public class CFutureMain2 { + public static Integer calc(Integer para) { + try { + // 模拟一个长时间的执行 + Thread.sleep(1000); + } catch (InterruptedException e) { + } + return para*para; + } + + public static void main(String[] args) throws InterruptedException, ExecutionException { + final CompletableFuture future = + CompletableFuture.supplyAsync(() -> calc(50)); + System.out.println(future.get()); + } +} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/completefuture/CFutureMain3.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/completefuture/CFutureMain3.java new file mode 100644 index 00000000..4d249326 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/completefuture/CFutureMain3.java @@ -0,0 +1,32 @@ +package cn.lastwhisper.concurrent.juc.completefuture; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + +/** + * 完成普通future的工作 + * + * 以下几个函数可以执行(创建)一个CompletableFuture任务 + * thenApply 转换 + * thenAccept 最后处理 + * @author Geym + * + */ +public class CFutureMain3 { + public static Integer calc(Integer para) { + try { + // 模拟一个长时间的执行 + Thread.sleep(1000); + } catch (InterruptedException e) { + } + return para*para; + } + + public static void main(String[] args) throws InterruptedException, ExecutionException { + CompletableFuture fu=CompletableFuture.supplyAsync(() -> calc(50)) + .thenApply((i)->Integer.toString(i)) + .thenApply((str)->"\""+str+"\"") + .thenAccept(System.out::println); + fu.get(); + } +} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/completefuture/CFutureMain4.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/completefuture/CFutureMain4.java new file mode 100644 index 00000000..b52726d9 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/completefuture/CFutureMain4.java @@ -0,0 +1,33 @@ +package cn.lastwhisper.concurrent.juc.completefuture; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + +/** + * 完成普通future的工作 + * + * exceptionally 异常处理 发生异常进行处理,如果没有异常,则它返回原有的结果 + * + * @author Geym + * + */ +public class CFutureMain4 { + + public static Integer calc(Integer para) { + return para / 0; + } + + public static void main(String[] args) throws InterruptedException,ExecutionException { + CompletableFuture fu = CompletableFuture + .supplyAsync(() -> calc(50)) + .exceptionally(ex -> { + System.out.println(ex.toString()); + return 0; + }) + .thenApply((i) -> Integer.toString(i)) + .thenApply((str) -> "\"" + str + "\"") + .thenAccept(System.out::println); + fu.get(); + } + +} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/completefuture/CFutureMain5.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/completefuture/CFutureMain5.java new file mode 100644 index 00000000..d9d3c3fd --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/completefuture/CFutureMain5.java @@ -0,0 +1,28 @@ +package cn.lastwhisper.concurrent.juc.completefuture; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + +/** + * 完成普通future的工作 + * + * thenCompose + * + * @author Geym + * + */ +public class CFutureMain5 { + + public static Integer calc(Integer para) { + return para/2; + } + + public static void main(String[] args) throws InterruptedException, ExecutionException { + CompletableFuture fu = + CompletableFuture.supplyAsync(() -> calc(50)) + .thenCompose((i)->CompletableFuture.supplyAsync(() -> calc(i))) + .thenApply((str)->"\"" + str + "\"").thenAccept(System.out::println); + fu.get(); + } + +} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/completefuture/CFutureMain6.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/completefuture/CFutureMain6.java new file mode 100644 index 00000000..3b1d1d85 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/completefuture/CFutureMain6.java @@ -0,0 +1,30 @@ +package cn.lastwhisper.concurrent.juc.completefuture; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + +/** + * 完成普通future的工作 + * + * thenCombine 合并结果 + * + * @author Geym + * + */ +public class CFutureMain6 { + + public static Integer calc(Integer para) { + return para / 2; + } + + public static void main(String[] args) throws InterruptedException,ExecutionException { + CompletableFuture intFuture = CompletableFuture.supplyAsync(() -> calc(50)); + CompletableFuture intFuture2 = CompletableFuture.supplyAsync(() -> calc(25)); + + CompletableFuture fu = intFuture.thenCombine(intFuture2, (i, j) -> (i + j)) + .thenApply((str) -> "\"" + str + "\"") + .thenAccept(System.out::println); + fu.get(); + } + +} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/completefuture/README.md b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/completefuture/README.md new file mode 100644 index 00000000..78f37c12 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/completefuture/README.md @@ -0,0 +1,6 @@ + +脱离线程池使用 +CFutureMain1 手动设置future完成状态 + + + diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/executor/ForkJoinPoolTest.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/executor/ForkJoinPoolTest.java new file mode 100644 index 00000000..a2293006 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/executor/ForkJoinPoolTest.java @@ -0,0 +1,69 @@ +package cn.lastwhisper.concurrent.juc.executor; + +import org.junit.Test; + +import java.time.Duration; +import java.time.Instant; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.ForkJoinTask; +import java.util.concurrent.RecursiveTask; + +/** + * fork/join任务偷窃 + * + * @author lastwhisper + */ +public class ForkJoinPoolTest { + public static void main(String[] args) { + Instant start = Instant.now(); + ForkJoinPool pool = new ForkJoinPool(); + ForkJoinTask task = new ForkJoinSumCalculate(0L, 100000000L); + Long sum = pool.invoke(task); + System.out.println("结果:" + sum); + Instant end = Instant.now(); + System.out.println("耗费时间:" + Duration.between(start, end).toMillis());//28 + } + + @Test + public void test1() { + Instant start = Instant.now(); + long sum = 0L; + for (long i = 0L; i <= 100000000L; i++) { + sum += i; + } + System.out.println(sum); + Instant end = Instant.now(); + System.out.println("耗费时间为:" + Duration.between(start, end).toMillis());//51 + } +} + +class ForkJoinSumCalculate extends RecursiveTask { + private static final long THUSHOLD = 10000000L;//临界值 + private long start; + private long end; + + public ForkJoinSumCalculate(long start, long end) { + this.start = start; + this.end = end; + } + + @Override + protected Long compute() { + long length = end - start; + if (length <= THUSHOLD) { + long sum = 0L; + for (long i = start; i <= end; i++) { + sum += i; + } + return sum; + } else { + long middle = ((end - start) >> 1) + start; + ForkJoinSumCalculate left = new ForkJoinSumCalculate(start, middle); + left.fork();//进行拆分,同时压入线程队列 + ForkJoinSumCalculate right = new ForkJoinSumCalculate(middle + 1, end); + right.fork(); + + return left.join() + right.join(); + } + } +} \ No newline at end of file diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/executor/MyThreadPoolDemo.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/executor/MyThreadPoolDemo.java deleted file mode 100644 index 4ca96e63..00000000 --- a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/executor/MyThreadPoolDemo.java +++ /dev/null @@ -1,70 +0,0 @@ -package cn.lastwhisper.concurrent.juc.executor; - -import java.util.concurrent.*; - -public class MyThreadPoolDemo { - public static void main(String[] args) { - ExecutorService threadPool = new ThreadPoolExecutor( - 2, - 5, - 1L, - TimeUnit.SECONDS, - new LinkedBlockingDeque(3), - Executors.defaultThreadFactory(), - //threadNum>maximumPoolSize+capacity+1会异常 - //new ThreadPoolExecutor.AbortPolicy() - //threadNum>maximumPoolSize+capacity+1将任务回退到调用者 - //new ThreadPoolExecutor.CallerRunsPolicy() - //抛弃队列中等待最久的任务,然后把当前任务加入队列中尝试再次提交 - //new ThreadPoolExecutor.DiscardOldestPolicy() - //直接丢弃任务,不予任何处理也不抛出异常 - new ThreadPoolExecutor.DiscardPolicy() - ); - //模拟10个用户来办理业务 没有用户就是来自外部的请求线程. - try { - for (int i = 1; i <= 10; i++) { - threadPool.execute(() -> { - System.out.println(Thread.currentThread().getName() + "\t 办理业务"); - }); - } - } catch (Exception e) { - e.printStackTrace(); - } finally { - threadPool.shutdown(); - } - //threadPoolInit(); - } - - private static void threadPoolInit() { - /** - * 一池5个处理线程 - */ - //ExecutorService threadPool= Executors.newFixedThreadPool(5); - /** - * 一池一线程 - */ - //ExecutorService threadPool= Executors.newSingleThreadExecutor(); - /** - * 一池N线程 - */ - ExecutorService threadPool = Executors.newCachedThreadPool(); - //模拟10个用户来办理业务 没有用户就是来自外部的请求线程. - try { - for (int i = 1; i <= 20; i++) { - threadPool.execute(() -> { - System.out.println(Thread.currentThread().getName() + "\t 办理业务"); - }); - try { - TimeUnit.MICROSECONDS.sleep(200); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } catch (Exception e) { - e.printStackTrace(); - } finally { - threadPool.shutdown(); - } - } -} - diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/executor/README.md b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/executor/README.md new file mode 100644 index 00000000..7bbb5e10 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/executor/README.md @@ -0,0 +1,8 @@ + +1. RejectedExecutionHandlerTest;线程池拒绝策略 +2. ScheduledExecutorTest;调度线程池 +3. ThreadPoolIdTest;验证线程池的线程复用 +4. ThreadPoolExceptionTest;线程池execute执行异常,线程会不断创建 + + + diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/executor/RejectedExecutionHandlerTest.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/executor/RejectedExecutionHandlerTest.java new file mode 100644 index 00000000..351c7935 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/executor/RejectedExecutionHandlerTest.java @@ -0,0 +1,45 @@ +package cn.lastwhisper.concurrent.juc.executor; + +import java.util.concurrent.*; + +public class RejectedExecutionHandlerTest { + public static void main(String[] args) { + ExecutorService threadPool = new ThreadPoolExecutor( + 2, + 5, + 1L, + TimeUnit.SECONDS, + new LinkedBlockingDeque(3), + Executors.defaultThreadFactory(), + //1、AbortPolicy()策略,当前threadNum>maximumPoolSize+capacity+1会异常 + //new ThreadPoolExecutor.AbortPolicy() + //2、CallerRunsPolicy()策略,threadNum>maximumPoolSize+capacity+1任务将由调用者自己执行 + //new ThreadPoolExecutor.CallerRunsPolicy() + //3、DiscardOldestPolicy()策略,抛弃队列中等待最久的任务,然后把当前任务加入队列中尝试再次提交 + //new ThreadPoolExecutor.DiscardOldestPolicy() + //4、DiscardPolicy()策略直接丢弃任务,不予任何处理也不抛出异常 +// new ThreadPoolExecutor.DiscardPolicy() + // 5、自定义策略 + new RejectedExecutionHandler() { + @Override + public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { + System.out.println(r.toString() + " is discard"); + } + } + ); + //模拟10个用户来办理业务 每个用户就是来自外部的请求线程. + try { + for (int i = 1; i <= 10; i++) { + threadPool.execute(() -> { + System.out.println(Thread.currentThread().getName() + "\t 办理业务"); + }); + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + threadPool.shutdown(); + } + } + +} + diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/executor/ScheduledExecutorTest.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/executor/ScheduledExecutorTest.java new file mode 100644 index 00000000..01a9d587 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/executor/ScheduledExecutorTest.java @@ -0,0 +1,153 @@ +package cn.lastwhisper.concurrent.juc.executor; + +import java.util.Random; +import java.util.concurrent.*; + +/** + * 一、线程池体系 + * java.util.concurrent.Executor接口: 负责线程的使用与调度的根接口 + * |--**.ExecutorService子接口: 线程池的主要接口 + * |--**AbstractExecutorService抽象类 + * |--**ThreadPoolExecutor线程池的实现类 + * |--**ForkJoinPool Fork/Join任务窃取实现类 + * |--**ScheduledExecutorService子接口: 负责线程的调度 + * |--**ScheduledThreadPoolExecutor 继承 ThreadPoolExecutor,实现 ScheduledExecutorService + * 二、线程池创建工具类 + * java.util.concurrent.Executors主要用于创建线程池 + * ExecutorService newFixedThreadPool() : 创建固定大小的线程池 + * ExecutorService newCachedThreadPool() : 缓存线程池,线程池的数量不固定,可以根据需求自动的更改数量。 + * ExecutorService newSingleThreadExecutor() : 创建单个线程池。线程池中只有一个线程 + * ScheduledExecutorService newScheduledThreadPool() : 创建固定大小的线程,可以延迟或定时的执行任务。 + * 三、线程池原理 + * java.util.concurrent.ThreadPoolExecutor + * 1.构造函数:ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit, + * BlockingQueue workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler) + * 参数: + * corePoolSize:指定线程池中的线程数量 + * maximumPoolSize:指定了线程池中的最大线程数量 + * keepAliveTime:超过corePoolSize的空闲线程,在多长时间内会被销毁 + * unit:keepAliveTime的单位 + * workQueue:任务队列,被提交但尚未执行的任务 + * SynchronousQueue:直接提交的队列 + * ArrayBlockingQueue:有界的任务队列 + * LinkedBlockingQueue:无界的任务队列 + * PriorityBlockingQueue:优先任务队列 + * threadFactory:线程工厂,用于创建线程,一般用默认即可 + * handler:拒绝策略。任务太多来不及处理,如何拒绝任务 + * AbortPolicy:直接抛出异常,阻止系统正常工作 + * CallerRunsPolicy:只要线程池未关闭,该策略直接在调用者线程中,运行当前被丢弃的任务 + * DiscardOldestPolicy:丢弃最老的一个请求 + * DiscardPolicy:丢弃无法处理的任务 + * @author lastwhisper + */ +public class ScheduledExecutorTest { + // 计划任务线程池 + static ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5); + // 普通的线程池 + static ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5); + + public static class MyTask implements Runnable { + @Override + public void run() { + System.out.println(System.currentTimeMillis() + ":Thread ID:" + Thread.currentThread().getId()); + try { + Thread.sleep(100); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + + public static void main(String[] args) throws Exception { + ScheduledExecutorTest test = new ScheduledExecutorTest(); + //测试普通的线程池 +// test.testFixedThreadPool(); + //测试计划任务线程池 + //test.testSchedule(); + //test.testScheduleAtFixedRate(); + test.testScheduleWithFixedDelay(); + } + + private void testFixedThreadPool() throws Exception { + for (int i = 0; i < 10; i++) { + Future future = fixedThreadPool.submit(new MyTask(), new Integer(0)); + System.out.println(future.get()); + } + fixedThreadPool.shutdown(); + } + + /** + * 1.scheduleWithFixedDelay + * + * 2.构造器: + * scheduleWithFixedDelay(Runnable command,long initialDelay,long delay,TimeUnit unit); + * command任务体; + * initialDelay初始延时时间; + * period:等待时间; + * unit:时间单位; + * 3.testScheduleWithFixedDelay不会等待执行体内的执行时间 + */ + private void testScheduleWithFixedDelay() throws Exception { + ((ScheduledThreadPoolExecutor)scheduledThreadPool).scheduleWithFixedDelay(new Runnable() { + @Override + public void run() { + try { + Thread.sleep(8000); + System.out.println(System.currentTimeMillis() / 1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + }, 0, 2, TimeUnit.SECONDS); + } + + /** + * 1.scheduleAtFixedRate + * 创建一个周期性任务,任务开始于给定的初始化延时。 + * 后续第一个任务会在initialDelay+1*period时执行,第二个任务会在initialDelay+2*period时执行,以此类推。 + * 2.构造器: + * scheduleAtFixedRate(Runnable command,long initialDelay,long period,TimeUnit unit); + * command任务体; + * initialDelay初始延时时间; + * period:等待时间; + * unit:时间单位; + * 3.scheduleAtFixedRate会等待执行体内的执行时间 + */ + private void testScheduleAtFixedRate() throws Exception { + scheduledThreadPool.scheduleAtFixedRate(new Runnable() { + @Override + public void run() { + try { + Thread.sleep(8000); + System.out.println(System.currentTimeMillis() / 1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + }, 0, 2, TimeUnit.SECONDS); + } + + /** + * 1.schedule:给定时间,对任务进行一次调度 + * 2.构造器: + * schedule(Callable callable,long delay, TimeUnit unit) + * schedule(Runnable command,long delay, TimeUnit unit) + * 参数意义: + * callable、command任务体; + * delay延时时间; + * unit:时间单位 + */ + private void testSchedule() throws ExecutionException, InterruptedException { + // 给定时间,对任务进行一次调度 + Future result = scheduledThreadPool.schedule(new Callable() { + @Override + public Integer call() throws Exception { + int num = new Random().nextInt(100);//生成随机数 + System.out.println(Thread.currentThread().getName() + " : " + num); + return num; + } + }, 1, TimeUnit.SECONDS); + System.out.println("返回的计算结果:" + result.get()); + scheduledThreadPool.shutdown(); + } +} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/executor/TestForkJoinPool.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/executor/TestForkJoinPool.java deleted file mode 100644 index 497b04b9..00000000 --- a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/executor/TestForkJoinPool.java +++ /dev/null @@ -1,67 +0,0 @@ -package cn.lastwhisper.concurrent.juc.executor; - -import org.junit.Test; - -import java.time.Duration; -import java.time.Instant; -import java.util.concurrent.ForkJoinPool; -import java.util.concurrent.ForkJoinTask; -import java.util.concurrent.RecursiveTask; - -/** - * fork/join任务偷窃 - * @author lastwhisper - */ -public class TestForkJoinPool { - public static void main(String[] args) { - Instant start = Instant.now(); - ForkJoinPool pool = new ForkJoinPool(); - ForkJoinTask task = new ForkJoinSumCalculate(0L, 100000000L); - Long sum = pool.invoke(task); - System.out.println("结果:" + sum); - Instant end = Instant.now(); - System.out.println("耗费时间:" + Duration.between(start, end).toMillis());//28 - } - @Test - public void test1(){ - Instant start = Instant.now(); - long sum = 0L; - for (long i = 0L; i <= 100000000L; i++) { - sum += i; - } - System.out.println(sum); - Instant end = Instant.now(); - System.out.println("耗费时间为:" + Duration.between(start, end).toMillis());//51 - } -} - -class ForkJoinSumCalculate extends RecursiveTask { - private static final long THUSHOLD = 10000000L;//临界值 - private long start; - private long end; - - public ForkJoinSumCalculate(long start, long end) { - this.start = start; - this.end = end; - } - - @Override - protected Long compute() { - long length = end - start; - if (length <= THUSHOLD) { - long sum = 0L; - for (long i = start; i <= end; i++) { - sum += i; - } - return sum; - } else { - long middle = ((end - start) >> 1) + start; - ForkJoinSumCalculate left = new ForkJoinSumCalculate(start, middle); - left.fork();//进行拆分,同时压入线程队列 - ForkJoinSumCalculate right = new ForkJoinSumCalculate(middle + 1, end); - right.fork(); - - return left.join() + right.join(); - } - } -} \ No newline at end of file diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/executor/TestRejectedExecutionHandler.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/executor/TestRejectedExecutionHandler.java deleted file mode 100644 index e5deac61..00000000 --- a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/executor/TestRejectedExecutionHandler.java +++ /dev/null @@ -1,36 +0,0 @@ -package cn.lastwhisper.concurrent.juc.executor; - -import java.util.concurrent.*; - -/** - * 自定义线程池的拒绝策略 - * @author lastwhisper - */ -public class TestRejectedExecutionHandler { - public static class MyTask implements Runnable{ - @Override - public void run() { - System.out.println(System.currentTimeMillis()+":Thread ID:"+Thread.currentThread().getId()); - try { - Thread.sleep(100); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } - - public static void main(String[] args) throws InterruptedException { - MyTask myTask = new MyTask(); - ExecutorService pool = new ThreadPoolExecutor(5, 5, 0, - TimeUnit.MILLISECONDS, new LinkedBlockingQueue(10), Executors.defaultThreadFactory(), new RejectedExecutionHandler() { - @Override - public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { - System.out.println(r.toString()+" is discard"); - } - }); - for (int i = 0; i < Integer.MAX_VALUE; i++) { - pool.submit(myTask); - Thread.sleep(10); - } - } -} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/executor/TestThreadPool.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/executor/TestThreadPool.java deleted file mode 100644 index 19e14e4c..00000000 --- a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/executor/TestThreadPool.java +++ /dev/null @@ -1,153 +0,0 @@ -package cn.lastwhisper.concurrent.juc.executor; - -import java.util.Random; -import java.util.concurrent.*; - -/** - * 一、线程池体系 - * java.util.concurrent.Executor接口: 负责线程的使用与调度的根接口 - * |--**.ExecutorService子接口: 线程池的主要接口 - * |--**AbstractExecutorService抽象类 - * |--**ThreadPoolExecutor线程池的实现类 - * |--**ForkJoinPool Fork/Join任务窃取实现类 - * |--**ScheduledExecutorService子接口: 负责线程的调度 - * |--**ScheduledThreadPoolExecutor 继承 ThreadPoolExecutor,实现 ScheduledExecutorService - * 二、线程池创建工具类 - * java.util.concurrent.Executors主要用于创建线程池 - * ExecutorService newFixedThreadPool() : 创建固定大小的线程池 - * ExecutorService newCachedThreadPool() : 缓存线程池,线程池的数量不固定,可以根据需求自动的更改数量。 - * ExecutorService newSingleThreadExecutor() : 创建单个线程池。线程池中只有一个线程 - * ScheduledExecutorService newScheduledThreadPool() : 创建固定大小的线程,可以延迟或定时的执行任务。 - * 三、线程池原理 - * java.util.concurrent.ThreadPoolExecutor - * 1.构造函数:ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit, - * BlockingQueue workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler) - * 参数: - * corePoolSize:指定线程池中的线程数量 - * maximumPoolSize:指定了线程池中的最大线程数量 - * keepAliveTime:超过corePoolSize的空闲线程,在多长时间内会被销毁 - * unit:keepAliveTime的单位 - * workQueue:任务队列,被提交但尚未执行的任务 - * SynchronousQueue:直接提交的队列 - * ArrayBlockingQueue:有界的任务队列 - * LinkedBlockingQueue:无界的任务队列 - * PriorityBlockingQueue:优先任务队列 - * threadFactory:线程工厂,用于创建线程,一般用默认即可 - * handler:拒绝策略。任务太多来不及处理,如何拒绝任务 - * AbortPolicy:直接抛出异常,阻止系统正常工作 - * CallerRunsPolicy:只要线程池未关闭,该策略直接在调用者线程中,运行当前被丢弃的任务 - * DiscardOldestPolicy:丢弃最老的一个请求 - * DiscardPolicy:丢弃无法处理的任务 - * @author lastwhisper - */ -public class TestThreadPool { - // 计划任务线程池 - static ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5); - // 普通的线程池 - static ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5); - - public static class MyTask implements Runnable { - @Override - public void run() { - System.out.println(System.currentTimeMillis() + ":Thread ID:" + Thread.currentThread().getId()); - try { - Thread.sleep(100); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } - - public static void main(String[] args) throws Exception { - TestThreadPool test = new TestThreadPool(); - //测试普通的线程池 - test.testFixedThreadPool(); - //测试计划任务线程池 - //test.testSchedule(); - //test.testScheduleAtFixedRate(); - //test.testScheduleWithFixedDelay(); - } - - private void testFixedThreadPool() throws Exception { - for (int i = 0; i < 10; i++) { - Future future = fixedThreadPool.submit(new MyTask(), new Integer(0)); - System.out.println(future.get()); - } - fixedThreadPool.shutdown(); - } - - /** - * 1.scheduleWithFixedDelay - * - * 2.构造器: - * scheduleWithFixedDelay(Runnable command,long initialDelay,long delay,TimeUnit unit); - * command任务体; - * initialDelay初始延时时间; - * period:等待时间; - * unit:时间单位; - * 3.testScheduleWithFixedDelay不会等待执行体内的执行时间 - */ - private void testScheduleWithFixedDelay() throws Exception { - scheduledThreadPool.scheduleWithFixedDelay(new Runnable() { - @Override - public void run() { - try { - Thread.sleep(8000); - System.out.println(System.currentTimeMillis() / 1000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - }, 0, 2, TimeUnit.SECONDS); - } - - /** - * 1.scheduleAtFixedRate - * 创建一个周期性任务,任务开始于给定的初始化延时。 - * 后续第一个任务会在initialDelay+1*period时执行,第二个任务会在initialDelay+2*period时执行,以此类推。 - * 2.构造器: - * scheduleAtFixedRate(Runnable command,long initialDelay,long period,TimeUnit unit); - * command任务体; - * initialDelay初始延时时间; - * period:等待时间; - * unit:时间单位; - * 3.scheduleAtFixedRate会等待执行体内的执行时间 - */ - private void testScheduleAtFixedRate() throws Exception { - scheduledThreadPool.scheduleAtFixedRate(new Runnable() { - @Override - public void run() { - try { - Thread.sleep(8000); - System.out.println(System.currentTimeMillis() / 1000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - }, 0, 2, TimeUnit.SECONDS); - } - - /** - * 1.schedule:给定时间,对任务进行一次调度 - * 2.构造器: - * schedule(Callable callable,long delay, TimeUnit unit) - * schedule(Runnable command,long delay, TimeUnit unit) - * 参数意义: - * callable、command任务体; - * delay延时时间; - * unit:时间单位 - */ - private void testSchedule() throws ExecutionException, InterruptedException { - // 给定时间,对任务进行一次调度 - Future result = scheduledThreadPool.schedule(new Callable() { - @Override - public Integer call() throws Exception { - int num = new Random().nextInt(100);//生成随机数 - System.out.println(Thread.currentThread().getName() + " : " + num); - return num; - } - }, 1, TimeUnit.SECONDS); - System.out.println("返回的计算结果:" + result.get()); - scheduledThreadPool.shutdown(); - } -} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/executor/ThreadPoolExceptionTest.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/executor/ThreadPoolExceptionTest.java new file mode 100644 index 00000000..039a9310 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/executor/ThreadPoolExceptionTest.java @@ -0,0 +1,60 @@ +package cn.lastwhisper.concurrent.juc.executor; + +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +/** + * 测试线程池出现异常时的线程id + * @author lastwhisper + * @date 2022/5/2 + */ +public class ThreadPoolExceptionTest { + + public static void main(String[] args) { + // 线程池会复用线程,线程id会重复出现; + // 但是线程池执行任务出现异常,会把异常线程移除,创建新的线程 + ExecutorService pool = Executors.newFixedThreadPool(1); + for (int i = 0; i < 100; i++) { + int finalI = i; + pool.execute(() -> { + if(finalI % 2==0){ + try { + int x = finalI/0; + } catch (Exception e) { + System.err.println("异常线程id:"+Thread.currentThread().getId()+" e:"+e); + throw e; + } + } + System.err.println("无异常线程id:"+Thread.currentThread().getId()); + }); + } + pool.shutdown(); + + +// ExecutorService pool = Executors.newFixedThreadPool(1); +// for (int i = 0; i < 50; i++) { +// int finalI = i; +// Future future = pool.submit(() -> { +// if (finalI % 2 == 0) { +// try { +// int x = finalI / 0; +// } catch (Exception e) { +// System.err.println("异常线程id:" + Thread.currentThread().getId() + " e:" + e); +// throw e; +// } +// } +// System.err.println("无异常线程id:" + Thread.currentThread().getId()); +// }); +// try { +// System.out.println(future.get()); +// } catch (InterruptedException | ExecutionException e) { +// e.printStackTrace(); +// } +// } +// pool.shutdown(); + + } + +} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/executor/ThreadPoolIdTest.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/executor/ThreadPoolIdTest.java new file mode 100644 index 00000000..fc11019f --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/executor/ThreadPoolIdTest.java @@ -0,0 +1,26 @@ +package cn.lastwhisper.concurrent.juc.executor; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +/** + * 测试线程池中的线程id + * @author lastwhisper + * @date 2020/2/28 + */ +public class ThreadPoolIdTest { + + public static void main(String[] args) { + // 线程池会复用线程,线程id会重复出现 + ExecutorService pool = Executors.newFixedThreadPool(10); + for (int i = 0; i < 100; i++) { + pool.execute(() -> { +// pool.submit(() -> { + System.err.println(Thread.currentThread().getId()); + }); + } + + pool.shutdown(); + } + +} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/executor/trace/CatchException.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/executor/trace/CatchException.java new file mode 100644 index 00000000..38971f00 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/executor/trace/CatchException.java @@ -0,0 +1,38 @@ +package cn.lastwhisper.concurrent.juc.executor.trace; + +import java.util.concurrent.*; + +/** + * submit吃掉异常 + * 1. 用Future.get()获得异常 + * 2. try-catch + * @author Geym + * + */ +public class CatchException { + public static void main(String[] args) throws InterruptedException, ExecutionException { + ThreadPoolExecutor pools=new ThreadPoolExecutor(0, Integer.MAX_VALUE, + 0L, TimeUnit.SECONDS, + new SynchronousQueue()); + + // 1、不打印异常;submit + for(int i=0;i<5;i++){ + pools.submit(new DivTask(100,i)); + } + System.out.println("======================================================"); + // 2、打印异常;execute + for (int i = 0; i < 5; i++) { + pools.execute(new DivTask(100, i)); + } + System.out.println("======================================================"); + // 3、打印异常;Future.get() + for (int i = 0; i < 5; i++) { + Future re = pools.submit(new DivTask(100, i)); + try { + re.get(); + } catch (ExecutionException e) { + e.printStackTrace(); + } + } + } +} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/executor/trace/DivTask.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/executor/trace/DivTask.java new file mode 100644 index 00000000..c9a63a76 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/executor/trace/DivTask.java @@ -0,0 +1,14 @@ +package cn.lastwhisper.concurrent.juc.executor.trace; + +public class DivTask implements Runnable { + int a,b; + public DivTask(int a,int b){ + this.a=a; + this.b=b; + } + @Override + public void run() { + double re=a/b; + System.out.println(re); + } +} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/executor/trace/README.md b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/executor/trace/README.md new file mode 100644 index 00000000..42f521c9 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/executor/trace/README.md @@ -0,0 +1,3 @@ +CatchException;线程池如何处理异常 +TraceMain;包装线程池异常 + diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/executor/trace/TraceMain.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/executor/trace/TraceMain.java new file mode 100644 index 00000000..36828112 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/executor/trace/TraceMain.java @@ -0,0 +1,19 @@ +package cn.lastwhisper.concurrent.juc.executor.trace; + +import java.util.concurrent.SynchronousQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + + +public class TraceMain { + + public static void main(String[] args) { + ThreadPoolExecutor pools=new TraceThreadPoolExecutor(0, Integer.MAX_VALUE, + 0L, TimeUnit.SECONDS, + new SynchronousQueue()); + for(int i=0;i<5;i++){ + pools.execute(new DivTask(100,i)); + } + } + +} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/executor/trace/TraceThreadPoolExecutor.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/executor/trace/TraceThreadPoolExecutor.java new file mode 100644 index 00000000..22c8e26e --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/executor/trace/TraceThreadPoolExecutor.java @@ -0,0 +1,44 @@ +package cn.lastwhisper.concurrent.juc.executor.trace; + +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.Future; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +public class TraceThreadPoolExecutor extends ThreadPoolExecutor { + public TraceThreadPoolExecutor(int corePoolSize, int maximumPoolSize, + long keepAliveTime, TimeUnit unit, BlockingQueue workQueue) { + super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue); + } + + @Override + public void execute(Runnable task) { + super.execute(wrap(task, clientTrace(), Thread.currentThread() + .getName())); + } + + @Override + public Future submit(Runnable task) { + return super.submit(wrap(task, clientTrace(), Thread.currentThread() + .getName())); + } + + private Exception clientTrace() { + return new Exception("Client stack trace"); + } + + private Runnable wrap(final Runnable task, final Exception clientStack, + String clientThreadName) { + return new Runnable() { + @Override + public void run() { + try { + task.run(); + } catch (Exception e) { + clientStack.printStackTrace(); + throw e; + } + } + }; + } +} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/future/FutureTest.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/future/FutureTest.java new file mode 100644 index 00000000..47f5438b --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/future/FutureTest.java @@ -0,0 +1,30 @@ +package cn.lastwhisper.concurrent.juc.future; + +import java.util.concurrent.*; + +/** + * @author cunchang + * @date 2022/4/22 5:18 PM + */ +public class FutureTest { + public static void main(String[] args) throws InterruptedException, ExecutionException { + FutureTask futureTask = new FutureTask<>(new Task()," circuit breaker defalut result"); + ExecutorService threadPool = Executors.newFixedThreadPool(1); + threadPool.submit(futureTask); + + System.out.println("异步提交任务"); + // 同步执行其他业务 + Thread.sleep(200); + System.out.println("同步执行其他业务,200ms"); + + // call方法未执行完,这里会阻塞 + try { + System.out.println("接口1000ms拿不到结果就熔断:"+futureTask.get(1, TimeUnit.SECONDS)); + } catch (TimeoutException e) { + threadPool.shutdown(); + System.err.println(e); + } + + threadPool.shutdown(); + } +} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/future/Task.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/future/Task.java new file mode 100644 index 00000000..29c8991d --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/future/Task.java @@ -0,0 +1,20 @@ +package cn.lastwhisper.concurrent.juc.future; + +/** + * @author cunchang + * @date 2022/4/22 5:15 PM + */ +public class Task implements Runnable { + + @Override + public void run() { + for (int i = 0; i < 12; i++) { + try { + Thread.sleep(100); + System.out.println("有12个任务,当前任务" + i + "执行中,已耗时" + i + "00ms,"); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } +} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/lock/ReentrantLockDemo.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/lock/ReentrantLockDemo.java new file mode 100644 index 00000000..b35a910d --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/lock/ReentrantLockDemo.java @@ -0,0 +1,32 @@ +package cn.lastwhisper.concurrent.juc.lock; + +import java.util.concurrent.locks.ReentrantLock; + +/** + * 重入锁的公平性 + * @author lastwhisper + */ +public class ReentrantLockDemo implements Runnable { + //是否公平,公平时交替打印 + private final ReentrantLock lock = new ReentrantLock(true); + + @Override + public void run() { + for(;;){ + try { + lock.lock(); + System.out.println(Thread.currentThread().getName()); + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + }finally { + lock.unlock(); + } + } + } + public static void main(String[] args){ + ReentrantLockDemo lockDemo = new ReentrantLockDemo(); + new Thread(lockDemo,"A").start(); + new Thread(lockDemo,"B").start(); + } +} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/lock/ReentrantLockInterruptedDemo.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/lock/ReentrantLockInterruptedDemo.java new file mode 100644 index 00000000..9749d5bf --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/lock/ReentrantLockInterruptedDemo.java @@ -0,0 +1,46 @@ +package cn.lastwhisper.concurrent.juc.lock; + +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.ReentrantLock; + +/** + * @author lastwhisper + */ +public class ReentrantLockInterruptedDemo { + + public static void main(String[] args) throws InterruptedException { + + ReentrantLock lock = new ReentrantLock(); + Thread t1 = new Thread(() -> { + try { + lock.lock(); + System.out.println("t1 come in"); + try { + TimeUnit.MINUTES.sleep(20); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } finally { + lock.unlock(); + } + }, "A"); + t1.start(); + + Thread t2 = new Thread(() -> { + try { + lock.lockInterruptibly(); + System.out.println("t2 come in"); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + System.out.println("t2线程被人中断"); + } finally { + lock.unlock(); + } + }, "B"); + t2.start(); + + Thread.sleep(1000); + t2.interrupt(); + Thread.sleep(1000); + } +} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/locks/SpinLockDemo.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/lock/SpinLockDemo.java similarity index 97% rename from java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/locks/SpinLockDemo.java rename to java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/lock/SpinLockDemo.java index dfc2e1fb..a269a7bf 100644 --- a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/locks/SpinLockDemo.java +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/lock/SpinLockDemo.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.concurrent.juc.locks; +package cn.lastwhisper.concurrent.juc.lock; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/locks/TestLock.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/lock/TestLock.java similarity index 96% rename from java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/locks/TestLock.java rename to java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/lock/TestLock.java index c4a93845..946048a4 100644 --- a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/locks/TestLock.java +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/lock/TestLock.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.concurrent.juc.locks; +package cn.lastwhisper.concurrent.juc.lock; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/lock/TestManyReadOneWriteCollection.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/lock/TestManyReadOneWriteCollection.java new file mode 100644 index 00000000..0c9e927c --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/lock/TestManyReadOneWriteCollection.java @@ -0,0 +1,111 @@ +package cn.lastwhisper.concurrent.juc.lock; + +import java.util.ArrayList; +import java.util.Random; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +/** + * 多读一写集合是否线程安全 + * @author lastwhisper + */ +public class TestManyReadOneWriteCollection { + // 读写锁 + private static ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); + private static Lock readLock = readWriteLock.readLock(); + private static Lock writeLock = readWriteLock.writeLock(); + // 闭锁 + private static CountDownLatch latch = new CountDownLatch(21); + + private static ExecutorService threadPool = Executors.newCachedThreadPool(); + + // 共享数据 + private ArrayList collection = new ArrayList<>(); + + { + for (int i = 0; i < 20; i++) { + collection.add(i); + } + } + + public static void main(String[] args) throws InterruptedException { + + TestManyReadOneWriteCollection rwl = new TestManyReadOneWriteCollection(); + // 读线程执行的主体 + Runnable readThread = () -> { + //System.out.println(rwl.handleReadLock(readLock));; + System.out.println(rwl.handleRead()); + latch.countDown(); + }; + // 写线程执行的主体 + Runnable writeThread = () -> { + //rwl.handleWriteLock(writeLock, new Random().nextInt(10000)); + rwl.handleWrite(new Random().nextInt(10000)); + latch.countDown(); + }; + + // 多读一写 + for (int i = 0; i < 10; i++) { + threadPool.execute(readThread); + } + for (int i = 0; i < 1; i++) { + threadPool.execute(writeThread); + } + for (int i = 0; i < 10; i++) { + threadPool.execute(readThread); + } + latch.await(); + threadPool.shutdown(); + } + + // 读取文件 + public String handleRead() { + StringBuilder result= new StringBuilder(); + //Thread.sleep(9); + for (Integer num : collection) { + result.append(num); + } + return result.toString(); + } + + // 写入文件 + public void handleWrite(int writeVal) { + //Thread.sleep(10); + for (int i = 0; i < writeVal; i++) { + collection.add(i); + } + } + + // 读取文件 + public String handleReadLock(Lock lock) { + StringBuilder result= new StringBuilder(); + lock.lock(); + try { + //Thread.sleep(9); + for (Integer num : collection) { + result.append(num); + } + } finally { + lock.unlock(); + } + return result.toString(); + } + + // 写入文件 + public void handleWriteLock(Lock lock, int writeVal) { + lock.lock(); + try { + //Thread.sleep(10); + for (int i = 0; i < writeVal; i++) { + collection.add(i); + } + } finally { + lock.unlock(); + } + } + +} \ No newline at end of file diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/locks/TestReadWriteLock.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/lock/TestReadWriteLock.java similarity index 91% rename from java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/locks/TestReadWriteLock.java rename to java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/lock/TestReadWriteLock.java index f73202fb..e0aeefbc 100644 --- a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/locks/TestReadWriteLock.java +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/lock/TestReadWriteLock.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.concurrent.juc.locks; +package cn.lastwhisper.concurrent.juc.lock; import java.time.Duration; import java.time.Instant; @@ -34,8 +34,8 @@ public static void main(String[] args) throws InterruptedException { Runnable readThread = new Runnable() { @Override public void run() { - //rwl.handleRead(readLock); - rwl.handleRead(lock); + rwl.handleRead(readLock); + //rwl.handleRead(lock); latch.countDown(); } }; @@ -43,8 +43,8 @@ public void run() { Runnable writeThread = new Runnable() { @Override public void run() { - //rwl.handleWrite(writeLock, new Random().nextInt()); - rwl.handleWrite(lock, new Random().nextInt()); + rwl.handleWrite(writeLock, new Random().nextInt()); + //rwl.handleWrite(lock, new Random().nextInt()); latch.countDown(); } }; diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/locks/ReentrantLockDemo.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/locks/ReentrantLockDemo.java deleted file mode 100644 index 3c7d34f1..00000000 --- a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/locks/ReentrantLockDemo.java +++ /dev/null @@ -1,36 +0,0 @@ -package cn.lastwhisper.concurrent.juc.locks; - -import java.util.Random; -import java.util.concurrent.locks.ReentrantLock; - -/** - * 重入锁的公平性 - * http://www.imooc.com/article/288805?block_id=tuijian_wz - * @author lastwhisper - */ -public class ReentrantLockDemo implements Runnable { - //是否公平,公平时交替打印 - private ReentrantLock lock = new ReentrantLock(true); - - @Override - public void run() { - while (true){ - try { - lock.lock(); - lock.lock(); - System.out.println(Thread.currentThread().getName()); - Thread.sleep(1000); - } catch (InterruptedException e) { - e.printStackTrace(); - }finally { - lock.unlock(); - lock.unlock(); - } - } - } - public static void main(String[] args){ - ReentrantLockDemo lockDemo = new ReentrantLockDemo(); - new Thread(lockDemo,"A").start(); - new Thread(lockDemo,"B").start(); - } -} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/locks/ReentrantLockToReentryDemo.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/locks/ReentrantLockToReentryDemo.java deleted file mode 100644 index 66565cf0..00000000 --- a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/locks/ReentrantLockToReentryDemo.java +++ /dev/null @@ -1,65 +0,0 @@ -package cn.lastwhisper.concurrent.juc.locks; - -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; - -class Phone implements Runnable { - private Lock lock = new ReentrantLock(); - - @Override - public void run() { - get(); - } - - private void get() { - lock.lock(); - try { - System.out.println(Thread.currentThread().getName() + "\tget\tlock"); - set(); - } finally { - System.out.println(Thread.currentThread().getName() + "\tget\tunlock"); - lock.unlock(); - } - } - - private void set() { - lock.lock(); - try { - System.out.println(Thread.currentThread().getName() + "\tset\tlock"); - } finally { - System.out.println(Thread.currentThread().getName() + "\tset\tunlock"); - lock.unlock(); - } - } -} - -/** - * Description: - * 可重入锁(也叫做递归锁) - * 指的是同一先生外层函数获得锁后,内层敌对函数任然能获取该锁的代码 - * 在同一线程外外层方法获取锁的时候,在进入内层方法会自动获取锁 - *

- * 也就是说,线程可以进入任何一个它已经标记的锁所同步的代码块 - * - * @author veliger@163.com - * @date 2019-04-12 23:36 - **/ -public class ReentrantLockToReentryDemo { - /** - * Thread-0 get - * Thread-0 set - * Thread-1 get - * Thread-1 set - * - * @param args - */ - public static void main(String[] args) { - Phone phone = new Phone(); - Thread t3 = new Thread(phone); - Thread t4 = new Thread(phone); - t3.start(); - t4.start(); - - } -} - diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/locks/TestLockSupport.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/locks/TestLockSupport.java deleted file mode 100644 index 4e948693..00000000 --- a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/locks/TestLockSupport.java +++ /dev/null @@ -1,41 +0,0 @@ -package cn.lastwhisper.concurrent.juc.locks; - -import java.util.concurrent.locks.LockSupport; - -/** - * 线程阻塞工具类 - * @author lastwhisper - */ -public class TestLockSupport { - private static ChangObjectThread t1 = new ChangObjectThread("t1"); - private static ChangObjectThread t2 = new ChangObjectThread("t2"); - - public static void main(String[] args) throws InterruptedException { - t1.start(); - Thread.sleep(1000); - t2.start(); - LockSupport.unpark(t1); - Thread.sleep(1000); - LockSupport.unpark(t2); - t1.join(); - t2.join(); - } -} - -class ChangObjectThread extends Thread { - final static Object lock = new Object(); - public ChangObjectThread(String name) { - super(name); - } - - @Override - public void run() { - synchronized (lock) { - System.out.println("in " + getName()); - // sleep - LockSupport.park(); - System.out.println("out " + getName()); - } - } - -} \ No newline at end of file diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/locksupport/LockSupportDemo.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/locksupport/LockSupportDemo.java new file mode 100644 index 00000000..cf6cbf12 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/locksupport/LockSupportDemo.java @@ -0,0 +1,115 @@ +package cn.lastwhisper.concurrent.juc.locksupport; + +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.LockSupport; +import java.util.concurrent.locks.ReentrantLock; + +/** + * + * on 2020/11/10 23:17 + */ +public class LockSupportDemo { + + static Object objectLock = new Object(); + static Lock lock = new ReentrantLock(); + static Condition condition = lock.newCondition(); + + public static void main(String[] args) { +// synchronizedWaitNotify(); +// lockAwaitSignal(); + lockSupport(); + } + + private static void lockSupport() { + Thread a = new Thread(() -> { + try { + TimeUnit.SECONDS.sleep(3L); + } catch (InterruptedException e) { + e.printStackTrace(); + } + System.out.println(Thread.currentThread().getName() + "\t" + "come in" + System.currentTimeMillis()); + LockSupport.park(); //wait 被阻塞,等待通知等待放行,它要通过需要许可证 + System.out.println(Thread.currentThread().getName() + "\t" + "---被唤醒--" + System.currentTimeMillis()); + }, "a"); + a.start(); + + //暂停几秒钟线程 + /* try { + TimeUnit.SECONDS.sleep(3L); + } catch (InterruptedException e) { + e.printStackTrace(); + }*/ + + Thread b = new Thread(() -> { + LockSupport.unpark(a); + System.out.println(Thread.currentThread().getName() + "\t" + "---被唤醒--"); + + }, "b"); + b.start(); + } + + private static void lockAwaitSignal() { + new Thread(() -> { + lock.lock(); + try { + System.out.println(Thread.currentThread().getName() + "\t" + "----come in"); + try { + condition.await(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + System.out.println(Thread.currentThread().getName() + "\t" + "----被唤醒"); + } finally { + lock.unlock(); + } + }, "A").start(); + + new Thread(() -> { + lock.lock(); + try { + condition.signal(); + System.out.println(Thread.currentThread().getName() + "\t" + "----通知---"); + } finally { + lock.unlock(); + } + }, "B").start(); + } + + /** + * synchronized/wait/notifyAll + */ + private static void synchronizedWaitNotify() { + new Thread(() -> { + //暂停几秒钟线程 +// try { +// TimeUnit.SECONDS.sleep(3); +// } catch (InterruptedException e) { +// e.printStackTrace(); +// } + synchronized (objectLock) { + System.out.println(Thread.currentThread().getName() + "\t" + "---come in--"); + try { + objectLock.wait(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + System.out.println(Thread.currentThread().getName() + "\t" + "-----被唤醒-----"); + } + + }, "A").start(); + + new Thread(() -> { + try { + TimeUnit.SECONDS.sleep(3); + } catch (InterruptedException e) { + e.printStackTrace(); + } + synchronized (objectLock) { + objectLock.notify(); + System.out.println(Thread.currentThread().getName() + "\t" + "---通知---"); + } + }, "B").start(); + } +} \ No newline at end of file diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/locksupport/README.md b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/locksupport/README.md new file mode 100644 index 00000000..35bc7546 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/locksupport/README.md @@ -0,0 +1,11 @@ +## 一、线程阻塞唤醒 +方式1: 使用Object中的wait()方法让线程等待, 使用Object中的notify()方法唤醒线程 +方式2: 使用JUC包中Condition的await()方法让线程等待,使用signal()方法唤醒线程 +方式3: LockSupport类可以阻塞当前线程以及唤醒指定被阻塞的线程 + +## 二、优缺点 +传统的synchronized和Lock实现等待唤醒通知的约束 +1. 线程先要获得并持有锁,必须在锁块(synchronized或lock)中 +2. 必须要先等待后唤醒,线程才能够被唤醒 + + diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/tools/README.md b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/tools/README.md new file mode 100644 index 00000000..e69de29b diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/tools/TestCountDownLatch.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/tools/TestCountDownLatch.java index 5061a2f2..ac5b7e72 100644 --- a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/tools/TestCountDownLatch.java +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/tools/TestCountDownLatch.java @@ -1,52 +1,70 @@ package cn.lastwhisper.concurrent.juc.tools; -import java.util.concurrent.CountDownLatch; +import java.time.LocalDate; +import java.time.Period; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.*; /** * 闭锁是一种同步方法,可以延迟线程的进度直到其到达终止状态。 * 闭锁可以用来确保某些活动直到其他活动都完成才继续执行: + * * @author lastwhisper */ public class TestCountDownLatch { - public static void main(String[] args) { + // 线程池并行执行任务 + private static ExecutorService threadPool = Executors.newFixedThreadPool(10); + + public static void main(String[] args) throws InterruptedException, ExecutionException { + CountDownLatch latch = new CountDownLatch(5); - CountDownLatchDemo cdl = new CountDownLatchDemo(latch); - long start = System.currentTimeMillis(); - for (int i = 0; i < 5; i++) { - new Thread(cdl).start(); + + List months = Arrays.asList("1月份", "2月份", "3月份", "4月份", "5月份"); + List> futureList = new ArrayList<>(); + // 并发执行每个月的报表 + for (String month : months) { + Future future = threadPool.submit(new Report(latch, month)); + futureList.add(future); } - try { - //等待所有线程执行完毕 - latch.await(); - } catch (InterruptedException e) { - e.printStackTrace(); + System.out.println("等待所有线程执行完毕"); + latch.await(); + // 对每个线程执行结果进行汇总 + List allReportData = new ArrayList<>(); + for (Future future : futureList) { + allReportData.add(future.get()); } - long end = System.currentTimeMillis(); - System.out.println("耗时:" + (end - start)); + + System.out.println(allReportData); + + // 关闭线程池 + threadPool.shutdown(); } } -class CountDownLatchDemo implements Runnable { +class Report implements Callable { private CountDownLatch latch; + private String month; - public CountDownLatchDemo(CountDownLatch latch) { + public Report(CountDownLatch latch, String month) { this.latch = latch; + this.month = month; } @Override - public void run() { - synchronized (this) { - try { - for (int i = 0; i < 1000; i++) { - if (i % 2 == 0) { - System.out.println(i); - } - } - } finally { - //线程完成后,进行减一 - latch.countDown(); - } - + public String call() { + try { + Thread.sleep(200); + System.out.println(month + "报表统计完毕"); + } catch (InterruptedException e) { + e.printStackTrace(); + } finally { + //线程完成后,进行减一 + latch.countDown(); } + return month + "报表数据"; } + + } \ No newline at end of file diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/tools/TestCountDownLatch2.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/tools/TestCountDownLatch2.java new file mode 100644 index 00000000..2a268b85 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/juc/tools/TestCountDownLatch2.java @@ -0,0 +1,54 @@ +package cn.lastwhisper.concurrent.juc.tools; + +import java.time.LocalDate; +import java.time.Period; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +/** + * 范围日期,按天提交到线程池,最后等待汇总 + * @author lastwhisper + */ +public class TestCountDownLatch2 { + + private static ExecutorService threadPool = Executors.newFixedThreadPool(10); + + public static void main(String[] args) throws InterruptedException, ExecutionException { + LocalDate startDate = LocalDate.now().plusDays(-30), endDate = LocalDate.now(); + + // 这种才能计算出日期之差 + int dayGap = (int) (endDate.toEpochDay() - startDate.toEpochDay())+1; + // 这种要同月才行 +// int dayGap = Period.between(endDate,startDate).getDays()+1; + System.out.println("startDate:" + startDate + " endDate:" + endDate + " 日期之差:" + dayGap); + + CountDownLatch countDownLatch = new CountDownLatch(dayGap); + + while (!startDate.isAfter(endDate)) { + LocalDate finalStartDate = startDate; + threadPool.submit(() -> { + try { + Thread.sleep(100); + System.out.println("startDate:" + finalStartDate); + } catch (InterruptedException e) { + System.out.println("startDate:" + finalStartDate+"InterruptedException:"+e); + Thread.interrupted(); + } finally { + countDownLatch.countDown(); + } + }); + startDate = startDate.plusDays(1L); + } + + try { + countDownLatch.await(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + // 关闭线程池,立即 + threadPool.shutdownNow(); + } +} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/unsafe/README.md b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/unsafe/README.md new file mode 100644 index 00000000..b15edf16 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/unsafe/README.md @@ -0,0 +1,7 @@ + + + + +为什么JUC中大量使用了sun.misc.Unsafe 这个类,但官方却不建议开发者使用? - 落白的回答 - 知乎 +https://www.zhihu.com/question/29266773/answer/2461567743 + diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/unsafe/UnSafeCreateTest.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/unsafe/UnSafeCreateTest.java new file mode 100644 index 00000000..8d0603fb --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/unsafe/UnSafeCreateTest.java @@ -0,0 +1,29 @@ +package cn.lastwhisper.concurrent.unsafe; + +import sun.misc.Unsafe; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; + +/** + * @author cunchang + * @date 2022/4/29 12:24 AM + */ +public class UnSafeCreateTest { + + public static void main(String[] args) throws Exception{ + // method 1 + Class unsafeClass = Unsafe.class; + Constructor constructor = unsafeClass.getDeclaredConstructor(); + constructor.setAccessible(true); + Unsafe unsafe1 = constructor.newInstance(); + System.out.println(unsafe1); + + // method2 + Field theUnsafe = unsafeClass.getDeclaredField("theUnsafe"); + theUnsafe.setAccessible(true); + Unsafe unsafe2 = (Unsafe) theUnsafe.get(null); + System.out.println(unsafe2); + } + +} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/unsafe/UnSafeMemoryTest.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/unsafe/UnSafeMemoryTest.java new file mode 100644 index 00000000..08a96f20 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/unsafe/UnSafeMemoryTest.java @@ -0,0 +1,36 @@ +package cn.lastwhisper.concurrent.unsafe; + +import sun.misc.Unsafe; + +import java.lang.reflect.Field; + +/** + * @author cunchang + * @date 2022/4/29 12:24 AM + */ +public class UnSafeMemoryTest { + /** + * 堆外内存不受jvm内存模型掌控,在nio(netty,mina)中大量使用对外内存进行管道传输,copy等, + * 使用它们的好处如下: + * 对垃圾回收停顿的改善。由于堆外内存是直接受操作系统管理而不是JVM,所以当我们使用堆外内存时,即可保持较小的堆内内存规模。从而在GC时减少回收停顿对于应用的影响。 + * 提升程序I/O操作的性能。通常在I/O通信过程中,会存在堆内内存到堆外内存的数据拷贝操作,对于需要频繁进行内存间数据拷贝且生命周期较短的暂存数据,都建议存储到堆外内存。而在jdk中,堆外内存对应的类为DirectByteBuffer,它内部也是通过unsafe分配的内存: + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe"); + theUnsafe.setAccessible(true); + Unsafe unsafe = (Unsafe) theUnsafe.get(null); + + // 分配 10M的堆外内存 + long _10M_Address = unsafe.allocateMemory(1 * 1024 * 1024 * 10); + // 将10M内存的 前面1M内存值设置为10 + unsafe.setMemory(_10M_Address, 1 * 1024 * 1024 * 1, (byte) 10); + // 获取第1M内存的值: 10 + System.out.println(unsafe.getByte(_10M_Address + 1000)); + // 获取第1M内存后的值: 0(没有设置) + System.out.println(unsafe.getByte(_10M_Address + 1 * 1024 * 1024 * 5)); + } + +} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/unsafe/UnSafeOpArrayTest.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/unsafe/UnSafeOpArrayTest.java new file mode 100644 index 00000000..7b0b5866 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/unsafe/UnSafeOpArrayTest.java @@ -0,0 +1,36 @@ +package cn.lastwhisper.concurrent.unsafe; + +import sun.misc.Unsafe; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.util.Arrays; + +/** + * @author cunchang + * @date 2022/4/29 12:24 AM + */ +public class UnSafeOpArrayTest { + + public static void main(String[] args) throws Exception{ + Class unsafeClass = Unsafe.class; + Constructor constructor = unsafeClass.getDeclaredConstructor(); + constructor.setAccessible(true); + Unsafe unsafe = constructor.newInstance(); + + Integer[] integers = new Integer[10]; + // 打印数组的原始值 + System.out.println(Arrays.toString(integers)); + // 获取Integer数组在内存中的固定的偏移量 + long arrayBaseOffset = unsafe.arrayBaseOffset(Integer[].class); + System.out.println(unsafe.arrayIndexScale(Integer[].class)); + System.out.println(unsafe.arrayIndexScale(double[].class)); + // 将数组中第一个元素的更新为100 + unsafe.putObject(integers, arrayBaseOffset, 100); + // 将数组中第五个元素更新为50 注意 引用类型占用4个字节,所以内存地址 需要 4 * 4 = 16 + unsafe.putObject(integers, arrayBaseOffset + 16, 50); + // 打印更新后的值 + System.out.println(Arrays.toString(integers)); + } + +} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/unsafe/UnSafeParkTest.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/unsafe/UnSafeParkTest.java new file mode 100644 index 00000000..d3f2240c --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/unsafe/UnSafeParkTest.java @@ -0,0 +1,43 @@ +package cn.lastwhisper.concurrent.unsafe; + +import sun.misc.Unsafe; + +import java.lang.reflect.Field; + +/** + * @author cunchang + * @date 2022/4/29 12:24 AM + */ +public class UnSafeParkTest { + + public static void main(String[] args) throws Exception { + Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe"); + theUnsafe.setAccessible(true); + Unsafe unsafe = (Unsafe) theUnsafe.get(null); + + Thread t1 = new Thread(() -> { + for (int i = 0; i < 10; i++) { + if (i == 5) { + // i == 5时,将当前线程挂起 + unsafe.park(false, 0L); + } + System.out.println(Thread.currentThread().getName() + " printing i : " + i); + } + }, " Thread__Unsafe__1"); + + t1.start(); + + // 主线程休息三秒 + Thread.sleep(3000L); + for (int i = 0; i < 10; i++) { + System.out.println(Thread.currentThread().getName() + " printing i : " + i); + if (i == 9) { + // 将线程 t1 唤醒 + unsafe.unpark(t1); + } + } + + System.in.read(); + } + +} diff --git a/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/unsafe/UnsafeCasTest.java b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/unsafe/UnsafeCasTest.java new file mode 100644 index 00000000..29250729 --- /dev/null +++ b/java-basic/concurrent/src/main/java/cn/lastwhisper/concurrent/unsafe/UnsafeCasTest.java @@ -0,0 +1,32 @@ +package cn.lastwhisper.concurrent.unsafe; + +import sun.misc.Unsafe; + +import java.lang.reflect.Field; + +public class UnsafeCasTest { + public static void main(String[] args) throws Exception { + Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe"); + theUnsafe.setAccessible(true); + Unsafe unsafe = (Unsafe) theUnsafe.get(null); + + User user = new User("jsbintask"); + long nameOffset = unsafe.objectFieldOffset(User.class.getDeclaredField("name")); + unsafe.compareAndSwapObject(user, nameOffset, "jsbintask1", "jsbintask2"); + System.out.println("第一次更新后的值:" + user.getName()); + unsafe.compareAndSwapObject(user, nameOffset, "jsbintask", "jsbintask2"); + System.out.println("第二次更新后的值:" + user.getName()); + } +} + +class User { + private String name; + + public User(String name) { + this.name = name; + } + + public String getName() { + return name; + } +} \ No newline at end of file diff --git a/java-basic/design-pattern/README.md b/java-basic/design-pattern/README.md index fba38945..4f68ee58 100644 --- a/java-basic/design-pattern/README.md +++ b/java-basic/design-pattern/README.md @@ -80,3 +80,8 @@ 中间也参考了无数的博客,这里只贴几个参考比较多的。 [chenssy设计模式](https://www.cnblogs.com/chenssy/category/482229.html) + + +# 4. 进阶 + + diff --git a/java-basic/design-pattern/pom.xml b/java-basic/design-pattern/pom.xml index da907140..5523f3eb 100644 --- a/java-basic/design-pattern/pom.xml +++ b/java-basic/design-pattern/pom.xml @@ -2,15 +2,12 @@ - - java-basic - cn.lastwhisper - 1.0-SNAPSHOT - + 4.0.0 cn.lastwhisper design-pattern + 1.0-SNAPSHOT UTF-8 @@ -147,14 +144,6 @@ 3.2.1 - - - junit - junit - 4.12 - - - joda-time joda-time @@ -290,6 +279,11 @@ 2.9.0 + + junit + junit + 4.13 + diff --git a/java-basic/design-pattern/src/main/java/com/desgin/advance/decorator_vs_proxy/Boxer.java b/java-basic/design-pattern/src/main/java/com/desgin/advance/decorator_vs_proxy/Boxer.java new file mode 100644 index 00000000..3d64d384 --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/advance/decorator_vs_proxy/Boxer.java @@ -0,0 +1,13 @@ +package com.desgin.advance.decorator_vs_proxy; + +/** + * 拳击手 + * @author lastwhisper + * @date 2020/4/12 + */ +public interface Boxer { + + // 打拳 + void fight(); + +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/advance/decorator_vs_proxy/BoxerImpl.java b/java-basic/design-pattern/src/main/java/com/desgin/advance/decorator_vs_proxy/BoxerImpl.java new file mode 100644 index 00000000..22eb67ea --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/advance/decorator_vs_proxy/BoxerImpl.java @@ -0,0 +1,30 @@ +package com.desgin.advance.decorator_vs_proxy; + +/** + * 泰森 + * @author lastwhisper + * @date 2020/4/12 + */ +public class BoxerImpl implements Boxer { + + private String name; + + @Override + public void fight() { + hook(); + duck(); + straight(); + } + + private void duck() { + System.out.println("拳手:闪避"); + } + + private void hook() { + System.out.println("拳手:勾拳"); + } + + private void straight() { + System.out.println("拳手:直拳"); + } +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/advance/decorator_vs_proxy/Client.java b/java-basic/design-pattern/src/main/java/com/desgin/advance/decorator_vs_proxy/Client.java new file mode 100644 index 00000000..f2162f89 --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/advance/decorator_vs_proxy/Client.java @@ -0,0 +1,35 @@ +package com.desgin.advance.decorator_vs_proxy; + +import com.desgin.advance.decorator_vs_proxy.decorator.FastShoesDecorator; +import com.desgin.advance.decorator_vs_proxy.proxy.AgentProxy; +import org.junit.Test; + +/** + * @author lastwhisper + * @date 2020/4/12 + */ +public class Client { + + // 代理模式 + @Test + public void test1() { + Boxer boxer = new BoxerImpl(); + Boxer agent = new AgentProxy(boxer); + System.out.println("准备比赛!"); + agent.fight(); + System.out.println("比赛结束!"); + } + + // 装饰者模式 + @Test + public void test2() { + Boxer boxer = new BoxerImpl(); + FastShoesDecorator fastShoesDecorator = new FastShoesDecorator(boxer); + Boxer agent = new AgentProxy(fastShoesDecorator); + System.out.println("准备比赛!"); + fastShoesDecorator.moveFast(); + agent.fight(); + System.out.println("比赛结束!"); + } + +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/advance/decorator_vs_proxy/README.md b/java-basic/design-pattern/src/main/java/com/desgin/advance/decorator_vs_proxy/README.md new file mode 100644 index 00000000..f568c025 --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/advance/decorator_vs_proxy/README.md @@ -0,0 +1,17 @@ +decorator_proxy为装饰者模式与代理模式的对比 +https://www.zhihu.com/question/41988550/answer/462204684 +拳击手、经纪人、移速鞋 + + + +看过钢铁侠没? +史塔克穿反浩克战甲(装饰模式) +但是史塔克没能力自己穿,只能让贾维斯帮自己从太空上叫下来(代理模式) +贾维斯只有一个(代理模式不会无限代理) +mark装甲有无数个(装饰模式可以无限增强) + + + + + + diff --git a/java-basic/design-pattern/src/main/java/com/desgin/advance/decorator_vs_proxy/decorator/FastShoesDecorator.java b/java-basic/design-pattern/src/main/java/com/desgin/advance/decorator_vs_proxy/decorator/FastShoesDecorator.java new file mode 100644 index 00000000..a4c72ceb --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/advance/decorator_vs_proxy/decorator/FastShoesDecorator.java @@ -0,0 +1,26 @@ +package com.desgin.advance.decorator_vs_proxy.decorator; + +import com.desgin.advance.decorator_vs_proxy.Boxer; + +/** + * 移速鞋 + * @author lastwhisper + * @date 2020/4/12 + */ +public class FastShoesDecorator implements Boxer { + private Boxer boxer; + + public FastShoesDecorator(Boxer boxer) { + this.boxer = boxer; + } + + public void moveFast() { + System.out.println("穿上非常快的鞋:移速+5"); + } + + @Override + public void fight() { + boxer.fight(); + } + +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/advance/decorator_vs_proxy/proxy/AgentProxy.java b/java-basic/design-pattern/src/main/java/com/desgin/advance/decorator_vs_proxy/proxy/AgentProxy.java new file mode 100644 index 00000000..7bdab293 --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/advance/decorator_vs_proxy/proxy/AgentProxy.java @@ -0,0 +1,37 @@ +package com.desgin.advance.decorator_vs_proxy.proxy; + +import com.desgin.advance.decorator_vs_proxy.Boxer; + +/** + * 经纪人 + * @author lastwhisper + * @date 2020/4/12 + */ +public class AgentProxy implements Boxer { + private Boxer boxer; + + public AgentProxy(Boxer boxer) { + this.boxer = boxer; + } + + @Override + public void fight() { + findOpponent(); + findSponsor(); + negotiate(); + System.out.println("让拳手去比赛"); + boxer.fight(); + } + + private void findOpponent() { + System.out.println("经纪人:寻找适用于当前拳手的对手"); + } + + private void findSponsor() { + System.out.println("经纪人:寻找赞助商"); + } + + private void negotiate() { + System.out.println("经纪人:洽谈"); + } +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/README.md b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/README.md new file mode 100644 index 00000000..b79df7d6 --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/README.md @@ -0,0 +1,10 @@ + +责任链实现 +v1:多个过滤器逻辑写在一起 +问题:如何支持可配置化拦截器? +v2:各个过滤器责任单一 +问题:如何支持可配置化拦截器? +v3:通过一个上下文类,支持配置化 +v4: +v4、v5:本质上差不多,但是v5通过模板方法,固定调用了流程,降低了使用门槛 + diff --git a/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/abstractImpl/v1/Client.java b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/abstractImpl/v1/Client.java new file mode 100644 index 00000000..24500b5a --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/abstractImpl/v1/Client.java @@ -0,0 +1,39 @@ +package com.desgin.mashibing.chainofresponsibility.abstractImpl.v1; + +/** + * @author lastwhisper + */ +public class Client { + static class HandlerA extends Handler{ + @Override + protected void handleProcess() { + System.out.println("handle by a"); + } + } + + static class HandlerB extends Handler{ + @Override + protected void handleProcess() { + System.out.println("handle by b"); + } + } + + static class HandlerC extends Handler{ + @Override + protected void handleProcess() { + System.out.println("handle by c"); + } + } + + public static void main(String[] args){ + Handler handlerA = new HandlerA(); + Handler handlerB = new HandlerB(); + Handler handlerC = new HandlerC(); + + handlerA.setSucessor(handlerB); + handlerB.setSucessor(handlerC); + + handlerA.execute(); + } + +} diff --git a/springboot-aop/principle/src/main/java/cn/lastwhisper/chain/v1/Handler.java b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/abstractImpl/v1/Handler.java similarity index 86% rename from springboot-aop/principle/src/main/java/cn/lastwhisper/chain/v1/Handler.java rename to java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/abstractImpl/v1/Handler.java index b50fc633..03d964a1 100644 --- a/springboot-aop/principle/src/main/java/cn/lastwhisper/chain/v1/Handler.java +++ b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/abstractImpl/v1/Handler.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.chain.v1; +package com.desgin.mashibing.chainofresponsibility.abstractImpl.v1; /** * @author lastwhisper diff --git a/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/abstractImpl/v2/Chain.java b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/abstractImpl/v2/Chain.java new file mode 100644 index 00000000..a8f118fd --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/abstractImpl/v2/Chain.java @@ -0,0 +1,24 @@ +package com.desgin.mashibing.chainofresponsibility.abstractImpl.v2; + +import java.util.List; + +/** + * 使用chain进行包装 + * @author lastwhisper + */ +public class Chain { + private List handlers; + private int index = 0; + + public Chain(List handlers) { + this.handlers = handlers; + } + + //将顺序关系封装 + public void proceed() { + if (index >= handlers.size()) { + return; + } + handlers.get(index++).execute(this); + } +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/abstractImpl/v2/ChainClient.java b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/abstractImpl/v2/ChainClient.java new file mode 100644 index 00000000..e0742ff3 --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/abstractImpl/v2/ChainClient.java @@ -0,0 +1,38 @@ +package com.desgin.mashibing.chainofresponsibility.abstractImpl.v2; + +import java.util.Arrays; +import java.util.List; + +/** + * Created by cat on 2017-02-28. + */ +public class ChainClient { + static class ChainHandlerA extends ChainHandler{ + @Override + protected void handleProcess() { + System.out.println("handle by chain a"); + } + } + static class ChainHandlerB extends ChainHandler{ + @Override + protected void handleProcess() { + System.out.println("handle by chain b"); + } + } + static class ChainHandlerC extends ChainHandler{ + @Override + protected void handleProcess() { + System.out.println("handle by chain c"); + } + } + + public static void main(String[] args){ + List handlers = Arrays.asList( + new ChainHandlerA(), + new ChainHandlerB(), + new ChainHandlerC() + ); + Chain chain = new Chain(handlers); + chain.proceed(); + } +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/abstractImpl/v2/ChainHandler.java b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/abstractImpl/v2/ChainHandler.java new file mode 100644 index 00000000..4a8b4014 --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/abstractImpl/v2/ChainHandler.java @@ -0,0 +1,15 @@ +package com.desgin.mashibing.chainofresponsibility.abstractImpl.v2; + +/** + * Created by cat on 2017-02-28. + */ +public abstract class ChainHandler { + + public void execute(Chain chain){ + handleProcess(); + chain.proceed(); + + } + + protected abstract void handleProcess(); +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/abstractImpl/v3/Chain.java b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/abstractImpl/v3/Chain.java new file mode 100644 index 00000000..75f30e77 --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/abstractImpl/v3/Chain.java @@ -0,0 +1,24 @@ +package com.desgin.mashibing.chainofresponsibility.abstractImpl.v3; + +import java.util.List; + +/** + * 使用chain进行包装 + * @author lastwhisper + */ +public class Chain { + private List handlers; + private int index = 0; + + public Chain(List handlers) { + this.handlers = handlers; + } + + //将顺序关系封装 + public void proceed() { + if (index >= handlers.size()) { + return; + } + handlers.get(index++).execute(this); + } +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/abstractImpl/v3/ChainClient.java b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/abstractImpl/v3/ChainClient.java new file mode 100644 index 00000000..72c7e54f --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/abstractImpl/v3/ChainClient.java @@ -0,0 +1,57 @@ +package com.desgin.mashibing.chainofresponsibility.abstractImpl.v3; + +import java.util.Arrays; +import java.util.List; + +/** + * Created by cat on 2017-02-28. + */ +public class ChainClient { + static class ChainHandlerA extends ChainHandler { + @Override + protected void handlePreProcess() { + System.out.println("ChainHandlerA handlePreProcess"); + } + + @Override + protected void handlePostProcess() { + System.out.println("ChainHandlerA handlePostProcess"); + } + } + + static class ChainHandlerB extends ChainHandler { + @Override + protected void handlePreProcess() { + System.out.println("ChainHandlerB handlePreProcess"); + } + + @Override + protected void handlePostProcess() { + System.out.println("ChainHandlerB handlePostProcess"); + } + } + + static class ChainHandlerC extends ChainHandler { + @Override + protected void handlePreProcess() { + System.out.println("ChainHandlerC handlePreProcess"); + } + + @Override + protected void handlePostProcess() { + System.out.println("ChainHandlerC handlePostProcess"); + } + } + + public static void main(String[] args) { + List handlers = Arrays.asList( + new ChainHandlerA(), + new ChainHandlerB(), + new ChainHandlerC() + ); + Chain chain = new Chain(handlers); + chain.proceed(); + + + } +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/abstractImpl/v3/ChainHandler.java b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/abstractImpl/v3/ChainHandler.java new file mode 100644 index 00000000..3e175f5c --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/abstractImpl/v3/ChainHandler.java @@ -0,0 +1,17 @@ +package com.desgin.mashibing.chainofresponsibility.abstractImpl.v3; + +/** + * Created by cat on 2017-02-28. + */ +public abstract class ChainHandler { + + // 模板方法 + public void execute(Chain chain){ + handlePreProcess(); + chain.proceed(); + handlePostProcess(); + } + + protected abstract void handlePreProcess(); + protected abstract void handlePostProcess(); +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v1/Main.java b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v1/Main.java new file mode 100644 index 00000000..1d29a78d --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v1/Main.java @@ -0,0 +1,15 @@ +package com.desgin.mashibing.chainofresponsibility.interfaceImpl.v1; + +/** + * @author lastwhisper + */ +public class Main { + + public static void main(String[] args) { + String msg = "大家好,QAQ, ,郭嘉,漂亮国!"; + MsgProcessor mp = new MsgProcessor(); + mp.setMsg(msg); + msg = mp.process(); + System.out.println(msg); + } +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v1/MsgProcessor.java b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v1/MsgProcessor.java new file mode 100644 index 00000000..644f849f --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v1/MsgProcessor.java @@ -0,0 +1,27 @@ +package com.desgin.mashibing.chainofresponsibility.interfaceImpl.v1; + +/** + * @author lastwhisper + */ +public class MsgProcessor { + String msg; + + public String getMsg() { + return msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } + + public String process() { + // process the html tag <> + String r = msg.replaceAll("<", "<") + .replaceAll(">", ">"); + // process the sensitive words + r= r.replaceAll("郭嘉", "**") + .replaceAll("漂亮国", "***"); + + return r; + } +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v2/FaceFilter.java b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v2/FaceFilter.java new file mode 100644 index 00000000..bceb5784 --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v2/FaceFilter.java @@ -0,0 +1,13 @@ +package com.desgin.mashibing.chainofresponsibility.interfaceImpl.v2; + +/** + * @author lastwhisper + */ +public class FaceFilter implements Filter { + // process the face tag <> + @Override + public String doFilter(String str) { + return str.replaceAll("QAQ", "^V^"); + } + +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v2/Filter.java b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v2/Filter.java new file mode 100644 index 00000000..d10b777f --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v2/Filter.java @@ -0,0 +1,5 @@ +package com.desgin.mashibing.chainofresponsibility.interfaceImpl.v2; + +public interface Filter { + String doFilter(String str); +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v2/HTMLFilter.java b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v2/HTMLFilter.java new file mode 100644 index 00000000..7af98970 --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v2/HTMLFilter.java @@ -0,0 +1,13 @@ +package com.desgin.mashibing.chainofresponsibility.interfaceImpl.v2; + +/** + * @author lastwhisper + */ +public class HTMLFilter implements Filter { + // process the html tag <> + @Override + public String doFilter(String str) { + return str.replaceAll("<", "<") + .replaceAll(">", ">"); + } +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v2/Main.java b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v2/Main.java new file mode 100644 index 00000000..32f028cb --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v2/Main.java @@ -0,0 +1,15 @@ +package com.desgin.mashibing.chainofresponsibility.interfaceImpl.v2; + +/** + * @author lastwhisper + */ +public class Main { + + public static void main(String[] args) { + String msg = "大家好,QAQ, ,郭嘉,漂亮国!"; + MsgProcessor mp = new MsgProcessor(); + mp.setMsg(msg); + msg = mp.process(); + System.out.println(msg); + } +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v2/MsgProcessor.java b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v2/MsgProcessor.java new file mode 100644 index 00000000..bf65a9fd --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v2/MsgProcessor.java @@ -0,0 +1,26 @@ +package com.desgin.mashibing.chainofresponsibility.interfaceImpl.v2; + +/** + * @author lastwhisper + */ +public class MsgProcessor { + String msg; + + Filter[] filters = {new HTMLFilter(), new SesitiveFilter(), new FaceFilter()}; + + public String getMsg() { + return msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } + + public String process() { + String r = msg; + for (Filter filter : filters) { + r = filter.doFilter(r); + } + return r; + } +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v2/SesitiveFilter.java b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v2/SesitiveFilter.java new file mode 100644 index 00000000..a1160abd --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v2/SesitiveFilter.java @@ -0,0 +1,14 @@ +package com.desgin.mashibing.chainofresponsibility.interfaceImpl.v2; + +/** + * @author lastwhisper + */ +public class SesitiveFilter implements Filter { + // process the sensitive words + @Override + public String doFilter(String str) { + String r = str.replaceAll("郭嘉", "**") + .replaceAll("漂亮国", "***"); + return r; + } +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v3/FaceFilter.java b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v3/FaceFilter.java new file mode 100644 index 00000000..0d9daf22 --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v3/FaceFilter.java @@ -0,0 +1,14 @@ +package com.desgin.mashibing.chainofresponsibility.interfaceImpl.v3; + +/** + * @author lastwhisper + */ +public class FaceFilter implements Filter { + // process the face tag <> + @Override + public String doFilter(String str) { + String r = str.replaceAll("QAQ", "^V^"); + return r; + } + +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v3/Filter.java b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v3/Filter.java new file mode 100644 index 00000000..a37e8c1f --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v3/Filter.java @@ -0,0 +1,5 @@ +package com.desgin.mashibing.chainofresponsibility.interfaceImpl.v3; + +public interface Filter { + String doFilter(String str); +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v3/FilterChain.java b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v3/FilterChain.java new file mode 100644 index 00000000..eefc65ab --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v3/FilterChain.java @@ -0,0 +1,25 @@ +package com.desgin.mashibing.chainofresponsibility.interfaceImpl.v3; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author lastwhisper + */ +public class FilterChain implements Filter{ + + List filters = new ArrayList(); + + public FilterChain addFilter(Filter f) { + filters.add(f); + return this; + } + + public String doFilter(String str) { + String r = str; + for (Filter filter : filters) { + r = filter.doFilter(r); + } + return r; + } +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v3/HTMLFilter.java b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v3/HTMLFilter.java new file mode 100644 index 00000000..801678de --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v3/HTMLFilter.java @@ -0,0 +1,14 @@ +package com.desgin.mashibing.chainofresponsibility.interfaceImpl.v3; + +/** + * @author lastwhisper + */ +public class HTMLFilter implements Filter { + // process the html tag <> + @Override + public String doFilter(String str) { + String r = str.replaceAll("<", "<") + .replaceAll(">", ">"); + return r; + } +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v3/Main.java b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v3/Main.java new file mode 100644 index 00000000..d7d597dd --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v3/Main.java @@ -0,0 +1,23 @@ +package com.desgin.mashibing.chainofresponsibility.interfaceImpl.v3; + + +/** + * @author lastwhisper + */ +public class Main { + + public static void main(String[] args) { + String msg = "大家好,QAQ, ,郭嘉,漂亮国!"; + FilterChain filterChain = new FilterChain(); + filterChain.addFilter(new HTMLFilter()) + .addFilter(new SesitiveFilter()); + + FilterChain filterChain2 = new FilterChain(); + filterChain2.addFilter(new FaceFilter()); + + filterChain.addFilter(filterChain2); + + msg = filterChain.doFilter(msg); + System.out.println(msg); + } +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v3/SesitiveFilter.java b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v3/SesitiveFilter.java new file mode 100644 index 00000000..b6017510 --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v3/SesitiveFilter.java @@ -0,0 +1,14 @@ +package com.desgin.mashibing.chainofresponsibility.interfaceImpl.v3; + +/** + * @author lastwhisper + */ +public class SesitiveFilter implements Filter { + // process the sensitive words + @Override + public String doFilter(String str) { + String r = str.replaceAll("郭嘉", "**") + .replaceAll("漂亮国", "***"); + return r; + } +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v4/FaceFilter.java b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v4/FaceFilter.java new file mode 100644 index 00000000..a97587c3 --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v4/FaceFilter.java @@ -0,0 +1,22 @@ +package com.desgin.mashibing.chainofresponsibility.interfaceImpl.v4; + +/** + * @author lastwhisper + */ +public class FaceFilter implements Filter { + + @Override + public void doFilter(Request request, Response response, FilterChain chain) { + // 处理request请求 + request.requestStr = request.requestStr.replaceAll("QAQ", "^V^") + + "---FaceFilter.request()"; + System.out.println("FaceFilter.request()"); + + chain.doFilter(request, response, chain); + + // 处理response响应 + response.responseStr = response.responseStr.replaceAll("QAQ", "^V^") + + "---FaceFilter.response()"; + System.out.println("FaceFilter.response()"); + } +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v4/Filter.java b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v4/Filter.java new file mode 100644 index 00000000..4c53bfe6 --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v4/Filter.java @@ -0,0 +1,5 @@ +package com.desgin.mashibing.chainofresponsibility.interfaceImpl.v4; + +public interface Filter { + void doFilter(Request request, Response response, FilterChain chain); +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v4/FilterChain.java b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v4/FilterChain.java new file mode 100644 index 00000000..70dc568d --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v4/FilterChain.java @@ -0,0 +1,25 @@ +package com.desgin.mashibing.chainofresponsibility.interfaceImpl.v4; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author lastwhisper + */ +public class FilterChain implements Filter { + + private List filters = new ArrayList(); + + private int index = 0; + + public FilterChain addFilter(Filter f) { + filters.add(f); + return this; + } + + @Override + public void doFilter(Request request, Response response, FilterChain chain) { + if (index == filters.size()) return; + filters.get(index++).doFilter(request, response, chain); + } +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v4/HTMLFilter.java b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v4/HTMLFilter.java new file mode 100644 index 00000000..a1e1cc43 --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v4/HTMLFilter.java @@ -0,0 +1,22 @@ +package com.desgin.mashibing.chainofresponsibility.interfaceImpl.v4; + +/** + * @author lastwhisper + */ +public class HTMLFilter implements Filter { + + @Override + public void doFilter(Request request, Response response, FilterChain chain) { + // 处理request请求 + request.requestStr = request.requestStr.replaceAll("<", "<") + .replaceAll(">", ">") + "---HTMLFilter.request()"; + System.out.println("HTMLFilter.request()"); + + chain.doFilter(request, response, chain); + + // 处理response响应 + response.responseStr = response.responseStr.replaceAll("<", "<") + .replaceAll(">", ">") + "---HTMLFilter.response()"; + System.out.println("HTMLFilter.response()"); + } +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v4/Main.java b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v4/Main.java new file mode 100644 index 00000000..ae9bb311 --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v4/Main.java @@ -0,0 +1,31 @@ +package com.desgin.mashibing.chainofresponsibility.interfaceImpl.v4; + + +/** + * @author lastwhisper + */ +public class Main { + + public static void main(String[] args) { + // 初始化数据 + String msg = "大家好,QAQ, ,郭嘉,漂亮国!"; + Request request = new Request(); + request.setRequestStr(msg); + Response response = new Response(); + response.setResponseStr(msg); + // 过滤链1 + FilterChain filterChain = new FilterChain(); + filterChain.addFilter(new HTMLFilter()) + .addFilter(new SesitiveFilter()); + //// 过滤链2 + FilterChain filterChain2 = new FilterChain(); + filterChain2.addFilter(new FaceFilter()); + //// 过滤链1+过滤链2 + filterChain.addFilter(filterChain2); + // 处理 + filterChain.doFilter(request, response, filterChain); + + System.out.println(request.getRequestStr()); + System.out.println(response.getResponseStr()); + } +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v4/Request.java b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v4/Request.java new file mode 100644 index 00000000..b6ddb6f3 --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v4/Request.java @@ -0,0 +1,16 @@ +package com.desgin.mashibing.chainofresponsibility.interfaceImpl.v4; + +/** + * @author lastwhisper + */ +public class Request { + String requestStr; + + public String getRequestStr() { + return requestStr; + } + + public void setRequestStr(String requestStr) { + this.requestStr = requestStr; + } +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v4/Response.java b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v4/Response.java new file mode 100644 index 00000000..8c597c72 --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v4/Response.java @@ -0,0 +1,16 @@ +package com.desgin.mashibing.chainofresponsibility.interfaceImpl.v4; + +/** + * @author lastwhisper + */ +public class Response { + String responseStr; + + public String getResponseStr() { + return responseStr; + } + + public void setResponseStr(String responseStr) { + this.responseStr = responseStr; + } +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v4/SesitiveFilter.java b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v4/SesitiveFilter.java new file mode 100644 index 00000000..2846cac6 --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v4/SesitiveFilter.java @@ -0,0 +1,22 @@ +package com.desgin.mashibing.chainofresponsibility.interfaceImpl.v4; + +/** + * @author lastwhisper + */ +public class SesitiveFilter implements Filter { + + @Override + public void doFilter(Request request, Response response, FilterChain chain) { + // 处理request请求 + request.requestStr = request.requestStr.replaceAll("郭嘉", "**") + .replaceAll("漂亮国", "***") + "---SesitiveFilter.request()"; + System.out.println("SesitiveFilter.request()"); + + chain.doFilter(request, response, chain); + + // 处理response响应 + response.responseStr = response.responseStr.replaceAll("郭嘉", "**") + .replaceAll("漂亮国", "***") + "---SesitiveFilter.response()"; + System.out.println("SesitiveFilter.response()"); + } +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v5/AbstractFilter.java b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v5/AbstractFilter.java new file mode 100644 index 00000000..bc0bcb28 --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v5/AbstractFilter.java @@ -0,0 +1,30 @@ +package com.desgin.mashibing.chainofresponsibility.interfaceImpl.v5; + + +/** + * @author cunchang + * @date 2021/5/11 12:58 下午 + */ +public abstract class AbstractFilter implements Filter { + + @Override + public void doFilter(Request request, Response response, FilterChain chain) { + handlePreProcess(request,response); + chain.doFilter(request,response,chain); + handlePostProcess(request,response); + } + + /** + * 责任链前置处理 + * @param request + * @param response + */ + protected abstract void handlePreProcess(Request request, Response response); + + /** + * 责任链后置处理 + * @param request + * @param response + */ + protected abstract void handlePostProcess(Request request, Response response); +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v5/FaceFilter.java b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v5/FaceFilter.java new file mode 100644 index 00000000..862495f8 --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v5/FaceFilter.java @@ -0,0 +1,23 @@ +package com.desgin.mashibing.chainofresponsibility.interfaceImpl.v5; + +/** + * @author lastwhisper + */ +public class FaceFilter extends AbstractFilter { + + @Override + protected void handlePreProcess(Request request, Response response) { + // 处理request请求 + request.requestStr = request.requestStr.replaceAll("QAQ", "^V^") + + "---FaceFilter.request()"; + System.out.println("FaceFilter.request()"); + } + + @Override + protected void handlePostProcess(Request request, Response response) { + // 处理response响应 + response.responseStr = response.responseStr.replaceAll("QAQ", "^V^") + + "---FaceFilter.response()"; + System.out.println("FaceFilter.response()"); + } +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v5/Filter.java b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v5/Filter.java new file mode 100644 index 00000000..6b1848de --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v5/Filter.java @@ -0,0 +1,11 @@ +package com.desgin.mashibing.chainofresponsibility.interfaceImpl.v5; + +public interface Filter { + /** + * 责任链 + * @param request + * @param response + * @param chain + */ + void doFilter(Request request, Response response, FilterChain chain); +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v5/FilterChain.java b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v5/FilterChain.java new file mode 100644 index 00000000..63736574 --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v5/FilterChain.java @@ -0,0 +1,25 @@ +package com.desgin.mashibing.chainofresponsibility.interfaceImpl.v5; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author lastwhisper + */ +public class FilterChain implements Filter { + + private List filters = new ArrayList(); + + private int index = 0; + + public FilterChain addFilter(Filter f) { + filters.add(f); + return this; + } + + @Override + public void doFilter(Request request, Response response, FilterChain chain) { + if (index == filters.size()) return; + filters.get(index++).doFilter(request, response, chain); + } +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v5/HTMLFilter.java b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v5/HTMLFilter.java new file mode 100644 index 00000000..02780de8 --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v5/HTMLFilter.java @@ -0,0 +1,23 @@ +package com.desgin.mashibing.chainofresponsibility.interfaceImpl.v5; + +/** + * @author lastwhisper + */ +public class HTMLFilter extends AbstractFilter { + + @Override + protected void handlePreProcess(Request request, Response response) { + // 处理request请求 + request.requestStr = request.requestStr.replaceAll("<", "<") + .replaceAll(">", ">") + "---HTMLFilter.request()"; + System.out.println("HTMLFilter.request()"); + } + + @Override + protected void handlePostProcess(Request request, Response response) { + // 处理response响应 + response.responseStr = response.responseStr.replaceAll("<", "<") + .replaceAll(">", ">") + "---HTMLFilter.response()"; + System.out.println("HTMLFilter.response()"); + } +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v5/Main.java b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v5/Main.java new file mode 100644 index 00000000..5ff0623b --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v5/Main.java @@ -0,0 +1,36 @@ +package com.desgin.mashibing.chainofresponsibility.interfaceImpl.v5; + + +/** + * @author lastwhisper + */ +public class Main { + + public static void main(String[] args) { + // 初始化数据 + String msg = "大家好,QAQ, ,郭嘉,漂亮国!"; + Request request = new Request(); + request.setRequestStr(msg); + Response response = new Response(); + response.setResponseStr(msg); + // 过滤链1 + FilterChain filterChain = new FilterChain(); + filterChain.addFilter(new HTMLFilter()) + .addFilter(new SesitiveFilter()); + // 过滤链2 + FilterChain filterChain2 = new FilterChain(); + filterChain2.addFilter(new FaceFilter()); + // 过滤链1+过滤链2 + filterChain.addFilter(filterChain2); + + // 处理前 + System.out.println(request.getRequestStr()); + System.out.println(response.getResponseStr()); + + filterChain.doFilter(request, response, filterChain); + + // 处理后 + System.out.println(request.getRequestStr()); + System.out.println(response.getResponseStr()); + } +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v5/Request.java b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v5/Request.java new file mode 100644 index 00000000..62c544b6 --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v5/Request.java @@ -0,0 +1,16 @@ +package com.desgin.mashibing.chainofresponsibility.interfaceImpl.v5; + +/** + * @author lastwhisper + */ +public class Request { + String requestStr; + + public String getRequestStr() { + return requestStr; + } + + public void setRequestStr(String requestStr) { + this.requestStr = requestStr; + } +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v5/Response.java b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v5/Response.java new file mode 100644 index 00000000..b314ac2a --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v5/Response.java @@ -0,0 +1,16 @@ +package com.desgin.mashibing.chainofresponsibility.interfaceImpl.v5; + +/** + * @author lastwhisper + */ +public class Response { + String responseStr; + + public String getResponseStr() { + return responseStr; + } + + public void setResponseStr(String responseStr) { + this.responseStr = responseStr; + } +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v5/SesitiveFilter.java b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v5/SesitiveFilter.java new file mode 100644 index 00000000..faaea7f6 --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/chainofresponsibility/interfaceImpl/v5/SesitiveFilter.java @@ -0,0 +1,22 @@ +package com.desgin.mashibing.chainofresponsibility.interfaceImpl.v5; + +/** + * @author lastwhisper + */ +public class SesitiveFilter implements Filter { + + @Override + public void doFilter(Request request, Response response, FilterChain chain) { + // 处理request请求 + request.requestStr = request.requestStr.replaceAll("郭嘉", "**") + .replaceAll("漂亮国", "***") + "---SesitiveFilter.request()"; + System.out.println("SesitiveFilter.request()"); + + chain.doFilter(request, response, chain); + + // 处理response响应 + response.responseStr = response.responseStr.replaceAll("郭嘉", "**") + .replaceAll("漂亮国", "***") + "---SesitiveFilter.response()"; + System.out.println("SesitiveFilter.response()"); + } +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/mashibing/command/Boy.java b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/command/Boy.java new file mode 100644 index 00000000..d0b9856c --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/command/Boy.java @@ -0,0 +1,39 @@ +package com.desgin.mashibing.command; + +import java.util.ArrayList; +import java.util.List; + +public class Boy { + private String name; + private List commands = new ArrayList(); + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public void pursue(MM mm) { + } + + public void doSomeThing() { + + } + + public void addCommand(Command c1) { + this.commands.add(c1); + } + + public void executeCommands() { + for(Command c : commands) { + c.execute(); + } + } + + public void undoCommands() { + // + } + +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/mashibing/command/Command.java b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/command/Command.java new file mode 100644 index 00000000..a1020c51 --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/command/Command.java @@ -0,0 +1,6 @@ +package com.desgin.mashibing.command; + +public abstract class Command { + public abstract void execute(); + public abstract void unDo(); +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/mashibing/command/HugCommand.java b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/command/HugCommand.java new file mode 100644 index 00000000..7eb289c8 --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/command/HugCommand.java @@ -0,0 +1,15 @@ +package com.desgin.mashibing.command; + +public class HugCommand extends Command { + + @Override + public void execute() { + System.out.println("hug"); + } + + @Override + public void unDo() { + System.out.println("open your arms"); + } + +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/mashibing/command/MM.java b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/command/MM.java new file mode 100644 index 00000000..afda0b9f --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/command/MM.java @@ -0,0 +1,21 @@ +package com.desgin.mashibing.command; + +public class MM { + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public void order(Boy b) { + Command c1 = new ShoppingCommand(); + b.addCommand(c1); + Command c2 = new HugCommand(); + b.addCommand(c2); + b.executeCommands(); + } +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/mashibing/command/ShoppingCommand.java b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/command/ShoppingCommand.java new file mode 100644 index 00000000..e98bf5f7 --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/command/ShoppingCommand.java @@ -0,0 +1,15 @@ +package com.desgin.mashibing.command; + +public class ShoppingCommand extends Command { + + @Override + public void execute() { + System.out.println("zoo"); + } + + @Override + public void unDo() { + System.out.println("undo zoo"); + } + +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/mashibing/iterator/ArrayList.java b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/iterator/ArrayList.java new file mode 100644 index 00000000..2c38ed51 --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/iterator/ArrayList.java @@ -0,0 +1,44 @@ +package com.desgin.mashibing.iterator; + +import com.desgin.mashibing.iterator.Collection; + +public class ArrayList implements Collection { + Object[] objects = new Object[10]; + int index = 0; + public void add(Object o) { + if(index == objects.length) { + Object[] newObjects = new Object[objects.length * 2]; + System.arraycopy(objects, 0, newObjects, 0, objects.length); + objects = newObjects; + } + objects[index] = o; + index ++; + } + + public int size() { + return index; + } + + public Iterator iterator() { + + return new ArrayListIterator(); + } + + private class ArrayListIterator implements Iterator { + private int currentIndex = 0; + + @Override + public boolean hasNext() { + if(currentIndex >= index) return false; + else return true; + } + + @Override + public Object next() { + Object o = objects[currentIndex]; + currentIndex ++; + return o; + } + + } +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/mashibing/iterator/Cat.java b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/iterator/Cat.java new file mode 100644 index 00000000..75ef13c6 --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/iterator/Cat.java @@ -0,0 +1,15 @@ +package com.desgin.mashibing.iterator; + +public class Cat { + public Cat(int id) { + super(); + this.id = id; + } + + private int id; + + @Override + public String toString() { + return "cat:" + id; + } +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/mashibing/iterator/Collection.java b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/iterator/Collection.java new file mode 100644 index 00000000..1554ee63 --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/iterator/Collection.java @@ -0,0 +1,7 @@ +package com.desgin.mashibing.iterator; + +public interface Collection { + void add(Object o); + int size(); + Iterator iterator(); +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/mashibing/iterator/Iterator.java b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/iterator/Iterator.java new file mode 100644 index 00000000..4ea28f81 --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/iterator/Iterator.java @@ -0,0 +1,6 @@ +package com.desgin.mashibing.iterator; + +public interface Iterator { + Object next(); + boolean hasNext(); +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/mashibing/iterator/LinkedList.java b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/iterator/LinkedList.java new file mode 100644 index 00000000..afb898a2 --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/iterator/LinkedList.java @@ -0,0 +1,28 @@ +package com.desgin.mashibing.iterator; + +import com.desgin.mashibing.iterator.Collection; + +public class LinkedList implements Collection { + Node head = null; + Node tail = null; + int size = 0; + public void add(Object o) { + Node n = new Node(o, null); + if(head == null) { + head = n; + tail = n; + } + tail.setNext(n); + tail = n; + size ++; + } + + public int size() { + return size; + } + + @Override + public Iterator iterator() { + return null; + } +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/mashibing/iterator/Node.java b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/iterator/Node.java new file mode 100644 index 00000000..324fc007 --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/iterator/Node.java @@ -0,0 +1,24 @@ +package com.desgin.mashibing.iterator; + +public class Node { + public Node(Object data, Node next) { + super(); + this.data = data; + this.next = next; + } + + public Object getData() { + return data; + } + public void setData(Object data) { + this.data = data; + } + public Node getNext() { + return next; + } + public void setNext(Node next) { + this.next = next; + } + private Object data; + private Node next; +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/mashibing/iterator/Test.java b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/iterator/Test.java new file mode 100644 index 00000000..ba6587f2 --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/iterator/Test.java @@ -0,0 +1,24 @@ +package com.desgin.mashibing.iterator; + +import com.desgin.mashibing.iterator.ArrayList; +import com.desgin.mashibing.iterator.LinkedList; + +public class Test { + public static void main(String[] args) { + //ArrayList al = new ArrayList(); + //LinkedList al = new LinkedList(); + Collection c = new ArrayList(); + for(int i=0; i<15; i++) { + c.add(new Cat(i)); + } + System.out.println(c.size()); + + Iterator it = c.iterator(); + while(it.hasNext()) { + Object o = it.next(); + System.out.print(o + " "); + } + } +} + + diff --git a/java-basic/design-pattern/src/main/java/com/desgin/mashibing/iterator/generic/GenericArrayList.java b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/iterator/generic/GenericArrayList.java new file mode 100644 index 00000000..c4de9e33 --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/iterator/generic/GenericArrayList.java @@ -0,0 +1,24 @@ +package com.desgin.mashibing.iterator.generic; + +public class GenericArrayList { + Object[] objects = new Object[10]; + int index = 0; + public void add(E o) { + if(index == objects.length) { + Object[] newObjects = new Object[objects.length * 2]; + System.arraycopy(objects, 0, newObjects, 0, objects.length); + objects = newObjects; + } + objects[index] = o; + index ++; + } + + public int size() { + return index; + } + + public static void main(String args[]) { + GenericArrayList a = new GenericArrayList(); + a.add("hello"); + } +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/mashibing/strategy/Cat.java b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/strategy/Cat.java new file mode 100644 index 00000000..617c067d --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/strategy/Cat.java @@ -0,0 +1,45 @@ +package com.desgin.mashibing.strategy; + + +public class Cat implements Comparable { + private int height; + //private Comparator comparator = new CatHeightComparator(); + private java.util.Comparator comparator = new CatHeightComparator(); + public java.util.Comparator getComparator() { + return comparator; + } + public void setComparator(java.util.Comparator comparator) { + this.comparator = comparator; + } + public int getHeight() { + return height; + } + public void setHeight(int height) { + this.height = height; + } + + + public Cat(int height, int weight) { + super(); + this.height = height; + this.weight = weight; + } + public int getWeight() { + return weight; + } + public void setWeight(int weight) { + this.weight = weight; + } + private int weight; + + @Override + public String toString() { + return height + "|" + weight; + } + + @Override + public int compareTo(Cat o) { + return comparator.compare(this, o); + } + +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/mashibing/strategy/CatHeightComparator.java b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/strategy/CatHeightComparator.java new file mode 100644 index 00000000..ddf061d8 --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/strategy/CatHeightComparator.java @@ -0,0 +1,15 @@ +package com.desgin.mashibing.strategy; + +public class CatHeightComparator implements java.util.Comparator { + + @Override + public int compare(Cat o1, Cat o2) { + Cat c1 = (Cat)o1; + Cat c2 = (Cat)o2; + if(c1.getHeight() > c2.getHeight()) return 1; + else if(c1.getHeight() < c2.getHeight()) return -1; + return 0; + + } + +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/mashibing/strategy/CatWeightComparator.java b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/strategy/CatWeightComparator.java new file mode 100644 index 00000000..616ce4c1 --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/strategy/CatWeightComparator.java @@ -0,0 +1,14 @@ +package com.desgin.mashibing.strategy; + +public class CatWeightComparator implements Comparator { + + @Override + public int compare(Object o1, Object o2) { + Cat c1 = (Cat)o1; + Cat c2 = (Cat)o2; + if(c1.getWeight() > c2.getWeight()) return -1; + else if(c1.getHeight() < c2.getHeight()) return 1; + return 0; + } + +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/mashibing/strategy/Comparable.java b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/strategy/Comparable.java new file mode 100644 index 00000000..6c392185 --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/strategy/Comparable.java @@ -0,0 +1,8 @@ +package com.desgin.mashibing.strategy; + +//使一个类本身具备比较性 +//优点:实现此接口的类可以自己重写自己规定比较的内容 +//缺点:因为只有一个方法,一个类只能有一种方式进行比较 +public interface Comparable { + public int compareTo(T o); +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/mashibing/strategy/Comparator.java b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/strategy/Comparator.java new file mode 100644 index 00000000..6608b934 --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/strategy/Comparator.java @@ -0,0 +1,5 @@ +package com.desgin.mashibing.strategy; + +public interface Comparator { + int compare(Object o1, Object o2); +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/mashibing/strategy/DataSorter.java b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/strategy/DataSorter.java new file mode 100644 index 00000000..2221e156 --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/strategy/DataSorter.java @@ -0,0 +1,55 @@ +package com.desgin.mashibing.strategy; + +import java.lang.Comparable; + +public class DataSorter { + + public static void sort(Object[] a) { + for(int i=a.length; i>0; i--) { + for(int j=0; j0; i--) { + for(int j=0; j a[j+1]) { + swap(a, j , j+1); + } + } + } + } + + private static void swap(int[] a, int x, int y) { + int temp = a[x]; + a[x] = a[y]; + a[y] = temp; + } + + public static void p(int[] a) { + for(int i=0; i d.getFood()) return 1; + else if(this.food < d.getFood()) return -1; + else return 0; + } + + @Override + public String toString() { + return this.food + ""; + } +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/mashibing/strategy/Test.java b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/strategy/Test.java new file mode 100644 index 00000000..56f96af7 --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/mashibing/strategy/Test.java @@ -0,0 +1,13 @@ +package com.desgin.mashibing.strategy; + +public class Test { + public static void main(String[] args) { + //int[] a = {9, 5, 3, 7, 1}; + Cat[] a = {new Cat(5, 5), new Cat(3, 3), new Cat(1, 1)}; + //Dog[] a = {new Dog(5), new Dog(3), new Dog(1)}; + DataSorter.sort(a); + java.util.Arrays.sort(a); + DataSorter.p(a); + + } +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/Approver.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/Approver.java deleted file mode 100644 index 7a17b5bf..00000000 --- a/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/Approver.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.desgin.pattern.behavioral.chainofresponsibility; - -/** - * 批准者 - */ -public abstract class Approver { - /** 责任链的核心就是在类里面包含了一个自己同样类型的一个对象 */ - protected Approver approver; - - public void setNextApprover(Approver approver) { - this.approver = approver; - } - - public abstract void deploy(Course course) ; -} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/ArticleApprover.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/ArticleApprover.java deleted file mode 100644 index 2a8d4359..00000000 --- a/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/ArticleApprover.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.desgin.pattern.behavioral.chainofresponsibility; - -import org.apache.commons.lang3.StringUtils; - -public class ArticleApprover extends Approver { - - @Override - public void deploy(Course course) { - if (StringUtils.isNoneEmpty(course.getArticle())) { - System.out.println(course.getName() + "含有手记,批准"); - //交给下一个责任链对象处理 - if (approver != null) { - approver.deploy(course); - } - } else { - System.out.println(course.getName() + "不含有手记,不批准,流程结束"); - return; - } - } -} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/Course.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/Course.java deleted file mode 100644 index 702b314a..00000000 --- a/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/Course.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.desgin.pattern.behavioral.chainofresponsibility; - -public class Course { - private String name; - private String article; - private String video; - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getArticle() { - return article; - } - - public void setArticle(String article) { - this.article = article; - } - - public String getVideo() { - return video; - } - - public void setVideo(String video) { - this.video = video; - } - - @Override - public String toString() { - return "Course{" + - "name='" + name + '\'' + - ", article='" + article + '\'' + - ", video='" + video + '\'' + - '}'; - } -} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/README.md b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/README.md new file mode 100644 index 00000000..fbef29f9 --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/README.md @@ -0,0 +1 @@ +请查看 design-pattern 项目 com/desgin/mashibing/chainofresponsibility 包 \ No newline at end of file diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/Test.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/Test.java deleted file mode 100644 index c232eec2..00000000 --- a/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/Test.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.desgin.pattern.behavioral.chainofresponsibility; - -public class Test { - public static void main(String[] args) { - Approver articleApprover = new ArticleApprover(); - Approver videoApprover = new VideoApprover(); - - Course course = new Course(); - course.setName("Java设计模式精讲"); - course.setArticle("Java设计模式精讲的手记"); - course.setVideo("Java设计模式精讲的视频"); - /** 先通过手记的审核才交给视频的审核,视频的审核过了才能进行发布上线 */ - articleApprover.setNextApprover(videoApprover); - articleApprover.deploy(course); - } -} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/VideoApprover.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/VideoApprover.java deleted file mode 100644 index 1cb9c4f6..00000000 --- a/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/VideoApprover.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.desgin.pattern.behavioral.chainofresponsibility; - -import org.apache.commons.lang3.StringUtils; - -public class VideoApprover extends Approver { - @Override - public void deploy(Course course) { - if (StringUtils.isNoneEmpty(course.getVideo())) { - System.out.println(course.getName() + "含有视频,批准"); - //交给下一个责任链对象处理 - if (approver != null) { - approver.deploy(course); - } - } else { - System.out.println(course.getName() + "不含有视频,不批准,流程结束"); - return; - } - } -} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version1/Main.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version1/Main.java deleted file mode 100644 index caec89e0..00000000 --- a/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version1/Main.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.desgin.pattern.behavioral.chainofresponsibility.mashibing.version1; - -/** - * @author lastwhisper - */ -public class Main { - - public static void main(String[] args) { - String msg = "大家好,QAQ, ,敏感字眼,不学习!"; - MsgProcessor mp = new MsgProcessor(); - mp.setMsg(msg); - msg = mp.process(); - System.out.println(msg); - } -} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version1/MsgProcessor.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version1/MsgProcessor.java deleted file mode 100644 index e4d39d0b..00000000 --- a/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version1/MsgProcessor.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.desgin.pattern.behavioral.chainofresponsibility.mashibing.version1; - -/** - * @author lastwhisper - */ -public class MsgProcessor { - String msg; - - public String getMsg() { - return msg; - } - - public void setMsg(String msg) { - this.msg = msg; - } - - public String process() { - // process the html tag <> - String r = msg.replaceAll("<", "[") - .replaceAll(">", "]"); - // process the sensitive words - r= r.replaceAll("不学习", "好好学习") - .replaceAll("敏感字眼", ""); - - return r; - } -} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version2/FaceFilter.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version2/FaceFilter.java deleted file mode 100644 index c8e2aa50..00000000 --- a/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version2/FaceFilter.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.desgin.pattern.behavioral.chainofresponsibility.mashibing.version2; - -/** - * @author lastwhisper - */ -public class FaceFilter implements Filter { - // process the face tag <> - @Override - public String doFilter(String str) { - String r = str.replaceAll("QAQ", "^V^"); - return r; - } - -} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version2/Filter.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version2/Filter.java deleted file mode 100644 index 2cae1c0e..00000000 --- a/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version2/Filter.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.desgin.pattern.behavioral.chainofresponsibility.mashibing.version2; - -public interface Filter { - String doFilter(String str); -} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version2/HTMLFilter.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version2/HTMLFilter.java deleted file mode 100644 index 86377771..00000000 --- a/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version2/HTMLFilter.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.desgin.pattern.behavioral.chainofresponsibility.mashibing.version2; - -/** - * @author lastwhisper - */ -public class HTMLFilter implements Filter { - // process the html tag <> - @Override - public String doFilter(String str) { - String r = str.replaceAll("<", "[") - .replaceAll(">", "]"); - return r; - } -} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version2/Main.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version2/Main.java deleted file mode 100644 index 1898a170..00000000 --- a/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version2/Main.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.desgin.pattern.behavioral.chainofresponsibility.mashibing.version2; - -/** - * @author lastwhisper - */ -public class Main { - - public static void main(String[] args) { - String msg = "大家好,QAQ, ,敏感字眼,不学习!"; - MsgProcessor mp = new MsgProcessor(); - mp.setMsg(msg); - msg = mp.process(); - System.out.println(msg); - } -} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version2/MsgProcessor.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version2/MsgProcessor.java deleted file mode 100644 index ffce5536..00000000 --- a/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version2/MsgProcessor.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.desgin.pattern.behavioral.chainofresponsibility.mashibing.version2; - -/** - * @author lastwhisper - */ -public class MsgProcessor { - String msg; - - Filter[] filters = {new HTMLFilter(), new SesitiveFilter(), new FaceFilter()}; - - public String getMsg() { - return msg; - } - - public void setMsg(String msg) { - this.msg = msg; - } - - public String process() { - String r = msg; - for (Filter filter : filters) { - r = filter.doFilter(r); - } - return r; - } -} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version2/SesitiveFilter.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version2/SesitiveFilter.java deleted file mode 100644 index ed062f8a..00000000 --- a/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version2/SesitiveFilter.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.desgin.pattern.behavioral.chainofresponsibility.mashibing.version2; - -/** - * @author lastwhisper - */ -public class SesitiveFilter implements Filter { - // process the sensitive words - @Override - public String doFilter(String str) { - String r = str.replaceAll("不学习", "好好学习") - .replaceAll("敏感字眼", ""); - return r; - } -} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version3/FaceFilter.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version3/FaceFilter.java deleted file mode 100644 index e9bff6b8..00000000 --- a/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version3/FaceFilter.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.desgin.pattern.behavioral.chainofresponsibility.mashibing.version3; - -/** - * @author lastwhisper - */ -public class FaceFilter implements Filter { - // process the face tag <> - @Override - public String doFilter(String str) { - String r = str.replaceAll("QAQ", "^V^"); - return r; - } - -} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version3/Filter.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version3/Filter.java deleted file mode 100644 index f0d49a82..00000000 --- a/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version3/Filter.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.desgin.pattern.behavioral.chainofresponsibility.mashibing.version3; - -public interface Filter { - String doFilter(String str); -} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version3/FilterChain.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version3/FilterChain.java deleted file mode 100644 index 55cac184..00000000 --- a/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version3/FilterChain.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.desgin.pattern.behavioral.chainofresponsibility.mashibing.version3; - -import java.util.ArrayList; -import java.util.List; - -/** - * @author lastwhisper - */ -public class FilterChain implements Filter{ - - List filters = new ArrayList(); - - public FilterChain addFilter(Filter f) { - filters.add(f); - return this; - } - - public String doFilter(String str) { - String r = str; - for (Filter filter : filters) { - r = filter.doFilter(r); - } - return r; - } -} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version3/HTMLFilter.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version3/HTMLFilter.java deleted file mode 100644 index 9cde94ff..00000000 --- a/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version3/HTMLFilter.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.desgin.pattern.behavioral.chainofresponsibility.mashibing.version3; - -/** - * @author lastwhisper - */ -public class HTMLFilter implements Filter { - // process the html tag <> - @Override - public String doFilter(String str) { - String r = str.replaceAll("<", "[") - .replaceAll(">", "]"); - return r; - } -} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version3/Main.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version3/Main.java deleted file mode 100644 index 7384099b..00000000 --- a/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version3/Main.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.desgin.pattern.behavioral.chainofresponsibility.mashibing.version3; - - -/** - * @author lastwhisper - */ -public class Main { - - public static void main(String[] args) { - String msg = "大家好,QAQ, ,敏感字眼,不学习!"; - FilterChain filterChain = new FilterChain(); - filterChain.addFilter(new HTMLFilter()) - .addFilter(new SesitiveFilter()); - - FilterChain filterChain2 = new FilterChain(); - filterChain2.addFilter(new FaceFilter()); - - filterChain.addFilter(filterChain2); - - msg = filterChain.doFilter(msg); - System.out.println(msg); - } -} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version3/SesitiveFilter.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version3/SesitiveFilter.java deleted file mode 100644 index bbd9a142..00000000 --- a/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version3/SesitiveFilter.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.desgin.pattern.behavioral.chainofresponsibility.mashibing.version3; - -/** - * @author lastwhisper - */ -public class SesitiveFilter implements Filter { - // process the sensitive words - @Override - public String doFilter(String str) { - String r = str.replaceAll("不学习", "好好学习") - .replaceAll("敏感字眼", ""); - return r; - } -} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version4/FaceFilter.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version4/FaceFilter.java deleted file mode 100644 index bc679660..00000000 --- a/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version4/FaceFilter.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.desgin.pattern.behavioral.chainofresponsibility.mashibing.version4; - -/** - * @author lastwhisper - */ -public class FaceFilter implements Filter { - - @Override - public void doFilter(Request request, Response response, FilterChain chain) { - // 处理request请求 - request.requestStr = request.requestStr.replaceAll("QAQ", "^V^") - + "---FaceFilter.request()"; - - // 处理response响应 - response.responseStr = response.responseStr.replaceAll("QAQ", "^V^") - + "---FaceFilter.response()"; - } -} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version4/Filter.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version4/Filter.java deleted file mode 100644 index 1e33bb35..00000000 --- a/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version4/Filter.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.desgin.pattern.behavioral.chainofresponsibility.mashibing.version4; - -public interface Filter { - void doFilter(Request request, Response response, FilterChain chain); -} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version4/FilterChain.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version4/FilterChain.java deleted file mode 100644 index 197cd88f..00000000 --- a/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version4/FilterChain.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.desgin.pattern.behavioral.chainofresponsibility.mashibing.version4; - -import java.util.ArrayList; -import java.util.List; - -/** - * @author lastwhisper - */ -public class FilterChain implements Filter { - - List filters = new ArrayList(); - - int index = 0; - - public FilterChain addFilter(Filter f) { - filters.add(f); - return this; - } - - @Override - public void doFilter(Request request, Response response, FilterChain chain) { - if (index == filters.size()) return; - //Filter filter = filters.get(index); - //index++; - //filter.doFilter(request, response, chain); - filters.get(index++).doFilter(request, response, chain); - } -} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version4/HTMLFilter.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version4/HTMLFilter.java deleted file mode 100644 index ea614cd7..00000000 --- a/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version4/HTMLFilter.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.desgin.pattern.behavioral.chainofresponsibility.mashibing.version4; - -/** - * @author lastwhisper - */ -public class HTMLFilter implements Filter { - - @Override - public void doFilter(Request request, Response response, FilterChain chain) { - // 处理request请求 - request.requestStr = request.requestStr.replaceAll("<", "[") - .replaceAll(">", "]") + "---HTMLFilter.request()"; - - chain.doFilter(request, response, chain); - - // 处理response响应 - response.responseStr = response.responseStr.replaceAll("<", "[") - .replaceAll(">", "]") + "---HTMLFilter.response()"; - } -} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version4/Main.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version4/Main.java deleted file mode 100644 index 187d32f5..00000000 --- a/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version4/Main.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.desgin.pattern.behavioral.chainofresponsibility.mashibing.version4; - - -/** - * @author lastwhisper - */ -public class Main { - - public static void main(String[] args) { - // 初始化数据 - String msg = "大家好,QAQ, ,敏感字眼,不学习!"; - Request request = new Request(); - request.setRequestStr(msg); - Response response = new Response(); - response.setResponseStr(msg); - // 过滤链1 - FilterChain filterChain = new FilterChain(); - filterChain.addFilter(new HTMLFilter()) - .addFilter(new SesitiveFilter()); - //// 过滤链2 - //FilterChain filterChain2 = new FilterChain(); - //filterChain2.addFilter(new FaceFilter()); - //// 过滤链1+过滤链2 - //filterChain.addFilter(filterChain2); - // 处理 - filterChain.doFilter(request, response, filterChain); - - System.out.println(request.getRequestStr()); - System.out.println(response.getResponseStr()); - } -} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version4/Request.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version4/Request.java deleted file mode 100644 index 9dc62243..00000000 --- a/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version4/Request.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.desgin.pattern.behavioral.chainofresponsibility.mashibing.version4; - -/** - * @author lastwhisper - */ -public class Request { - String requestStr; - - public String getRequestStr() { - return requestStr; - } - - public void setRequestStr(String requestStr) { - this.requestStr = requestStr; - } -} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version4/Response.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version4/Response.java deleted file mode 100644 index b145d239..00000000 --- a/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version4/Response.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.desgin.pattern.behavioral.chainofresponsibility.mashibing.version4; - -/** - * @author lastwhisper - */ -public class Response { - String responseStr; - - public String getResponseStr() { - return responseStr; - } - - public void setResponseStr(String responseStr) { - this.responseStr = responseStr; - } -} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version4/SesitiveFilter.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version4/SesitiveFilter.java deleted file mode 100644 index 1d2bcd0a..00000000 --- a/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/chainofresponsibility/mashibing/version4/SesitiveFilter.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.desgin.pattern.behavioral.chainofresponsibility.mashibing.version4; - -/** - * @author lastwhisper - */ -public class SesitiveFilter implements Filter { - - @Override - public void doFilter(Request request, Response response, FilterChain chain) { - // 处理request请求 - request.requestStr = request.requestStr.replaceAll("不学习", "好好学习") - .replaceAll("敏感字眼", "") + "---SesitiveFilter.request()"; - // 处理response响应 - response.responseStr = response.responseStr.replaceAll("不学习", "好好学习") - .replaceAll("敏感字眼", "") + "---SesitiveFilter.response()"; - } -} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/memento/ArticleMementoManager.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/memento/ArticleMementoManager.java index 7f636693..f8ac5a2e 100644 --- a/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/memento/ArticleMementoManager.java +++ b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/memento/ArticleMementoManager.java @@ -9,8 +9,7 @@ public class ArticleMementoManager { private final Stack ARTICLE_MEMENTO_STACK = new Stack<>(); public ArticleMemento getMemento() { - ArticleMemento articleMemento = ARTICLE_MEMENTO_STACK.pop(); - return articleMemento; + return ARTICLE_MEMENTO_STACK.pop(); } public void addMemento(ArticleMemento articleMemento) { diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/my/WechatServer.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/my/WechatServer.java index bf36b711..b65af3e9 100644 --- a/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/my/WechatServer.java +++ b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/observer/my/WechatServer.java @@ -36,8 +36,7 @@ public void removeObserver(Observer o) { /**遍历*/ @Override public void notifyObserver() { - for (int i = 0; i < list.size(); i++) { - Observer oserver = list.get(i); + for (Observer oserver : list) { oserver.update(message); } } diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/state/Test.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/state/Test.java index 80c37684..e748f33c 100644 --- a/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/state/Test.java +++ b/java-basic/design-pattern/src/main/java/com/desgin/pattern/behavioral/state/Test.java @@ -6,6 +6,7 @@ public class Test { public static void main(String[] args){ CourseVideoContext courseVideoContext = new CourseVideoContext(); + // 改变一个对象,所属的类 courseVideoContext.setCourseVideoState(new PlayState()); System.out.println("当前状态"+ courseVideoContext.getCourseVideoState().getClass().getSimpleName()); diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/prototype/Mail.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/prototype/Mail.java deleted file mode 100644 index 1fa56565..00000000 --- a/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/prototype/Mail.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.desgin.pattern.creational.prototype; - -/** - * Create by lastwhisper on 2019/1/27 - */ -public class Mail implements Cloneable{ - private String name; - private String emailAddress; - private String content; - - public Mail() { - System.out.println("Mail Class Constructor"); - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getEmailAddress() { - return emailAddress; - } - - public void setEmailAddress(String emailAddress) { - this.emailAddress = emailAddress; - } - - public String getContent() { - return content; - } - - public void setContent(String content) { - this.content = content; - } - - @Override - public String toString() { - return "Mail{" + - "name='" + name + '\'' + - ", emailAddress='" + emailAddress + '\'' + - ", content='" + content + '\'' + - '}'+super.toString(); - } - - @Override - protected Object clone() throws CloneNotSupportedException { - System.out.println("clone mail object"); - return super.clone(); - } -} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/prototype/MailUtils.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/prototype/MailUtils.java deleted file mode 100644 index 753e47e3..00000000 --- a/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/prototype/MailUtils.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.desgin.pattern.creational.prototype; - -import java.text.MessageFormat; - -/** - * Create by lastwhisper on 2019/1/27 - */ -public class MailUtils { - public static void sendMail(Mail mail){ - String outputContent = "向{0}同学,邮件地址:{1},邮件内容:{2}发送邮件成功"; - System.out.println(MessageFormat.format(outputContent, - mail.getName(),mail.getEmailAddress(),mail.getContent())); - } - public static void saveOriginMailRecord(Mail mail){ - System.out.println("存储originMail记录,originMail:"+mail.getContent()); - } -} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/prototype/Test.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/prototype/Test.java deleted file mode 100644 index 586573a2..00000000 --- a/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/prototype/Test.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.desgin.pattern.creational.prototype; - -/** - * Create by lastwhisper on 2019/1/27 - */ -public class Test { - public static void main(String[] args) throws CloneNotSupportedException { - Mail mail = new Mail(); - mail.setContent("初始化模板"); - System.out.println("初始化mail:"+mail); - for (int i = 0; i < 10; i++) { - Mail mailTemp = (Mail) mail.clone(); -// mail.setName("姓名" + i); -// mail.setEmailAddress("姓名" + i + "@qq.com"); -// mail.setContent("恭喜您,QQ号中大奖了"); - mailTemp.setName("姓名" + i); - mailTemp.setEmailAddress("姓名" + i + "@qq.com"); - mailTemp.setContent("恭喜您,QQ号中大奖了"); - MailUtils.sendMail(mailTemp); - System.out.println("克隆的mailTemp:"+mailTemp); - } - MailUtils.saveOriginMailRecord(mail); - } -} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/prototype/clone/Pig.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/prototype/clone/Pig.java deleted file mode 100644 index d45402fb..00000000 --- a/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/prototype/clone/Pig.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.desgin.pattern.creational.prototype.clone; - -import java.util.Date; - -/** - * Create by lastwhisper on 2019/1/27 - */ -public class Pig implements Cloneable { - private String name; - private Date birthday; - - public Pig() { - } - - public Pig(String name, Date birthday) { - this.name = name; - this.birthday = birthday; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public Date getBirthday() { - return birthday; - } - - public void setBirthday(Date birthday) { - this.birthday = birthday; - } - - @Override - public String toString() { - return "Pig{" + - "name='" + name + '\'' + - ", birthday=" + birthday + - '}' + super.toString(); - } - - @Override - protected Object clone() throws CloneNotSupportedException { - Pig pig = (Pig) super.clone(); - //深克隆 - pig.birthday = (Date) pig.birthday.clone(); - return pig; - } -} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/prototype/clone/Test.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/prototype/clone/Test.java deleted file mode 100644 index 515e4df5..00000000 --- a/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/prototype/clone/Test.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.desgin.pattern.creational.prototype.clone; - -import com.desgin.pattern.creational.singleton.HungrySingleton; - -/** - * Create by lastwhisper on 2019/1/27 - */ -public class Test { - public static void main(String[] args) throws CloneNotSupportedException { -// Date birthday = new Date(0L); -// Pig pig1 = new Pig("佩奇", birthday); -// Pig pig2 = (Pig) pig1.clone(); -// System.out.println(pig1); -// System.out.println(pig2); -// pig1.getBirthday().setTime(666666666666L); -// System.out.println(pig1); -// System.out.println(pig2); - HungrySingleton instance = HungrySingleton.getInstance(); - - } -} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/LazyDoubleCheckSingleton.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/LazyDoubleCheckSingleton.java index 753adee3..eb3bd774 100644 --- a/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/LazyDoubleCheckSingleton.java +++ b/java-basic/design-pattern/src/main/java/com/desgin/pattern/creational/singleton/LazyDoubleCheckSingleton.java @@ -5,13 +5,15 @@ */ public class LazyDoubleCheckSingleton { private static volatile LazyDoubleCheckSingleton lazyDoubleCheckSingleton = null; - private LazyDoubleCheckSingleton(){ + + private LazyDoubleCheckSingleton() { } - public static LazyDoubleCheckSingleton getInstance(){ - if(lazyDoubleCheckSingleton == null){ - synchronized (LazyDoubleCheckSingleton.class){ - if(lazyDoubleCheckSingleton == null){ + + public static LazyDoubleCheckSingleton getInstance() { + if (lazyDoubleCheckSingleton == null) { + synchronized (LazyDoubleCheckSingleton.class) { + if (lazyDoubleCheckSingleton == null) { lazyDoubleCheckSingleton = new LazyDoubleCheckSingleton(); //第一步 分配内存给这个对象 //第二步 初始化这个对象 diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/AC220.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/AC220.java deleted file mode 100644 index 2eeae6d2..00000000 --- a/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/AC220.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.desgin.pattern.structural.adapter; - -public class AC220 { - public int outputAC220V() { - int output = 220; - System.out.println("输出220V的交流电"+output+"V"); - return output; - } -} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/DC5.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/DC5.java deleted file mode 100644 index 7d9124e6..00000000 --- a/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/DC5.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.desgin.pattern.structural.adapter; - -public interface DC5 { - int outputDC5V(); -} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/PowerAdapter.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/PowerAdapter.java deleted file mode 100644 index a6ec40c5..00000000 --- a/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/PowerAdapter.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.desgin.pattern.structural.adapter; - -public class PowerAdapter implements DC5 { - - private AC220 ac220 = new AC220(); - - @Override - public int outputDC5V() { - int adapterInput = ac220.outputAC220V(); - /** 变压器 */ - int adapterOutput = adapterInput / 44; - System.out.println("通过PowerAdapter电源适配器输入AC" + adapterInput + "V" + "输出DC:" + adapterOutput + "V"); - return adapterOutput; - } -} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/Test.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/Test.java deleted file mode 100644 index a0cd3786..00000000 --- a/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/Test.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.desgin.pattern.structural.adapter; - -public class Test { - public static void main(String[]args){ - DC5 dc5 = new PowerAdapter(); - dc5.outputDC5V(); - } -} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/classadapter/Test.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/classadapter/Test.java index 88b128a5..672a267f 100644 --- a/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/classadapter/Test.java +++ b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/classadapter/Test.java @@ -5,7 +5,7 @@ public static void main(String[] args) { Target target = new ConcreteTarget(); target.request(); - /** 现在,我们就来通过适配器类来进行实现 */ + /* 现在,我们就来通过适配器类来进行实现 */ Target adapterTarget = new Adapter(); adapterTarget.request(); } diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/exmaple/AC220.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/exmaple/AC220.java new file mode 100644 index 00000000..3c393c1a --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/exmaple/AC220.java @@ -0,0 +1,9 @@ +package com.desgin.pattern.structural.adapter.exmaple; + +public class AC220 { + public int outputAC220V() { + int output = 220; + System.out.println("输出220V的交流电"+output+"V"); + return output; + } +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/exmaple/DC5.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/exmaple/DC5.java new file mode 100644 index 00000000..f935f8d0 --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/exmaple/DC5.java @@ -0,0 +1,5 @@ +package com.desgin.pattern.structural.adapter.exmaple; + +public interface DC5 { + int outputDC5V(); +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/exmaple/PowerAdapter.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/exmaple/PowerAdapter.java new file mode 100644 index 00000000..56fdca4a --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/exmaple/PowerAdapter.java @@ -0,0 +1,18 @@ +package com.desgin.pattern.structural.adapter.exmaple; + +/** + * 对象适配器 + */ +public class PowerAdapter implements DC5 { + + private AC220 ac220 = new AC220(); + + @Override + public int outputDC5V() { + int adapterInput = ac220.outputAC220V(); + /* 变压器 */ + int adapterOutput = adapterInput / 44; + System.out.println("通过PowerAdapter电源适配器输入AC" + adapterInput + "V" + "输出DC:" + adapterOutput + "V"); + return adapterOutput; + } +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/exmaple/Test.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/exmaple/Test.java new file mode 100644 index 00000000..31fd2f66 --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/adapter/exmaple/Test.java @@ -0,0 +1,8 @@ +package com.desgin.pattern.structural.adapter.exmaple; + +public class Test { + public static void main(String[]args){ + DC5 dc5 = new PowerAdapter(); + dc5.outputDC5V(); + } +} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/IOrderDao.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/IOrderDao.java deleted file mode 100644 index 84fec5c3..00000000 --- a/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/IOrderDao.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.desgin.pattern.structural.proxy; - -public interface IOrderDao { - int insert(Order order); -} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/IOrderService.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/IOrderService.java deleted file mode 100644 index 6ad40c8c..00000000 --- a/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/IOrderService.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.desgin.pattern.structural.proxy; - -public interface IOrderService { - /** 保存订单,参数为订单对象,返回值为生效行数 */ - int saveOrder(Order order); -} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/Order.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/Order.java deleted file mode 100644 index 9f5e3cb7..00000000 --- a/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/Order.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.desgin.pattern.structural.proxy; - -public class Order { - private Object orderInfo; - private Integer userId; - - public Object getOrderInfo() { - return orderInfo; - } - - public void setOrderInfo(Object orderInfo) { - this.orderInfo = orderInfo; - } - - public Integer getUserId() { - return userId; - } - - public void setUserId(Integer userId) { - this.userId = userId; - } -} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/OrderDaoImpl.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/OrderDaoImpl.java deleted file mode 100644 index bdad76e3..00000000 --- a/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/OrderDaoImpl.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.desgin.pattern.structural.proxy; - -public class OrderDaoImpl implements IOrderDao { - @Override - public int insert(Order order) { - System.out.println("Dao层添加order成功"); - return 1; - } -} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/OrderServiceImpl.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/OrderServiceImpl.java deleted file mode 100644 index 4cca5932..00000000 --- a/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/OrderServiceImpl.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.desgin.pattern.structural.proxy; - -public class OrderServiceImpl implements IOrderService { - - private IOrderDao iOrderDao; - - @Override - public int saveOrder(Order order) { - /** Spring会自己注入,我们这里就直接new出来了 */ - iOrderDao = new OrderDaoImpl(); - System.out.println("Service调用Dao层添加Order层"); - return iOrderDao.insert(order); - } -} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/README.md b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/README.md new file mode 100644 index 00000000..7cff2471 --- /dev/null +++ b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/README.md @@ -0,0 +1 @@ +移至 java-advance/proxy 目录 \ No newline at end of file diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/db/DataSourceContextHolder.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/db/DataSourceContextHolder.java deleted file mode 100644 index 01f4b4f6..00000000 --- a/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/db/DataSourceContextHolder.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.desgin.pattern.structural.proxy.db; - -public class DataSourceContextHolder { - private static final ThreadLocal CONTEXT_HOLDER = new ThreadLocal<>(); - - public static void setDBType(String dbType) { - CONTEXT_HOLDER.set(dbType); - } - - public static String getDBType() { - return CONTEXT_HOLDER.get(); - } - - public static void clearDBType() { - CONTEXT_HOLDER.remove(); - } -} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/db/DynamicDataSource.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/db/DynamicDataSource.java deleted file mode 100644 index 05b6c1cd..00000000 --- a/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/db/DynamicDataSource.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.desgin.pattern.structural.proxy.db; - -import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; - -public class DynamicDataSource extends AbstractRoutingDataSource { - @Override - protected Object determineCurrentLookupKey() { - return DataSourceContextHolder.getDBType(); - } -} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/dynamicproxy/OrderServiceDynamicProxy.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/dynamicproxy/OrderServiceDynamicProxy.java deleted file mode 100644 index 5e52c678..00000000 --- a/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/dynamicproxy/OrderServiceDynamicProxy.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.desgin.pattern.structural.proxy.dynamicproxy; - -import com.desgin.pattern.structural.proxy.Order; -import com.desgin.pattern.structural.proxy.db.DataSourceContextHolder; - -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; - -/** - * Create by lastwhisper on 2019/2/10 - */ -public class OrderServiceDynamicProxy implements InvocationHandler { - - /** 这是目标类 */ - private Object target; - - /** 通过构造器把目标类注入进来 */ - public OrderServiceDynamicProxy(Object target) { - this.target = target; - } - - /** 获取目标对象 */ - public Object getProxy() { - Class clazz = target.getClass(); - return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this); - } - - /** - * proxy:代理类代理的真实代理对象com.sun.proxy.$Proxy0 - * method:我们所要调用某个对象真实的方法的Method对象 - * args:指代代理对象方法传递的参数 - */ - @Override - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - Object argObject = args[0]; - beforeMethod(argObject); - Object object = method.invoke(target, args); - afterMethod(); - return object; - } - - public void beforeMethod(Object obj) { - int userId = 0; - System.out.println("动态代理before code"); - if (obj instanceof Order) { - Order order = (Order) obj; - userId = order.getUserId(); - } - /** 这里就是实现一个分库的功能,对userId取模2,这里就只会得到0或者是1 */ - int dbRouter = userId % 2; - System.out.println("动态代理分配到【db"+dbRouter+"】处理数据"); - //todo 设置dataSource; - DataSourceContextHolder.setDBType(String.valueOf(dbRouter)); - } - public void afterMethod() { - System.out.println("动态代理after code"); - } -} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/dynamicproxy/Test.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/dynamicproxy/Test.java deleted file mode 100644 index db551300..00000000 --- a/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/dynamicproxy/Test.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.desgin.pattern.structural.proxy.dynamicproxy; - -import com.desgin.pattern.structural.proxy.IOrderService; -import com.desgin.pattern.structural.proxy.Order; -import com.desgin.pattern.structural.proxy.OrderServiceImpl; - -public class Test { - public static void main(String[]args){ - Order order = new Order(); - order.setUserId(2); - /** 这里没有采用spring自动注入的方式,而是采用了直接new的方式 */ - IOrderService orderServiceProxy = (IOrderService) new OrderServiceDynamicProxy(new OrderServiceImpl()).getProxy(); - orderServiceProxy.saveOrder(order); - } -} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/my/dynamicproxy/Calculator.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/my/dynamicproxy/Calculator.java deleted file mode 100644 index 54b26b10..00000000 --- a/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/my/dynamicproxy/Calculator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.desgin.pattern.structural.proxy.my.dynamicproxy; - -/** - * @author lastwhisper - */ -public interface Calculator { - int add(int a, int b); - int subtract(int a, int b); -} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/my/dynamicproxy/CalculatorDynamicProxy.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/my/dynamicproxy/CalculatorDynamicProxy.java deleted file mode 100644 index f4b61081..00000000 --- a/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/my/dynamicproxy/CalculatorDynamicProxy.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.desgin.pattern.structural.proxy.my.dynamicproxy; - -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; - -/** - * 动态代理 - * @author lastwhisper - */ -public class CalculatorDynamicProxy implements InvocationHandler { - // 目标类 - private Object target; - - // 代理类通过构造器接收目标对象(被代理类) - public CalculatorDynamicProxy(Object target) { - this.target = target; - } - - /** 获取目标对象 */ - public Object getProxy() { - Class clazz = target.getClass(); - return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this); - } - - /** - * proxy:代理类代理的真实代理对象com.sun.proxy.$Proxy0 - * method:我们所要调用某个对象真实的方法的Method对象 - * args:指代代理对象方法传递的参数 - */ - @Override - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - Object argObject = args[0]; - beforeMethod(); - Object object = method.invoke(target, args); - afterMethod(); - return object; - } - - public void beforeMethod() { - System.out.println("proxy代理,日志开始记录"); - } - - public void afterMethod() { - System.out.println("proxy代理,日志结束,已记录到数据库中"); - } -} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/my/dynamicproxy/CalculatorImpl.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/my/dynamicproxy/CalculatorImpl.java deleted file mode 100644 index 64a66ab8..00000000 --- a/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/my/dynamicproxy/CalculatorImpl.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.desgin.pattern.structural.proxy.my.dynamicproxy; - -/** - * @author lastwhisper - */ -public class CalculatorImpl implements Calculator { - - @Override - public int add(int a, int b) { - int result = a + b; - return result; - } - - @Override - public int subtract(int a, int b) { - int result = a - b; - return result; - } -} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/my/dynamicproxy/Client.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/my/dynamicproxy/Client.java deleted file mode 100644 index 7a445068..00000000 --- a/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/my/dynamicproxy/Client.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.desgin.pattern.structural.proxy.my.dynamicproxy; - -/** - * @author lastwhisper - */ -public class Client { - public static void main(String[] args) { - Calculator calculator = (Calculator) new CalculatorDynamicProxy(new CalculatorImpl()).getProxy(); - System.out.println(calculator.add(1, 2)); - } -} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/my/hardcode/Calculator.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/my/hardcode/Calculator.java deleted file mode 100644 index 8278ef64..00000000 --- a/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/my/hardcode/Calculator.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.desgin.pattern.structural.proxy.my.hardcode; -// 硬编码 -public class Calculator { - - //加 - public int add(int a, int b) { - System.out.println("add日志开始记录"); - int result = a + b; - System.out.println("add日志结束,已记录到数据库中"); - return result; - } - - //减 - public int subtract(int a, int b) { - System.out.println("subtract日志开始记录"); - int result = a - b; - System.out.println("subtract日志结束,已记录到数据库中"); - return result; - } - - //乘法、除法... -} \ No newline at end of file diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/my/staticproxy/Calculator.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/my/staticproxy/Calculator.java deleted file mode 100644 index 562d1ba7..00000000 --- a/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/my/staticproxy/Calculator.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.desgin.pattern.structural.proxy.my.staticproxy; - -/** - * @author lastwhisper - */ -public interface Calculator { - int add(int a, int b); - int subtract(int a, int b); -} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/my/staticproxy/CalculatorImpl.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/my/staticproxy/CalculatorImpl.java deleted file mode 100644 index e1cb4ac0..00000000 --- a/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/my/staticproxy/CalculatorImpl.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.desgin.pattern.structural.proxy.my.staticproxy; - -/** - * @author lastwhisper - */ -public class CalculatorImpl implements Calculator { - - @Override - public int add(int a, int b) { - int result = a + b; - return result; - } - - @Override - public int subtract(int a, int b) { - int result = a - b; - return result; - } -} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/my/staticproxy/CalculatorStaticProxy.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/my/staticproxy/CalculatorStaticProxy.java deleted file mode 100644 index b31c4dea..00000000 --- a/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/my/staticproxy/CalculatorStaticProxy.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.desgin.pattern.structural.proxy.my.staticproxy; - -/** - * 静态代理 - * @author lastwhisper - */ -public class CalculatorStaticProxy { - // 被代理类 - private Calculator calculator; - // 代理类通过构造器接收被代理类 - public CalculatorStaticProxy(Calculator calculator) { - this.calculator = calculator; - } - - public int proxyAdd(int a, int b) { - System.out.println("proxy代理,add日志开始记录"); - int result = calculator.add(a, b); - System.out.println("proxy代理,add日志结束,已记录到数据库中"); - return result; - } - - public int proxySubtract(int a, int b) { - System.out.println("proxy代理,subtract日志开始记录"); - int result = calculator.subtract(a, b); - System.out.println("proxy代理,subtract日志结束,已记录到数据库中"); - return result; - } -} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/my/staticproxy/Client.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/my/staticproxy/Client.java deleted file mode 100644 index 91faae34..00000000 --- a/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/my/staticproxy/Client.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.desgin.pattern.structural.proxy.my.staticproxy; - -/** - * @author lastwhisper - */ -public class Client { - public static void main(String[] args) { - CalculatorStaticProxy calculatorProxy = new CalculatorStaticProxy(new CalculatorImpl()); - int result = calculatorProxy.proxyAdd(5, 3); - - result = calculatorProxy.proxySubtract(5, 3); - } -} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/staticproxy/OrderServiceStaticProxy.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/staticproxy/OrderServiceStaticProxy.java deleted file mode 100644 index 14233795..00000000 --- a/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/staticproxy/OrderServiceStaticProxy.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.desgin.pattern.structural.proxy.staticproxy; - -import com.desgin.pattern.structural.proxy.IOrderService; -import com.desgin.pattern.structural.proxy.Order; -import com.desgin.pattern.structural.proxy.OrderServiceImpl; -import com.desgin.pattern.structural.proxy.db.DataSourceContextHolder; - -public class OrderServiceStaticProxy { - /** 在代理类里面注入目标对象 */ - private IOrderService iOrderService; - - /** 我们要在这静态代理类里面增强这个方法 */ - public int saveOrder(Order order){ - beforeMethod(order); - /** 如果这里有spring容器的话,就不用显示的new了 */ - iOrderService = new OrderServiceImpl(); - int result = iOrderService.saveOrder(order); - afterMethod(); - return result; - } - - /** 我们要增强,我们就来写上一个before和after */ - private void beforeMethod(Order order){ - int userId = order.getUserId(); - /** 这里就是实现一个分库的功能,对userId取模2,这里就只会得到0或者是1 */ - int dbRouter = userId % 2; - System.out.println("静态代理分配到【db"+dbRouter+"】处理数据"); - - //todo 设置dataSource; - DataSourceContextHolder.setDBType("db"+dbRouter); - System.out.println("静态代理 before code"); - } - - private void afterMethod(){ - System.out.println("静态代理 after code"); - } -} diff --git a/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/staticproxy/Test.java b/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/staticproxy/Test.java deleted file mode 100644 index 6abc0f70..00000000 --- a/java-basic/design-pattern/src/main/java/com/desgin/pattern/structural/proxy/staticproxy/Test.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.desgin.pattern.structural.proxy.staticproxy; - -import com.desgin.pattern.structural.proxy.Order; - -public class Test { - public static void main(String[]args){ - Order order = new Order(); - order.setUserId(0); - /** 这里没有采用spring自动注入的方式,而是采用了直接new的方式 */ - OrderServiceStaticProxy orderServiceStaticProxy = new OrderServiceStaticProxy(); - orderServiceStaticProxy.saveOrder(order); - } -} diff --git a/java-basic/feature-jdk5/README.md b/java-basic/feature-jdk5/README.md new file mode 100644 index 00000000..7a237054 --- /dev/null +++ b/java-basic/feature-jdk5/README.md @@ -0,0 +1,18 @@ +参考“传智 张孝详 Java高新技术” + +# Jdk5的一些新特性学习 +- 自动拆装箱 AutoBox +- 静态导入 StaticImport +- 可变参数 VariableParameter +- 枚举 enumtest +- 注解 annotation +- 反省与JavaBean introspection +- beanutils beanutils +- 反射 reflect +- 泛型 generic +- 类加载器;已从当前项目移除,查看该项目 github/code/java-basic/jvm/ +- 动态代理;已从当前项目移除,查看该项目 github/code/java-advance/proxy +- throwable + + + diff --git a/java-basic/feature-jdk5/pom.xml b/java-basic/feature-jdk5/pom.xml new file mode 100644 index 00000000..c9fa7dfe --- /dev/null +++ b/java-basic/feature-jdk5/pom.xml @@ -0,0 +1,49 @@ + + + 4.0.0 + + feature-jdk5 + cn.cunchang + 1.0-SNAPSHOT + + + UTF-8 + + + + + + junit + junit + 4.13 + + + + + + feature-jdk5 + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + 1.8 + 1.8 + + + + + + src/main/java + + **/*.xml + + true + + + + + \ No newline at end of file diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/AutoBox.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/AutoBox.java similarity index 90% rename from java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/AutoBox.java rename to java-basic/feature-jdk5/src/main/java/cn/lastwhisper/AutoBox.java index 75f3ac7e..f7375452 100644 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/AutoBox.java +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/AutoBox.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.jdk5.feature; +package cn.lastwhisper; /** * jdk5新特性:自动拆箱与装箱 diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/StaticImport.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/StaticImport.java similarity index 92% rename from java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/StaticImport.java rename to java-basic/feature-jdk5/src/main/java/cn/lastwhisper/StaticImport.java index 8a71fef9..b5cb690a 100644 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/StaticImport.java +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/StaticImport.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.jdk5.feature; +package cn.lastwhisper; import static java.lang.Math.abs; import static java.lang.Math.*; diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/VariableParameter.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/VariableParameter.java similarity index 96% rename from java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/VariableParameter.java rename to java-basic/feature-jdk5/src/main/java/cn/lastwhisper/VariableParameter.java index 13dfc994..bcc1ffff 100644 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/VariableParameter.java +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/VariableParameter.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.jdk5.feature; +package cn.lastwhisper; /** * jdk5新特性:可变参数+增强for循环 diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/annotation/AnnotationTest.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/annotation/AnnotationTest.java new file mode 100644 index 00000000..13d7ef08 --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/annotation/AnnotationTest.java @@ -0,0 +1,64 @@ +package cn.lastwhisper.annotation; + +import org.junit.Test; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Proxy; +import java.util.Arrays; +import java.util.Map; + +/** + * jdk5新特性:注解 + * + * @author lastwhisper + */ +public class AnnotationTest { + + @Test + public void test一个什么都有的注解() { + if (UseAnnotation.class.isAnnotationPresent(MyAnnotation.class)) { + MyAnnotation annotation = UseAnnotation.class.getAnnotation(MyAnnotation.class); + System.out.println(annotation.color()); + System.out.println(annotation.value()); + System.out.println(Arrays.toString(annotation.arrayAttr())); + System.out.println(annotation.annotation().value()); + System.out.println(annotation.clazz()); + System.out.println(annotation.enumLevel()); + } + } + + /** + * Changing Annotation Parameters At Runtime + *

+ * https://segmentfault.com/a/1190000011213222 + * + * @throws Exception + */ + @Test + public void test运行期动态修改注解value() throws Exception { + Class clazz = Class.forName("cn.lastwhisper.annotation.StudentRsp"); + //获取 StudentRsp 的 name 字段 + Field field = clazz.getDeclaredField("name"); + //获取 name 字段上的 JsonProperty 注解实例 + JsonProperty jsonProperty = field.getAnnotation(JsonProperty.class); + + System.out.println("当前 jsonProperty value:" + jsonProperty.value()); + + //获取 JsonProperty 这个代理实例所持有的 InvocationHandler + InvocationHandler invocationHandler = Proxy.getInvocationHandler(jsonProperty); + // 获取 AnnotationInvocationHandler 的 memberValues 字段 + Field hField = invocationHandler.getClass().getDeclaredField("memberValues"); + // 设置访问权限 + hField.setAccessible(true); + // 获取 memberValues + Map memberValues = (Map) hField.get(invocationHandler); + // 修改 value 属性值 + memberValues.put("value", "beisen_pro_name"); + + // 获取 JsonProperty 的 value 属性值 + System.out.println("当前 jsonProperty value:" + jsonProperty.value()); + + } + +} diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/annotation/JsonProperty.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/annotation/JsonProperty.java new file mode 100644 index 00000000..d5f5c89c --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/annotation/JsonProperty.java @@ -0,0 +1,15 @@ +package cn.lastwhisper.annotation; + + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.METHOD, ElementType.TYPE, ElementType.FIELD}) +public @interface JsonProperty { + + String value(); + +} diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/annotation/MyAnnotation.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/annotation/MyAnnotation.java new file mode 100644 index 00000000..80651e83 --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/annotation/MyAnnotation.java @@ -0,0 +1,39 @@ +package cn.lastwhisper.annotation; + +// 自定义注解 + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + + +@Retention(RetentionPolicy.RUNTIME)//保留策略 +@Target({ElementType.METHOD, ElementType.TYPE})//作用目标 // 为什么是TYPE,因为Class的父类是Type +public @interface MyAnnotation { + // 八大基本数据类型、String、Class、Enum、注解类型对应的数组类型 + + String color() default "green"; + + String value();//value比较特殊 + + int[] arrayAttr() default {1, 2, 3}; + + Class clazz() default Formatter.class; + + Level enumLevel() default Level.GOOD; + + MetaAnnotation annotation() default @MetaAnnotation("xxx"); + +} + + +interface Formatter { +} + +@interface MetaAnnotation { + String value(); +} + +enum Level {BAD, INDIFFERENT, GOOD} + diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/annotation/StudentRsp.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/annotation/StudentRsp.java new file mode 100644 index 00000000..5cb199d4 --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/annotation/StudentRsp.java @@ -0,0 +1,17 @@ +package cn.lastwhisper.annotation; + +/** + * @author cunchang + * @date 2021/4/19 8:02 下午 + */ +public class StudentRsp { + + /** + * stable beisen_test_name + * real beisen_pro_name + */ + @JsonProperty("beisen_test_name") + public String name; + + +} diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/annotation/UseAnnotation.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/annotation/UseAnnotation.java new file mode 100644 index 00000000..804054d9 --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/annotation/UseAnnotation.java @@ -0,0 +1,22 @@ +package cn.lastwhisper.annotation; + +/** + * @author lastwhisper + */ +@MyAnnotation(color = "red", value = "/user/login", + arrayAttr = {4, 5, 6}, enumLevel = Level.INDIFFERENT, + annotation = @MetaAnnotation("yyy"), clazz = Formatter.class) +public class UseAnnotation { + + @MyAnnotation("yyy") + @SuppressWarnings("deprecation") + public static void deprecatedFun() { + sayHello(); + } + + @Deprecated + public static void sayHello() { + System.out.println("被弃用的函数"); + } + +} diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/enumtest/EnumTest.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/enums/EnumTest.java similarity index 92% rename from java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/enumtest/EnumTest.java rename to java-basic/feature-jdk5/src/main/java/cn/lastwhisper/enums/EnumTest.java index 3e03e326..db9424b8 100644 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/enumtest/EnumTest.java +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/enums/EnumTest.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.jdk5.feature.enumtest; +package cn.lastwhisper.enums; import java.util.Arrays; @@ -72,7 +72,8 @@ public static void main(String[] args) { System.out.println(monday); System.out.println(monday.name()); System.out.println(monday.ordinal());// 下标 - System.out.println(WeekDay2.valueOf("Thursday"));// 静态方法 + // java.lang.Enum.valueOf 从map去拿性能不差的 + System.out.println(WeekDay2.valueOf("Thursday1"));// 静态方法 System.out.println(Arrays.toString(WeekDay2.values()));// 静态方法 } diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/enumtest/WeekDay.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/enums/WeekDay.java similarity index 97% rename from java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/enumtest/WeekDay.java rename to java-basic/feature-jdk5/src/main/java/cn/lastwhisper/enums/WeekDay.java index ee6a1b92..00802dde 100644 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/enumtest/WeekDay.java +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/enums/WeekDay.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.jdk5.feature.enumtest; +package cn.lastwhisper.enums; /** * 实现枚举功能 diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/enumtest/WeekDay1.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/enums/WeekDay1.java similarity index 97% rename from java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/enumtest/WeekDay1.java rename to java-basic/feature-jdk5/src/main/java/cn/lastwhisper/enums/WeekDay1.java index acb0ec5c..9a5b67c0 100644 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/enumtest/WeekDay1.java +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/enums/WeekDay1.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.jdk5.feature.enumtest; +package cn.lastwhisper.enums; /** * 实现枚举功能 diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/equals/EqualsWithExtends.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/equals/EqualsWithExtends.java new file mode 100644 index 00000000..94816423 --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/equals/EqualsWithExtends.java @@ -0,0 +1,55 @@ +package cn.lastwhisper.equals; + +class BaseClass { + private int x; + + public BaseClass(int i) { + x = i; + } + + // equals()的对等性被打破 + // public boolean equals(Object rhs) { +// if (!(rhs instanceof BaseClass)) +// return false; +// +// return x == ((BaseClass) rhs).x; +// } + + public boolean equals(Object rhs) { + // Class保证equlas的对等性 + if (rhs == null || getClass() != rhs.getClass()) + return false; + + return x == ((BaseClass) rhs).x; + } +} + +class DerivedClass extends BaseClass { + private int y; + + public DerivedClass(int i, int j) { + super(i); + y = j; + } + + public boolean equals(Object rhs) { + if (!(rhs instanceof DerivedClass)) + return false; + + return super.equals(rhs) && + y == ((DerivedClass) rhs).y; + } +} + +public class EqualsWithExtends { + public static void main(String[] args) { + BaseClass a = new BaseClass(5); + DerivedClass b = new DerivedClass(5, 8); + DerivedClass c = new DerivedClass(5, 8); + + System.out.println("b.equals(c): " + b.equals(c)); + // equals()的对等性被打破 + System.out.println("a.equals(b): " + a.equals(b)); + System.out.println("b.equals(a): " + b.equals(a)); + } +} \ No newline at end of file diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/equals/HashCode.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/equals/HashCode.java new file mode 100644 index 00000000..48031345 --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/equals/HashCode.java @@ -0,0 +1,88 @@ +package cn.lastwhisper.equals; + +import cn.lastwhisper.reflect.ReflectPoint; +import org.junit.Test; + +import java.util.*; + +/** + * hashcode导致内存泄漏 + * hashcode比较对象是否相等 + * @author lastwhisper + */ +public class HashCode { + /** + * + * 内存泄漏memory leak :是指程序在申请内存后,无法释放已申请的内存空间, + * 一次内存泄漏似乎不会有大的影响,但内存泄漏堆积后的后果就是内存溢出。 + * 各种内存泄漏 https://www.cnblogs.com/panxuejun/p/5883044.html + */ + static class Person { + private Integer id; + private String name; + + public Person(Integer id, String name) { + this.id = id; + this.name = name; + } + + // 重写了对象的equals规则,一定要重写hashcode规则 + //@Override + //public boolean equals(Object obj) { + // if (this == obj) return true; + // if (obj == null || obj.getClass() != getClass()) return false; + // Person person = (Person) obj; + // return id == person.id; + //} + // + //@Override + //public int hashCode() { + // return Objects.hash(id); + //} + } + + /** + * 思考一个问题,不重写hashcode和equals,这两个对象相同吗? + * //重写对象的equals方法,不重写hashcode方法导致的问题 + */ + @Test + public void testOverrideEquals() { + Person p1 = new Person(1, "张三"); + Person p2 = new Person(1, "张三"); + System.out.println(p1.equals(p2));//true + + Map map = new HashMap(); + map.put(p1, "张三"); + System.out.println(map.get(p2)); + + } + + /** + * 重写对象的equals、hashcode方法 + * 不要修改对象的属性,因为修改对象的属性,会导致hashcode发生变化 + * 从而无法使用remove真的移除集合中的对象,对象被集合强引用,导致内存泄漏 + */ + @Test + public void testHashCodeToOOM() { + Set set = new HashSet(); + ReflectPoint pt1 = new ReflectPoint(1, 1); + ReflectPoint pt2 = new ReflectPoint(2, 2); + ReflectPoint pt3 = new ReflectPoint(1, 1); + + set.add(pt1); + set.add(pt2); + set.add(pt3);//重写hashcode发现重复 + set.add(pt1);//内存地址一样发现重复 + + // 对象重写hashcode方法,添加到集合中后不要修改对象的属性值 + pt1.setX(2); + set.remove(pt1); + // 1. 没有重写hashcode size=3。 + // 2. 重写hashcode size=2。 + // 3. 在2的基础上修改对象的属性值,再移除对象,size=2,内存泄漏。 + System.out.println(set.size()); + } + +} + + diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/exception/ErrorAndException.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/exception/ErrorAndException.java new file mode 100644 index 00000000..01834525 --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/exception/ErrorAndException.java @@ -0,0 +1,53 @@ +package cn.lastwhisper.exception; + +import java.io.FileNotFoundException; + +/** + * 异常 + * Error + * Exception + * RuntimeException + * + * @author lastwhisper + */ +public class ErrorAndException { + // Error + private void throwError(){ + throw new StackOverflowError(); + } + + /** + * uncheck exception + * (1)RuntimeException 的子类 + * (2)在方法签名上可以不显示声明 throws *Exception + * (3)调用方可以不 try/catch ,或者 throws *Exception + * 比如:NullPointerException + * + */ + private void throwRuntimeException(){ + throw new NullPointerException(); + } + + /** + * check exception + * (1)非 RuntimeException 的子类 + * (2)在方法签名上必须显示声明 throws *Exception + * (3)调用方必须 try/catch ,或者 throws *Exception + * 比如:FileNotFoundException + */ + private void throwCheckedException() throws FileNotFoundException { + throw new FileNotFoundException(); + } + + public static void main(String[] args) { + ErrorAndException errorAndException = new ErrorAndException(); + errorAndException.throwError(); + errorAndException.throwRuntimeException(); + // 受检查异常,声明throws FileNotFoundException或者try/catch + try { + errorAndException.throwCheckedException(); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + } +} diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/generic/Generic1.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/generic/Generic1.java similarity index 97% rename from java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/generic/Generic1.java rename to java-basic/feature-jdk5/src/main/java/cn/lastwhisper/generic/Generic1.java index 4ad7fe9e..4bfc3489 100644 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/generic/Generic1.java +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/generic/Generic1.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.jdk5.feature.generic; +package cn.lastwhisper.generic; import java.util.ArrayList; import java.util.Collection; diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/generic/Generic2.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/generic/Generic2.java similarity index 97% rename from java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/generic/Generic2.java rename to java-basic/feature-jdk5/src/main/java/cn/lastwhisper/generic/Generic2.java index ab5310ed..6602709b 100644 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/generic/Generic2.java +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/generic/Generic2.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.jdk5.feature.generic; +package cn.lastwhisper.generic; import java.util.Arrays; diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/generic/Generic3.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/generic/Generic3.java similarity index 96% rename from java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/generic/Generic3.java rename to java-basic/feature-jdk5/src/main/java/cn/lastwhisper/generic/Generic3.java index f9a9b0ec..573691e6 100644 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/generic/Generic3.java +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/generic/Generic3.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.jdk5.feature.generic; +package cn.lastwhisper.generic; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/generic/Generic4/BaseDao.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/generic/Generic4/BaseDao.java similarity index 86% rename from java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/generic/Generic4/BaseDao.java rename to java-basic/feature-jdk5/src/main/java/cn/lastwhisper/generic/Generic4/BaseDao.java index 989a8127..37002119 100644 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/generic/Generic4/BaseDao.java +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/generic/Generic4/BaseDao.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.jdk5.feature.generic.Generic4; +package cn.lastwhisper.generic.Generic4; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/generic/Generic4/BaseDaoImpl.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/generic/Generic4/BaseDaoImpl.java similarity index 96% rename from java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/generic/Generic4/BaseDaoImpl.java rename to java-basic/feature-jdk5/src/main/java/cn/lastwhisper/generic/Generic4/BaseDaoImpl.java index 11470148..261eae36 100644 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/generic/Generic4/BaseDaoImpl.java +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/generic/Generic4/BaseDaoImpl.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.jdk5.feature.generic.Generic4; +package cn.lastwhisper.generic.Generic4; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/generic/Generic4/Client.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/generic/Generic4/Client.java new file mode 100644 index 00000000..b762bdbf --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/generic/Generic4/Client.java @@ -0,0 +1,18 @@ +package cn.lastwhisper.generic.Generic4; + +/** + * 该层模拟service + * @author lastwhisper + */ +public class Client { + public static void main(String[] args) { + Person person = new Person(); + person.setId(1L); + person.setName("张三"); + // 交给Spring的IOC容器管理 + PersonDao personDao = new PersonDaoImpl(); + // 持久化到数据库 + personDao.save(person); + + } +} diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/generic/Generic4/Person.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/generic/Generic4/Person.java new file mode 100644 index 00000000..cf42d9d8 --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/generic/Generic4/Person.java @@ -0,0 +1,40 @@ +package cn.lastwhisper.generic.Generic4; + +public class Person { + + // 编号 + private Long id; + + // 姓名 + private String name; + + public Person() { + } + + public Person(Long id, String name) { + this.id = id; + this.name = name; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @Override + public String toString() { + return "Person [id=" + id + ", name=" + name + "]"; + } + +} \ No newline at end of file diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/generic/Generic4/PersonDao.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/generic/Generic4/PersonDao.java new file mode 100644 index 00000000..9ecb5017 --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/generic/Generic4/PersonDao.java @@ -0,0 +1,8 @@ +package cn.lastwhisper.generic.Generic4; + +/** + * extends BaseDao是为了可以使用通用的方法 + * @author lastwhisper + */ +public interface PersonDao extends BaseDao { +} diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/generic/Generic4/PersonDaoImpl.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/generic/Generic4/PersonDaoImpl.java similarity index 85% rename from java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/generic/Generic4/PersonDaoImpl.java rename to java-basic/feature-jdk5/src/main/java/cn/lastwhisper/generic/Generic4/PersonDaoImpl.java index ff1c064f..9ca57f70 100644 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/generic/Generic4/PersonDaoImpl.java +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/generic/Generic4/PersonDaoImpl.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.jdk5.feature.generic.Generic4; +package cn.lastwhisper.generic.Generic4; /** * extends BaseDaoImpl让通用模板知道你的泛型参数是啥,并且可以使用通用的方法 diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/introspection/IntrospectorTest.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/introspection/IntrospectorTest.java similarity index 98% rename from java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/introspection/IntrospectorTest.java rename to java-basic/feature-jdk5/src/main/java/cn/lastwhisper/introspection/IntrospectorTest.java index af5a65f9..7c51edea 100644 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/introspection/IntrospectorTest.java +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/introspection/IntrospectorTest.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.jdk5.feature.introspection; +package cn.lastwhisper.introspection; import java.beans.BeanInfo; import java.beans.Introspector; diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/introspection/Point.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/introspection/Point.java similarity index 93% rename from java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/introspection/Point.java rename to java-basic/feature-jdk5/src/main/java/cn/lastwhisper/introspection/Point.java index c76654ce..2ab6ebb0 100644 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/introspection/Point.java +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/introspection/Point.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.jdk5.feature.introspection; +package cn.lastwhisper.introspection; /** * JavaBean diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/PropertiesDemo.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/PropertiesDemo.java new file mode 100644 index 00000000..138dba32 --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/PropertiesDemo.java @@ -0,0 +1,148 @@ +package cn.lastwhisper.io.io; + +import org.junit.Test; + +import java.io.*; +import java.util.Properties; +import java.util.PropertyResourceBundle; +import java.util.ResourceBundle; + +public class PropertiesDemo { + + private static final String DEFAULT_ENCODING = "UTF-8"; + + /** + * 使用java.util.Properties类的load()方法加载properties文件 + */ + @Test + public void testLoad1() { + try { + // 获取文件流(方法1或2均可) + InputStream inputStream = new BufferedInputStream(new FileInputStream(new File("src/main/resources/config.properties"))); //方法1 +// InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("config.properties"); //方法2 + + Properties prop = new Properties(); + prop.load(new InputStreamReader(inputStream, DEFAULT_ENCODING)); //加载格式化后的流 + + String targetDirs = prop.getProperty("targetDirs"); + String deleteDirs = prop.getProperty("deleteDirs"); + String deleteFiles = prop.getProperty("deleteFiles"); + System.out.println("targetDirs: " + targetDirs); + System.out.println("deleteDirs: " + deleteDirs); + System.out.println("deleteFiles: " + deleteFiles); + + } catch (FileNotFoundException e) { + System.out.println("properties文件路径有误!"); + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * 使用class变量的getResourceAsStream()方法 + * 注意:getResourceAsStream()方法的参数路径/包路径+properties文件名+.后缀 + */ + @Test + public void testLoad2() { + try { + InputStream inputStream = PropertiesDemo.class.getResourceAsStream("/config.properties"); + + Properties prop = new Properties(); + prop.load(inputStream); + + String targetDirs = prop.getProperty("targetDirs"); + String deleteDirs = prop.getProperty("deleteDirs"); + String deleteFiles = prop.getProperty("deleteFiles"); + System.out.println("targetDirs: " + targetDirs); + System.out.println("deleteDirs: " + deleteDirs); + System.out.println("deleteFiles: " + deleteFiles); + + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * 使用class.getClassLoader()所得到的java.lang.ClassLoader的getResourceAsStream()方法 + * 注意:getResourceAsStream(name)方法的参数必须是包路径+文件名+.后缀 + */ + @Test + public void testLoad3() { + try { + InputStream inputStream = PropertiesDemo.class.getClassLoader().getResourceAsStream("config.properties"); + + Properties prop = new Properties(); + prop.load(inputStream); + + String targetDirs = prop.getProperty("targetDirs"); + String deleteDirs = prop.getProperty("deleteDirs"); + String deleteFiles = prop.getProperty("deleteFiles"); + System.out.println("targetDirs: " + targetDirs); + System.out.println("deleteDirs: " + deleteDirs); + System.out.println("deleteFiles: " + deleteFiles); + + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * 使用java.lang.ClassLoader类的getSystemResourceAsStream()静态方法 + * getSystemResourceAsStream()方法的参数必须是包路径+文件名+.后缀 + */ + @Test + public void testLoad4() { + try { + InputStream inputStream = ClassLoader.getSystemResourceAsStream("config.properties"); + + Properties prop = new Properties(); + prop.load(inputStream); + + String targetDirs = prop.getProperty("targetDirs"); + String deleteDirs = prop.getProperty("deleteDirs"); + String deleteFiles = prop.getProperty("deleteFiles"); + System.out.println("targetDirs: " + targetDirs); + System.out.println("deleteDirs: " + deleteDirs); + System.out.println("deleteFiles: " + deleteFiles); + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * 使用java.util.ResourceBundle类的getBundle()方法 + * 注意:注意:这个getBundle()方法的参数相对同目录路径,并去掉.properties后缀,否则将抛异常 + */ + @Test + public void testLoad5() { + ResourceBundle resource = ResourceBundle.getBundle("config"); + + String targetDirs = resource.getString("targetDirs"); + String deleteDirs = resource.getString("deleteDirs"); + String deleteFiles = resource.getString("deleteFiles"); + System.out.println("targetDirs: " + targetDirs); + System.out.println("deleteDirs: " + deleteDirs); + System.out.println("deleteFiles: " + deleteFiles); + } + + /** + * 使用java.util.PropertyResourceBundle类的构造函数 + */ + public static void Method6() { + ResourceBundle resource; + try { + InputStream inputStream = new BufferedInputStream(new FileInputStream(new File("src/main/resources/demo/config.properties"))); + resource = new PropertyResourceBundle(inputStream); + + String driverClassName = resource.getString("driverClassName"); + System.out.println("Method6: " + driverClassName); + + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + } + +} diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/StringCodingDemo.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/StringCodingDemo.java new file mode 100644 index 00000000..1e29817c --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/StringCodingDemo.java @@ -0,0 +1,57 @@ +package cn.lastwhisper.io.io; + +import org.junit.Test; + +import java.util.Arrays; + + +public class StringCodingDemo { + + /* + * 计算机是如何识别什么时候该把两个字节转换为一个中文呢? + * 在计算机中中文的存储分两个字节: + * 第一个字节肯定是负数。 + * 第二个字节常见的是负数,可能有正数。但是没影响。 + */ + @Test + public void testDoubleByte() { + String s1 = "abcde"; + // [97, 98, 99, 100, 101] + + String s2 = "我爱你中国"; + // [-26, -120, -111, -25, -120, -79, -28, -67, -96, -28, -72, -83, -27, -101, -67] + + System.out.println(Arrays.toString(s1.getBytes())); + System.out.println(Arrays.toString(s2.getBytes())); + } + + /** + * 字符编码解码 + * + * String(byte[] bytes, String charsetName):通过指定的字符集解码字节数组 + * byte[] getBytes(String charsetName):使用指定的字符集合把字符串编码为字节数组 + * + * 编码:把看得懂的变成看不懂的 + * String -- byte[] + * + * 解码:把看不懂的变成看得懂的 + * byte[] -- String + */ + @Test + public void testCode() { + String s = "你好"; + + // String -- byte[] + byte[] bys = s.getBytes(); //默认GBK [-60, -29, -70, -61] + // byte[] bys = s.getBytes("GBK");// [-60, -29, -70, -61] + // byte[] bys = s.getBytes("UTF-8");// [-28, -67, -96, -27, -91, -67] + System.out.println(Arrays.toString(bys)); + + // byte[] -- String + String ss = new String(bys); // 你好 + // String ss = new String(bys, "GBK"); // 你好 + // String ss = new String(bys, "UTF-8"); // ??? + System.out.println(ss); + } + +} \ No newline at end of file diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/bytestream/BufferedInputStreamDemo.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/bytestream/BufferedInputStreamDemo.java new file mode 100644 index 00000000..7e44964d --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/bytestream/BufferedInputStreamDemo.java @@ -0,0 +1,33 @@ +package cn.lastwhisper.io.io.bytestream; + +import java.io.BufferedInputStream; +import java.io.FileInputStream; +import java.io.IOException; + +/** + * + * @author lastwhisper + * @date 2020/6/13 + */ +public class BufferedInputStreamDemo { + + public static void main(String[] args) throws IOException { + BufferedInputStream bis = new BufferedInputStream( + new FileInputStream("D:\\a.txt")); + + // 中文乱码 + //int by; + //while ((by = bis.read()) != -1) { + //System.out.print((char) by); + //} + + byte[] buffer = new byte[1024]; + int len; + while ((len = bis.read(buffer)) != -1) { + System.out.print(new String(buffer, 0, len)); + } + // 释放资源 + bis.close(); + } + +} diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/bytestream/BufferedOutputStreamDemo.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/bytestream/BufferedOutputStreamDemo.java new file mode 100644 index 00000000..2e6216a9 --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/bytestream/BufferedOutputStreamDemo.java @@ -0,0 +1,38 @@ +package cn.lastwhisper.io.io.bytestream; + +import java.io.BufferedOutputStream; +import java.io.FileOutputStream; +import java.io.IOException; + +/** + * + * @author lastwhisper + * @date 2020/6/13 + */ +public class BufferedOutputStreamDemo { + + /* + * 通过定义数组的方式确实比以前一次读取一个字节的方式快很多,所以,看来有一个缓冲区还是非常好的。 + * 既然是这样的话,那么,java开始在设计的时候,它也考虑到了这个问题,就专门提供了带缓冲区的字节类。 + * 这种类被称为:缓冲区类(高效类) + * 写数据:BufferedOutputStream + * 读数据:BufferedInputStream + * + * 构造方法可以指定缓冲区的大小,但是我们一般用不上,因为默认缓冲区大小就足够了。 + * + * 为什么不传递一个具体的文件或者文件路径,而是传递一个OutputStream对象呢? + * 原因很简单,字节缓冲区流仅仅提供缓冲区,为高效而设计的。但是呢,真正的读写操作还得靠基本的流对象实现。 + */ + + public static void main(String[] args) throws IOException { + BufferedOutputStream bos = new BufferedOutputStream( + new FileOutputStream("bos.txt")); + + // 写数据 + bos.write("hello".getBytes()); + + // 释放资源 + bos.close(); + } + +} diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/bytestream/FileInputStreamDemo.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/bytestream/FileInputStreamDemo.java new file mode 100644 index 00000000..50df8abf --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/bytestream/FileInputStreamDemo.java @@ -0,0 +1,56 @@ +package cn.lastwhisper.io.io.bytestream; + +import org.junit.Test; + +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; + +/** + * + * @author lastwhisper + * @date 2020/6/13 + */ +public class FileInputStreamDemo { + + /* + * 字节输入流操作步骤: + * A:创建字节输入流对象 + * B:调用read()方法读取数据,并把数据显示在控制台 + * C:释放资源 + * + * 读取数据的方式: + * A:int read():一次读取一个字节 + * B:int read(byte[] b):一次读取一个字节数组 + */ + @Test + public void testByteRead() throws IOException { + // 1、创建字节输入流对象 + InputStream is = new FileInputStream("fos.txt"); + // 2、调用read()方法读取数据 + // 一个字节一个字节的读,中文表示需要两个字节,会乱码 + int by; + while ((by = is.read()) != -1) { + System.out.print((char)by); + } + // 3、释放资源 + is.close(); + } + + @Test + public void testBufferRead() throws IOException { + // 1、创建字节输入流对象 + InputStream is = new FileInputStream("fos.txt"); + // 2、调用read()方法读取数据 + // 通过字节数组缓冲区,优化性能 + int len; + byte[] buffer = new byte[1024]; + while ((len = is.read(buffer)) != -1) { + System.out.println(new String(buffer, 0, len)); + } + // 3、释放资源 + is.close(); + } + + +} diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/bytestream/FileOutputStreamDemo.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/bytestream/FileOutputStreamDemo.java new file mode 100644 index 00000000..a0873540 --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/bytestream/FileOutputStreamDemo.java @@ -0,0 +1,75 @@ +package cn.lastwhisper.io.io.bytestream; + +import org.junit.Test; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +/** + * + * @author lastwhisper + * @date 2020/6/13 + */ +public class FileOutputStreamDemo { + + /* + * IO流的分类: + * 流向: + * 输入流 读取数据 + * 输出流 写出数据 + * 数据类型: + * 字节流 + * 字节输入流 读取数据 InputStream + * 字节输出流 写出数据 OutputStream + * 字符流 + * 字符输入流 读取数据 Reader + * 字符输出流 写出数据 Writer + * + * 字节输出流操作步骤: + * A:创建字节输出流对象 + * B:写数据 + * C:释放资源 + */ + + @Test + public void testWrite() throws IOException { + // 1、创建字节输出流 + /* + * 创建字节输出流对象了做了几件事情: + * A:调用系统功能去创建文件 + * B:创建FileOutputStream对象 + * C:把FileOutputStream对象指向这个文件 + */ + File file = new File("fos.txt"); + OutputStream os = new FileOutputStream(file); + //OutputStream os = new FileOutputStream("fos.txt"); + // 2、向字节输出流写入字节流 + os.write("hello java IO\n".getBytes()); + os.write("hello python IO".getBytes()); + // 3、释放资源 + /* + * 为什么一定要close()呢? + * A:让流对象变成垃圾,这样就可以被垃圾回收器回收了 + * B:通知系统去释放跟该文件相关的资源 + */ + os.close(); + //java.io.IOException: Stream Closed + //os.write("java".getBytes()); + } + + @Test + public void testWriteAppend() throws IOException { + //1、创建字节输出流,追加写入数据 + OutputStream os = new FileOutputStream("fos.txt",true); + // 2、向字节输出流写入字节流 + os.write(97); + byte[] bytes={97,98,99,100,101}; + os.write(bytes); + os.write(bytes,1,3); + // 3、释放资源 + os.close(); + } + +} diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/bytestream/IOByteStreamCopyFile.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/bytestream/IOByteStreamCopyFile.java new file mode 100644 index 00000000..850622b9 --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/bytestream/IOByteStreamCopyFile.java @@ -0,0 +1,55 @@ +package cn.lastwhisper.io.io.bytestream; + +import org.junit.Test; + +import java.io.*; + +/** + * + * 字节流四种方式复制文件: + * 基本字节流一次读写一个字节: 共耗时:117235毫秒 + * 基本字节流一次读写一个字节数组: 共耗时:156毫秒 + * 高效字节流一次读写一个字节: 共耗时:1141毫秒 + * 高效字节流一次读写一个字节数组: 共耗时:47毫秒 + * + * @author lastwhisper + * @date 2020/6/13 + */ +public class IOByteStreamCopyFile { + + @Test + public void testByteCopy() throws IOException { + // 封装数据源 + InputStream fis = new FileInputStream("D:\\a.txt"); + // 封装目的地 + OutputStream fos = new FileOutputStream("D:\\b.txt"); + + // 一个字节一个字节的复制 + int by; + while ((by = fis.read()) != -1) { + fos.write(by); + } + // 释放资源(先关谁都行) + fos.close(); + fis.close(); + } + + @Test + public void testByteBufferCopy() throws IOException { + // 封装数据源 + InputStream fis = new FileInputStream("D:\\a.txt"); + // 封装目的地 + OutputStream fos = new FileOutputStream("D:\\b.txt"); + + // 复制数据 + byte[] buffer = new byte[1024]; + int len; + while ((len = fis.read(buffer)) != -1) { + fos.write(buffer, 0, len); + } + // 释放资源(先关谁都行) + fos.close(); + fis.close(); + } + +} diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/charstream/BufferedReaderDemo.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/charstream/BufferedReaderDemo.java new file mode 100644 index 00000000..a35164b9 --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/charstream/BufferedReaderDemo.java @@ -0,0 +1,54 @@ +package cn.lastwhisper.io.io.charstream; + +import org.junit.Test; + +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; + +/** + * + * @author lastwhisper + * @date 2020/6/14 + */ +public class BufferedReaderDemo { + + @Test + public void testCharRead() throws IOException { + // 1、创建字符缓冲输入流对象 + BufferedReader br = new BufferedReader(new FileReader("bw.txt")); + + // 2、读输入流 + // 方式1 + // int ch = 0; + // while ((ch = br.read()) != -1) { + // System.out.print((char) ch); + // } + + // 方式2 + char[] chars = new char[1024]; + int len; + while ((len = br.read(chars)) != -1) { + System.out.print(new String(chars, 0, len)); + } + + // 3、释放资源 + br.close(); + } + + + @Test + public void testCharRead2() throws IOException { + BufferedReader br = new BufferedReader(new FileReader("bw2.txt")); + + // 最终版代码 + String line; + while ((line = br.readLine()) != null) { + System.out.println(line); + } + + //释放资源 + br.close(); + } + +} diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/charstream/BufferedWriterDemo.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/charstream/BufferedWriterDemo.java new file mode 100644 index 00000000..45db1ddd --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/charstream/BufferedWriterDemo.java @@ -0,0 +1,55 @@ +package cn.lastwhisper.io.io.charstream; + +import org.junit.Test; + +import java.io.BufferedWriter; +import java.io.FileWriter; +import java.io.IOException; + +/** + * + * @author lastwhisper + * @date 2020/6/14 + */ +public class BufferedWriterDemo { + + /* + * 字符流为了高效读写,也提供了对应的字符缓冲流。 + * BufferedWriter:字符缓冲输出流 + * BufferedReader:字符缓冲输入流 + * + * BufferedWriter:字符缓冲输出流 + * 将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。 + * 可以指定缓冲区的大小,或者接受默认的大小。在大多数情况下,默认值就足够大了。 + */ + @Test + public void testCharBufferWrite() throws IOException { + // 1、创建字符缓冲输出流 + // BufferedWriter bw = new BufferedWriter(new OutputStreamWriter( + // new FileOutputStream("bw.txt"))); + BufferedWriter bw = new BufferedWriter(new FileWriter("bw.txt")); + + // 2、写入缓冲区 + bw.write("hello"); + bw.write("world"); + bw.write("java\n"); + bw.write("java 牛逼"); + bw.flush(); + + // 3、关闭流 + bw.close(); + } + + @Test + public void testCharBufferWrite2() throws IOException { + BufferedWriter bw = new BufferedWriter(new FileWriter("bw2.txt")); + for (int x = 0; x < 10; x++) { + bw.write("hello" + x); + // bw.write("\r\n"); + bw.newLine(); + bw.flush(); + } + bw.close(); + } + +} diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/charstream/IOCharBufferStreamCopyFile.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/charstream/IOCharBufferStreamCopyFile.java new file mode 100644 index 00000000..c2dff14c --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/charstream/IOCharBufferStreamCopyFile.java @@ -0,0 +1,55 @@ +package cn.lastwhisper.io.io.charstream; + +import org.junit.Test; + +import java.io.*; + +/** + * + * @author lastwhisper + * @date 2020/6/14 + */ +public class IOCharBufferStreamCopyFile { + + @Test + public void testCharBufferCopy() throws IOException { + // 封装数据源 + BufferedReader br = new BufferedReader(new FileReader("a.txt")); + // 封装目的地 + BufferedWriter bw = new BufferedWriter(new FileWriter("b.txt")); + + // 两种方式其中的一种一次读写一个字符数组 + char[] chars = new char[1024]; + int len ; + while ((len = br.read(chars)) != -1) { + bw.write(chars, 0, len); + bw.flush(); + } + + // 释放资源 + bw.close(); + br.close(); + } + + @Test + public void testCharBufferCopy2() throws IOException { + // 封装数据源 + BufferedReader br = new BufferedReader(new FileReader("a.txt")); + // 封装目的地 + BufferedWriter bw = new BufferedWriter(new FileWriter("b.txt")); + + // 读写数据 + String line; + while ((line = br.readLine()) != null) { + bw.write(line); + bw.newLine(); + bw.flush(); + } + + // 释放资源 + bw.close(); + br.close(); + } + + +} diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/charstream/IOCharStreamCopyFile.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/charstream/IOCharStreamCopyFile.java new file mode 100644 index 00000000..f0c17ae1 --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/charstream/IOCharStreamCopyFile.java @@ -0,0 +1,74 @@ +package cn.lastwhisper.io.io.charstream; + +import org.junit.Test; + +import java.io.*; + +/** + * + * @author lastwhisper + * @date 2020/6/14 + */ +public class IOCharStreamCopyFile { + + @Test + public void testCharCopy() throws IOException { + // 1、创建字符输入输出流 + InputStreamReader isr = new InputStreamReader(new FileInputStream("d:\\a.txt")); + OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("d:\\b.txt")); + + // 2、将字符输入流的数据读出来,写到字符输出流中 + // 一个字符一个字符的读写 + //int ch; + //while ((ch = isr.read()) != -1) { + // osw.write(ch); + //} + + int len; + char[] cbuf = new char[1024]; + while ((len = isr.read(cbuf)) != -1) { + osw.write(cbuf, 0, len); + } + + // 3、关闭流 + osw.close(); + isr.close(); + } + + /* + * 由于我们常见的操作都是使用本地默认编码,所以,不用指定编码。 + * 而转换流的名称有点长,所以,Java就提供了其子类供我们使用。 + * OutputStreamWriter = FileOutputStream + 编码表(GBK) + * FileWriter = FileOutputStream + 编码表(GBK) + * + * InputStreamReader = FileInputStream + 编码表(GBK) + * FileReader = FileInputStream + 编码表(GBK) + * + */ + @Test + public void testFileRWCopy() throws IOException { + // 1、创建字符输入输出流 + FileReader fr = new FileReader("d:\\a.txt"); + FileWriter fw = new FileWriter("d:\\b.txt"); + + // 一次一个字符 + // int ch = 0; + // while ((ch = fr.read()) != -1) { + // fw.write(ch); + // } + + // 一次一个字符数组 + char[] chs = new char[1024]; + int len = 0; + while ((len = fr.read(chs)) != -1) { + fw.write(chs, 0, len); + fw.flush(); + } + + // 释放资源 + fw.close(); + fr.close(); + } + + +} diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/charstream/InputStreamReaderDemo.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/charstream/InputStreamReaderDemo.java new file mode 100644 index 00000000..a2502d4b --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/charstream/InputStreamReaderDemo.java @@ -0,0 +1,63 @@ +package cn.lastwhisper.io.io.charstream; + +import org.junit.Test; + +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStreamReader; + +/** + * + * @author lastwhisper + * @date 2020/6/14 + */ +public class InputStreamReaderDemo { + + + /* + * InputStreamReader的方法: + * int read():一次读取一个字符 + * int read(char[] chs):一次读取一个字符数组 + */ + @Test + public void testCharRead() throws IOException { + // 1、创建字符输入流 + // InputStreamReader isr = new InputStreamReader(new FileInputStream("osw.txt")); + + // InputStreamReader isr = new InputStreamReader(new FileInputStream("osw.txt"), "GBK"); + InputStreamReader isr = new InputStreamReader( + new FileInputStream("osw.txt"), "UTF-8"); + + // 2、写入数据 + // 一次读取一个字符 + int ch; + while ((ch = isr.read()) != -1) { + System.out.print((char) ch); + } + + // 3、释放资源 + isr.close(); + } + + @Test + public void testCharBufferRead() throws IOException { + // 1、创建字符输入流 + // InputStreamReader isr = new InputStreamReader(new FileInputStream("osw.txt")); + + // InputStreamReader isr = new InputStreamReader(new FileInputStream("osw.txt"), "GBK"); + InputStreamReader isr = new InputStreamReader( + new FileInputStream("osw.txt"), "UTF-8"); + + // 2、写入数据 + // 一次读取一个字符数组 + char[] chars = new char[1024]; + int len; + while ((len = isr.read(chars)) != -1) { + System.out.print(new String(chars, 0, len)); + } + + // 3、释放资源 + isr.close(); + } + +} diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/charstream/OutputStreamWriterDemo.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/charstream/OutputStreamWriterDemo.java new file mode 100644 index 00000000..ecaf2556 --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/charstream/OutputStreamWriterDemo.java @@ -0,0 +1,86 @@ +package cn.lastwhisper.io.io.charstream; + +import org.junit.Test; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; + +/** + * + * @author lastwhisper + * @date 2020/6/14 + */ +public class OutputStreamWriterDemo { + + /* + * OutputStreamWriter(OutputStream out):根据默认编码把字节流的数据转换为字符流 + * OutputStreamWriter(OutputStream out,String charsetName):根据指定编码把字节流数据转换为字符流 + * 把字节流转换为字符流。 + * 字符流 = 字节流 +编码表。 + */ + @Test + public void testWriteCoding() throws IOException { + // 1、创建字符输出流 + // OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream( + // "osw.txt")); // 默认GBK + // OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream( + // "osw.txt"), "GBK"); // 指定GBK + OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream( + "osw.txt"), "UTF-8"); // 指定UTF-8 + // 2、写数据 + osw.write("中国"); + // 3、 释放资源 + osw.close(); + } + + /* + * OutputStreamWriter的方法: + * public void write(int c):写一个字符 + * public void write(char[] cbuf):写一个字符数组 + * public void write(char[] cbuf,int off,int len):写一个字符数组的一部分 + * public void write(String str):写一个字符串 + * public void write(String str,int off,int len):写一个字符串的一部分 + * + * 面试题:close()和flush()的区别? + * A:close()关闭流对象,但是先刷新一次缓冲区。关闭之后,流对象不可以继续再使用了。 + * B:flush()仅仅刷新缓冲区,刷新之后,流对象还可以继续使用。 + */ + @Test + public void testWriteChar() throws IOException { + // 1、创建字符输出流 + OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("osw2.txt")); + + // 2、写数据 + // public void write(int c):写一个字符 + // osw.write('a'); + // osw.write(97); + // 为什么数据没有进去呢? + // 原因是:字符 = 2字节 + // 文件中数据存储的基本单位是字节。 + // void flush() + + // public void write(char[] cbuf):写一个字符数组 + // char[] chs = {'a','b','c','d','e'}; + // osw.write(chs); + + // public void write(char[] cbuf,int off,int len):写一个字符数组的一部分 + // osw.write(chs,1,3); + + // public void write(String str):写一个字符串 + // osw.write("我爱林青霞"); + + // public void write(String str,int off,int len):写一个字符串的一部分 + osw.write("我爱林青霞", 2, 3); + + // 刷新缓冲区 + osw.flush(); + // osw.write("我爱林青霞", 2, 3); + + // 3、释放资源 + osw.close(); + // java.io.IOException: Stream closed + // osw.write("我爱林青霞", 2, 3); + } + +} \ No newline at end of file diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/charstream/other/LineNumberReaderDemo.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/charstream/other/LineNumberReaderDemo.java new file mode 100644 index 00000000..9462d557 --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/charstream/other/LineNumberReaderDemo.java @@ -0,0 +1,34 @@ +package cn.lastwhisper.io.io.charstream.other; + +import java.io.FileReader; +import java.io.IOException; +import java.io.LineNumberReader; + +/** + * + * @author lastwhisper + * @date 2020/6/14 + */ +public class LineNumberReaderDemo { + + /* + * BufferedReader + * |--LineNumberReader + * public int getLineNumber()获得当前行号。 + * public void setLineNumber(int lineNumber) + */ + public static void main(String[] args) throws IOException { + LineNumberReader lnr = new LineNumberReader(new FileReader("d:\\a.txt")); + + // 行号从10开始 + lnr.setLineNumber(10); + + String line; + while ((line = lnr.readLine()) != null) { + System.out.println(lnr.getLineNumber() + " : " + line); + } + + lnr.close(); + } + +} diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/file/FileDemo.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/file/FileDemo.java new file mode 100644 index 00000000..14e11a7a --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/file/FileDemo.java @@ -0,0 +1,142 @@ +package cn.lastwhisper.io.io.file; + +import org.junit.Test; + +import java.io.File; +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * File API + * @author lastwhisper + * @date 2020/6/13 + */ +public class FileDemo { + + /* + * 我们要想实现IO的操作,就必须知道硬盘上文件的表现形式。 + * 而Java就提供了一个类File供我们使用。 + * + * File:文件和目录(文件夹)路径名的抽象表示形式 + */ + @Test + public void testConstructor() { + // Creates a new File instance by converting the given pathname string into an abstract pathname. + File file1 = new File("D:\\demo\\a.txt"); + // Creates a new File instance from a parent pathname string and a child pathname string. + File file2 = new File("D:\\demo\\", "a.txt"); + // Creates a new File instance from a parent abstract pathname and a child pathname string. + File file3 = new File("D:\\demo\\"); + File file4 = new File(file3, "a.txt"); + } + + /** + * 文件以及文件夹创建 + */ + @Test + public void testCreate() throws IOException { + File file1 = new File("D:\\demo"); + System.out.println("mkdir:" + file1.mkdir()); + + File file2 = new File(file1, "a.txt"); + System.out.println("ctfile:" + file2.createNewFile()); + + // java.io.IOException: 系统找不到指定的路径。 + // file 的创建,建立在dir的基础下 + //File file3 = new File("D:\\test\\b.txt"); + //System.out.println("ctfile:" + file3.createNewFile()); + + // dir 的创建,建立在dir的基础下 + File file4 = new File("D:\\dir1\\dir2"); + System.out.println("mkdir:" + file4.mkdirs()); + } + + /** + * 文件以及文件夹删除 + * 1、要删除一个文件夹,请注意该文件夹内不能包含文件或者文件夹 + * 2、Java中的删除不走回收站 + */ + @Test + public void testDelete() throws IOException { + File file1 = new File("D:\\a.txt"); + System.out.println("ctfile:" + file1.createNewFile()); + System.out.println("delete:" + file1.delete()); + } + + /* + * 重命名功能:public boolean renameTo(File dest) + * 如果路径名相同,就是改名。 + * 如果路径名不同,就是改名并剪切。 + * + * 路径以盘符开始:绝对路径 c:\\a.txt + * 路径不以盘符开始:相对路径 a.txt + */ + @Test + public void testRename() throws IOException { + // 需求:我要修改这个文件的名称为"b.txt" + // File file = new File("D:\\a.txt"); + // File newFile = new File("D:\\b.txt"); + // System.out.println("renameTo:" + file.renameTo(newFile)); + + File file2 = new File("D:\\a.txt"); + File newFile2 = new File("D:\\b.txt"); + System.out.println("renameTo:" + file2.renameTo(newFile2)); + } + + /* + * 文件权限 + */ + @Test + public void testSecurity() throws IOException { + File file = new File("D:\\a.txt"); + if(!file.exists()){ + file.createNewFile(); + } + System.out.println("判断是否是目录:" + file.isDirectory());// false + System.out.println("判断是否是文件:" + file.isFile());// true + System.out.println("判断是否存在:" + file.exists());// true + System.out.println("判断是否可读:" + file.canRead());// true + System.out.println("判断是否可写:" + file.canWrite());// true + System.out.println("判断是否隐藏:" + file.isHidden());// false + } + + /* + * 文件详情 + */ + @Test + public void testFindDetail() throws IOException { + File file = new File("D:\\a.txt"); + System.out.println("获取绝对路径:" + file.getAbsolutePath()); + System.out.println("获取相对路径:" + file.getPath()); + System.out.println("获取名称:" + file.getName()); + System.out.println("获取字节数:" + file.length()); + System.out.println("获取最后一次的修改时间:" + file.lastModified()); + + // 1592035972157 + Date d = new Date(1592035972157L); + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + String s = sdf.format(d); + System.out.println(s); + } + + /** + * 文件相关信息 + */ + @Test + public void testList(){ + File file = new File("d:\\"); + // public String[] list():获取指定目录下的所有文件或者文件夹的名称数组 + String[] strArray = file.list(); + for (String s : strArray) { + System.out.println(s); + } + System.out.println("------------"); + // public File[] listFiles():获取指定目录下的所有文件或者文件夹的File数组 + File[] fileArray = file.listFiles(); + for (File f : fileArray) { + System.out.println(f.getName()); + } + } + +} diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/otherstream/ByteArrayStreamDemo.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/otherstream/ByteArrayStreamDemo.java new file mode 100644 index 00000000..16267a48 --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/otherstream/ByteArrayStreamDemo.java @@ -0,0 +1,52 @@ +package cn.lastwhisper.io.io.otherstream; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +/** + * + * @author lastwhisper + * @date 2020/6/14 + */ +public class ByteArrayStreamDemo { + + /* + * 内存操作流:用于处理临时存储信息的,程序结束,数据就从内存中消失。 + * 字节数组: + * ByteArrayInputStream + * ByteArrayOutputStream + * 字符数组: + * CharArrayReader + * CharArrayWriter + * 字符串: + * StringReader + * StringWriter + */ + public static void main(String[] args) throws IOException { + // 写数据 + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + // 写数据 + for (int x = 0; x < 10; x++) { + baos.write(("hello" + x).getBytes()); + } + + // 释放资源,内存操作流不需要释放资源 + baos.close(); + + byte[] bys = baos.toByteArray(); + + // 读数据 + ByteArrayInputStream bais = new ByteArrayInputStream(bys); + + int by; + while ((by = bais.read()) != -1) { + System.out.print((char) by); + } + + bais.close(); + + } + +} diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/otherstream/DataStreamDemo.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/otherstream/DataStreamDemo.java new file mode 100644 index 00000000..d9f57fdc --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/otherstream/DataStreamDemo.java @@ -0,0 +1,67 @@ +package cn.lastwhisper.io.io.otherstream; + +import org.junit.Test; + +import java.io.*; + +/** + * @author lastwhisper + * @date 2020/6/14 + */ +public class DataStreamDemo { + + /** + * 可以读写基本数据类型的数据 + * 数据输入流:DataInputStream + * DataInputStream(InputStream in) + * 数据输出流:DataOutputStream + * DataOutputStream(OutputStream out) + */ + @Test + public void testWrite() throws IOException { + // 创建数据输出流对象 + DataOutputStream dos = new DataOutputStream(new FileOutputStream("dos.txt")); + + // 写数据了 + dos.writeByte(10); + dos.writeShort(100); + dos.writeInt(1000); + dos.writeLong(10000); + dos.writeFloat(12.34F); + dos.writeDouble(12.56); + dos.writeChar('a'); + dos.writeBoolean(true); + + // 释放资源 + dos.close(); + } + + @Test + public void testRead() throws IOException { + // 创建数据输入流对象 + DataInputStream dis = new DataInputStream(new FileInputStream("dos.txt")); + + // 读数据 + byte b = dis.readByte(); + short s = dis.readShort(); + int i = dis.readInt(); + long l = dis.readLong(); + float f = dis.readFloat(); + double d = dis.readDouble(); + char c = dis.readChar(); + boolean bb = dis.readBoolean(); + + // 释放资源 + dis.close(); + + System.out.println(b); + System.out.println(s); + System.out.println(i); + System.out.println(l); + System.out.println(f); + System.out.println(d); + System.out.println(c); + System.out.println(bb); + } + +} diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/otherstream/ObjectStreamDemo.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/otherstream/ObjectStreamDemo.java new file mode 100644 index 00000000..77b8be02 --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/otherstream/ObjectStreamDemo.java @@ -0,0 +1,49 @@ +package cn.lastwhisper.io.io.otherstream; + +import org.junit.Test; + +import java.io.*; + +/** + * + * @author lastwhisper + * @date 2020/6/14 + */ +public class ObjectStreamDemo { + + /* + * 序列化流:把对象按照流一样的方式存入文本文件或者在网络中传输。对象 -- 流数据(ObjectOutputStream) + * 反序列化流:把文本文件中的流对象数据或者网络中的流对象数据还原成对象。流数据 -- 对象(ObjectInputStream) + */ + @Test + public void testObjectWrite() throws IOException { + // 创建序列化流对象 + ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream( + "oos.txt")); + + // 创建对象 + Person p = new Person("林青霞", 27); + + oos.writeObject(p); + + // 释放资源 + oos.close(); + } + + @Test + public void testObjectRead() throws IOException, ClassNotFoundException { + // 创建反序列化对象 + ObjectInputStream ois = new ObjectInputStream(new FileInputStream( + "oos.txt")); + + // 还原对象 + Object obj = ois.readObject(); + + // 释放资源 + ois.close(); + + // 输出对象 + System.out.println(obj); + } + +} diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/otherstream/Person.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/otherstream/Person.java new file mode 100644 index 00000000..8017d0dd --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/otherstream/Person.java @@ -0,0 +1,74 @@ +package cn.lastwhisper.io.io.otherstream; + +import java.io.Serializable; + +/* + * NotSerializableException:未序列化异常 + * + * 类通过实现 java.io.Serializable 接口以启用其序列化功能。未实现此接口的类将无法使其任何状态序列化或反序列化。 + * 该接口居然没有任何方法,类似于这种没有方法的接口被称为标记接口。 + * + * java.io.InvalidClassException: + * cn.itcast_07.Person; local class incompatible: + * stream classdesc serialVersionUID = -2071565876962058344, + * local class serialVersionUID = -8345153069362641443 + * + * 为什么会有问题呢? + * Person类实现了序列化接口,那么它本身也应该有一个标记值。 + * 这个标记值假设是100。 + * 开始的时候: + * Person.class -- id=100 + * wirte数据: oos.txt -- id=100 + * read数据: oos.txt -- id=100 + * + * 现在: + * Person.class -- id=200 + * wirte数据: oos.txt -- id=100 + * read数据: oos.txt -- id=100 + * + * 注意: + * 我一个类中可能有很多的成员变量,有些我不想进行序列化。请问该怎么办呢? + * 使用transient关键字声明不需要序列化的成员变量 + */ +public class Person implements Serializable { + private static final long serialVersionUID = -2071565876962058344L; + + private String name; + + // private int age; + + private transient int age; + + // int age; + + public Person() { + super(); + } + + public Person(String name, int age) { + super(); + this.name = name; + this.age = age; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + @Override + public String toString() { + return "Person [name=" + name + ", age=" + age + "]"; + } +} diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/otherstream/PrintWriterDemo.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/otherstream/PrintWriterDemo.java new file mode 100644 index 00000000..0e4bd479 --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/otherstream/PrintWriterDemo.java @@ -0,0 +1,93 @@ +package cn.lastwhisper.io.io.otherstream; + +import org.junit.Test; + +import java.io.*; + +/** + * + * @author lastwhisper + * @date 2020/6/14 + */ +public class PrintWriterDemo { + + /* + * 打印流 + * 字节流打印流 PrintStream + * 字符打印流 PrintWriter + * + * 打印流的特点: + * A:只有写数据的,没有读取数据。只能操作目的地,不能操作数据源。 + * B:可以操作任意类型的数据。 + * C:如果启动了自动刷新,能够自动刷新。 + * D:该流是可以直接操作文本文件的。 + * 哪些流对象是可以直接操作文本文件的呢? + * FileInputStream + * FileOutputStream + * FileReader + * FileWriter + * PrintStream + * PrintWriter + * 看API,查流对象的构造方法,如果同时有File类型和String类型的参数,一般来说就是可以直接操作文件的。 + * + * 流: + * 基本流:就是能够直接读写文件的 + * 高级流:在基本流基础上提供了一些其他的功能 + */ + @Test + public void testPrintWriter() throws FileNotFoundException { + // 作为Writer的子类使用 + PrintWriter pw = new PrintWriter("pw.txt"); + + pw.write("hello"); + pw.write("world"); + pw.write("java"); + pw.close(); + } + + /* + * 1:可以操作任意类型的数据。 + * print() + * println() + * 2:启动自动刷新 + * PrintWriter pw = new PrintWriter(new FileWriter("pw2.txt"), true); + * 还是应该调用println()的方法才可以 + * 这个时候不仅仅自动刷新了,还实现了数据的换行。 + * + * println() + * 其实等价于于: + * bw.write(); + * bw.newLine(); + * bw.flush(); + */ + @Test + public void testPrintWriter2() throws IOException { + // 创建打印流对象 + // PrintWriter pw = new PrintWriter("pw2.txt"); + PrintWriter pw = new PrintWriter(new FileWriter("pw2.txt"), true); + + // write()只能写字节和字符 + // println()可以写任意类型数据 + pw.println("hello"); + pw.println(true); + pw.println(100); + pw.close(); + } + + + @Test + public void testCopy() throws IOException { + BufferedReader br = new BufferedReader(new FileReader( + "DataStreamDemo.java")); + // 封装目的地 + PrintWriter pw = new PrintWriter(new FileWriter("Copy.java"), true); + + String line; + while ((line = br.readLine()) != null) { + pw.println(line); + } + + pw.close(); + br.close(); + } +} diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/otherstream/RandomAccessFileDemo.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/otherstream/RandomAccessFileDemo.java new file mode 100644 index 00000000..36a57da0 --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/otherstream/RandomAccessFileDemo.java @@ -0,0 +1,67 @@ +package cn.lastwhisper.io.io.otherstream; + +import org.junit.Test; + +import java.io.IOException; +import java.io.RandomAccessFile; + +/** + * + * @author lastwhisper + * @date 2020/6/14 + */ +public class RandomAccessFileDemo { + + /* + * 随机访问流: + * RandomAccessFile类不属于流,是Object类的子类。 + * 但它融合了InputStream和OutputStream的功能。 + * 支持对文件的随机访问读取和写入。 + * + * public RandomAccessFile(String name,String mode):第一个参数是文件路径,第二个参数是操作文件的模式。 + * 模式有四种,我们最常用的一种叫"rw",这种方式表示我既可以写数据,也可以读取数据 + * + * 访问模式 + * "r" 以只读方式打开。调用结果对象的任何 write 方法都将导致抛出 IOException。 + * "rw" 打开以便读取和写入。如果该文件尚不存在,则尝试创建该文件。 + * "rws" 打开以便读取和写入,对于 "rw",还要求对文件的内容或元数据的每个更新都同步写入到底层存储设备。 + * "rwd" 打开以便读取和写入,对于 "rw",还要求对文件内容的每个更新都同步写入到底层存储设备。 + * + */ + @Test + public void testWrite() throws IOException { + // 1、创建随机访问流对象 + RandomAccessFile raf = new RandomAccessFile("raf.txt", "rw"); + // 2、写入数据 + raf.writeInt(100); + raf.writeChar('a'); + raf.writeUTF("中国"); + // 3、关闭资源 + raf.close(); + } + + + @Test + public void testRead() throws IOException { + // 1、创建随机访问流对象 + RandomAccessFile raf = new RandomAccessFile("raf.txt", "rw"); + int i = raf.readInt(); + System.out.println(i); + // 该文件指针可以通过 getFilePointer方法读取,并通过 seek 方法设置。 + System.out.println("当前文件的指针位置是:" + raf.getFilePointer()); + + char ch = raf.readChar(); + System.out.println(ch); + System.out.println("当前文件的指针位置是:" + raf.getFilePointer()); + + String s = raf.readUTF(); + System.out.println(s); + System.out.println("当前文件的指针位置是:" + raf.getFilePointer()); + + // 我不想重头开始了,我就要读取a,怎么办呢? + raf.seek(4); + ch = raf.readChar(); + System.out.println(ch); + } + +} diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/otherstream/SequenceInputStreamDemo.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/otherstream/SequenceInputStreamDemo.java new file mode 100644 index 00000000..3be09076 --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/otherstream/SequenceInputStreamDemo.java @@ -0,0 +1,44 @@ +package cn.lastwhisper.io.io.otherstream; + +import java.io.*; +import java.util.Enumeration; +import java.util.Vector; + +/** + * + * @author lastwhisper + * @date 2020/6/14 + */ +public class SequenceInputStreamDemo { + + public static void main(String[] args) throws IOException { + // 需求:把下面的三个文件的内容复制到Copy.java中 + // ByteArrayStreamDemo.java,CopyFileDemo.java,DataStreamDemo.java + + // SequenceInputStream(Enumeration e) + // 通过简单的回顾我们知道了Enumeration是Vector中的一个方法的返回值类型。 + // Enumeration elements() + Vector v = new Vector(); + InputStream s1 = new FileInputStream("a.txt"); + InputStream s2 = new FileInputStream("b.txt"); + InputStream s3 = new FileInputStream("c.txt"); + v.add(s1); + v.add(s2); + v.add(s3); + Enumeration en = v.elements(); + SequenceInputStream sis = new SequenceInputStream(en); + BufferedOutputStream bos = new BufferedOutputStream( + new FileOutputStream("d.txt")); + + // 如何写读写呢,其实很简单,你就按照以前怎么读写,现在还是怎么读写 + byte[] bytes = new byte[1024]; + int len; + while ((len = sis.read(bytes)) != -1) { + bos.write(bytes, 0, len); + } + + bos.close(); + sis.close(); + } + +} diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/otherstream/SystemInDemo.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/otherstream/SystemInDemo.java new file mode 100644 index 00000000..e4a1fc36 --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/otherstream/SystemInDemo.java @@ -0,0 +1,44 @@ +package cn.lastwhisper.io.io.otherstream; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; + +/** + * System.in 标准输入流。是从键盘获取数据的 + * + * 键盘录入数据: + * A:main方法的args接收参数。 + * java HelloWorld hello world java + * B:Scanner(JDK5以后的) + * Scanner sc = new Scanner(System.in); + * String s = sc.nextLine(); + * int x = sc.nextInt() + * C:通过字符缓冲流包装标准输入流实现 + * BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); + * @author lastwhisper + * @date 2020/6/14 + */ +public class SystemInDemo { + + /** + * 如何从控制台键盘中获取数据? + * System.in是字节输入流,需要使用字符输入流包装 + * 再使用 BufferedReader 读取一行数据 + */ + public static void main(String[] args) throws IOException { + + BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); + + System.out.println("请输入一个字符串:"); + String line = br.readLine(); + System.out.println("你输入的字符串是:" + line); + + System.out.println("请输入一个整数:"); + // int i = Integer.parseInt(br.readLine()); + line = br.readLine(); + int i = Integer.parseInt(line); + System.out.println("你输入的整数是:" + i); + } + +} diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/otherstream/SystemOutDemo.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/otherstream/SystemOutDemo.java new file mode 100644 index 00000000..b8fe8024 --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/io/otherstream/SystemOutDemo.java @@ -0,0 +1,36 @@ +package cn.lastwhisper.io.io.otherstream; + +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.OutputStreamWriter; + +/** + * + * @author lastwhisper + * @date 2020/6/14 + */ +public class SystemOutDemo { + + + /** + * 如何将数据输出到控制台? + * System.out是字节输出流,需要使用字符输出流包装 + * 再使用 BufferedWriter 打印一行数据 + */ + public static void main(String[] args) throws IOException { + BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out)); + + bw.write("hello"); + bw.newLine(); + // bw.flush(); + bw.write("world"); + bw.newLine(); + // bw.flush(); + bw.write("java"); + bw.newLine(); + bw.flush();//打断点,只有调用 flush 方法才会输出到控制台 + + bw.close(); + } + +} diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/nio/README.md b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/nio/README.md new file mode 100644 index 00000000..31bc4305 --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/nio/README.md @@ -0,0 +1,14 @@ +参考 https://blog.csdn.net/zxm1306192988/article/details/60581173 + +1. 缓冲区(Buffer);TestBuffer +2. 通道(Channel);TestChannel +3. 选择器(Selector) + TestBlockingNIO;不使用Selector + TestNIO;使用Selector + TestNIO_UDP +4. 管道 (Pipe) + TestPipe +5. Path 、Paths 、Files + TestNIOPathFiles + + diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/io/nio/TestBlockingNIO.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/nio/TestBlockingNIO.java similarity index 76% rename from java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/io/nio/TestBlockingNIO.java rename to java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/nio/TestBlockingNIO.java index b81c8f02..7a885014 100644 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/io/nio/TestBlockingNIO.java +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/nio/TestBlockingNIO.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.jdk5.feature.io.nio; +package cn.lastwhisper.io.nio; import org.junit.Test; @@ -39,7 +39,7 @@ public void client() throws IOException{ //1. 获取通道 SocketChannel sChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 9898)); - FileChannel inChannel = FileChannel.open(Paths.get("1.jpg"), StandardOpenOption.READ); + FileChannel inChannel = FileChannel.open(Paths.get("/Users/kaisui/Downloads/1.csv"), StandardOpenOption.READ); //2. 分配指定大小的缓冲区 ByteBuffer buf = ByteBuffer.allocate(1024); @@ -51,6 +51,15 @@ public void client() throws IOException{ buf.clear(); } + //接收服务端的反馈 + int len = 0; + while((len = sChannel.read(buf)) != -1){ + buf.flip(); + System.out.println(new String(buf.array(), 0, len)); + buf.clear(); + } + + //4. 关闭通道 inChannel.close(); sChannel.close(); @@ -62,7 +71,7 @@ public void server() throws IOException{ //1. 获取通道 ServerSocketChannel ssChannel = ServerSocketChannel.open(); - FileChannel outChannel = FileChannel.open(Paths.get("2.jpg"), StandardOpenOption.WRITE, StandardOpenOption.CREATE); + FileChannel outChannel = FileChannel.open(Paths.get("/Users/kaisui/Downloads/2.csv"), StandardOpenOption.WRITE, StandardOpenOption.CREATE); //2. 绑定连接 ssChannel.bind(new InetSocketAddress(9898)); @@ -80,6 +89,11 @@ public void server() throws IOException{ buf.clear(); } + //发送反馈给客户端 + buf.put("服务端接收数据成功".getBytes()); + buf.flip(); + sChannel.write(buf); + //6. 关闭通道 sChannel.close(); outChannel.close(); diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/io/nio/TestBuffer.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/nio/TestBuffer.java similarity index 99% rename from java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/io/nio/TestBuffer.java rename to java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/nio/TestBuffer.java index b6ec29a0..3ad6f7df 100644 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/io/nio/TestBuffer.java +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/nio/TestBuffer.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.jdk5.feature.io.nio; +package cn.lastwhisper.io.nio; import org.junit.Test; @@ -77,7 +77,7 @@ public void test1() { System.out.println("--------------get()------------"); byte[] dst = new byte[buffer.limit()]; buffer.get(dst); - System.out.println(new String(dst, 0, dst.length));//abcd + System.out.println(new String(dst, 0, dst.length));//abced System.out.println(buffer.position());//5 System.out.println(buffer.limit());//5 System.out.println(buffer.capacity());//1024 diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/io/nio/TestChannel.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/nio/TestChannel.java similarity index 99% rename from java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/io/nio/TestChannel.java rename to java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/nio/TestChannel.java index f60dc495..12acf27a 100644 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/io/nio/TestChannel.java +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/nio/TestChannel.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.jdk5.feature.io.nio; +package cn.lastwhisper.io.nio; import org.junit.Test; diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/nio/TestNIO.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/nio/TestNIO.java new file mode 100644 index 00000000..c8ef08d7 --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/nio/TestNIO.java @@ -0,0 +1,96 @@ +package cn.lastwhisper.io.nio; + +import org.junit.Test; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.nio.ByteBuffer; +import java.nio.channels.SelectionKey; +import java.nio.channels.Selector; +import java.nio.channels.ServerSocketChannel; +import java.nio.channels.SocketChannel; +import java.util.Date; +import java.util.Iterator; +import java.util.Scanner; +/** + * TCP + */ +public class TestNIO { + //客户端 + @Test + public void client() throws IOException { + //1.获取通道 + SocketChannel sChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 9898)); + //2.切换非阻塞模式 + sChannel.configureBlocking(false); + //3.分配指定大小的缓冲区 + ByteBuffer buf = ByteBuffer.allocate(1024); + //4.发送数据给服务端 + Scanner scan = new Scanner(System.in); + while (scan.hasNext()) { + String str = scan.next(); + buf.put((new Date().toString() + "\n" + str).getBytes()); + buf.flip(); + sChannel.write(buf); + buf.clear(); + } + //5.关闭通道 + sChannel.close(); + } + + //服务端 + @Test + public void server() throws IOException { + //1.获取通道 + ServerSocketChannel ssChannel = ServerSocketChannel.open(); + + //2.切换非阻塞式模式 + ssChannel.configureBlocking(false); + + //3.绑定连接 + ssChannel.bind(new InetSocketAddress(9898)); + + //4.获取选择器 + Selector selector = Selector.open(); + + //5.将通道注册到选择器上,并且指定“监听接收事件” + ssChannel.register(selector, SelectionKey.OP_ACCEPT); + + //6.轮询式的获取选择器上已经“准备就绪”的事件 + while (selector.select() > 0) { + + //7.获取当前选择器中所有注册的“选择键(已就绪的监听事件)” + Iterator it = selector.selectedKeys().iterator(); + + while (it.hasNext()) { + //8.获取准备“就绪”的事件 + SelectionKey sk = it.next(); + + //9.判断具体是什么时间准备就绪 + if (sk.isAcceptable()) { + //10.若“接收就绪”,获取客户端连接 + SocketChannel sChannel = ssChannel.accept(); + + //11.切换非阻塞模式 + sChannel.configureBlocking(false); + + //12.将该通道注册到选择器上 + sChannel.register(selector, SelectionKey.OP_READ); + } else if (sk.isReadable()) { + //13.获取当前选择器上“读就绪”状态的通道 + SocketChannel sChannel = (SocketChannel) sk.channel(); + //14.读取数据 + ByteBuffer buf = ByteBuffer.allocate(1024); + int len = 0; + while ((len = sChannel.read(buf)) > 0) { + buf.flip(); + System.out.println(new String(buf.array(), 0, len)); + buf.clear(); + } + } + //15.取消选择键SelectionKey + it.remove(); + } + } + } +} \ No newline at end of file diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/nio/TestNIOPathFiles.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/nio/TestNIOPathFiles.java new file mode 100644 index 00000000..ab552555 --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/nio/TestNIOPathFiles.java @@ -0,0 +1,158 @@ +package cn.lastwhisper.io.nio; + +import org.junit.Test; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.channels.SeekableByteChannel; +import java.nio.file.*; +import java.nio.file.attribute.BasicFileAttributes; +import java.nio.file.attribute.DosFileAttributeView; + +public class TestNIOPathFiles { + + + //自动资源管理:自动关闭实现 AutoCloseable 接口的资源 + @Test + public void test8() { + try (FileChannel inChannel = FileChannel.open(Paths.get("1.jpg"), StandardOpenOption.READ); + FileChannel outChannel = FileChannel.open(Paths.get("2.jpg"), StandardOpenOption.WRITE, StandardOpenOption.CREATE)) { + + ByteBuffer buf = ByteBuffer.allocate(1024); + inChannel.read(buf); + + } catch (IOException e) { + + } + } + + /* + Files常用方法:用于操作内容 + SeekableByteChannel newByteChannel(Path path, OpenOption…how) : 获取与指定文件的连接,how 指定打开方式。 + DirectoryStream newDirectoryStream(Path path) : 打开 path 指定的目录 + InputStream newInputStream(Path path, OpenOption…how):获取 InputStream 对象 + OutputStream newOutputStream(Path path, OpenOption…how) : 获取 OutputStream 对象 + */ + @Test + public void test7() throws IOException { + SeekableByteChannel newByteChannel = Files.newByteChannel(Paths.get("1.jpg"), StandardOpenOption.READ); + + DirectoryStream newDirectoryStream = Files.newDirectoryStream(Paths.get("e:/")); + + for (Path path : newDirectoryStream) { + System.out.println(path); + } + } + + /* + Files常用方法:用于判断 + boolean exists(Path path, LinkOption … opts) : 判断文件是否存在 + boolean isDirectory(Path path, LinkOption … opts) : 判断是否是目录 + boolean isExecutable(Path path) : 判断是否是可执行文件 + boolean isHidden(Path path) : 判断是否是隐藏文件 + boolean isReadable(Path path) : 判断文件是否可读 + boolean isWritable(Path path) : 判断文件是否可写 + boolean notExists(Path path, LinkOption … opts) : 判断文件是否不存在 + public static A readAttributes(Path path,Class type,LinkOption... options) : 获取与 path 指定的文件相关联的属性。 + */ + @Test + public void test6() throws IOException { + Path path = Paths.get("e:/nio/hello7.txt"); +// System.out.println(Files.exists(path, LinkOption.NOFOLLOW_LINKS)); + + BasicFileAttributes readAttributes = Files.readAttributes(path, BasicFileAttributes.class, LinkOption.NOFOLLOW_LINKS); + System.out.println(readAttributes.creationTime()); + System.out.println(readAttributes.lastModifiedTime()); + + DosFileAttributeView fileAttributeView = Files.getFileAttributeView(path, DosFileAttributeView.class, LinkOption.NOFOLLOW_LINKS); + + fileAttributeView.setHidden(false); + } + + /* + Files常用方法: + Path copy(Path src, Path dest, CopyOption … how) : 文件的复制 + Path createDirectory(Path path, FileAttribute … attr) : 创建一个目录 + Path createFile(Path path, FileAttribute … arr) : 创建一个文件 + void delete(Path path) : 删除一个文件 + Path move(Path src, Path dest, CopyOption…how) : 将 src 移动到 dest 位置 + long size(Path path) : 返回 path 指定文件的大小 + */ + @Test + public void test5() throws IOException { + Path path1 = Paths.get("e:/nio/hello2.txt"); + Path path2 = Paths.get("e:/nio/hello7.txt"); + + System.out.println(Files.size(path2)); + +// Files.move(path1, path2, StandardCopyOption.ATOMIC_MOVE); + } + + @Test + public void test4() throws IOException { + Path dir = Paths.get("e:/nio/nio2"); +// Files.createDirectory(dir); + + Path file = Paths.get("e:/nio/nio2/hello3.txt"); +// Files.createFile(file); + + Files.deleteIfExists(file); + } + + @Test + public void test3() throws IOException { + Path path1 = Paths.get("e:/nio/hello.txt"); + Path path2 = Paths.get("e:/nio/hello2.txt"); + + Files.copy(path1, path2, StandardCopyOption.REPLACE_EXISTING); + } + + /* + Paths 提供的 get() 方法用来获取 Path 对象: + Path get(String first, String … more) : 用于将多个字符串串连成路径。 + Path 常用方法: + boolean endsWith(String path) : 判断是否以 path 路径结束 + boolean startsWith(String path) : 判断是否以 path 路径开始 + boolean isAbsolute() : 判断是否是绝对路径 + Path getFileName() : 返回与调用 Path 对象关联的文件名 + Path getName(int idx) : 返回的指定索引位置 idx 的路径名称 + int getNameCount() : 返回Path 根目录后面元素的数量 + Path getParent() :返回Path对象包含整个路径,不包含 Path 对象指定的文件路径 + Path getRoot() :返回调用 Path 对象的根路径 + Path resolve(Path p) :将相对路径解析为绝对路径 + Path toAbsolutePath() : 作为绝对路径返回调用 Path 对象 + String toString() : 返回调用 Path 对象的字符串表示形式 + */ + @Test + public void test2() { + Path path = Paths.get("e:/nio/hello.txt"); + + System.out.println(path.getParent()); + System.out.println(path.getRoot()); + +// Path newPath = path.resolve("e:/hello.txt"); +// System.out.println(newPath); + + Path path2 = Paths.get("1.jpg"); + Path newPath = path2.toAbsolutePath(); + System.out.println(newPath); + + System.out.println(path.toString()); + } + + @Test + public void test1() { + Path path = Paths.get("e:/", "nio/hello.txt"); + + System.out.println(path.endsWith("hello.txt")); + System.out.println(path.startsWith("e:/")); + + System.out.println(path.isAbsolute()); + System.out.println(path.getFileName()); + + for (int i = 0; i < path.getNameCount(); i++) { + System.out.println(path.getName(i)); + } + } +} diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/nio/TestNIO_UDP.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/nio/TestNIO_UDP.java new file mode 100644 index 00000000..4bfe6287 --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/nio/TestNIO_UDP.java @@ -0,0 +1,59 @@ +package cn.lastwhisper.io.nio; + +import org.junit.Test; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.nio.ByteBuffer; +import java.nio.channels.DatagramChannel; +import java.nio.channels.SelectionKey; +import java.nio.channels.Selector; +import java.util.Date; +import java.util.Iterator; +import java.util.Scanner; +/** + * UDP + */ +public class TestNIO_UDP { + + @Test + public void send() throws IOException { + DatagramChannel dc = DatagramChannel.open(); + dc.configureBlocking(false); + ByteBuffer buf = ByteBuffer.allocate(1024); + Scanner scan = new Scanner(System.in); + while (scan.hasNext()) { + String str = scan.next(); + buf.put((new Date().toString() + "\n" + str).getBytes()); + buf.flip(); + dc.send(buf, new InetSocketAddress("127.0.0.1", 9898)); + buf.clear(); + } + dc.close(); + } + + @Test + public void receive() throws IOException { + DatagramChannel dc = DatagramChannel.open(); + dc.configureBlocking(false); + dc.bind(new InetSocketAddress(9898)); + Selector selector = Selector.open(); + dc.register(selector, SelectionKey.OP_READ); + while (selector.select() > 0) { + Iterator it = selector.selectedKeys().iterator(); + while (it.hasNext()) { + SelectionKey sk = it.next(); + + if (sk.isReadable()) { + ByteBuffer buf = ByteBuffer.allocate(1024); + dc.receive(buf) + ; + buf.flip(); + System.out.println(new String(buf.array(), 0, buf.limit())); + buf.clear(); + } + } + it.remove(); + } + } +} \ No newline at end of file diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/io/nio/TestPipe.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/nio/TestPipe.java similarity index 95% rename from java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/io/nio/TestPipe.java rename to java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/nio/TestPipe.java index 292f229d..ff792a9d 100644 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/io/nio/TestPipe.java +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/nio/TestPipe.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.jdk5.feature.io.nio; +package cn.lastwhisper.io.nio; import org.junit.Test; diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/nio/v1/BIOServer.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/nio/v1/BIOServer.java new file mode 100644 index 00000000..c899ce00 --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/nio/v1/BIOServer.java @@ -0,0 +1,33 @@ +package cn.lastwhisper.io.nio.v1; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.ServerSocket; +import java.net.Socket; + +/** + * @author lastwhisper + */ +public class BIOServer { + static byte[] bytes = new byte[1024]; + + public static void main(String[] args) { + try (ServerSocket serverSocket = new ServerSocket();) { + serverSocket.bind(new InetSocketAddress(8080)); + while (true) { + System.out.println("wait conn"); + // 等待连接阻塞 + Socket socket = serverSocket.accept(); + System.out.println("conn success"); + // 等待数据阻塞 + socket.getInputStream().read(bytes); + + String content = new String(bytes); + System.out.println("receive data success || content:" + content); + } + + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/nio/v1/Client.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/nio/v1/Client.java new file mode 100644 index 00000000..abdb9d1d --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/nio/v1/Client.java @@ -0,0 +1,25 @@ +package cn.lastwhisper.io.nio.v1; + +import java.io.IOException; +import java.net.Socket; +import java.util.Scanner; + +/** + * 三个socket + * @author lastwhisper + */ +public class Client { + public static void main(String[] args) { + try (Socket socket = new Socket("127.0.0.1", 8080);) { + // client阻塞 等待数据 + Scanner scanner = new Scanner(System.in); + String txt = scanner.next(); + + socket.getOutputStream().write(txt.getBytes()); + + } catch (IOException e) { + e.printStackTrace(); + } + + } +} diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/nio/v2/MockNIOServer.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/nio/v2/MockNIOServer.java new file mode 100644 index 00000000..64d80957 --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/nio/v2/MockNIOServer.java @@ -0,0 +1,81 @@ +package cn.lastwhisper.io.nio.v2; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.nio.ByteBuffer; +import java.nio.channels.ServerSocketChannel; +import java.nio.channels.SocketChannel; +import java.util.ArrayList; +import java.util.Date; +import java.util.Iterator; +import java.util.List; + +/** + * 单线程并发 + * 应用程序循环 + * + * @author lastwhisper + */ +public class MockNIOServer { + static List list = new ArrayList<>(); + static ByteBuffer byteBuffer = ByteBuffer.allocate(512); + + public static void main(String[] args) throws InterruptedException { + try { + ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); + serverSocketChannel.bind(new InetSocketAddress(8080)); + // 设置非阻塞 + serverSocketChannel.configureBlocking(false); + while (true) { + SocketChannel socketChannel = serverSocketChannel.accept(); + if (socketChannel == null) { + Thread.sleep(500); + boolean empty = handleChannelList(); + System.out.printf("date:%s,没有新的连接,处理已有通道集合 empty:%s\n", new Date(),empty); + } else { + System.out.printf("date:%s,有新的连接,加入通道集合,处理通道集合\n", new Date()); + // 设置客户端和服务端之间的通道非阻塞,不设置的话socketChannel#read无数据就会阻塞 + socketChannel.configureBlocking(false); + list.add(socketChannel); + handleChannelList(); + } + + } + + } catch (IOException e) { + e.printStackTrace(); + } + } + + private static boolean handleChannelList() throws IOException, InterruptedException { + if(list.isEmpty()){ + return true; + } + Iterator iterator = list.iterator(); + while (iterator.hasNext()){ + SocketChannel socketChannel = iterator.next(); + Thread.sleep(500);// 减少日志打印 + Date current = new Date(); + // 如果前面没有设置socketChannel.configureBlocking(false),这里read不到数据就会阻塞 +// System.out.printf("date:%s,通道id:%s,尝试读数据\n", current, socketChannel.hashCode()); + int length = socketChannel.read(byteBuffer);// length=2('1'、'\n') + if (length > 0) { + byteBuffer.flip();// 切换到读模式 + Thread.sleep(500);// 模拟业务处理耗时 + byte[] dst = new byte[byteBuffer.limit()]; + byteBuffer.get(dst);//读取数据到dst数组 + String content = new String(dst, 0, dst.length); + byteBuffer.clear();// 清空Buffer + System.out.printf("date:%s,通道id:%s,读到了数据:%s\n", current, socketChannel.hashCode(), content); + if (content.equals("exit") || content.equals("exit\n")) { + socketChannel.close(); + iterator.remove(); + System.out.printf("date:%s,通道id:%s,客户端通过exit命令退出连接\n", new Date(), socketChannel.hashCode()); + } + } else { + System.out.printf("date:%s,通道id:%s,没读到了数据,处理别的通道\n", current, socketChannel.hashCode()); + } + } + return false; + } +} diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/nio/v2/MyNIOServer.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/nio/v2/MyNIOServer.java new file mode 100644 index 00000000..f5546678 --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/nio/v2/MyNIOServer.java @@ -0,0 +1,53 @@ +package cn.lastwhisper.io.nio.v2; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.util.ArrayList; +import java.util.List; + +/** + * 应用层做轮询 + * @author lastwhisper + */ +public class MyNIOServer { + static byte[] bytes = new byte[1024]; + static List list = new ArrayList<>(); + + public static void main(String[] args) { + try (ServerSocket serverSocket = new ServerSocket();) { + serverSocket.bind(new InetSocketAddress(8080)); + // 设置serverSocket非阻塞 +// serverSocket.setConfigureBlocking(false); + while (true) { + // serverSocket.accept()阻塞 + Socket socket = serverSocket.accept(); + if (socket == null) { + System.out.println("没有人连接,处理已有连接"); + handleSocketList(); + } else { + // 设置Socket非阻塞 + // socket.setConfigureBlocking(false); + System.out.println("有人连接,处理已有连接"); + list.add(socket); + handleSocketList(); + } + + } + + } catch (IOException e) { + e.printStackTrace(); + } + } + + private static void handleSocketList() throws IOException { + for (Socket s : list) { + int length = s.getInputStream().read(bytes); + if (length != 0) { + String content = new String(bytes); + System.out.println(content); + } + } + } +} diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/io/nio/v3/NIOClient.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/nio/v3/NIOClient.java similarity index 88% rename from java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/io/nio/v3/NIOClient.java rename to java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/nio/v3/NIOClient.java index 0fc92f96..0e6064a4 100644 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/io/nio/v3/NIOClient.java +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/nio/v3/NIOClient.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.jdk5.feature.io.nio.v3; +package cn.lastwhisper.io.nio.v3; import java.io.IOException; import java.io.OutputStream; diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/io/nio/v3/NIOServer.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/nio/v3/NIOServer.java similarity index 98% rename from java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/io/nio/v3/NIOServer.java rename to java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/nio/v3/NIOServer.java index 38a4d6bb..3a408401 100644 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/io/nio/v3/NIOServer.java +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/nio/v3/NIOServer.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.jdk5.feature.io.nio.v3; +package cn.lastwhisper.io.nio.v3; import java.io.IOException; import java.net.InetSocketAddress; diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/io/socket/TCPClient.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/socket/TCPClient.java similarity index 95% rename from java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/io/socket/TCPClient.java rename to java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/socket/TCPClient.java index 3ec3f661..97dfd6b7 100644 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/io/socket/TCPClient.java +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/socket/TCPClient.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.jdk5.feature.io.socket; +package cn.lastwhisper.io.socket; import java.io.IOException; import java.io.InputStream; diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/socket/TCPServer.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/socket/TCPServer.java new file mode 100644 index 00000000..105e6ee8 --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/socket/TCPServer.java @@ -0,0 +1,47 @@ +package cn.lastwhisper.io.socket; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.ServerSocket; +import java.net.Socket; + +/** + * @author lastwhisper + */ +public class TCPServer { + public static void main(String[] args) { + try { + ServerSocket ss = new ServerSocket(65000); + while (true) { + // 监听请求 + Socket socket = ss.accept(); + new Thread() { + @Override + public void run() { + // 获取socket的输出流 + // 获取socket的输入流 + try (OutputStream os = socket.getOutputStream(); + InputStream is = socket.getInputStream();) { + int ch; + byte[] buff = new byte[1024]; + // buff主要用来读取输入的内容,存入byte数组,ch读取数组的长度 + ch = is.read(buff); + // 将接收的byte数组转成字符串 + String content = new String(buff, 0, ch); + System.out.println(content); + + os.write(String.valueOf(content.length()).getBytes()); + } catch (IOException e) { + e.printStackTrace(); + } + + } + }.start(); + } + } catch (IOException e) { + e.printStackTrace(); + } + + } +} diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/io/socket/UDPClient.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/socket/UDPClient.java similarity index 83% rename from java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/io/socket/UDPClient.java rename to java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/socket/UDPClient.java index de37fc71..1760930c 100644 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/io/socket/UDPClient.java +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/socket/UDPClient.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.jdk5.feature.io.socket; +package cn.lastwhisper.io.socket; import java.io.IOException; import java.net.*; @@ -24,10 +24,6 @@ public static void main(String[] args) { System.out.println(new String(receivePacket.getData(), 0, receivePacket.getLength())); - } catch (SocketException e) { - e.printStackTrace(); - } catch (UnknownHostException e) { - e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/io/socket/UDPServer.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/socket/UDPServer.java similarity index 90% rename from java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/io/socket/UDPServer.java rename to java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/socket/UDPServer.java index d3e03378..6ac137bf 100644 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/io/socket/UDPServer.java +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/io/socket/UDPServer.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.jdk5.feature.io.socket; +package cn.lastwhisper.io.socket; import java.io.IOException; import java.net.DatagramPacket; @@ -29,8 +29,6 @@ public static void main(String[] args) { socket.send(packetToClient); - } catch (SocketException e) { - e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/reflect/ReflectExecutMain.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/reflect/ReflectExecutMain.java similarity index 93% rename from java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/reflect/ReflectExecutMain.java rename to java-basic/feature-jdk5/src/main/java/cn/lastwhisper/reflect/ReflectExecutMain.java index 293832df..140c48bb 100644 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/reflect/ReflectExecutMain.java +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/reflect/ReflectExecutMain.java @@ -1,6 +1,5 @@ -package cn.lastwhisper.jdk5.feature.reflect; +package cn.lastwhisper.reflect; -import java.io.FileInputStream; import java.io.InputStream; import java.lang.reflect.Method; import java.util.Properties; diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/reflect/ReflectForClass.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/reflect/ReflectForClass.java new file mode 100644 index 00000000..18b2c536 --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/reflect/ReflectForClass.java @@ -0,0 +1,49 @@ +package cn.lastwhisper.reflect; + +import org.junit.Test; + +/** + * 反射之Class对象 + * @author lastwhisper + */ +public class ReflectForClass { + public static void main(String[] args) throws ClassNotFoundException { + String str1 = "abc"; + Class cls1 = str1.getClass(); + Class cls2 = String.class; + Class cls3 = Class.forName("java.lang.String"); + System.out.println(cls1 == cls2); + System.out.println(cls1 == cls3); + + System.out.println(cls1.isPrimitive()); + System.out.println(int.class.isPrimitive()); + System.out.println(int.class == Integer.class); + System.out.println(int.class == Integer.TYPE); + System.out.println(int[].class.isPrimitive()); + } + + /** + * 测试同一个类加载器,Class.forName拿到的Class是不是同一个 + * @throws Exception + */ + @Test + public void classforName() throws Exception { + Class clazz1 = Class.forName("cn.lastwhisper.reflect.pojo.MyObject"); + Class clazz2 = Class.forName("cn.lastwhisper.reflect.pojo.MyObject"); + System.out.println(clazz1 == clazz2); + } + + /** + * 测试同一个Class对象反射创建目标对象时,是不是永远是同一个 + * @throws Exception + */ + @Test + public void reflectNewObj() throws Exception { + Class clazz = Class.forName("cn.lastwhisper.reflect.pojo.MyObject"); + Object newObj1 = clazz.newInstance(); + Object newObj2 = clazz.newInstance(); + System.out.println(newObj1 == newObj2); + } + + +} diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/reflect/ReflectForConstructor.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/reflect/ReflectForConstructor.java similarity index 89% rename from java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/reflect/ReflectForConstructor.java rename to java-basic/feature-jdk5/src/main/java/cn/lastwhisper/reflect/ReflectForConstructor.java index 6b93263c..554cb768 100644 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/reflect/ReflectForConstructor.java +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/reflect/ReflectForConstructor.java @@ -1,10 +1,11 @@ -package cn.lastwhisper.jdk5.feature.reflect; +package cn.lastwhisper.reflect; import java.lang.reflect.Constructor; /** * 反射之Constructor类 - * Constructor类代表某个类中的一个构造方法 + * Constructor类代表某个类中的一个构造方法 + * * @author lastwhisper */ public class ReflectForConstructor { @@ -21,4 +22,7 @@ public static void main(String[] args) throws Exception { // 3.2 反射方式 constructor.newInstance与clazz.newInstance String str2 = constructor.newInstance(new StringBuffer("constructor.newInstance String")); } + + + } diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/reflect/ReflectForField.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/reflect/ReflectForField.java similarity index 93% rename from java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/reflect/ReflectForField.java rename to java-basic/feature-jdk5/src/main/java/cn/lastwhisper/reflect/ReflectForField.java index 37097fd5..07cedfa5 100644 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/reflect/ReflectForField.java +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/reflect/ReflectForField.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.jdk5.feature.reflect; +package cn.lastwhisper.reflect; import java.lang.reflect.Field; diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/reflect/ReflectForMethod.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/reflect/ReflectForMethod.java similarity index 94% rename from java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/reflect/ReflectForMethod.java rename to java-basic/feature-jdk5/src/main/java/cn/lastwhisper/reflect/ReflectForMethod.java index 53ce1d4e..69e0ee2a 100644 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/reflect/ReflectForMethod.java +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/reflect/ReflectForMethod.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.jdk5.feature.reflect; +package cn.lastwhisper.reflect; import java.lang.reflect.Method; diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/reflect/ReflectPoint.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/reflect/ReflectPoint.java similarity index 95% rename from java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/reflect/ReflectPoint.java rename to java-basic/feature-jdk5/src/main/java/cn/lastwhisper/reflect/ReflectPoint.java index 6df6a535..64dbff33 100644 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/reflect/ReflectPoint.java +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/reflect/ReflectPoint.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.jdk5.feature.reflect; +package cn.lastwhisper.reflect; import java.util.Objects; @@ -38,7 +38,6 @@ public int hashCode() { return Objects.hash(x, y); } - public int getX() { return x; } diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/reflect/ReflectToArray.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/reflect/ReflectToArray.java similarity index 93% rename from java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/reflect/ReflectToArray.java rename to java-basic/feature-jdk5/src/main/java/cn/lastwhisper/reflect/ReflectToArray.java index 21367616..7f3412d0 100644 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/reflect/ReflectToArray.java +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/reflect/ReflectToArray.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.jdk5.feature.reflect; +package cn.lastwhisper.reflect; import java.lang.reflect.Array; diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/reflect/ReflectUpdateField.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/reflect/ReflectUpdateField.java similarity index 96% rename from java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/reflect/ReflectUpdateField.java rename to java-basic/feature-jdk5/src/main/java/cn/lastwhisper/reflect/ReflectUpdateField.java index 76aa09ee..a7436a77 100644 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/reflect/ReflectUpdateField.java +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/reflect/ReflectUpdateField.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.jdk5.feature.reflect; +package cn.lastwhisper.reflect; import java.lang.reflect.Field; diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/reflect/ReflectUtils.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/reflect/ReflectUtils.java new file mode 100644 index 00000000..5c079305 --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/reflect/ReflectUtils.java @@ -0,0 +1,121 @@ +package cn.lastwhisper.reflect; + +import java.beans.PropertyDescriptor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; + +public class ReflectUtils { + /** + * 通过字段名从对象或对象的父类中得到字段的值 + * @param object 对象实例 + * @param fieldName 字段名 + * @return 字段对应的值 + */ + public static Object getValue(Object object, String fieldName) { + if (object == null) { + return null; + } + if ("".equals(fieldName)) { + return null; + } + Field field = null; + Class clazz = object.getClass(); + for (; clazz != Object.class; clazz = clazz.getSuperclass()) { + try { + field = clazz.getDeclaredField(fieldName); + field.setAccessible(true); + return field.get(object); + } catch (Exception e) { + //这里甚么都不要做!并且这里的异常必须这样写,不能抛出去。 + //如果这里的异常打印或者往外抛,则就不会执行clazz = clazz.getSuperclass(),最后就不会进入到父类中了 + } + } + return null; + } + + + /** + * 通过字段名从对象或对象的父类中得到字段的值(调用字典的get方法) + * @param object 对象实例 + * @param fieldName 字段名 + * @return 字段对应的值 + * @throws Exception + */ + public static Object getValueOfGet(Object object, String fieldName){ + if (object == null) { + return null; + } + if ("".equals(fieldName)) { + return null; + } + Field field; + Class clazz = object.getClass(); + for (; clazz != Object.class; clazz = clazz.getSuperclass()) { + try { + field = clazz.getDeclaredField(fieldName); + field.setAccessible(true); + + PropertyDescriptor pd = new PropertyDescriptor(field.getName(), clazz); + //获得get方法 + Method getMethod = pd.getReadMethod(); + //执行get方法返回一个Object + return getMethod.invoke(object); + } catch (Exception e) { + //这里甚么都不要做!并且这里的异常必须这样写,不能抛出去。 + //如果这里的异常打印或者往外抛,则就不会执行clazz = clazz.getSuperclass(),最后就不会进入到父类中了 + } + } + + return null; + } + + /** + * 通过字段名从对象或对象的父类中得到字段的值(调用字典的get方法,可以取出复杂的对象的值) + * @param object 对象实例 + * @param fieldName 字段名 + * @return 字段对应的值 + * @throws Exception + */ + public static Object getValueOfGetIncludeObjectFeild(Object object, String fieldName) + throws Exception { + + if (object == null) { + return null; + } + if ("".equals(fieldName)) { + return null; + } + + if (HashMap.class.equals(object.getClass())) { + return ((Map) object).get(fieldName); + } + + Field field = null; + Class clazz = object.getClass(); + for (; clazz != Object.class; clazz = clazz.getSuperclass()) { + try { + if (fieldName.contains(".")) { + // 如:operatorUser.name、operatorUser.org.name,递归调用 + String[] splitFiledName = fieldName.split("\\."); + return getValueOfGetIncludeObjectFeild( + getValueOfGetIncludeObjectFeild(object, splitFiledName[0]), + splitFiledName[1]); + } + field = clazz.getDeclaredField(fieldName); + field.setAccessible(true); + + PropertyDescriptor pd = new PropertyDescriptor(field.getName(), clazz); + //获得get方法 + Method getMethod = pd.getReadMethod(); + //执行get方法返回一个Object + return getMethod.invoke(object); + } catch (Exception e) { + //这里甚么都不要做!并且这里的异常必须这样写,不能抛出去。 + //如果这里的异常打印或者往外抛,则就不会执行clazz = clazz.getSuperclass(),最后就不会进入到父类中了 + } + } + return null; + } +} diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/reflect/pojo/MyObject.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/reflect/pojo/MyObject.java new file mode 100644 index 00000000..84ac9727 --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/reflect/pojo/MyObject.java @@ -0,0 +1,5 @@ +package cn.lastwhisper.reflect.pojo; + +public class MyObject { + +} \ No newline at end of file diff --git a/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/serializable/Test.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/serializable/Test.java new file mode 100644 index 00000000..7e6ea47b --- /dev/null +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/serializable/Test.java @@ -0,0 +1,36 @@ +package cn.lastwhisper.serializable; + +import java.io.*; +/** + * 静态变量序列化 + */ +public class Test implements Serializable { + + private static final long serialVersionUID = 1L; + public static int staticVar = 5; + + public static void main(String[] args) { + try { + //初始时staticVar为5 + ObjectOutputStream out = new ObjectOutputStream( + new FileOutputStream("D:\\result.obj")); + out.writeObject(new Test()); + out.close(); + //序列化后修改为10 + Test.staticVar = 10; + ObjectInputStream oin = new ObjectInputStream(new FileInputStream( + "D:\\result.obj")); + Test t = (Test) oin.readObject(); + oin.close(); + //再读取,通过t.staticVar打印新的值 + // 打印10说明,序列化并没有保存static字段,如果保存了staticVar应该为5 + System.out.println(t.staticVar); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + } +} \ No newline at end of file diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/serializable/Test2.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/serializable/Test2.java similarity index 95% rename from java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/serializable/Test2.java rename to java-basic/feature-jdk5/src/main/java/cn/lastwhisper/serializable/Test2.java index 9ad58b2c..81ef993a 100644 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/serializable/Test2.java +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/serializable/Test2.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.jdk5.feature.serializable; +package cn.lastwhisper.serializable; import java.io.*; diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/serializable/Test3.java b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/serializable/Test3.java similarity index 92% rename from java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/serializable/Test3.java rename to java-basic/feature-jdk5/src/main/java/cn/lastwhisper/serializable/Test3.java index d19f6798..bf7432f4 100644 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/serializable/Test3.java +++ b/java-basic/feature-jdk5/src/main/java/cn/lastwhisper/serializable/Test3.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.jdk5.feature.serializable; +package cn.lastwhisper.serializable; import java.io.*; @@ -38,9 +38,7 @@ private void readObject(ObjectInputStream in) { Object object = readFields.get("password", ""); System.out.println("要解密的字符串:" + object.toString()); password = "pass";//模拟解密,需要获得本地的密钥 - } catch (IOException e) { - e.printStackTrace(); - } catch (ClassNotFoundException e) { + } catch (IOException | ClassNotFoundException e) { e.printStackTrace(); } diff --git a/java-basic/feature-jdk5/src/main/resources/ExtClassloaderJar.jar b/java-basic/feature-jdk5/src/main/resources/ExtClassloaderJar.jar new file mode 100644 index 00000000..010ce5ec Binary files /dev/null and b/java-basic/feature-jdk5/src/main/resources/ExtClassloaderJar.jar differ diff --git a/java-basic/feature-jdk5/src/main/resources/config.properties b/java-basic/feature-jdk5/src/main/resources/config.properties new file mode 100644 index 00000000..7a986afa --- /dev/null +++ b/java-basic/feature-jdk5/src/main/resources/config.properties @@ -0,0 +1,4 @@ +# +className=TestArrayArguments + + diff --git a/java-basic/feature-jdk8/README.md b/java-basic/feature-jdk8/README.md new file mode 100644 index 00000000..17b65ae5 --- /dev/null +++ b/java-basic/feature-jdk8/README.md @@ -0,0 +1,18 @@ + +# Jdk8的一些新特性学习 +- annotation 注解 +- date 日期 +- interfa 接口 +- lambda lambda +- optional optional +- stream stream + +参考 https://blog.csdn.net/zxm1306192988/article/details/73744378 + + +# jdk6~7特性 +- spi + - http://www.spring4all.com/article/260 + - resources/META-INF/services下为spi配置文件 + + diff --git a/java-basic/feature-jdk8/pom.xml b/java-basic/feature-jdk8/pom.xml new file mode 100644 index 00000000..98cbb2ce --- /dev/null +++ b/java-basic/feature-jdk8/pom.xml @@ -0,0 +1,18 @@ + + + + 4.0.0 + cn.lastwhisper + feature-jdk8 + 1.0-SNAPSHOT + + + + junit + junit + 4.13 + + + \ No newline at end of file diff --git a/java-basic/feature-jdk8/src/main/java/cn/cunchang/annotation/MyAnnotation.java b/java-basic/feature-jdk8/src/main/java/cn/cunchang/annotation/MyAnnotation.java new file mode 100644 index 00000000..091e9dc7 --- /dev/null +++ b/java-basic/feature-jdk8/src/main/java/cn/cunchang/annotation/MyAnnotation.java @@ -0,0 +1,15 @@ +package cn.cunchang.annotation; + +import java.lang.annotation.Repeatable; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.*; + +@Repeatable(MyAnnotations.class)//指定重复注解的容器 +@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, TYPE_PARAMETER})//可以修饰的目标 +@Retention(RetentionPolicy.RUNTIME)//生命周期 +public @interface MyAnnotation { + String value() default "java"; +} \ No newline at end of file diff --git a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/annotation/MyAnnotations.java b/java-basic/feature-jdk8/src/main/java/cn/cunchang/annotation/MyAnnotations.java similarity index 91% rename from java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/annotation/MyAnnotations.java rename to java-basic/feature-jdk8/src/main/java/cn/cunchang/annotation/MyAnnotations.java index bc0c4fa2..3b74e0e5 100644 --- a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/annotation/MyAnnotations.java +++ b/java-basic/feature-jdk8/src/main/java/cn/cunchang/annotation/MyAnnotations.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.jdk8.annotation; +package cn.cunchang.annotation; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; diff --git a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/annotation/TestAnnotation.java b/java-basic/feature-jdk8/src/main/java/cn/cunchang/annotation/TestAnnotation.java similarity index 94% rename from java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/annotation/TestAnnotation.java rename to java-basic/feature-jdk8/src/main/java/cn/cunchang/annotation/TestAnnotation.java index 115f5c0f..b85751d3 100644 --- a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/annotation/TestAnnotation.java +++ b/java-basic/feature-jdk8/src/main/java/cn/cunchang/annotation/TestAnnotation.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.jdk8.annotation; +package cn.cunchang.annotation; import org.junit.Test; diff --git a/java-basic/feature-jdk8/src/main/java/cn/cunchang/date/LocalDateTest.java b/java-basic/feature-jdk8/src/main/java/cn/cunchang/date/LocalDateTest.java new file mode 100644 index 00000000..c42cec9c --- /dev/null +++ b/java-basic/feature-jdk8/src/main/java/cn/cunchang/date/LocalDateTest.java @@ -0,0 +1,16 @@ +package cn.cunchang.date; + +import java.time.LocalDate; + +/** + * @author cunchang + * @date 2021/1/10 6:18 下午 + */ +public class LocalDateTest { + + public static void main(String[] args) { + LocalDate localDate = LocalDate.ofEpochDay(1610273688163L); + System.out.println(localDate); + } + +} diff --git a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/date/TestLocalDateTime.java b/java-basic/feature-jdk8/src/main/java/cn/cunchang/date/TestLocalDateTime.java similarity index 99% rename from java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/date/TestLocalDateTime.java rename to java-basic/feature-jdk8/src/main/java/cn/cunchang/date/TestLocalDateTime.java index e698728e..7809980e 100644 --- a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/date/TestLocalDateTime.java +++ b/java-basic/feature-jdk8/src/main/java/cn/cunchang/date/TestLocalDateTime.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.jdk8.date; +package cn.cunchang.date; import org.junit.Test; diff --git a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/date/TestLocalDateTime2.java b/java-basic/feature-jdk8/src/main/java/cn/cunchang/date/TestLocalDateTime2.java similarity index 98% rename from java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/date/TestLocalDateTime2.java rename to java-basic/feature-jdk8/src/main/java/cn/cunchang/date/TestLocalDateTime2.java index 3ac0ea9f..0b7b671a 100644 --- a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/date/TestLocalDateTime2.java +++ b/java-basic/feature-jdk8/src/main/java/cn/cunchang/date/TestLocalDateTime2.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.jdk8.date; +package cn.cunchang.date; import org.junit.Test; diff --git a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/interfa/MyInterface.java b/java-basic/feature-jdk8/src/main/java/cn/cunchang/interfa/MyInterface.java similarity index 91% rename from java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/interfa/MyInterface.java rename to java-basic/feature-jdk8/src/main/java/cn/cunchang/interfa/MyInterface.java index eba8d714..00a0cc28 100644 --- a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/interfa/MyInterface.java +++ b/java-basic/feature-jdk8/src/main/java/cn/cunchang/interfa/MyInterface.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.jdk8.interfa; +package cn.cunchang.interfa; public interface MyInterface { diff --git a/java-basic/feature-jdk8/src/main/java/cn/cunchang/lambda/Employee.java b/java-basic/feature-jdk8/src/main/java/cn/cunchang/lambda/Employee.java new file mode 100644 index 00000000..f03acac6 --- /dev/null +++ b/java-basic/feature-jdk8/src/main/java/cn/cunchang/lambda/Employee.java @@ -0,0 +1,102 @@ +package cn.cunchang.lambda; + +import java.util.Objects; + +public class Employee { + + private Integer id; + private String name; + private Integer age; + private double salary; + + public Employee() { + } + + public Employee(Integer id) { + this.id = id; + } + + public Employee(String name) { + this.name = name; + } + + public Employee(String name, Integer age) { + this.name = name; + this.age = age; + } + + public Employee(String name, Integer age, double salary) { + this.name = name; + this.age = age; + this.salary = salary; + } + + public Employee(Integer id, String name, Integer age, double salary) { + this.id = id; + this.name = name; + this.age = age; + this.salary = salary; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getAge() { + return age; + } + + public void setAge(Integer age) { + this.age = age; + } + + public double getSalary() { + return salary; + } + + public void setSalary(double salary) { + this.salary = salary; + } + + public String show() { + return "测试方法引用!"; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Employee employee = (Employee) o; + return id.equals(employee.id) && + age.equals(employee.age) && + Double.compare(employee.salary, salary) == 0 && + Objects.equals(name, employee.name); + } + + @Override + public int hashCode() { + return Objects.hash(id, name, age, salary); + } + + @Override + public String toString() { + return "Employee [id=" + id + ", name=" + name + ", age=" + age + ", salary=" + salary + "]"; + } + +} diff --git a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/lambda/MyFun.java b/java-basic/feature-jdk8/src/main/java/cn/cunchang/lambda/MyFun.java similarity index 77% rename from java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/lambda/MyFun.java rename to java-basic/feature-jdk8/src/main/java/cn/cunchang/lambda/MyFun.java index 01530476..04d40788 100644 --- a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/lambda/MyFun.java +++ b/java-basic/feature-jdk8/src/main/java/cn/cunchang/lambda/MyFun.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.jdk8.lambda; +package cn.cunchang.lambda; /** * @author lastwhisper diff --git a/java-basic/feature-jdk8/src/main/java/cn/cunchang/lambda/TestLambda.java b/java-basic/feature-jdk8/src/main/java/cn/cunchang/lambda/TestLambda.java new file mode 100644 index 00000000..d3cf0e02 --- /dev/null +++ b/java-basic/feature-jdk8/src/main/java/cn/cunchang/lambda/TestLambda.java @@ -0,0 +1,137 @@ +package cn.cunchang.lambda; + +import cn.cunchang.lambda.strategy.EmployeeAgeFilter; +import cn.cunchang.lambda.strategy.Filter; +import cn.cunchang.lambda.strategy.EmployeeSalaryFilter; +import org.junit.Test; + +import java.util.*; + +/** + * @author lastwhisper + */ +public class TestLambda { + List employees = Arrays.asList( + new Employee("张三", 18, 9496.2), + new Employee("李四", 52, 2396.2), + new Employee("王五", 56, 996.2), + new Employee("赵六", 38, 940.2) + ); + + // 原来匿名内部类 + @Test + public void testInnerClass() { + Comparator comparator = new Comparator() { + @Override + public int compare(Integer o1, Integer o2) { + return 0; + } + }; + + TreeSet treeSet = new TreeSet<>(comparator); + } + + // 将匿名内部类优化为lambda表达式 + @Test + public void testLambda() { + Comparator comparator = (o1, o2) -> Integer.compare(o1, o2); + TreeSet treeSet = new TreeSet<>(comparator); + } + + // 传统方式进行条件过滤 + @Test + public void test3() { + //需求:获取当前公司中员工年龄大于35的员工信息 + List emps = filterEmployeesByAge(employees); + for (Employee e : emps) { + System.out.println(e); + } + System.out.println("---------------------"); + + //需求:获取当前公司中员工工资大于2000的员工信息 + List emps2 = filterEmployeesBySalary(employees); + for (Employee e : emps2) { + System.out.println(e); + } + } + + public List filterEmployeesByAge(List list) { + List emps = new ArrayList<>(); + for (Employee emp : list) { + if (emp.getAge() >= 35) { + emps.add(emp); + } + } + return emps; + } + + public List filterEmployeesBySalary(List list) { + List emps = new ArrayList<>(); + for (Employee emp : list) { + if (emp.getSalary() >= 2000) { + emps.add(emp); + } + } + return emps; + } + + // test3 优化方式一:策略设计模式 + @Test + public void test4() { + List emps = filterEmployees(employees, new EmployeeAgeFilter()); + for (Employee e : emps) { + System.out.println(e); + } + System.out.println("---------------------"); + List emps2 = filterEmployees(employees, new EmployeeSalaryFilter()); + for (Employee e : emps2) { + System.out.println(e); + } + } + + public List filterEmployees(List list, Filter filter) { + List emps = new ArrayList(); + for (Employee emp : list) { + if (filter.eqCondition(emp)) { + emps.add(emp); + } + } + return emps; + } + + // test3 优化方式二:匿名内部类 + @Test + public void test5() { + List list = filterEmployees(employees, new Filter() { + @Override + public boolean eqCondition(Employee t) { + return t.getSalary() >= 2000; + } + }); + for (Employee employee : list) { + System.out.println(employee); + } + } + + // test3 优化方式三:Lambda表达式 + @Test + public void test6() { + List list = filterEmployees(employees, (e) -> e.getSalary() >= 2000); + list.forEach(System.out::println); + } + + // test3 优化方式四:stream API + @Test + public void test7(){ + employees.stream() + .filter((e)->e.getSalary()>=2000) + .forEach(System.out::println); + System.out.println("------------------"); + employees.stream() + .map(Employee::getName) + .forEach(System.out::println); + } + + + +} diff --git a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/lambda/TestLambda2.java b/java-basic/feature-jdk8/src/main/java/cn/cunchang/lambda/TestLambda2.java similarity index 98% rename from java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/lambda/TestLambda2.java rename to java-basic/feature-jdk8/src/main/java/cn/cunchang/lambda/TestLambda2.java index 2b202c29..397bcd3d 100644 --- a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/lambda/TestLambda2.java +++ b/java-basic/feature-jdk8/src/main/java/cn/cunchang/lambda/TestLambda2.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.jdk8.lambda; +package cn.cunchang.lambda; import org.junit.Test; diff --git a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/lambda/TestLambda3.java b/java-basic/feature-jdk8/src/main/java/cn/cunchang/lambda/TestLambda3.java similarity index 98% rename from java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/lambda/TestLambda3.java rename to java-basic/feature-jdk8/src/main/java/cn/cunchang/lambda/TestLambda3.java index 84705098..83212fc3 100644 --- a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/lambda/TestLambda3.java +++ b/java-basic/feature-jdk8/src/main/java/cn/cunchang/lambda/TestLambda3.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.jdk8.lambda; +package cn.cunchang.lambda; import org.junit.Test; diff --git a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/lambda/TestMethodRef.java b/java-basic/feature-jdk8/src/main/java/cn/cunchang/lambda/TestMethodRef.java similarity index 97% rename from java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/lambda/TestMethodRef.java rename to java-basic/feature-jdk8/src/main/java/cn/cunchang/lambda/TestMethodRef.java index d398f8bd..b0059d00 100644 --- a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/lambda/TestMethodRef.java +++ b/java-basic/feature-jdk8/src/main/java/cn/cunchang/lambda/TestMethodRef.java @@ -1,6 +1,5 @@ -package cn.lastwhisper.jdk8.lambda; +package cn.cunchang.lambda; -import cn.lastwhisper.jdk8.lambda.Employee; import org.junit.Test; import java.io.PrintStream; diff --git a/java-basic/feature-jdk8/src/main/java/cn/cunchang/lambda/example/MyFun2.java b/java-basic/feature-jdk8/src/main/java/cn/cunchang/lambda/example/MyFun2.java new file mode 100644 index 00000000..3584ebeb --- /dev/null +++ b/java-basic/feature-jdk8/src/main/java/cn/cunchang/lambda/example/MyFun2.java @@ -0,0 +1,11 @@ +package cn.cunchang.lambda.example; + +/** + * @author lastwhisper + */ +@FunctionalInterface +public interface MyFun2 { + + public String getValue(String str); + +} diff --git a/java-basic/feature-jdk8/src/main/java/cn/cunchang/lambda/example/MyFun3.java b/java-basic/feature-jdk8/src/main/java/cn/cunchang/lambda/example/MyFun3.java new file mode 100644 index 00000000..1945ea1d --- /dev/null +++ b/java-basic/feature-jdk8/src/main/java/cn/cunchang/lambda/example/MyFun3.java @@ -0,0 +1,8 @@ +package cn.cunchang.lambda.example; + +@FunctionalInterface +public interface MyFun3 { + + public R operation(T t1, T t2); + +} diff --git a/java-basic/feature-jdk8/src/main/java/cn/cunchang/lambda/example/TestLambda.java b/java-basic/feature-jdk8/src/main/java/cn/cunchang/lambda/example/TestLambda.java new file mode 100644 index 00000000..f8c89557 --- /dev/null +++ b/java-basic/feature-jdk8/src/main/java/cn/cunchang/lambda/example/TestLambda.java @@ -0,0 +1,93 @@ +package cn.cunchang.lambda.example; + +import cn.cunchang.lambda.Employee; +import org.junit.Test; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +/** + * @author lastwhisper + */ +public class TestLambda { + + List emps = Arrays.asList( + new Employee(101, "a", 18, 9999.99), + new Employee(102, "b", 59, 6666.66), + new Employee(103, "c", 28, 3333.33), + new Employee(104, "d", 8, 7777.77), + new Employee(105, "e", 38, 5555.55) + ); + + /** + * 调用Collections.sort()方法,通过定制排序, + * 比较两个Employee(先按年龄比,年龄相同按姓名比),使用Lambda表达式作为参数传递。 + */ + @Test + public void test1() { + //Collections.sort(emps, new Comparator() { + // @Override + // public int compare(Employee o1, Employee o2) { + // if (o1.getAge() == o2.getAge()) { + // return o1.getName().compareTo(o2.getName()); + // } + // return o1.getAge() - o2.getAge(); + // } + //}); + + Collections.sort(emps, (o1, o2) -> { + if (o1.getAge() == o2.getAge()) { + return o1.getName().compareTo(o2.getName()); + } + return o1.getAge() - o2.getAge(); + }); + for (Employee emp : emps) { + System.out.println(emp); + } + } + + /** + * (1)声明函数式接口,接口中声明抽象方法:public String getValue(String str); + * (2)声明类LambdaTest,类中编写方法使用接口作为参数,将一个字符串转换成大写,并作为方法的返回值。 + * (3)再将一个字符串的第2个到第4个索引位置进行截取子串。 + */ + @Test + public void test2() { + String str = "abcde"; + System.out.println(bridge(str, x -> x.toUpperCase())); + System.out.println(bridge(str, x -> x.substring(2, 4))); + } + + public String bridge(String str, MyFun2 mf) { + return mf.getValue(str); + } + + /** + * (1)声明一个带两个泛型的函数式接口,泛型类型为 : T 为参数,R 为返回值。 + * (2)接口中声明对应抽象方法 + * (3)在LambdaTest类中声明方法,使用接口作为参数,计算两个long型参数的和。 + * (4)再计算两个long型参数的乘积 + */ + @Test + public void test3() { + Long num1 = 10l; + Long num2 = 15l; + System.out.println(bridge2(num1, num2, (x, y) -> x + y)); + System.out.println(bridge2(num1, num2, (x, y) -> x * y)); + } + + public Long bridge2(Long num1, Long num2, MyFun3 mf) { + return mf.operation(num1, num2); + } + + /** + * + */ + @Test + public void test4() { + + } + + +} diff --git a/java-basic/feature-jdk8/src/main/java/cn/cunchang/lambda/strategy/EmployeeAgeFilter.java b/java-basic/feature-jdk8/src/main/java/cn/cunchang/lambda/strategy/EmployeeAgeFilter.java new file mode 100644 index 00000000..950d2830 --- /dev/null +++ b/java-basic/feature-jdk8/src/main/java/cn/cunchang/lambda/strategy/EmployeeAgeFilter.java @@ -0,0 +1,13 @@ +package cn.cunchang.lambda.strategy; + +import cn.cunchang.lambda.Employee; + +/** + * @author lastwhisper + */ +public class EmployeeAgeFilter implements Filter { + @Override + public boolean eqCondition(Employee employee) { + return employee.getAge() >= 35; + } +} diff --git a/java-basic/feature-jdk8/src/main/java/cn/cunchang/lambda/strategy/EmployeeSalaryFilter.java b/java-basic/feature-jdk8/src/main/java/cn/cunchang/lambda/strategy/EmployeeSalaryFilter.java new file mode 100644 index 00000000..5bf8de49 --- /dev/null +++ b/java-basic/feature-jdk8/src/main/java/cn/cunchang/lambda/strategy/EmployeeSalaryFilter.java @@ -0,0 +1,13 @@ +package cn.cunchang.lambda.strategy; + +import cn.cunchang.lambda.Employee; + +/** + * @author lastwhisper + */ +public class EmployeeSalaryFilter implements Filter { + @Override + public boolean eqCondition(Employee employee) { + return employee.getSalary() >= 2000; + } +} diff --git a/java-basic/feature-jdk8/src/main/java/cn/cunchang/lambda/strategy/Filter.java b/java-basic/feature-jdk8/src/main/java/cn/cunchang/lambda/strategy/Filter.java new file mode 100644 index 00000000..29f79cc7 --- /dev/null +++ b/java-basic/feature-jdk8/src/main/java/cn/cunchang/lambda/strategy/Filter.java @@ -0,0 +1,8 @@ +package cn.cunchang.lambda.strategy; + +/** + * 过滤接口 + */ +public interface Filter { + boolean eqCondition(T t); +} diff --git a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/optional/Godness.java b/java-basic/feature-jdk8/src/main/java/cn/cunchang/optional/Godness.java similarity index 89% rename from java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/optional/Godness.java rename to java-basic/feature-jdk8/src/main/java/cn/cunchang/optional/Godness.java index b0bf6e95..cd35a531 100644 --- a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/optional/Godness.java +++ b/java-basic/feature-jdk8/src/main/java/cn/cunchang/optional/Godness.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.jdk8.optional; +package cn.cunchang.optional; public class Godness { diff --git a/java-basic/feature-jdk8/src/main/java/cn/cunchang/optional/Man.java b/java-basic/feature-jdk8/src/main/java/cn/cunchang/optional/Man.java new file mode 100644 index 00000000..c9a33df4 --- /dev/null +++ b/java-basic/feature-jdk8/src/main/java/cn/cunchang/optional/Man.java @@ -0,0 +1,27 @@ +package cn.cunchang.optional; + +public class Man { + + private Godness god; + + public Man() { + } + + public Man(Godness god) { + this.god = god; + } + + public Godness getGod() { + return god; + } + + public void setGod(Godness god) { + this.god = god; + } + + @Override + public String toString() { + return "Man [god=" + god + "]"; + } + +} diff --git a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/optional/NewMan.java b/java-basic/feature-jdk8/src/main/java/cn/cunchang/optional/NewMan.java similarity index 93% rename from java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/optional/NewMan.java rename to java-basic/feature-jdk8/src/main/java/cn/cunchang/optional/NewMan.java index b406d210..7efbd803 100644 --- a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/optional/NewMan.java +++ b/java-basic/feature-jdk8/src/main/java/cn/cunchang/optional/NewMan.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.jdk8.optional; +package cn.cunchang.optional; import java.util.Optional; diff --git a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/optional/TestOptional.java b/java-basic/feature-jdk8/src/main/java/cn/cunchang/optional/TestOptional.java similarity index 91% rename from java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/optional/TestOptional.java rename to java-basic/feature-jdk8/src/main/java/cn/cunchang/optional/TestOptional.java index 963a98b4..210373a7 100644 --- a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/optional/TestOptional.java +++ b/java-basic/feature-jdk8/src/main/java/cn/cunchang/optional/TestOptional.java @@ -1,6 +1,6 @@ -package cn.lastwhisper.jdk8.optional; +package cn.cunchang.optional; -import cn.lastwhisper.jdk8.stream.Employee; +import cn.cunchang.stream.Employee; import org.junit.Test; import java.util.Optional; @@ -114,4 +114,17 @@ public String getGodnessName2(Optional man){ .getName(); } + @Test + public void test7() { + Optional.ofNullable(null).map(o -> { + if (o == null) { + return null; + } else { + return o; + } + }).ifPresent(o -> { + System.out.println(o+"1"); + }); + } + } diff --git a/java-basic/feature-jdk8/src/main/java/cn/cunchang/stream/CollectorsTest.java b/java-basic/feature-jdk8/src/main/java/cn/cunchang/stream/CollectorsTest.java new file mode 100644 index 00000000..c96c48e2 --- /dev/null +++ b/java-basic/feature-jdk8/src/main/java/cn/cunchang/stream/CollectorsTest.java @@ -0,0 +1,30 @@ +package cn.cunchang.stream; + +import cn.cunchang.lambda.Employee; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * @author cunchang + * @date 2022/5/25 6:02 PM + */ +public class CollectorsTest { + + static List employees = Arrays.asList( + new cn.cunchang.lambda.Employee("张三", 18, 9999.99), + new cn.cunchang.lambda.Employee("张三", 58, 5555.55)); + + public static void main(String[] args) { + Map map = employees.stream() + .collect(Collectors.toMap(Employee::getName, employee -> employee)); + // merge 策略 +// Map map = employees.stream() +// .collect(Collectors.toMap(Employee::getName, employee -> employee, (t, t2) -> t)); + System.out.println(map); + } + + +} diff --git a/java-basic/feature-jdk8/src/main/java/cn/cunchang/stream/Employee.java b/java-basic/feature-jdk8/src/main/java/cn/cunchang/stream/Employee.java new file mode 100644 index 00000000..cf10d055 --- /dev/null +++ b/java-basic/feature-jdk8/src/main/java/cn/cunchang/stream/Employee.java @@ -0,0 +1,127 @@ +package cn.cunchang.stream; + + + +public class Employee { + + private Integer id; + private String name; + private Integer age; + private double salary; + private Status status; + + public Employee() { + } + + public Employee(String name) { + this.name = name; + } + + public Employee(String name, Integer age) { + this.name = name; + this.age = age; + } + + public Employee(Integer id, String name, Integer age, double salary) { + this.id = id; + this.name = name; + this.age = age; + this.salary = salary; + } + + public Employee(Integer id, String name, Integer age, double salary, Status status) { + this.id = id; + this.name = name; + this.age = age; + this.salary = salary; + this.status = status; + } + + public Status getStatus() { + return status; + } + + public void setStatus(Status status) { + this.status = status; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getAge() { + return age; + } + + public void setAge(Integer age) { + this.age = age; + } + + public double getSalary() { + return salary; + } + + public void setSalary(double salary) { + this.salary = salary; + } + + public String show() { + return "测试方法引用!"; + } + + @Override + public int hashCode() { + final Integer prime = 31; + Integer result = 1; + result = prime * result + age; + result = prime * result + id; + result = prime * result + ((name == null) ? 0 : name.hashCode()); + long temp; + temp = Double.doubleToLongBits(salary); + result = prime * result + (int) (temp ^ (temp >>> 32)); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Employee other = (Employee) obj; + if (age != other.age) + return false; + if (id != other.id) + return false; + if (name == null) { + if (other.name != null) + return false; + } else if (!name.equals(other.name)) + return false; + if (Double.doubleToLongBits(salary) != Double.doubleToLongBits(other.salary)) + return false; + return true; + } + + @Override + public String toString() { + return "Employee [id=" + id + ", name=" + name + ", age=" + age + ", salary=" + salary + ", status=" + status + + "]"; + } + + +} diff --git a/java-basic/feature-jdk8/src/main/java/cn/cunchang/stream/Status.java b/java-basic/feature-jdk8/src/main/java/cn/cunchang/stream/Status.java new file mode 100644 index 00000000..803709a1 --- /dev/null +++ b/java-basic/feature-jdk8/src/main/java/cn/cunchang/stream/Status.java @@ -0,0 +1,5 @@ +package cn.cunchang.stream; + +public enum Status { + FREE, BUSY, VOCATION; +} \ No newline at end of file diff --git a/java-basic/feature-jdk8/src/main/java/cn/cunchang/stream/StreamMapFlatMapDemo.java b/java-basic/feature-jdk8/src/main/java/cn/cunchang/stream/StreamMapFlatMapDemo.java new file mode 100644 index 00000000..0382ac50 --- /dev/null +++ b/java-basic/feature-jdk8/src/main/java/cn/cunchang/stream/StreamMapFlatMapDemo.java @@ -0,0 +1,78 @@ +package cn.cunchang.stream; + +import org.junit.Test; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Stream; + +import static java.util.stream.Collectors.toList; + +/** + * map和flatmap的区别 + *

+ * https://www.cnblogs.com/wangjing666/p/9999666.html + * + * @author cunchang + * @date 2021/10/5 4:43 下午 + */ +public class StreamMapFlatMapDemo { + + // 对给定单词列表 ["Hello","World"],你想返回字母去重列表["H","e","l","o","W","r","d"] + + /** + * 错误方式 + */ + @Test + public void test1() { + String[] words = new String[]{"Hello", "World"}; + List a = Arrays.stream(words) + .map(word -> word.split("")) + .distinct() + .collect(toList()); + a.forEach(System.out::print); + } + + /** + * 正确 + */ + @Test + public void test2() { + String[] words = new String[]{"Hello","World"}; + List a = Arrays.stream(words) + // Arrays.stream(words)得到 [Hello, World] + .map(word -> word.split("")) + // map 输入一个元素,返回一个元素 + // "Hello" -> "Hello".split("") => ["H","e","l","l","o"] + // "World" -> "World".split("") => ["W","o","r","l","d"] + // map处理后得到 Stream 内容 [H, e, l, l, o],[W, o, r, l, d] + .flatMap(Arrays::stream) + // flatMap 输入一个元素,返回多个元素 + // flatMap将 Stream 平铺 Stream + // [H, e, l, l, o],[W, o, r, l, d] =>[H, e, l, l, o, W, o, r, l, d] + .distinct() + .collect(toList()); + System.out.println(a); //[H, e, l, o, W, r, d] + } + + @Test + public void test3() { + String[] words = new String[]{"Hello","World"}; + Stream stringStream = Arrays.stream(words); + // [Hello, World] +// System.out.println(stringStream.collect(toList())); + + Stream stringArrStream = stringStream.map(word -> word.split("")); + // [[Ljava.lang.String;@136432db, [Ljava.lang.String;@7382f612] +// System.out.println(stringArrStream.collect(toList())); + // [H, e, l, l, o],[W, o, r, l, d] +// List strArrList = stringArrStream.collect(toList()); +// for (String[] strArr : strArrList) { +// System.out.println(Arrays.toString(strArr)); +// } + + // [H, e, l, l, o, W, o, r, l, d] + stringArrStream.flatMap(Arrays::stream).forEach(System.out::println); + } + +} diff --git a/java-basic/feature-jdk8/src/main/java/cn/cunchang/stream/TestStreamAPI.java b/java-basic/feature-jdk8/src/main/java/cn/cunchang/stream/TestStreamAPI.java new file mode 100644 index 00000000..48f5ebf4 --- /dev/null +++ b/java-basic/feature-jdk8/src/main/java/cn/cunchang/stream/TestStreamAPI.java @@ -0,0 +1,53 @@ +package cn.cunchang.stream; + +import cn.cunchang.lambda.Employee; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Stream; + +/* + * 一、Stream API 的操作步骤: + * 1. 创建 Stream + * 2. 中间操作 + * 3. 终止操作(终端操作) + */ +public class TestStreamAPI { + + /** + * 创建Stream + */ + @Test + public void test1() { + // 1.可以通过Collection 系列集合提供的stream()或parallelStream() + List list = new ArrayList<>(); + Stream stream1 = list.stream(); + + // 2.通过 Arrays 中的静态方法stream()获取数组流 + cn.cunchang.lambda.Employee[] emps = new cn.cunchang.lambda.Employee[10]; + Stream stream2 = Arrays.stream(emps); + + // 3.通过Stream 类中的静态方法of() + Stream stream3 = Stream.of("a", "b", "c"); + + // 4.创建无限流 + // 迭代 + Stream stream4 = Stream.iterate(0, (x) -> x + 2); + stream4.limit(10).forEach(System.out::println); + // 生成 + Stream.generate(Math::random) + .limit(5) + .forEach(System.out::println); + } + + @Test + public void test2(){ + Stream.of(1,2,3,4,5,6,7,8,9) + .parallel(); + Stream.of(1,2,3,4,5,6,7,8,9) + .sequential(); + } + +} diff --git a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/stream/TestStreamAPI2.java b/java-basic/feature-jdk8/src/main/java/cn/cunchang/stream/TestStreamAPI2.java similarity index 83% rename from java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/stream/TestStreamAPI2.java rename to java-basic/feature-jdk8/src/main/java/cn/cunchang/stream/TestStreamAPI2.java index 31000a8d..aeaec51c 100644 --- a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/stream/TestStreamAPI2.java +++ b/java-basic/feature-jdk8/src/main/java/cn/cunchang/stream/TestStreamAPI2.java @@ -1,6 +1,6 @@ -package cn.lastwhisper.jdk8.stream; +package cn.cunchang.stream; -import cn.lastwhisper.jdk8.lambda.Employee; +import cn.cunchang.lambda.Employee; import org.junit.Test; import java.util.ArrayList; @@ -18,19 +18,19 @@ */ public class TestStreamAPI2 { - List employees = Arrays.asList( - new Employee("张三", 18, 9999.99), - new Employee("李四", 58, 5555.55), - new Employee("王五", 26, 3333.33), - new Employee("赵六", 36, 6666.66), - new Employee("田七", 12, 8888.88) + List employees = Arrays.asList( + new cn.cunchang.lambda.Employee("张三", 18, 9999.99), + new cn.cunchang.lambda.Employee("李四", 58, 5555.55), + new cn.cunchang.lambda.Employee("王五", 26, 3333.33), + new cn.cunchang.lambda.Employee("赵六", 36, 6666.66), + new cn.cunchang.lambda.Employee("田七", 12, 8888.88) //, //new Employee("田七", 12, 8888.88) ); /** * 中间操作:筛选与切片 - * filter——接收 Lambda , 从流中排除某些元素。 + * filter——接收 Lambda ,true留下, 从流中排除某些元素。 * limit——截断流,使其元素不超过给定数量。 * skip(n) —— 跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个,则返回一个空流。与 limit(n) 互补 * distinct——筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素 @@ -39,7 +39,7 @@ public class TestStreamAPI2 { @Test public void test1() { //中间操作:不会执行任何操作 - Stream stream = employees.stream() + Stream stream = employees.stream() .filter((e) -> e.getAge() > 35); //终止操作:一次性执行全部内容,即 惰性求值 @@ -49,7 +49,7 @@ public void test1() { //外部迭代 @Test public void test2() { - Iterator it = employees.iterator(); + Iterator it = employees.iterator(); while (it.hasNext()) { System.out.println(it.next()); @@ -116,11 +116,13 @@ public static Stream filterCharacter(String str) { */ @Test public void test7() { - List list = Arrays.asList("ccc", "bbb", "aaa"); + // string日期天然有序 + List list = Arrays.asList("20191210", "20191211", "20191212"); list.stream() .sorted() .forEach(System.out::println); + employees.stream() .sorted((e1, e2) -> { if (e1.getAge().equals(e2.getAge())) { diff --git a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/stream/TestStreamAPI3.java b/java-basic/feature-jdk8/src/main/java/cn/cunchang/stream/TestStreamAPI3.java similarity index 84% rename from java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/stream/TestStreamAPI3.java rename to java-basic/feature-jdk8/src/main/java/cn/cunchang/stream/TestStreamAPI3.java index 94786c55..aa65b29f 100644 --- a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/stream/TestStreamAPI3.java +++ b/java-basic/feature-jdk8/src/main/java/cn/cunchang/stream/TestStreamAPI3.java @@ -1,8 +1,9 @@ -package cn.lastwhisper.jdk8.stream; +package cn.cunchang.stream; import org.junit.Test; import java.util.*; +import java.util.function.Function; import java.util.stream.Collectors; /* @@ -156,12 +157,39 @@ public void test5() { public void test6() { // 根据状态分组 - Map> map = employees.stream() - .collect(Collectors.groupingBy(Employee::getStatus)); - for (Map.Entry> entry : map.entrySet()) { +// Map> map = employees.stream() +// .collect(Collectors.groupingBy(Employee::getStatus)); +// for (Map.Entry> entry : map.entrySet()) { +// System.out.println("----------------根据状态分组-----------------"); +// System.out.println(entry.getKey()); +// entry.getValue().forEach(System.out::println); +// } + + // 根据非唯一键分组,将相同值分到一组 +// Map> map = employees.stream() +// .collect(Collectors.groupingBy(Employee::getStatus)); + + Map map2 = employees.stream() + .collect(Collectors.toMap(Employee::getStatus, Function.identity(),(o1,o2)->{return o1;})); + + // 根据唯一键分组,每一组只有一个数据 + Map map3 = employees.stream() + .collect(Collectors.toMap(Employee::getId,o->{return o;})); + + } + + // 根据状态进行分组求和 + @Test + public void test11() { + + // 根据状态分组 + Map statusSumSalaryMap = employees.stream() + .collect(Collectors.groupingBy(Employee::getStatus, + Collectors.summarizingDouble(Employee::getSalary))); + for (Map.Entry entry : statusSumSalaryMap.entrySet()) { System.out.println("----------------根据状态分组-----------------"); System.out.println(entry.getKey()); - entry.getValue().forEach(System.out::println); + System.out.println(entry.getValue().getSum()); } } diff --git a/java-basic/feature-jdk8/src/main/java/cn/cunchang/stream/example/TestStreamAPI.java b/java-basic/feature-jdk8/src/main/java/cn/cunchang/stream/example/TestStreamAPI.java new file mode 100644 index 00000000..8d62df3c --- /dev/null +++ b/java-basic/feature-jdk8/src/main/java/cn/cunchang/stream/example/TestStreamAPI.java @@ -0,0 +1,57 @@ +package cn.cunchang.stream.example; + +import cn.cunchang.stream.Employee; +import cn.cunchang.stream.Status; +import org.junit.Test; + +import java.math.BigDecimal; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; +import java.util.stream.Stream; + +/** + * @author lastwhisper + */ +public class TestStreamAPI { + + List emps = Arrays.asList( + new Employee(102, "李四", 59, 6666.66, Status.BUSY), + new Employee(101, "张三", 18, 9999.99, Status.FREE), + new Employee(103, "王五", 28, 3333.33, Status.VOCATION), + new Employee(104, "赵六", 8, 7777.77, Status.BUSY), + new Employee(104, "赵六", 8, 7777.77, Status.FREE), + new Employee(104, "赵六", 8, 7777.77, Status.FREE), + new Employee(105, "田七", 38, 5555.55, Status.BUSY) + ); + + /** + * 给定一个数字列表,如何返回一个由每个数的平方构成的列表呢? + * 给定【1,2,3,4,5】, 应该返回【1,4,9,16,25】。 + */ + @Test + public void test1() { + Stream.of(1, 2, 3, 4, 5).map(x -> x * x).forEach(System.out::println); + } + + /** + * 怎样用 map 和 reduce 方法数一数流中有多少个Employee呢? + */ + @Test + public void test2() { + Optional reduce = emps.stream().map(e -> 1).reduce(Integer::sum); + System.out.println(reduce.get()); + } + + /** + * BigDecimal相加 + */ + @Test + public void test3() { + BigDecimal reduce = emps.stream() + .map(employee -> BigDecimal.valueOf(employee.getSalary())) + .reduce(BigDecimal.ZERO, BigDecimal::add); + System.out.println(reduce); + } + +} diff --git a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/stream/example/TestTransaction.java b/java-basic/feature-jdk8/src/main/java/cn/cunchang/stream/example/TestTransaction.java similarity index 97% rename from java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/stream/example/TestTransaction.java rename to java-basic/feature-jdk8/src/main/java/cn/cunchang/stream/example/TestTransaction.java index 56448da0..2127b44e 100644 --- a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/stream/example/TestTransaction.java +++ b/java-basic/feature-jdk8/src/main/java/cn/cunchang/stream/example/TestTransaction.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.jdk8.stream.example; +package cn.cunchang.stream.example; import org.junit.Before; import org.junit.Test; @@ -7,7 +7,6 @@ import java.util.Comparator; import java.util.List; import java.util.Optional; -import java.util.stream.Collectors; /** * @author lastwhisper diff --git a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/stream/example/Trader.java b/java-basic/feature-jdk8/src/main/java/cn/cunchang/stream/example/Trader.java similarity index 93% rename from java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/stream/example/Trader.java rename to java-basic/feature-jdk8/src/main/java/cn/cunchang/stream/example/Trader.java index 70854376..d6287464 100644 --- a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/stream/example/Trader.java +++ b/java-basic/feature-jdk8/src/main/java/cn/cunchang/stream/example/Trader.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.jdk8.stream.example; +package cn.cunchang.stream.example; //交易员类 public class Trader { diff --git a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/stream/example/Transaction.java b/java-basic/feature-jdk8/src/main/java/cn/cunchang/stream/example/Transaction.java similarity index 95% rename from java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/stream/example/Transaction.java rename to java-basic/feature-jdk8/src/main/java/cn/cunchang/stream/example/Transaction.java index 1985404d..1c95bbd2 100644 --- a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/stream/example/Transaction.java +++ b/java-basic/feature-jdk8/src/main/java/cn/cunchang/stream/example/Transaction.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.jdk8.stream.example; +package cn.cunchang.stream.example; //交易类 public class Transaction { diff --git a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/stream/parallel/ForkJoinCalculate.java b/java-basic/feature-jdk8/src/main/java/cn/cunchang/stream/parallel/ForkJoinCalculate.java similarity index 96% rename from java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/stream/parallel/ForkJoinCalculate.java rename to java-basic/feature-jdk8/src/main/java/cn/cunchang/stream/parallel/ForkJoinCalculate.java index 0426d4e9..25baab69 100644 --- a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/stream/parallel/ForkJoinCalculate.java +++ b/java-basic/feature-jdk8/src/main/java/cn/cunchang/stream/parallel/ForkJoinCalculate.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.jdk8.stream.parallel; +package cn.cunchang.stream.parallel; import java.util.concurrent.RecursiveTask; diff --git a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/stream/parallel/TestForkJoin.java b/java-basic/feature-jdk8/src/main/java/cn/cunchang/stream/parallel/TestForkJoin.java similarity index 93% rename from java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/stream/parallel/TestForkJoin.java rename to java-basic/feature-jdk8/src/main/java/cn/cunchang/stream/parallel/TestForkJoin.java index ffd31e10..31bea0b1 100644 --- a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/stream/parallel/TestForkJoin.java +++ b/java-basic/feature-jdk8/src/main/java/cn/cunchang/stream/parallel/TestForkJoin.java @@ -1,9 +1,7 @@ -package cn.lastwhisper.jdk8.stream.parallel; +package cn.cunchang.stream.parallel; import org.junit.Test; -import java.time.Duration; -import java.time.Instant; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.ForkJoinTask; import java.util.stream.LongStream; diff --git "a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/\345\217\202\350\200\203" "b/java-basic/feature-jdk8/src/main/java/cn/cunchang/\345\217\202\350\200\203.txt" similarity index 100% rename from "java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/\345\217\202\350\200\203" rename to "java-basic/feature-jdk8/src/main/java/cn/cunchang/\345\217\202\350\200\203.txt" diff --git a/java-basic/interview/README.MD b/java-basic/interview/README.MD new file mode 100644 index 00000000..7fbaec42 --- /dev/null +++ b/java-basic/interview/README.MD @@ -0,0 +1,8 @@ +Java学习中的一些疑惑的地方 +uuid 测试Java uuid是否可重复 +cpu 控制Java程序cpu的使用率 +Convert 进制转换 +timestamp 时间戳 +test1 修改集合内对象是否会同步 +RelationFile rm -rf +string 测试string相关 diff --git a/java-basic/interview/pom.xml b/java-basic/interview/pom.xml index 4648919a..eb0c5343 100644 --- a/java-basic/interview/pom.xml +++ b/java-basic/interview/pom.xml @@ -2,15 +2,32 @@ - - java-basic - cn.lastwhisper - 1.0-SNAPSHOT - 4.0.0 cn.lastwhisper interview + 1.0-SNAPSHOT + + + junit + junit + 4.13 + test + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.6.1 + + 1.8 + 1.8 + + + + \ No newline at end of file diff --git a/java-basic/interview/readme b/java-basic/interview/readme deleted file mode 100644 index 86ef4a12..00000000 --- a/java-basic/interview/readme +++ /dev/null @@ -1,6 +0,0 @@ -Java学习中的一些疑惑的地方 -uuid 测试Java uuid是否可重复 -cpu 控制Java程序cpu的使用率 -Convert 进制转换 -timestamp 时间戳 - diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/ComparableAndComparator/my/DataSort.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/ComparableAndComparator/my/DataSort.java deleted file mode 100644 index 4d93896f..00000000 --- a/java-basic/interview/src/main/java/cn/lastwhisper/interview/ComparableAndComparator/my/DataSort.java +++ /dev/null @@ -1,18 +0,0 @@ -package cn.lastwhisper.interview.ComparableAndComparator.my; - -//排序类 -public class DataSort { - public static void sort(Object[] objs) { - for (int i = 0; i < objs.length - 1; i++) { - for (int j = i + 1; j < objs.length; j++) { - MyComparable c1 = (MyComparable) objs[i]; - MyComparable c2 = (MyComparable) objs[j]; - if (c1.compareTo(c2) > 0) { - Object temp = objs[i]; - objs[i] = objs[j]; - objs[j] = temp; - } - } - } - } -} \ No newline at end of file diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/ComparableAndComparator/my/MyComparable.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/ComparableAndComparator/my/MyComparable.java deleted file mode 100644 index 3835f718..00000000 --- a/java-basic/interview/src/main/java/cn/lastwhisper/interview/ComparableAndComparator/my/MyComparable.java +++ /dev/null @@ -1,8 +0,0 @@ -package cn.lastwhisper.interview.ComparableAndComparator.my; - -//使一个类本身具备比较性 -//优点:实现此接口的类可以自己重写自己规定比较的内容 -//缺点:因为只有一个方法,一个类只能有一种方式进行比较 -public interface MyComparable { - public int compareTo(E e); -} \ No newline at end of file diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/ComparableAndComparator/my/Person.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/ComparableAndComparator/my/Person.java deleted file mode 100644 index 55527d5f..00000000 --- a/java-basic/interview/src/main/java/cn/lastwhisper/interview/ComparableAndComparator/my/Person.java +++ /dev/null @@ -1,29 +0,0 @@ -package cn.lastwhisper.interview.ComparableAndComparator.my; - -//人 -public class Person implements MyComparable{ - private int age; - - public Person(int age) { - super(); - this.age = age; - } - - public int compareTo(Object e) { - if(e instanceof Person){ - Person temp=(Person)e; - if(this.age>temp.getAge())return 1; - else if(this.age map.length) { - throw new IllegalArgumentException("进制数不允许大于" + map.length); - } - if (decimal < radix) { - return map[decimal]; - } - StringBuilder sb = new StringBuilder(); - // 余数 - int remainder = -1; - // 被除数 - int divisor = decimal; - while (divisor != 0 && divisor / radix >= 0) { - remainder = divisor % radix; //取余 - divisor = divisor / radix; // 整除 - sb.append(map[remainder]); - } - return sb.reverse().toString(); - } -} diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/Initiative/SubClass.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/Initiative/SubClass.java deleted file mode 100644 index 276c2235..00000000 --- a/java-basic/interview/src/main/java/cn/lastwhisper/interview/Initiative/SubClass.java +++ /dev/null @@ -1,24 +0,0 @@ -package cn.lastwhisper.interview.Initiative; - -/** - * 子类 - * @author lastwhisper - */ -public class SubClass extends SuperClass { - - static { - System.out.println("子类的静态代码块"); - } - - { - System.out.println("子类的代码块"); - } - - public SubClass() { - System.out.println("子类的构造函数"); - } - - public static void main(String[] args) { - new SubClass(); - } -} diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/Initiative/SuperClass.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/Initiative/SuperClass.java deleted file mode 100644 index a2c1fbae..00000000 --- a/java-basic/interview/src/main/java/cn/lastwhisper/interview/Initiative/SuperClass.java +++ /dev/null @@ -1,21 +0,0 @@ -package cn.lastwhisper.interview.Initiative; - -/** - * 父类 - * @author lastwhisper - */ -public class SuperClass { - - static { - System.out.println("父类的静态代码块"); - } - - { - System.out.println("父类的代码块"); - } - - public SuperClass() { - System.out.println("父类的构造函数"); - } -} - diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/Initiative/Test.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/Initiative/Test.java deleted file mode 100644 index b873f5d2..00000000 --- a/java-basic/interview/src/main/java/cn/lastwhisper/interview/Initiative/Test.java +++ /dev/null @@ -1,10 +0,0 @@ -package cn.lastwhisper.interview.Initiative; - -/** - * @author lastwhisper - */ -public class Test { - public static void main(String[] args) { - new SubClass(); - } -} diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/Int2String/Int2String.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/Int2String/Int2String.java deleted file mode 100644 index 55383ad8..00000000 --- a/java-basic/interview/src/main/java/cn/lastwhisper/interview/Int2String/Int2String.java +++ /dev/null @@ -1,65 +0,0 @@ -package cn.lastwhisper.interview.Int2String; - -/** - * 数字类型转为String - * @author lastwhisper - * @date 2019/11/14 - */ -public class Int2String { - - public void longToString(int n) { - long startTime = System.currentTimeMillis(); - for (int i = 0; i < n; i++) { - long num = 123456789L + n; - String s = Long.toString(num); - } - long endTime = System.currentTimeMillis(); - System.out.println(n + "次long转String,使用longToString耗时:" + (endTime - startTime)); - } - - public void stringValueOf(int n) { - long startTime = System.currentTimeMillis(); - for (int i = 0; i < n; i++) { - long num = 123456789L + n; - String s = String.valueOf(num); - } - long endTime = System.currentTimeMillis(); - System.out.println(n + "次long转String,使用stringValueOf耗时:" + (endTime - startTime)); - } - - public void stringAdd(int n) { - long startTime = System.currentTimeMillis(); - for (int i = 0; i < n; i++) { - long num = 123456789L + n; - String s = num + ""; - } - long endTime = System.currentTimeMillis(); - System.out.println(n + "次long转String,使用stringAdd耗时:" + (endTime - startTime)); - } - - public void stringBuilder(int n) { - long startTime = System.currentTimeMillis(); - for (int i = 0; i < n; i++) { - long num = 123456789L + n; - StringBuilder sb = new StringBuilder(); - sb.append(num); - String s = sb.toString(); - } - long endTime = System.currentTimeMillis(); - System.out.println(n + "次long转String,使用stringBuilder耗时:" + (endTime - startTime)); - } - - /** - * 10000000次long转String,使用stringValueOf耗时:334 - * 10000000次long转String,使用stringBuilder耗时:395 - */ - public static void main(String[] args) { - int n = 10000000; - Int2String int2String = new Int2String(); - int2String.longToString(n); - int2String.stringValueOf(n); - int2String.stringBuilder(n); - int2String.stringAdd(n); - } - -} diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/RelationFile/DeleteFile.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/RelationFile/DeleteFile.java deleted file mode 100644 index 0c84b140..00000000 --- a/java-basic/interview/src/main/java/cn/lastwhisper/interview/RelationFile/DeleteFile.java +++ /dev/null @@ -1,61 +0,0 @@ -package cn.lastwhisper.interview.RelationFile; - -import java.io.File; - -/** - * 删除指定文件夹 - * @author lastwhisper - * @date 2019/11/22 - */ -public class DeleteFile { - - public static void main(String[] args) { - File file = new File("D:\\code"); - recursionFindDirectory(file); - } - - /** - * 递归找到target目录 - */ - public static void recursionFindDirectory(File file) { - File[] files = file.listFiles(); - if (files == null) { - return; - } - for (File f : files) { - System.out.println("log.info f.getName=" + f.getName() + " f.isDirectory=" + f.isDirectory()); - if ("target".equals(f.getName())) { - recursionDeleteFile(f); - f.delete(); - System.out.println("log.info f=" + f.getName() + " is delete"); - } else { - recursionFindDirectory(f); - } - } - } - - /** - * 递归删除target目录下的文件 - */ - public static void recursionDeleteFile(File file) { - if (file == null) { - return; - } - File[] files = file.listFiles(); - if (files == null) { - return; - } - for (File f : files) { - if (f.isDirectory()) { - System.out.println("log.info f=" + f.getName() + " f.isDirectory=" + f.isDirectory()); - recursionDeleteFile(f); - } else { - f.delete(); - System.out.println("log.info f=" + f.getName() + " is delete"); - } - } - file.delete(); - System.out.println("log.info f=" + file.getName() + " is delete"); - } - -} diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/Sax/Person.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/Sax/Person.java deleted file mode 100644 index 020c12b5..00000000 --- a/java-basic/interview/src/main/java/cn/lastwhisper/interview/Sax/Person.java +++ /dev/null @@ -1,32 +0,0 @@ -package cn.lastwhisper.interview.Sax; - -public class Person { - private String name; - private int age; - - public Person() { - } - - public Person(String name, int age) { - super(); - this.name = name; - this.age = age; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public int getAge() { - return age; - } - - public void setAge(int age) { - this.age = age; - } - -} diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/Sax/SaxTest.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/Sax/SaxTest.java deleted file mode 100644 index 4a1e2422..00000000 --- a/java-basic/interview/src/main/java/cn/lastwhisper/interview/Sax/SaxTest.java +++ /dev/null @@ -1,101 +0,0 @@ -package cn.lastwhisper.interview.Sax; - -import org.xml.sax.Attributes; -import org.xml.sax.SAXException; -import org.xml.sax.XMLReader; -import org.xml.sax.helpers.DefaultHandler; - -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.parsers.SAXParser; -import javax.xml.parsers.SAXParserFactory; -import java.io.IOException; - -/** - * @author lastwhisper - * @desc SAX方式解析xml文件 - * @email gaojun56@163.com - */ -public class SaxTest { - public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException { - // SAX解析 - // 1.获取解析工厂 - SAXParserFactory factory = SAXParserFactory.newInstance(); - // 2.从解析工厂获取解析器 - SAXParser parse = factory.newSAXParser(); - // 3.得到解读器 - XMLReader reader=parse.getXMLReader(); - // 4.设置内容处理器 - reader.setContentHandler(new PHandler()); - // 5.读取xml的文档内容 - reader.parse("src/main/java/cn/lastwhisper/cn.lastwhisper.javabasic/Sax/person.xml"); - - } - -} - -class PHandler extends DefaultHandler { - /** - * @author lastwhisper - * @desc 文档解析开始时调用,该方法只会调用一次 - * @param - * @return void - */ - @Override - public void startDocument() throws SAXException { - System.out.println("----解析文档开始----"); - } - - /** - * @author lastwhisper - * @desc 每当遇到起始标签时调用 - * @param uri xml文档的命名空间 - * @param localName 标签的名字 - * @param qName 带命名空间的标签的名字 - * @param attributes 标签的属性集 - * @return void - */ - @Override - public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { - System.out.println("标签<"+qName + ">解析开始"); - } - - /** - * @author lastwhisper - * @desc 解析标签内的内容的时候调用 - * @param ch 当前读取到的TextNode(文本节点)的字节数组 - * @param start 字节开始的位置,为0则读取全部 - * @param length 当前TextNode的长度 - * @return void - */ - @Override - public void characters(char[] ch, int start, int length) throws SAXException { - String contents = new String(ch, start, length).trim(); - if (contents.length() > 0) { - System.out.println("内容为-->" + contents); - } else { - System.out.println("内容为-->" + "空"); - } - } - /** - * @author lastwhisper - * @desc 每当遇到结束标签时调用 - * @param uri xml文档的命名空间 - * @param localName 标签的名字 - * @param qName 带命名空间的标签的名字 - * @return void - */ - @Override - public void endElement(String uri, String localName, String qName) throws SAXException { - System.out.println("标签解析结束"); - } - /** - * @author lastwhisper - * @desc 文档解析结束后调用,该方法只会调用一次 - * @param - * @return void - */ - @Override - public void endDocument() throws SAXException { - System.out.println("----解析文档结束----"); - } -} \ No newline at end of file diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/Sax/SaxXmlToPojo.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/Sax/SaxXmlToPojo.java deleted file mode 100644 index 42aec8ea..00000000 --- a/java-basic/interview/src/main/java/cn/lastwhisper/interview/Sax/SaxXmlToPojo.java +++ /dev/null @@ -1,126 +0,0 @@ -package cn.lastwhisper.interview.Sax; - -import org.xml.sax.Attributes; -import org.xml.sax.SAXException; -import org.xml.sax.XMLReader; -import org.xml.sax.helpers.DefaultHandler; - -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.parsers.SAXParser; -import javax.xml.parsers.SAXParserFactory; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -/** - * @author lastwhisper - * @desc 将xml数据解析到pojo中 - * - * @email gaojun56@163.com - */ -public class SaxXmlToPojo { - public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException { - // SAX解析 - // 1.获取解析工厂 - SAXParserFactory factory = SAXParserFactory.newInstance(); - // 2.从解析工厂获取解析器 - SAXParser parse = factory.newSAXParser(); - // 3.得到解读器 - XMLReader reader = parse.getXMLReader(); - // 4.设置内容处理器 - PersonHandler personHandler = new PersonHandler(); - reader.setContentHandler(personHandler); - // 5.读取xml的文档内容 - reader.parse("src/main/java/cn/lastwhisper/cn.lastwhisper.javabasic/Sax/person.xml"); - - List persons = personHandler.getPersons(); - for (Person person : persons) { - System.out.println("姓名:" + person.getName() + " 年龄:" + person.getAge()); - } - } - -} - -class PersonHandler extends DefaultHandler { - private List persons; - private Person person; - private String tag; // 存储操作标签 - - /** - * @author lastwhisper - * @desc 文档解析开始时调用,该方法只会调用一次 - * @param - * @return void - */ - @Override - public void startDocument() throws SAXException { - persons = new ArrayList(); - } - - /** - * @author lastwhisper - * @desc 标签(节点)解析开始时调用 - * @param uri xml文档的命名空间 - * @param localName 标签的名字 - * @param qName 带命名空间的标签的名字 - * @param attributes 标签的属性集 - * @return void - */ - @Override - public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { - tag = qName; - if ("person".equals(tag)) { - person = new Person(); - } - } - - /** - * @author lastwhisper - * @desc 解析标签的内容的时候调用 - * @param ch 字符 - * @param start 字符数组中的起始位置 - * @param length 要从字符数组使用的字符数 - * @return void - */ - @Override - public void characters(char[] ch, int start, int length) throws SAXException { - String contents = new String(ch, start, length).trim(); - if ("name".equals(tag)) { - person.setName(contents); - } else if ("age".equals(tag)) { - if (contents.length() > 0) { - person.setAge(Integer.valueOf(contents)); - } - } - } - - /** - * @author lastwhisper - * @desc 标签(节点)解析结束后调用 - * @param uri xml文档的命名空间 - * @param localName 标签的名字 - * @param qName 带命名空间的标签的名字 - * @return void - */ - @Override - public void endElement(String uri, String localName, String qName) throws SAXException { - if ("person".equals(qName)) { - persons.add(person); - } - tag = null; //tag丢弃了 - } - - /** - * @author lastwhisper - * @desc 文档解析结束后调用,该方法只会调用一次 - * @param - * @return void - */ - @Override - public void endDocument() throws SAXException { - } - - public List getPersons() { - return persons; - } -} \ No newline at end of file diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/Sax/person.xml b/java-basic/interview/src/main/java/cn/lastwhisper/interview/Sax/person.xml deleted file mode 100644 index b2072b04..00000000 --- a/java-basic/interview/src/main/java/cn/lastwhisper/interview/Sax/person.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - 韩信 - 25 - - - 李白 - 23 - - diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/array/ArrayCopy.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/array/ArrayCopy.java deleted file mode 100644 index ceaea7f5..00000000 --- a/java-basic/interview/src/main/java/cn/lastwhisper/interview/array/ArrayCopy.java +++ /dev/null @@ -1,23 +0,0 @@ -package cn.lastwhisper.interview.array; - -/** - * - * @author lastwhisper - * @date 2019/11/24 - */ -public class ArrayCopy { - - public static void main(String[] args) { - //char[][] Array2D = {{a, b, c}, {d, e, f}}; - //char[][] Array2Dnew = {{a, a, a, b, b, b, c, c, c}, - // {a, a, a, b, b, b, c, c, c}, - // {a, a, a, b, b, b, c, c, c}, - // {d, d, d, e, e, e, f, f, f}, - // {d, d, d, e, e, e, f, f, f}, - // {d, d, d, e, e, e, f, f, f}}; - - - - } - -} diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/timestamp/TimeStampTest.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/timestamp/TimeStampTest.java deleted file mode 100644 index d4bea7d5..00000000 --- a/java-basic/interview/src/main/java/cn/lastwhisper/interview/timestamp/TimeStampTest.java +++ /dev/null @@ -1,16 +0,0 @@ -package cn.lastwhisper.interview.timestamp; - -/** - * 时间戳 - * @author lastwhisper - * @date 2019/11/24 - */ -public class TimeStampTest { - /** - * 时间戳的二进制为41位 - */ - public static void main(String[] args){ - long currentTimeMillis = System.currentTimeMillis(); - System.out.println(Long.toBinaryString(currentTimeMillis).length()); - } -} diff --git a/java-basic/interview/src/main/java/cn/lastwhisper/interview/uuid/UUIDTest.java b/java-basic/interview/src/main/java/cn/lastwhisper/interview/uuid/UUIDTest.java deleted file mode 100644 index f503156b..00000000 --- a/java-basic/interview/src/main/java/cn/lastwhisper/interview/uuid/UUIDTest.java +++ /dev/null @@ -1,36 +0,0 @@ -package cn.lastwhisper.interview.uuid; - -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; - -/** - * - * @author lastwhisper - * @date 2019/11/23 - */ -public class UUIDTest { - private static Set set = new HashSet(); - - public static void main(String[] args) throws InterruptedException { - long busyTime = 7; - int i = 0; - while (true) { - long nowSys = System.currentTimeMillis(); - while ((System.currentTimeMillis() - nowSys) <= busyTime) { - i++; - String uuid = UUID.randomUUID().toString(); - System.out.println("log info 第 " + i + " 次生成uuid:" + uuid); - if (set.contains(uuid)) { - System.err.println("log error 第 " + i + " 次生成uuid:" + uuid + " 发生重复"); - break; - } else { - set.add(uuid); - } - } - Thread.sleep(1); - } - - } - -} diff --git a/java-basic/interview/target/classes/META-INF/interview.kotlin_module b/java-basic/interview/target/classes/META-INF/interview.kotlin_module deleted file mode 100644 index 2983af70..00000000 Binary files a/java-basic/interview/target/classes/META-INF/interview.kotlin_module and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/AccessModifier/A1.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/AccessModifier/A1.class deleted file mode 100644 index 3e32a171..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/AccessModifier/A1.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/AccessModifier/A2.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/AccessModifier/A2.class deleted file mode 100644 index d8ed2794..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/AccessModifier/A2.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/AccessModifier/defaulttest/A.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/AccessModifier/defaulttest/A.class deleted file mode 100644 index b0c9281d..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/AccessModifier/defaulttest/A.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/AccessModifier/defaulttest/B.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/AccessModifier/defaulttest/B.class deleted file mode 100644 index 9002d84e..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/AccessModifier/defaulttest/B.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/AccessModifier/privatetest/A.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/AccessModifier/privatetest/A.class deleted file mode 100644 index 956b66c2..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/AccessModifier/privatetest/A.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/AccessModifier/privatetest/B$1.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/AccessModifier/privatetest/B$1.class deleted file mode 100644 index c5604776..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/AccessModifier/privatetest/B$1.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/AccessModifier/privatetest/B$C$D.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/AccessModifier/privatetest/B$C$D.class deleted file mode 100644 index c71ad5a9..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/AccessModifier/privatetest/B$C$D.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/AccessModifier/privatetest/B$C.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/AccessModifier/privatetest/B$C.class deleted file mode 100644 index 91e8a6f5..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/AccessModifier/privatetest/B$C.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/AccessModifier/privatetest/B.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/AccessModifier/privatetest/B.class deleted file mode 100644 index fe374942..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/AccessModifier/privatetest/B.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/AccessModifier/protectedtest/A.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/AccessModifier/protectedtest/A.class deleted file mode 100644 index a6df578c..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/AccessModifier/protectedtest/A.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/AccessModifier/protectedtest/B.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/AccessModifier/protectedtest/B.class deleted file mode 100644 index 06d74727..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/AccessModifier/protectedtest/B.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/AccessModifier/publictest/A.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/AccessModifier/publictest/A.class deleted file mode 100644 index c963f602..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/AccessModifier/publictest/A.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/AccessModifier/publictest/B.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/AccessModifier/publictest/B.class deleted file mode 100644 index 6e264fcd..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/AccessModifier/publictest/B.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/ComparableAndComparator/CompareComparatorAndComparableTest$1.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/ComparableAndComparator/CompareComparatorAndComparableTest$1.class deleted file mode 100644 index 0f637b37..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/ComparableAndComparator/CompareComparatorAndComparableTest$1.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/ComparableAndComparator/CompareComparatorAndComparableTest$AscAgeComparator.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/ComparableAndComparator/CompareComparatorAndComparableTest$AscAgeComparator.class deleted file mode 100644 index 58999236..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/ComparableAndComparator/CompareComparatorAndComparableTest$AscAgeComparator.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/ComparableAndComparator/CompareComparatorAndComparableTest$DescAgeComparator.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/ComparableAndComparator/CompareComparatorAndComparableTest$DescAgeComparator.class deleted file mode 100644 index 4f0ac19f..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/ComparableAndComparator/CompareComparatorAndComparableTest$DescAgeComparator.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/ComparableAndComparator/CompareComparatorAndComparableTest$Person.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/ComparableAndComparator/CompareComparatorAndComparableTest$Person.class deleted file mode 100644 index 6d1bd295..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/ComparableAndComparator/CompareComparatorAndComparableTest$Person.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/ComparableAndComparator/CompareComparatorAndComparableTest.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/ComparableAndComparator/CompareComparatorAndComparableTest.class deleted file mode 100644 index e952668b..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/ComparableAndComparator/CompareComparatorAndComparableTest.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/ComparableAndComparator/my/DataSort.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/ComparableAndComparator/my/DataSort.class deleted file mode 100644 index 6ba445cd..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/ComparableAndComparator/my/DataSort.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/ComparableAndComparator/my/MyComparable.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/ComparableAndComparator/my/MyComparable.class deleted file mode 100644 index 16e7c6ed..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/ComparableAndComparator/my/MyComparable.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/ComparableAndComparator/my/Person.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/ComparableAndComparator/my/Person.class deleted file mode 100644 index 5f493100..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/ComparableAndComparator/my/Person.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/ComparableAndComparator/my/Test.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/ComparableAndComparator/my/Test.class deleted file mode 100644 index 51de2dec..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/ComparableAndComparator/my/Test.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/Convert/Main.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/Convert/Main.class deleted file mode 100644 index 64a476d9..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/Convert/Main.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/EqualsAndhashCode/ConflictHashCodeTest1$Person.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/EqualsAndhashCode/ConflictHashCodeTest1$Person.class deleted file mode 100644 index 76dd2e6c..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/EqualsAndhashCode/ConflictHashCodeTest1$Person.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/EqualsAndhashCode/ConflictHashCodeTest1.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/EqualsAndhashCode/ConflictHashCodeTest1.class deleted file mode 100644 index 8d44f164..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/EqualsAndhashCode/ConflictHashCodeTest1.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/EqualsAndhashCode/ConflictHashCodeTest2$Person.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/EqualsAndhashCode/ConflictHashCodeTest2$Person.class deleted file mode 100644 index 10529af0..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/EqualsAndhashCode/ConflictHashCodeTest2$Person.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/EqualsAndhashCode/ConflictHashCodeTest2.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/EqualsAndhashCode/ConflictHashCodeTest2.class deleted file mode 100644 index 241ee6e5..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/EqualsAndhashCode/ConflictHashCodeTest2.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/EqualsAndhashCode/EqualsTest1$Person.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/EqualsAndhashCode/EqualsTest1$Person.class deleted file mode 100644 index 06f53231..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/EqualsAndhashCode/EqualsTest1$Person.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/EqualsAndhashCode/EqualsTest1.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/EqualsAndhashCode/EqualsTest1.class deleted file mode 100644 index ccc78f04..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/EqualsAndhashCode/EqualsTest1.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/EqualsAndhashCode/EqualsTest2$Person.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/EqualsAndhashCode/EqualsTest2$Person.class deleted file mode 100644 index 787578b3..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/EqualsAndhashCode/EqualsTest2$Person.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/EqualsAndhashCode/EqualsTest2.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/EqualsAndhashCode/EqualsTest2.class deleted file mode 100644 index 27d906b4..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/EqualsAndhashCode/EqualsTest2.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/EqualsAndhashCode/EqualsTest3$Person.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/EqualsAndhashCode/EqualsTest3$Person.class deleted file mode 100644 index ebbb4da8..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/EqualsAndhashCode/EqualsTest3$Person.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/EqualsAndhashCode/EqualsTest3.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/EqualsAndhashCode/EqualsTest3.class deleted file mode 100644 index 86a40558..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/EqualsAndhashCode/EqualsTest3.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/EqualsAndhashCode/NormalHashCodeTest$Person.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/EqualsAndhashCode/NormalHashCodeTest$Person.class deleted file mode 100644 index d04834a8..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/EqualsAndhashCode/NormalHashCodeTest$Person.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/EqualsAndhashCode/NormalHashCodeTest.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/EqualsAndhashCode/NormalHashCodeTest.class deleted file mode 100644 index e9b89078..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/EqualsAndhashCode/NormalHashCodeTest.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/Exception/FinallyReturnTest.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/Exception/FinallyReturnTest.class deleted file mode 100644 index 0bee4ec3..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/Exception/FinallyReturnTest.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/Exception/FinallyTest.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/Exception/FinallyTest.class deleted file mode 100644 index 7a2a9860..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/Exception/FinallyTest.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/Exception/MyException.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/Exception/MyException.class deleted file mode 100644 index 8c664d75..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/Exception/MyException.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/Exception/ThrowsAndThrowTest.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/Exception/ThrowsAndThrowTest.class deleted file mode 100644 index 48dad9cb..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/Exception/ThrowsAndThrowTest.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/Exception/TryCatchTest.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/Exception/TryCatchTest.class deleted file mode 100644 index 0c49abf3..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/Exception/TryCatchTest.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/Exception/TryTest.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/Exception/TryTest.class deleted file mode 100644 index 3b001b5c..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/Exception/TryTest.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/Initiative/SubClass.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/Initiative/SubClass.class deleted file mode 100644 index 4ae43551..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/Initiative/SubClass.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/Initiative/SuperClass.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/Initiative/SuperClass.class deleted file mode 100644 index 03c83261..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/Initiative/SuperClass.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/Initiative/Test.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/Initiative/Test.class deleted file mode 100644 index 71fd9de3..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/Initiative/Test.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/InnerClass/Static/OuterClass$1.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/InnerClass/Static/OuterClass$1.class deleted file mode 100644 index f72275d9..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/InnerClass/Static/OuterClass$1.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/InnerClass/Static/OuterClass$InnerClass.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/InnerClass/Static/OuterClass$InnerClass.class deleted file mode 100644 index 0a9e6716..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/InnerClass/Static/OuterClass$InnerClass.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/InnerClass/Static/OuterClass.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/InnerClass/Static/OuterClass.class deleted file mode 100644 index 72c86d9f..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/InnerClass/Static/OuterClass.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/InnerClass/Static/Outter$Inner.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/InnerClass/Static/Outter$Inner.class deleted file mode 100644 index 18036192..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/InnerClass/Static/Outter$Inner.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/InnerClass/Static/Outter.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/InnerClass/Static/Outter.class deleted file mode 100644 index 8fce486d..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/InnerClass/Static/Outter.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/InnerClass/anonymous/FinalTest$1.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/InnerClass/anonymous/FinalTest$1.class deleted file mode 100644 index e528c960..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/InnerClass/anonymous/FinalTest$1.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/InnerClass/anonymous/FinalTest.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/InnerClass/anonymous/FinalTest.class deleted file mode 100644 index c050e743..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/InnerClass/anonymous/FinalTest.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/InnerClass/anonymous/InnerClass.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/InnerClass/anonymous/InnerClass.class deleted file mode 100644 index 987b989c..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/InnerClass/anonymous/InnerClass.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/InnerClass/anonymous/OuterClass$1.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/InnerClass/anonymous/OuterClass$1.class deleted file mode 100644 index 0a8d1457..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/InnerClass/anonymous/OuterClass$1.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/InnerClass/anonymous/OuterClass.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/InnerClass/anonymous/OuterClass.class deleted file mode 100644 index 9ae6e683..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/InnerClass/anonymous/OuterClass.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/InnerClass/anonymous/OuterClassExample$1.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/InnerClass/anonymous/OuterClassExample$1.class deleted file mode 100644 index 3d41bc5c..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/InnerClass/anonymous/OuterClassExample$1.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/InnerClass/anonymous/OuterClassExample.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/InnerClass/anonymous/OuterClassExample.class deleted file mode 100644 index d4d3ecc0..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/InnerClass/anonymous/OuterClassExample.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/InnerClass/local/OuterClass$1InnerClass.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/InnerClass/local/OuterClass$1InnerClass.class deleted file mode 100644 index 7f89677a..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/InnerClass/local/OuterClass$1InnerClass.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/InnerClass/local/OuterClass.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/InnerClass/local/OuterClass.class deleted file mode 100644 index 81ef1bdf..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/InnerClass/local/OuterClass.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/InnerClass/local/Outter$1Inner.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/InnerClass/local/Outter$1Inner.class deleted file mode 100644 index d09b33ef..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/InnerClass/local/Outter$1Inner.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/InnerClass/local/Outter.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/InnerClass/local/Outter.class deleted file mode 100644 index f00ee500..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/InnerClass/local/Outter.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/InnerClass/member/OuterClass$InnerClass.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/InnerClass/member/OuterClass$InnerClass.class deleted file mode 100644 index 1eb23242..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/InnerClass/member/OuterClass$InnerClass.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/InnerClass/member/OuterClass.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/InnerClass/member/OuterClass.class deleted file mode 100644 index b59ae5af..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/InnerClass/member/OuterClass.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/InnerClass/member/Outter$Inner.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/InnerClass/member/Outter$Inner.class deleted file mode 100644 index 64571177..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/InnerClass/member/Outter$Inner.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/InnerClass/member/Outter.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/InnerClass/member/Outter.class deleted file mode 100644 index 6510e24e..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/InnerClass/member/Outter.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/Int2String/Int2String.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/Int2String/Int2String.class deleted file mode 100644 index ba7c39d2..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/Int2String/Int2String.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/IterableAndIterator/IterableAndIterator.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/IterableAndIterator/IterableAndIterator.class deleted file mode 100644 index ce3c973b..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/IterableAndIterator/IterableAndIterator.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/IterableAndIterator/ResizingArrayStack$1.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/IterableAndIterator/ResizingArrayStack$1.class deleted file mode 100644 index 8f9698ce..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/IterableAndIterator/ResizingArrayStack$1.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/IterableAndIterator/ResizingArrayStack$ReverseArrayIterator.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/IterableAndIterator/ResizingArrayStack$ReverseArrayIterator.class deleted file mode 100644 index 4e6b7b5d..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/IterableAndIterator/ResizingArrayStack$ReverseArrayIterator.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/IterableAndIterator/ResizingArrayStack.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/IterableAndIterator/ResizingArrayStack.class deleted file mode 100644 index dd2bd61e..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/IterableAndIterator/ResizingArrayStack.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/Main.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/Main.class deleted file mode 100644 index 0a85cdf3..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/Main.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/Operator/Division.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/Operator/Division.class deleted file mode 100644 index 35dc6045..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/Operator/Division.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/Operator/LogicalBitOperation.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/Operator/LogicalBitOperation.class deleted file mode 100644 index 0b6b033e..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/Operator/LogicalBitOperation.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/Operator/LogicalOperator.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/Operator/LogicalOperator.class deleted file mode 100644 index 0962bcb4..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/Operator/LogicalOperator.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/Operator/ShiftOperator.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/Operator/ShiftOperator.class deleted file mode 100644 index a01310dc..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/Operator/ShiftOperator.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/OverloadVsOverride/OverLoadClass.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/OverloadVsOverride/OverLoadClass.class deleted file mode 100644 index c8001084..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/OverloadVsOverride/OverLoadClass.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/OverloadVsOverride/SubClass.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/OverloadVsOverride/SubClass.class deleted file mode 100644 index 0ec0ef90..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/OverloadVsOverride/SubClass.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/OverloadVsOverride/SuperClass.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/OverloadVsOverride/SuperClass.class deleted file mode 100644 index af9938a8..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/OverloadVsOverride/SuperClass.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/RelationFile/DeleteFile.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/RelationFile/DeleteFile.class deleted file mode 100644 index 530a8c4c..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/RelationFile/DeleteFile.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/Sax/PHandler.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/Sax/PHandler.class deleted file mode 100644 index ed95767a..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/Sax/PHandler.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/Sax/Person.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/Sax/Person.class deleted file mode 100644 index d35c3d7a..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/Sax/Person.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/Sax/PersonHandler.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/Sax/PersonHandler.class deleted file mode 100644 index e64c4055..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/Sax/PersonHandler.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/Sax/SaxTest.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/Sax/SaxTest.class deleted file mode 100644 index 1c4460af..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/Sax/SaxTest.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/Sax/SaxXmlToPojo.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/Sax/SaxXmlToPojo.class deleted file mode 100644 index 45fef55f..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/Sax/SaxXmlToPojo.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/SwapTwoInteger/Swap1.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/SwapTwoInteger/Swap1.class deleted file mode 100644 index d5fba62b..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/SwapTwoInteger/Swap1.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/SwapTwoInteger/Swap2.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/SwapTwoInteger/Swap2.class deleted file mode 100644 index 95190aab..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/SwapTwoInteger/Swap2.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/CycleWait.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/CycleWait.class deleted file mode 100644 index 51f281f2..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/CycleWait.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/FutureTaskDemo.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/FutureTaskDemo.class deleted file mode 100644 index f2e8bec3..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/FutureTaskDemo.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/InterruptDemo$1.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/InterruptDemo$1.class deleted file mode 100644 index 92cd1dd3..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/InterruptDemo$1.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/InterruptDemo.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/InterruptDemo.class deleted file mode 100644 index 8675c84c..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/InterruptDemo.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/MyCallable.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/MyCallable.class deleted file mode 100644 index 21e6dd69..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/MyCallable.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/MyRunnable.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/MyRunnable.class deleted file mode 100644 index 59c309d2..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/MyRunnable.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/MyThread.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/MyThread.class deleted file mode 100644 index 8b7ab3ab..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/MyThread.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/SyncBlockAndMethod.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/SyncBlockAndMethod.class deleted file mode 100644 index 4850213e..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/SyncBlockAndMethod.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/SynchronizeDemo$1.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/SynchronizeDemo$1.class deleted file mode 100644 index 91a3485f..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/SynchronizeDemo$1.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/SynchronizeDemo$2.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/SynchronizeDemo$2.class deleted file mode 100644 index d7150c53..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/SynchronizeDemo$2.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/SynchronizeDemo$Outputer.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/SynchronizeDemo$Outputer.class deleted file mode 100644 index 014d49bf..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/SynchronizeDemo$Outputer.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/SynchronizeDemo.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/SynchronizeDemo.class deleted file mode 100644 index 486efe2d..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/SynchronizeDemo.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/ThreadDemo.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/ThreadDemo.class deleted file mode 100644 index d73ff611..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/ThreadDemo.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/ThreadPoolDemo.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/ThreadPoolDemo.class deleted file mode 100644 index 936a4e42..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/ThreadPoolDemo.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/ThreadTest$1.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/ThreadTest$1.class deleted file mode 100644 index bb4ff578..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/ThreadTest$1.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/ThreadTest.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/ThreadTest.class deleted file mode 100644 index 85d8d716..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/ThreadTest.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/VolatileDemo.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/VolatileDemo.class deleted file mode 100644 index 5a691f24..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/VolatileDemo.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/WaitSleepDemo$1.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/WaitSleepDemo$1.class deleted file mode 100644 index dcdc66df..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/WaitSleepDemo$1.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/WaitSleepDemo$2.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/WaitSleepDemo$2.class deleted file mode 100644 index de4b404f..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/WaitSleepDemo$2.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/WaitSleepDemo.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/WaitSleepDemo.class deleted file mode 100644 index 13c3d535..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/WaitSleepDemo.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/WaitSleepDemo1$1.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/WaitSleepDemo1$1.class deleted file mode 100644 index e4cb4dc8..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/WaitSleepDemo1$1.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/WaitSleepDemo1$2.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/WaitSleepDemo1$2.class deleted file mode 100644 index 1bc143ee..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/WaitSleepDemo1$2.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/WaitSleepDemo1.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/WaitSleepDemo1.class deleted file mode 100644 index 67bba331..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/WaitSleepDemo1.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/YieldDemo$1.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/YieldDemo$1.class deleted file mode 100644 index fdd54956..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/YieldDemo$1.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/YieldDemo.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/YieldDemo.class deleted file mode 100644 index 2a1532b0..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/Thread/YieldDemo.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/ValueAndaddress/Example1.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/ValueAndaddress/Example1.class deleted file mode 100644 index 48da1b2f..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/ValueAndaddress/Example1.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/ValueAndaddress/Example2$1.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/ValueAndaddress/Example2$1.class deleted file mode 100644 index 8e11fe06..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/ValueAndaddress/Example2$1.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/ValueAndaddress/Example2$User.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/ValueAndaddress/Example2$User.class deleted file mode 100644 index 1ea0bd6d..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/ValueAndaddress/Example2$User.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/ValueAndaddress/Example2.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/ValueAndaddress/Example2.class deleted file mode 100644 index a024130b..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/ValueAndaddress/Example2.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/ValueAndaddress/Example3.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/ValueAndaddress/Example3.class deleted file mode 100644 index b2e30ffd..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/ValueAndaddress/Example3.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/ValueAndaddress/Example4$1.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/ValueAndaddress/Example4$1.class deleted file mode 100644 index c14a9b20..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/ValueAndaddress/Example4$1.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/ValueAndaddress/Example4$User.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/ValueAndaddress/Example4$User.class deleted file mode 100644 index 4ee46e37..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/ValueAndaddress/Example4$User.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/ValueAndaddress/Example4.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/ValueAndaddress/Example4.class deleted file mode 100644 index 82c7bd15..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/ValueAndaddress/Example4.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/array/ArrayCopy.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/array/ArrayCopy.class deleted file mode 100644 index 7cebf751..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/array/ArrayCopy.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/cpu/ControlCpu.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/cpu/ControlCpu.class deleted file mode 100644 index c394152c..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/cpu/ControlCpu.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/timestamp/TimeStampTest.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/timestamp/TimeStampTest.class deleted file mode 100644 index 0e306afe..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/timestamp/TimeStampTest.class and /dev/null differ diff --git a/java-basic/interview/target/classes/cn/lastwhisper/interview/uuid/UUIDTest.class b/java-basic/interview/target/classes/cn/lastwhisper/interview/uuid/UUIDTest.class deleted file mode 100644 index 8c3b2e98..00000000 Binary files a/java-basic/interview/target/classes/cn/lastwhisper/interview/uuid/UUIDTest.class and /dev/null differ diff --git a/java-basic/interview/target/classes/project-parent.zip b/java-basic/interview/target/classes/project-parent.zip deleted file mode 100644 index ef687d96..00000000 Binary files a/java-basic/interview/target/classes/project-parent.zip and /dev/null differ diff --git a/java-basic/jdk11/pom.xml b/java-basic/jdk11/pom.xml deleted file mode 100644 index 4573058f..00000000 --- a/java-basic/jdk11/pom.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - java-basic - cn.lastwhisper - 1.0-SNAPSHOT - - 4.0.0 - - cn.lastwhisper - jdk11 - - - \ No newline at end of file diff --git a/java-basic/jdk12/pom.xml b/java-basic/jdk12/pom.xml deleted file mode 100644 index 858593bd..00000000 --- a/java-basic/jdk12/pom.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - java-basic - cn.lastwhisper - 1.0-SNAPSHOT - - 4.0.0 - - cn.lastwhisper - jdk12 - - - \ No newline at end of file diff --git a/java-basic/jdk13/pom.xml b/java-basic/jdk13/pom.xml deleted file mode 100644 index d5e9dedd..00000000 --- a/java-basic/jdk13/pom.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - java-basic - cn.lastwhisper - 1.0-SNAPSHOT - - 4.0.0 - - cn.lastwhisper - jdk13 - - - \ No newline at end of file diff --git a/java-basic/jdk5/README.md b/java-basic/jdk5/README.md deleted file mode 100644 index d9171dd7..00000000 --- a/java-basic/jdk5/README.md +++ /dev/null @@ -1,20 +0,0 @@ -参考“传智 张孝详 Java高新技术” - -# Jdk5的一些新特性以及基础知识 -1. 自动拆装箱 AutoBox -2. 静态导入 StaticImport -3. 可变参数 VariableParameter -4. 枚举 enumtest -5. 注解 annotation -6. 反省与JavaBean introspection -7. beanutils beanutils -8. 反射 reflect -9. 泛型 generic -10. 类加载器 classloader -11. 动态代理与SpringAop实现 proxy - -12.spi -http://www.spring4all.com/article/260 -13.throwable -14.collection - diff --git a/java-basic/jdk5/pom.xml b/java-basic/jdk5/pom.xml deleted file mode 100644 index 160bd49b..00000000 --- a/java-basic/jdk5/pom.xml +++ /dev/null @@ -1,115 +0,0 @@ - - - - java-basic - cn.lastwhisper - 1.0-SNAPSHOT - - 4.0.0 - - cn.lastwhisper - jdk5 - - - UTF-8 - 4.0.3.RELEASE - 5.1.24 - - - - - org.springframework - spring-test - ${org.springframework.version} - - - org.springframework - spring-beans - ${org.springframework.version} - - - org.springframework - spring-core - ${org.springframework.version} - - - org.springframework - spring-context - ${org.springframework.version} - - - org.springframework - spring-web - ${org.springframework.version} - - - org.springframework - spring-aop - ${org.springframework.version} - - - org.springframework - spring-expression - ${org.springframework.version} - - - org.springframework - spring-context-support - ${org.springframework.version} - - - org.springframework - spring-webmvc - ${org.springframework.version} - - - org.springframework - spring-jdbc - ${org.springframework.version} - - - org.springframework - spring-tx - ${org.springframework.version} - - - - mysql - mysql-connector-java - ${mysql.connector} - - - - - com.thoughtworks.qdox - qdox - 1.12.1 - - - - - demos - - - org.apache.maven.plugins - maven-compiler-plugin - - 1.8 - 1.8 - - - - - - src/main/java - - **/*.xml - - true - - - - - \ No newline at end of file diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/HashCode.java b/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/HashCode.java deleted file mode 100644 index 7f2547ce..00000000 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/HashCode.java +++ /dev/null @@ -1,90 +0,0 @@ -package cn.lastwhisper.jdk5.feature; - -import cn.lastwhisper.jdk5.feature.reflect.ReflectPoint; -import org.junit.Test; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -/** - * hashcode导致内存泄漏 - * hashcode比较对象是否相等 - * @author lastwhisper - */ -public class HashCode { - /** - * - * 内存泄漏memory leak :是指程序在申请内存后,无法释放已申请的内存空间, - * 一次内存泄漏似乎不会有大的影响,但内存泄漏堆积后的后果就是内存溢出。 - * 各种内存泄漏 https://www.cnblogs.com/panxuejun/p/5883044.html - */ - static class Person { - private Integer id; - private String name; - - public Person(Integer id, String name) { - this.id = id; - this.name = name; - } - - // 重写了对象的equals规则,一定要重写hashcode规则 - @Override - public boolean equals(Object obj) { - if (this == obj) return true; - if (obj == null || obj.getClass() != getClass()) return false; - Person person = (Person) obj; - return id == person.id; - } - - //@Override - //public int hashCode() { - // return Objects.hash(id); - //} - } - - /** - * 重写对象的equals方法,不重写hashcode方法导致的问题 - */ - @Test - public void testOverrideEquals() { - Person p1 = new Person(1, "张三"); - Person p2 = new Person(1, "李四"); - System.out.println(p1.equals(p2));//true - - Map map = new HashMap<>(); - map.put(p1, "张三"); - System.out.println(map.get(p2)); - - } - - /** - * 重写对象的equals、hashcode方法 - * 不要修改对象的属性,因为修改对象的属性,会导致hashcode发生变化 - * 从而无法使用remove真的移除集合中的对象,对象被集合强引用,导致内存泄漏 - */ - @Test - public void testHashCodeToOOM() { - Set set = new HashSet(); - ReflectPoint pt1 = new ReflectPoint(1, 1); - ReflectPoint pt2 = new ReflectPoint(2, 2); - ReflectPoint pt3 = new ReflectPoint(1, 1); - - set.add(pt1); - set.add(pt2); - set.add(pt3);//重写hashcode发现重复 - set.add(pt1);// - - // 对象重写hashcode方法,添加到集合中后不要修改对象的属性值 - pt1.setX(2); - set.remove(pt1); - // 1. 没有重写hashcode size=3。 - // 2. 重写hashcode size=2。 - // 3. 在2的基础上修改对象的属性值,再移除对象,size=2,内存泄漏。 - System.out.println(set.size()); - } - -} - - diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/annotation/AnnotationTest.java b/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/annotation/AnnotationTest.java deleted file mode 100644 index af0a86f4..00000000 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/annotation/AnnotationTest.java +++ /dev/null @@ -1,23 +0,0 @@ -package cn.lastwhisper.jdk5.feature.annotation; - -import java.util.Arrays; - -/** - * jdk5新特性:注解 - * @author lastwhisper - */ -public class AnnotationTest { - - public static void main(String[] args) { - if (UseAnnotation.class.isAnnotationPresent(MyAnnotation.class)) { - MyAnnotation annotation = UseAnnotation.class.getAnnotation(MyAnnotation.class); - System.out.println(annotation.color()); - System.out.println(annotation.value()); - System.out.println(Arrays.toString(annotation.arrayAttr())); - System.out.println(annotation.annotation().value()); - System.out.println(annotation.clazz()); - System.out.println(annotation.enumLevel()); - } - } - -} diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/annotation/Level.java b/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/annotation/Level.java deleted file mode 100644 index 01e8f0f2..00000000 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/annotation/Level.java +++ /dev/null @@ -1,3 +0,0 @@ -package cn.lastwhisper.jdk5.feature.annotation; - -public enum Level {BAD, INDIFFERENT, GOOD} \ No newline at end of file diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/annotation/MetaAnnotation.java b/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/annotation/MetaAnnotation.java deleted file mode 100644 index 81ee2b36..00000000 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/annotation/MetaAnnotation.java +++ /dev/null @@ -1,5 +0,0 @@ -package cn.lastwhisper.jdk5.feature.annotation; - -public @interface MetaAnnotation { - String value(); -} \ No newline at end of file diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/annotation/MyAnnotation.java b/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/annotation/MyAnnotation.java deleted file mode 100644 index 007948ea..00000000 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/annotation/MyAnnotation.java +++ /dev/null @@ -1,33 +0,0 @@ -package cn.lastwhisper.jdk5.feature.annotation; - -// 自定义注解 - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - - -@Retention(RetentionPolicy.RUNTIME)//保留策略 -@Target({ElementType.METHOD, ElementType.TYPE})//作用目标 // 为什么是TYPE,因为Class的父类是Type -public @interface MyAnnotation { - // 八大基本数据类型、String、Class、Enum、注解类型对应的数组类型 - - String color() default "green"; - - String value();//value比较特殊 - - int[] arrayAttr() default {1, 2, 3}; - - Class clazz() default Formatter.class; - - Level enumLevel() default Level.GOOD; - - MetaAnnotation annotation() default @MetaAnnotation("xxxx"); - -} - - -interface Formatter { -} - diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/annotation/UseAnnotation.java b/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/annotation/UseAnnotation.java deleted file mode 100644 index 292c6b81..00000000 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/annotation/UseAnnotation.java +++ /dev/null @@ -1,22 +0,0 @@ -package cn.lastwhisper.jdk5.feature.annotation; - -/** - * @author lastwhisper - */ -@MyAnnotation(color = "red", value = "xxx", - arrayAttr = {4, 5, 6}, enumLevel = Level.INDIFFERENT, - annotation = @MetaAnnotation("yyy"), clazz = Formatter.class) -public class UseAnnotation { - - - @MyAnnotation("yyy") - @SuppressWarnings("deprecation") - public static void deprecatedFun() { - sayHello(); - } - - @Deprecated - public static void sayHello() { - System.out.println("被弃用的函数"); - } -} diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/classloader/ClassLoaderObject.java b/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/classloader/ClassLoaderObject.java deleted file mode 100644 index 8b356421..00000000 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/classloader/ClassLoaderObject.java +++ /dev/null @@ -1,24 +0,0 @@ -package cn.lastwhisper.jdk5.feature.classloader; - -import java.lang.reflect.Field; -import java.util.Vector; - -/** - * 获取ClassLoader下面加载的类 - * @author lastwhisper - */ -public class ClassLoaderObject { - /** - * @author lastwhisper - */ - public static void main(String[] args) throws Exception { - - Field f = ClassLoader.class.getDeclaredField("classes"); - f.setAccessible(true); - Vector classes = (Vector) f.get(ClassLoader.getSystemClassLoader()); - for (Object object : classes) { - System.out.println(object); - } - - } -} diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/classloader/ClassLoaderStructure.java b/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/classloader/ClassLoaderStructure.java deleted file mode 100644 index d6b3b251..00000000 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/classloader/ClassLoaderStructure.java +++ /dev/null @@ -1,28 +0,0 @@ -package cn.lastwhisper.jdk5.feature.classloader; - -/** - * 类加载器的结构、以及对应类加载器加载类的范围 - * @author lastwhisper - */ -public class ClassLoaderStructure { - - public static void main(String[] args) throws ClassNotFoundException { - Object obj = new Object(); - System.out.println("Object的类加载器:"+obj.getClass().getClassLoader()); - - Class clazz = Class.forName("cn.lastwhisper.cn.lastwhisper.javabasic.ClassLoader.other.Hello"); - System.out.println("ext下的类加载器:"+clazz.getClassLoader()); - - ClassLoaderStructure test01 = new ClassLoaderStructure(); - System.out.println("classpath下的类加载器:"+test01.getClass().getClassLoader()); - - System.out.println(""); - - System.out.println("classpath下的类加载器:"+test01.getClass().getClassLoader()); - System.out.println("classpath下的类加载器的父类加载器:"+test01.getClass().getClassLoader().getParent()); - System.out.println("classpath下的类加载器的父类加载器的父类加载器:"+test01.getClass().getClassLoader().getParent().getParent()); - - // java.lang.ClassLoader - - } -} diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/classloader/ClassLoaderUnique.java b/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/classloader/ClassLoaderUnique.java deleted file mode 100644 index 066cea61..00000000 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/classloader/ClassLoaderUnique.java +++ /dev/null @@ -1,47 +0,0 @@ -package cn.lastwhisper.jdk5.feature.classloader; - -import java.io.IOException; -import java.io.InputStream; - -/** - * 类加载器与instanceof关键字演示 - * @author lastwhisper - */ -public class ClassLoaderUnique { - - /** - * 对于任意一个类,都需要由加载它的类加载器和这个类本身一同确立 - * 其在Java虚拟机中的唯一性,每一个类加载器,都有一个独立的名称空间。 - * 即,两个类来自同一个Class文件,被同一个虚拟机加载,只要类加载器不同,两个类就不相等。 - * 不相等包括:equals()、isAssignableFrom()、isInstance()、instanceof - * @author lastwhisper - */ - public static void main(String[] args) throws Exception { - ClassLoader classLoader = new ClassLoader() { - @Override - public Class loadClass(String name) throws ClassNotFoundException { - try { - String fileName = name.substring(name.lastIndexOf(".") + 1) + ".class"; - InputStream is = getClass().getResourceAsStream(fileName); - if (is == null) { - return super.loadClass(name); - } - byte[] b = new byte[is.available()]; - is.read(b); - return defineClass(name, b, 0, b.length); - } catch (IOException e) { - - throw new ClassNotFoundException(name); - } - - } - }; - - Object obj = classLoader.loadClass("cn.lastwhisper.cn.lastwhisper.javabasic.ClassLoader.ClassLoaderUnique").newInstance(); - - System.out.println(obj.getClass()); - // obj由自定义的类加载器加载、cn.lastwhisper.cn.lastwhisper.javabasic.ClassLoader.ClassLoaderTest由系统类加载器加载的。 - System.out.println(obj instanceof ClassLoaderUnique); - - } -} diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/classloader/DemoObj.java b/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/classloader/DemoObj.java deleted file mode 100644 index ba26a729..00000000 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/classloader/DemoObj.java +++ /dev/null @@ -1,10 +0,0 @@ -package cn.lastwhisper.jdk5.feature.classloader; - -/** - * @author lastwhisper - */ -public class DemoObj { - static { - System.out.println("类构造器"); - } -} diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/classloader/LoadDiff.java b/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/classloader/LoadDiff.java deleted file mode 100644 index 783961d3..00000000 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/classloader/LoadDiff.java +++ /dev/null @@ -1,15 +0,0 @@ -package cn.lastwhisper.jdk5.feature.classloader; - -/** - * 隐式加载与显示加载 - * @author lastwhisper - */ -public class LoadDiff { - public static void main(String[] args) throws ClassNotFoundException { - // 在SpringIOC中,为了加快初始化速度,大量使用了延迟加载技术,使用ClassLoader不会执行“链接”、“初始化”的步骤。 - ClassLoader classLoader = DemoObj.class.getClassLoader(); - // 连接Mysql,注册驱动com.mysql.jdbc.Driver - //Class clazz = Class.forName("cn.lastwhisper.jdk5.feature.classloader.DemoObj"); - - } -} diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/classloader/custom/ClassLoader1.java b/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/classloader/custom/ClassLoader1.java deleted file mode 100644 index a8b53d20..00000000 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/classloader/custom/ClassLoader1.java +++ /dev/null @@ -1,63 +0,0 @@ -package cn.lastwhisper.jdk5.feature.classloader.custom; - -import java.io.*; - -/** - * 自定义类加载器并证明双亲委派机制 - * 以及解释loadClass、findClass、defineClass的功能 - * resolveClass的功能以及resolveClass与forName的区别 - * @author lastwhisper - */ -public class ClassLoader1 extends ClassLoader { - - private String rootDir; - - public ClassLoader1(String rootDir) { - this.rootDir = rootDir; - } - - /** - * 重写loadClass会破坏双亲委派机制 - * 重写findClass不会破坏双亲委派机制 - * 不管重写loadClass还是findClass,都需要直接使用defineClass实现类加载 - * resolveClass用于链接(加载、链接、初始化) - * @param name - * @return java.lang.Class - */ - @Override - public Class findClass(String name) throws ClassNotFoundException { - byte[] bytes = loadClassData(name); - return defineClass(name, bytes, 0, bytes.length); - } - - private byte[] loadClassData(String className) { - // 获取class文件的路径 - String path = classNameToPath(className); - InputStream is = null; - ByteArrayOutputStream out = null; - try { - is = new FileInputStream(new File(path)); - out = new ByteArrayOutputStream(); - byte[] buffer = new byte[2048]; - int b = 0; - while ((b = is.read(buffer)) != -1) { - out.write(buffer, 0, b); - } - } catch (Exception e) { - e.printStackTrace(); - } finally { - try { - if (is != null) is.close(); - if (out != null) out.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - return out.toByteArray(); - } - - private String classNameToPath(String className) { - return rootDir + File.separatorChar - + className.replace('.', File.separatorChar) + ".class"; - } -} diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/classloader/custom/Test.java b/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/classloader/custom/Test.java deleted file mode 100644 index d0852ba2..00000000 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/classloader/custom/Test.java +++ /dev/null @@ -1,16 +0,0 @@ -package cn.lastwhisper.jdk5.feature.classloader.custom; - -/** - * 用于测试 - * @author lastwhisper - */ -public class Test { - public static void main(String[] args) throws Exception { - ClassLoader1 classLoader1 = new ClassLoader1("D:\\code\\GitRepository\\JavaNotes\\java-basic\\jdk5\\target\\classes\\cn\\lastwhisper\\jdk5\\feature\\classloader\\custom\\"); - Class clazz1 = classLoader1.loadClass("cn.lastwhisper.jdk5.feature.classloader.DemoObj"); - //Class clazz1 = classLoader1.loadClass("DemoObj"); - Object obj = clazz1.newInstance(); - System.out.println(obj.getClass().getClassLoader()); - - } -} diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/classloader/encrypt/ClassLoader2.java b/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/classloader/encrypt/ClassLoader2.java deleted file mode 100644 index 0299fca9..00000000 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/classloader/encrypt/ClassLoader2.java +++ /dev/null @@ -1,73 +0,0 @@ -package cn.lastwhisper.jdk5.feature.classloader.encrypt; - -import java.io.*; - -/** - * 讲解classloader的实际作用,如自定义类加载器加载加密的字节码文件 - * @author lastwhisper - */ -public class ClassLoader2 extends ClassLoader { - - public static void main(String[] args) throws Exception { - // 1. 将正常的.class文件加密 - //encryptClass(); - // 2. 加载并解密字节码.class文件 - decryptAndLoadClass(); - } - - @Override - protected Class findClass(String name) throws ClassNotFoundException { - String classPathFile = "D:\\code\\GitRepository\\JavaNotes\\java-basic\\jdk5\\src\\main\\java\\cn\\lastwhisper\\jdk5\\feature\\classloader\\encrypt\\ClassLoaderAttachment.class"; - try { - FileInputStream fis = new FileInputStream(classPathFile); - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - // 将fos加密到fis - cypher(fis, bos); - byte[] bytes = bos.toByteArray(); - //return this.defineClass(bytes, 0, bytes.length); - return this.defineClass(name, bytes, 0, bytes.length); - }catch (Exception e) { - e.printStackTrace(); - } - return super.findClass(name); - } - - public static void decryptAndLoadClass()throws Exception { - ClassLoader2 classLoader2 = new ClassLoader2(); - // cn.lastwhisper.jdk5.feature.classloader.encrypt.ClassLoader2@5cad8086 - //Class clazz = classLoader2.loadClass("ClassLoaderAttachment"); - // sun.misc.Launcher$AppClassLoader@18b4aac2 - Class clazz = classLoader2.loadClass("cn.lastwhisper.jdk5.feature.classloader.encrypt.ClassLoaderAttachment"); - Object obj = clazz.newInstance(); - System.out.println(obj.getClass().getClassLoader()); - System.out.println(obj); - } - - // 将正常的.class文件加密 - public static void encryptClass() throws Exception { - String srcPath = "D:\\code\\GitRepository\\JavaNotes\\java-basic\\jdk5\\target\\classes\\cn\\lastwhisper\\jdk5\\feature\\classloader\\encrypt\\ClassLoaderAttachment.class"; - String destPath = "D:\\code\\GitRepository\\JavaNotes\\java-basic\\jdk5\\src\\main\\java\\cn\\lastwhisper\\jdk5\\feature\\classloader\\encrypt\\ClassLoaderAttachment.class"; - FileInputStream fis = new FileInputStream(srcPath); - FileOutputStream fos = new FileOutputStream(destPath); - // 将fis加密到fos - cypher(fis, fos); - fis.close(); - fos.close(); - } - - // 异或加密解密 - public static void cypher(InputStream istream, OutputStream ostream) throws Exception { - //下面这段代码可能遇到255的字节,当成byte就成了-1 - /*byte b = 0; - while((b = (byte)istream.read()) != -1) - { - ostream.write(b ^ 0xff); - }*/ - - int b = 0; - while ((b = istream.read()) != -1) { - ostream.write(((byte) b) ^ 0xff); - } - } - -} diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/classloader/encrypt/ClassLoaderAttachment.class b/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/classloader/encrypt/ClassLoaderAttachment.class deleted file mode 100644 index f4ffbeef..00000000 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/classloader/encrypt/ClassLoaderAttachment.class +++ /dev/null @@ -1 +0,0 @@ -5EAÖ֩𳖑ГЕЙМКмֳГЬ弓ѕ췚߻ߋГЕЙМКм񕞉ЊлHNO \ No newline at end of file diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/classloader/encrypt/ClassLoaderAttachment.java b/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/classloader/encrypt/ClassLoaderAttachment.java deleted file mode 100644 index d1bcbca5..00000000 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/classloader/encrypt/ClassLoaderAttachment.java +++ /dev/null @@ -1,14 +0,0 @@ -package cn.lastwhisper.jdk5.feature.classloader.encrypt; - -import java.util.Date; - -/** - * 继承Date是有原因的!!!自己定义的类加载器还原字节码后,创建的对象由Date变量接收。 - * @author lastwhisper - */ -public class ClassLoaderAttachment extends Date { - @Override - public String toString() { - return "Hello Date toString"; - } -} diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/classloader/hotdeploy/ClassLoaderHotDeploy.java b/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/classloader/hotdeploy/ClassLoaderHotDeploy.java deleted file mode 100644 index f858ae1c..00000000 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/classloader/hotdeploy/ClassLoaderHotDeploy.java +++ /dev/null @@ -1,93 +0,0 @@ -package cn.lastwhisper.jdk5.feature.classloader.hotdeploy; - -import java.io.ByteArrayOutputStream; -import java.io.FileInputStream; -import java.io.IOException; -import java.util.HashSet; -import java.util.Set; -import java.util.Timer; -import java.util.TimerTask; - -/** - * 代码热部署 - * @author lastwhisper - */ -public class ClassLoaderHotDeploy { - - - public static void main(String[] args) { - new Timer().schedule(new TimerTask() { - @Override - public void run() { - String path = MyClassLoader.class.getResource("").getPath(); - System.out.println(path); - String className = "cn.lastwhisper.jdk5.feature.classloader.hotdeploy.HotCodeTest"; - - Set set = new HashSet<>(); - set.add(className); - - MyClassLoader myClassLoader = new MyClassLoader(path, set); - - try { - Object object = myClassLoader.loadClass(className).newInstance(); - object.getClass().getMethod("printVersion").invoke(object); - } catch (Exception e) { - e.printStackTrace(); - } - - - } - }, 0, 2000); - } - - -} - -class MyClassLoader extends ClassLoader { - // 用于读取.class文件的路径 - private String path; - // 用于标记这些name的类是先由自身加载的 - private Set useMyClassLoader; - - public MyClassLoader(String path, Set useMyClassLoader) { - this.path = path; - this.useMyClassLoader = useMyClassLoader; - } - - @Override - public Class loadClass(String name) throws ClassNotFoundException { - Class c = findLoadedClass(name); - if (c == null && useMyClassLoader.contains(name)) { - c = findClass(name); - if (c != null) { - return c; - } - } - return super.loadClass(name); - } - - @Override - protected Class findClass(String name) { - //根据文件系统路径加载class文件,并返回byte数组 - byte[] classBytes = getClassByte(name); - //调用ClassLoader提供的方法,将二进制数组转换成Class类的实例 - return defineClass(name, classBytes, 0, classBytes.length); - } - - private byte[] getClassByte(String name) { - String className = name.substring(name.lastIndexOf('.') + 1, name.length()) + ".class"; - try { - FileInputStream fileInputStream = new FileInputStream(path + className); - byte[] buffer = new byte[1024]; - int length = 0; - ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); - while ((length = fileInputStream.read(buffer)) > 0) { - byteArrayOutputStream.write(buffer, 0, length); - } - return byteArrayOutputStream.toByteArray(); - } catch (IOException e) { - e.printStackTrace(); - } - return new byte[]{}; - } -} diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/classloader/hotdeploy/HotCodeTest.java b/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/classloader/hotdeploy/HotCodeTest.java deleted file mode 100644 index ead8326b..00000000 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/classloader/hotdeploy/HotCodeTest.java +++ /dev/null @@ -1,7 +0,0 @@ -package cn.lastwhisper.jdk5.feature.classloader.hotdeploy; - -public class HotCodeTest { - public void printVersion(){ - System.out.println("当前版本是2哦"); - } -} \ No newline at end of file diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/collection/ArraysAsList.java b/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/collection/ArraysAsList.java deleted file mode 100644 index 62b2f552..00000000 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/collection/ArraysAsList.java +++ /dev/null @@ -1,45 +0,0 @@ -package cn.lastwhisper.jdk5.feature.collection; - -import org.junit.Test; - -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -/** - * 数组与集合的转换 - * @author lastwhisper - */ -public class ArraysAsList { - /** - * 将String数组转为集合 - */ - @Test - public void testStringArrAsList(){ - String[] stringArray = new String[3]; - stringArray[0] = "one"; - stringArray[1] = "two"; - stringArray[2] = "three"; - - List stringList = Arrays.asList(stringArray); - // 修改集合中的元素,数组会发生变化 - stringList.set(0,"oneList"); - System.out.println(stringArray[0]); - // 修改数组中的元素,集合会发生变化 - stringArray[1] = "twoArr"; - System.out.println(stringList.get(1)); - } - - @Test - public void testIntArrAsList(){ - int[] intArr = {1,2,3}; - String[] stringArr = {"1","2","3"}; - System.out.println(intArr.getClass()); //class [I - System.out.println(stringArr.getClass()); //class [Ljava.lang.String - List intList = Arrays.asList(intArr); - List stringList = Arrays.asList(stringArr); - - } - - -} diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/collection/LRUCache.java b/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/collection/LRUCache.java deleted file mode 100644 index c0decaf0..00000000 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/collection/LRUCache.java +++ /dev/null @@ -1,30 +0,0 @@ -package cn.lastwhisper.jdk5.feature.collection; - -import java.util.LinkedHashMap; -import java.util.Map; - -/** - * @author lastwhisper - */ -public class LRUCache extends LinkedHashMap { - private static final int MAX_ENTRIES = 3; - - LRUCache() { - super(MAX_ENTRIES, 0.75f, true); - } - - @Override - protected boolean removeEldestEntry(Map.Entry eldest) { - return size() > MAX_ENTRIES; - } - - public static void main(String[] args){ - LRUCache cache = new LRUCache<>(); - cache.put(1, "a"); - cache.put(2, "b"); - cache.put(3, "c");//1,2,3 - cache.get(1);//2,3,1 - cache.put(4, "d");//3,1,4 - System.out.println(cache.keySet()); - } -} diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/collection/SafeHashMapDemo.java b/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/collection/SafeHashMapDemo.java deleted file mode 100644 index 20fb6e84..00000000 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/collection/SafeHashMapDemo.java +++ /dev/null @@ -1,18 +0,0 @@ -package cn.lastwhisper.jdk5.feature.collection; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -/** - * @author lastwhisper - */ -public class SafeHashMapDemo { - public static void main(String[] args){ - Map hashMap = new HashMap<>(); - Map synchronizedMap = Collections.synchronizedMap(hashMap); - synchronizedMap.put("map","1"); - synchronizedMap.put("list","2"); - System.out.println(synchronizedMap.get("map")); - } -} diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/collection/TestArrayListGrow.java b/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/collection/TestArrayListGrow.java deleted file mode 100644 index c510e05d..00000000 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/collection/TestArrayListGrow.java +++ /dev/null @@ -1,37 +0,0 @@ -package cn.lastwhisper.jdk5.feature.collection; - -import java.util.ArrayList; - -/** - * 测试ArrayList的扩容机制 - * @author lastwhisper - * @date 2019/10/24 - */ -public class TestArrayListGrow { - /** - * 创建ArrayList不指定初始容量,第一次add时直接扩容到DEFAULT_CAPACITY=10 - * 所以如果能确定ArrayList的大小一定要指定初始容量 - * - * add逻辑: - * ensureCapacityInternal——确保内部需要的容量够用minCapacity=size + 1 - * calculateCapacity——判断ArrayList是否是第一次创建且未指定初始容量,如果是minCapacity=DEFAULT_CAPACITY - * ensureExplicitCapacity——minCapacity>elementData.length,扩容1.5*elementData.length - */ - public static void main(String[] args){ - ArrayList arrayList = new ArrayList<>(); - // 此处应该扩容 0->10 - arrayList.add(1); - arrayList.add(2); - arrayList.add(3); - arrayList.add(4); - arrayList.add(5); - arrayList.add(6); - arrayList.add(7); - arrayList.add(8); - arrayList.add(9); - arrayList.add(10); - // 此处应该扩容 10->15 - arrayList.add(11); - arrayList.add(12); - } -} diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/collection/TestList.java b/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/collection/TestList.java deleted file mode 100644 index ea787357..00000000 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/collection/TestList.java +++ /dev/null @@ -1,119 +0,0 @@ -package cn.lastwhisper.jdk5.feature.collection; - -import org.junit.Assert; -import org.junit.Test; - -import java.util.*; - -/** - * @author lastwhisper - */ -public class TestList { - - public static class modification extends Thread { - private List arrayList; - - public modification(List arrayList) { - this.arrayList = arrayList; - } - - @Override - public void run() { - // 需要同步机制 - Iterator iterator = arrayList.iterator(); - while (iterator.hasNext()) { - String data = iterator.next(); - if ("a".equals(data)) { - iterator.remove();//Exception in thread "Thread-1" java.util.ConcurrentModificationException - } - System.out.print(Thread.currentThread().getId() + " " + data + "\n"); - } - } - } - - // 测试ArrayList在创建迭代器后,使用iterator.remove()并发修改 - @Test - public void testThreadFailFast() { - List arrayList = new ArrayList<>(); - arrayList.add("a"); - arrayList.add("b"); - arrayList.add("c"); - arrayList.add("d"); - new modification(arrayList).start(); - new modification(arrayList).start(); - new modification(arrayList).start(); - } - - // 测试ArrayList在创建迭代器后,使用iterator.remove()单线程修改 - // fail-fast - @Test - public void testArrayList() { - List arrayList = new ArrayList<>(); - arrayList.add("a"); - arrayList.add("b"); - arrayList.add("c"); - arrayList.add("d"); - //for (String data : arrayList) { - // if (data.equals("a")) { - // arrayList.remove("a"); - // } - // System.out.println(data); - //} - - //Iterator iterator = arrayList.iterator(); - //while (iterator.hasNext()) { - // String data = iterator.next(); - // if (data.equals("a")) { - // arrayList.remove("a"); - // } - // System.out.println(data); - //} - - Iterator iterator = arrayList.iterator(); - while (iterator.hasNext()) { - String data = iterator.next(); - if (data.equals("a")) { - iterator.remove(); - } - System.out.println(data); - } - System.out.println("size=" + arrayList.size()); - } - - @Test - public void testLinkedList() { - List linkedList = new LinkedList<>(); - linkedList.add("a"); - linkedList.add("b"); - linkedList.add("c"); - linkedList.add("d"); - - Iterator iterator = linkedList.iterator(); - while (iterator.hasNext()) { - String data = iterator.next(); - if (data.equals("a")) { - linkedList.remove("a"); - } - System.out.println(data); - } - System.out.println("size=" + linkedList.size()); - } - - /** - * 测试集合的并交差集操作 - */ - @Test - public void testUnion() { - List list1 = new ArrayList<>(); - list1.add("1"); - list1.add("2"); - List list2 = new ArrayList<>(); - list2.add("1"); - list2.add("3"); - list1.retainAll(list2) ; - Objects.requireNonNull(list1); - //Assert.assertNotNull(list1); - list1.forEach(System.out::println); - } - -} diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/collection/TestMap.java b/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/collection/TestMap.java deleted file mode 100644 index 44a0e442..00000000 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/collection/TestMap.java +++ /dev/null @@ -1,124 +0,0 @@ -package cn.lastwhisper.jdk5.feature.collection; - -import org.junit.Test; - -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.TreeMap; - -/** - * @author lastwhisper - */ -public class TestMap { - - static class Person { - public Long id; - public String name; - - public Person(Long id, String name) { - this.id = id; - this.name = name; - } - - } - - /* - * JDK1.7 - * 为什么要用数组+链表? - * 1、Object的hashcode太大 - * 2、为什么冲突后插到链表的头部?效率快 - * 3、为什么数组的大小是2^n? - * indexFor函数算下标 (范围 00001111),hashcode高位怎么变都不影响结果 - * &比%快 - * 4、hashmap的扩容机制 - * 在元素插入之前扩容 - * 扩容——》空间换时间 - * put——addEntry——resize——transfer(transfer会导致倒序) - * transfer多线程扩容会出现循环链表 - * transfer中的indexFor会将原链表中元素打散 - * - * 5、getEntry - * if (e.hash == hash && - * ((k = e.key) == key || (key != null && key.equals(k)))) - * 为什么重写equals方法,一定要重写hashcode方法 - * 对象做hashmap做key,要声明成final - * - * 6、public HashMap(int initialCapacity, float loadFactor)什么时候用? - * 解决循环链表,不让hashmap扩容 - * - * JDK1.8 - * 为什么要用数组+链表(红黑树)? - * 新元素加到尾结点 - * hashmap的扩容机制 - * - * 在元素插入之后扩容 - * put——resize - * - * - */ - @Test - public void testHashMap() { - HashMap hashMap = new HashMap<>(); - hashMap.put(null, null); - /* - * put方法 - * 1、key==null单独处理 - * putForNullKey,null没有hash值,强制放到table[0] - * 2、key已经存在覆盖value,并返回oldValue; - * 不存在addEntry头插法,添加新value,返回null - * - */ - String a1 = hashMap.put("a", "old"); - String a2 = hashMap.put("a", "new"); - System.out.println(a1 + "\t" + a2); - hashMap.get("a"); - } - - /** - * LinkedHashMap可以保证put的kv有序 - * - */ - @Test - public void testLinkedHashMap() { - LinkedHashMap linkedHashMap = new LinkedHashMap<>(); - linkedHashMap.put(1L, "1"); - linkedHashMap.put(4L, "4"); - linkedHashMap.put(3L, "3"); - linkedHashMap.put(7L, "7"); - for (Map.Entry entry : linkedHashMap.entrySet()) { - System.out.println(entry.getKey() + "\t" + entry.getValue()); - } - } - - /** - * TreeMap可以保证put的kv有序 - * 按key实现的comparable接口的compareTo方法规则进行排序 - */ - @Test - public void testTreeMap() { - TreeMap treeMap = new TreeMap<>(); - treeMap.put(1L, "1"); - treeMap.put(4L, "4"); - treeMap.put(3L, "3"); - treeMap.put(7L, "7"); - for (Map.Entry entry : treeMap.entrySet()) { - System.out.println(entry.getKey() + "\t" + entry.getValue()); - } - } - - /** - * TreeMap的key一定要重写comparable接口 - * 因为在插入时key需要比较顺序 - */ - @Test - public void testTreeMapKeyNoComparable() { - //java.lang.ClassCastException: - // Person cannot be cast to class java.lang.Comparable - TreeMap treeMap = new TreeMap(); - Person tom = new Person(1L, "tom"); - treeMap.put(tom, 1L); - } - - -} diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/generic/Generic4/Client.java b/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/generic/Generic4/Client.java deleted file mode 100644 index 275a9190..00000000 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/generic/Generic4/Client.java +++ /dev/null @@ -1,18 +0,0 @@ -package cn.lastwhisper.jdk5.feature.generic.Generic4; - -/** - * 该层模拟service - * @author lastwhisper - */ -public class Client { - public static void main(String[] args) { - Person person = new Person(); - person.setId(1L); - person.setName("张三"); - // 交给Spring的IOC容器管理 - PersonDao personDao = new PersonDaoImpl(); - // 持久化到数据库 - personDao.save(person); - - } -} diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/generic/Generic4/Person.java b/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/generic/Generic4/Person.java deleted file mode 100644 index 23c154bf..00000000 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/generic/Generic4/Person.java +++ /dev/null @@ -1,40 +0,0 @@ -package cn.lastwhisper.jdk5.feature.generic.Generic4; - -public class Person { - - // 编号 - private Long id; - - // 姓名 - private String name; - - public Person() { - } - - public Person(Long id, String name) { - this.id = id; - this.name = name; - } - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - @Override - public String toString() { - return "Person [id=" + id + ", name=" + name + "]"; - } - -} \ No newline at end of file diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/generic/Generic4/PersonDao.java b/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/generic/Generic4/PersonDao.java deleted file mode 100644 index 9542399b..00000000 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/generic/Generic4/PersonDao.java +++ /dev/null @@ -1,8 +0,0 @@ -package cn.lastwhisper.jdk5.feature.generic.Generic4; - -/** - * extends BaseDao是为了可以使用通用的方法 - * @author lastwhisper - */ -public interface PersonDao extends BaseDao { -} diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/io/bio/IODecorator.java b/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/io/bio/IODecorator.java deleted file mode 100644 index ad19606b..00000000 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/io/bio/IODecorator.java +++ /dev/null @@ -1,20 +0,0 @@ -package cn.lastwhisper.jdk5.feature.io.bio; - -import java.io.*; - -/** - * @author lastwhisper - */ -public class IODecorator { - public static void main(String[] args) { - try { - InputStream is = new BufferedInputStream(new FileInputStream("")); - BufferedReader bd = new BufferedReader(new FileReader("")); - bd.readLine(); - } catch (FileNotFoundException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } - } -} diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/io/nio/TestBlockingNIO2.java b/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/io/nio/TestBlockingNIO2.java deleted file mode 100644 index a8ad8486..00000000 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/io/nio/TestBlockingNIO2.java +++ /dev/null @@ -1,74 +0,0 @@ -package cn.lastwhisper.jdk5.feature.io.nio; - -import java.io.IOException; -import java.net.InetSocketAddress; -import java.nio.ByteBuffer; -import java.nio.channels.FileChannel; -import java.nio.channels.ServerSocketChannel; -import java.nio.channels.SocketChannel; -import java.nio.file.Paths; -import java.nio.file.StandardOpenOption; - -import org.junit.Test; - -public class TestBlockingNIO2 { - - //客户端 - @Test - public void client() throws IOException{ - SocketChannel sChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 9898)); - - FileChannel inChannel = FileChannel.open(Paths.get("1.jpg"), StandardOpenOption.READ); - - ByteBuffer buf = ByteBuffer.allocate(1024); - - while(inChannel.read(buf) != -1){ - buf.flip(); - sChannel.write(buf); - buf.clear(); - } - - sChannel.shutdownOutput(); - - //接收服务端的反馈 - int len = 0; - while((len = sChannel.read(buf)) != -1){ - buf.flip(); - System.out.println(new String(buf.array(), 0, len)); - buf.clear(); - } - - inChannel.close(); - sChannel.close(); - } - - //服务端 - @Test - public void server() throws IOException{ - ServerSocketChannel ssChannel = ServerSocketChannel.open(); - - FileChannel outChannel = FileChannel.open(Paths.get("2.jpg"), StandardOpenOption.WRITE, StandardOpenOption.CREATE); - - ssChannel.bind(new InetSocketAddress(9898)); - - SocketChannel sChannel = ssChannel.accept(); - - ByteBuffer buf = ByteBuffer.allocate(1024); - - while(sChannel.read(buf) != -1){ - buf.flip(); - outChannel.write(buf); - buf.clear(); - } - - //发送反馈给客户端 - buf.put("服务端接收数据成功".getBytes()); - buf.flip(); - sChannel.write(buf); - - sChannel.close(); - outChannel.close(); - ssChannel.close(); - } - -} diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/io/nio/TestNIO_2.java b/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/io/nio/TestNIO_2.java deleted file mode 100644 index dd85e35a..00000000 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/io/nio/TestNIO_2.java +++ /dev/null @@ -1,158 +0,0 @@ -package cn.lastwhisper.jdk5.feature.io.nio; - -import org.junit.Test; - -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.channels.FileChannel; -import java.nio.channels.SeekableByteChannel; -import java.nio.file.*; -import java.nio.file.attribute.BasicFileAttributes; -import java.nio.file.attribute.DosFileAttributeView; - -public class TestNIO_2 { - - - //自动资源管理:自动关闭实现 AutoCloseable 接口的资源 - @Test - public void test8() { - try (FileChannel inChannel = FileChannel.open(Paths.get("1.jpg"), StandardOpenOption.READ); - FileChannel outChannel = FileChannel.open(Paths.get("2.jpg"), StandardOpenOption.WRITE, StandardOpenOption.CREATE)) { - - ByteBuffer buf = ByteBuffer.allocate(1024); - inChannel.read(buf); - - } catch (IOException e) { - - } - } - - /* - Files常用方法:用于操作内容 - SeekableByteChannel newByteChannel(Path path, OpenOption…how) : 获取与指定文件的连接,how 指定打开方式。 - DirectoryStream newDirectoryStream(Path path) : 打开 path 指定的目录 - InputStream newInputStream(Path path, OpenOption…how):获取 InputStream 对象 - OutputStream newOutputStream(Path path, OpenOption…how) : 获取 OutputStream 对象 - */ - @Test - public void test7() throws IOException { - SeekableByteChannel newByteChannel = Files.newByteChannel(Paths.get("1.jpg"), StandardOpenOption.READ); - - DirectoryStream newDirectoryStream = Files.newDirectoryStream(Paths.get("e:/")); - - for (Path path : newDirectoryStream) { - System.out.println(path); - } - } - - /* - Files常用方法:用于判断 - boolean exists(Path path, LinkOption … opts) : 判断文件是否存在 - boolean isDirectory(Path path, LinkOption … opts) : 判断是否是目录 - boolean isExecutable(Path path) : 判断是否是可执行文件 - boolean isHidden(Path path) : 判断是否是隐藏文件 - boolean isReadable(Path path) : 判断文件是否可读 - boolean isWritable(Path path) : 判断文件是否可写 - boolean notExists(Path path, LinkOption … opts) : 判断文件是否不存在 - public static A readAttributes(Path path,Class type,LinkOption... options) : 获取与 path 指定的文件相关联的属性。 - */ - @Test - public void test6() throws IOException { - Path path = Paths.get("e:/nio/hello7.txt"); -// System.out.println(Files.exists(path, LinkOption.NOFOLLOW_LINKS)); - - BasicFileAttributes readAttributes = Files.readAttributes(path, BasicFileAttributes.class, LinkOption.NOFOLLOW_LINKS); - System.out.println(readAttributes.creationTime()); - System.out.println(readAttributes.lastModifiedTime()); - - DosFileAttributeView fileAttributeView = Files.getFileAttributeView(path, DosFileAttributeView.class, LinkOption.NOFOLLOW_LINKS); - - fileAttributeView.setHidden(false); - } - - /* - Files常用方法: - Path copy(Path src, Path dest, CopyOption … how) : 文件的复制 - Path createDirectory(Path path, FileAttribute … attr) : 创建一个目录 - Path createFile(Path path, FileAttribute … arr) : 创建一个文件 - void delete(Path path) : 删除一个文件 - Path move(Path src, Path dest, CopyOption…how) : 将 src 移动到 dest 位置 - long size(Path path) : 返回 path 指定文件的大小 - */ - @Test - public void test5() throws IOException { - Path path1 = Paths.get("e:/nio/hello2.txt"); - Path path2 = Paths.get("e:/nio/hello7.txt"); - - System.out.println(Files.size(path2)); - -// Files.move(path1, path2, StandardCopyOption.ATOMIC_MOVE); - } - - @Test - public void test4() throws IOException { - Path dir = Paths.get("e:/nio/nio2"); -// Files.createDirectory(dir); - - Path file = Paths.get("e:/nio/nio2/hello3.txt"); -// Files.createFile(file); - - Files.deleteIfExists(file); - } - - @Test - public void test3() throws IOException { - Path path1 = Paths.get("e:/nio/hello.txt"); - Path path2 = Paths.get("e:/nio/hello2.txt"); - - Files.copy(path1, path2, StandardCopyOption.REPLACE_EXISTING); - } - - /* - Paths 提供的 get() 方法用来获取 Path 对象: - Path get(String first, String … more) : 用于将多个字符串串连成路径。 - Path 常用方法: - boolean endsWith(String path) : 判断是否以 path 路径结束 - boolean startsWith(String path) : 判断是否以 path 路径开始 - boolean isAbsolute() : 判断是否是绝对路径 - Path getFileName() : 返回与调用 Path 对象关联的文件名 - Path getName(int idx) : 返回的指定索引位置 idx 的路径名称 - int getNameCount() : 返回Path 根目录后面元素的数量 - Path getParent() :返回Path对象包含整个路径,不包含 Path 对象指定的文件路径 - Path getRoot() :返回调用 Path 对象的根路径 - Path resolve(Path p) :将相对路径解析为绝对路径 - Path toAbsolutePath() : 作为绝对路径返回调用 Path 对象 - String toString() : 返回调用 Path 对象的字符串表示形式 - */ - @Test - public void test2() { - Path path = Paths.get("e:/nio/hello.txt"); - - System.out.println(path.getParent()); - System.out.println(path.getRoot()); - -// Path newPath = path.resolve("e:/hello.txt"); -// System.out.println(newPath); - - Path path2 = Paths.get("1.jpg"); - Path newPath = path2.toAbsolutePath(); - System.out.println(newPath); - - System.out.println(path.toString()); - } - - @Test - public void test1() { - Path path = Paths.get("e:/", "nio/hello.txt"); - - System.out.println(path.endsWith("hello.txt")); - System.out.println(path.startsWith("e:/")); - - System.out.println(path.isAbsolute()); - System.out.println(path.getFileName()); - - for (int i = 0; i < path.getNameCount(); i++) { - System.out.println(path.getName(i)); - } - } -} diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/io/nio/TestNonBlockingNIO.java b/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/io/nio/TestNonBlockingNIO.java deleted file mode 100644 index d397aff4..00000000 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/io/nio/TestNonBlockingNIO.java +++ /dev/null @@ -1,96 +0,0 @@ -package cn.lastwhisper.jdk5.feature.io.nio; - -import org.junit.Test; - -import java.io.IOException; -import java.net.InetSocketAddress; -import java.nio.ByteBuffer; -import java.nio.channels.SelectionKey; -import java.nio.channels.Selector; -import java.nio.channels.ServerSocketChannel; -import java.nio.channels.SocketChannel; -import java.util.Date; -import java.util.Iterator; -import java.util.Scanner; -/** - * TCP - */ -public class TestNonBlockingNIO { - //客户端 - @Test - public void client() throws IOException { - //1.获取通道 - SocketChannel sChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 9898)); - //2.切换非阻塞模式 - sChannel.configureBlocking(false); - //3.分配指定大小的缓冲区 - ByteBuffer buf = ByteBuffer.allocate(1024); - //4.发送数据给服务端 - Scanner scan = new Scanner(System.in); - while (scan.hasNext()) { - String str = scan.next(); - buf.put((new Date().toString() + "\n" + str).getBytes()); - buf.flip(); - sChannel.write(buf); - buf.clear(); - } - //5.关闭通道 - sChannel.close(); - } - - //服务端 - @Test - public void server() throws IOException { - //1.获取通道 - ServerSocketChannel ssChannel = ServerSocketChannel.open(); - - //2.切换非阻塞式模式 - ssChannel.configureBlocking(false); - - //3.绑定连接 - ssChannel.bind(new InetSocketAddress(9898)); - - //4.获取选择器 - Selector selector = Selector.open(); - - //5.将通道注册到选择器上,并且指定“监听接收事件” - ssChannel.register(selector, SelectionKey.OP_ACCEPT); - - //6.轮询式的获取选择器上已经“准备就绪”的事件 - while (selector.select() > 0) { - - //7.获取当前选择器中所有注册的“选择键(已就绪的监听事件)” - Iterator it = selector.selectedKeys().iterator(); - - while (it.hasNext()) { - //8.获取准备“就绪”的事件 - SelectionKey sk = it.next(); - - //9.判断具体是什么时间准备就绪 - if (sk.isAcceptable()) { - //10.若“接收就绪”,获取客户端连接 - SocketChannel sChannel = ssChannel.accept(); - - //11.切换非阻塞模式 - sChannel.configureBlocking(false); - - //12.将该通道注册到选择器上 - sChannel.register(selector, SelectionKey.OP_READ); - } else if (sk.isReadable()) { - //13.获取当前选择器上“读就绪”状态的通道 - SocketChannel sChannel = (SocketChannel) sk.channel(); - //14.读取数据 - ByteBuffer buf = ByteBuffer.allocate(1024); - int len = 0; - while ((len = sChannel.read(buf)) > 0) { - buf.flip(); - System.out.println(new String(buf.array(), 0, len)); - buf.clear(); - } - } - //15.取消选择键SelectionKey - it.remove(); - } - } - } -} \ No newline at end of file diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/io/nio/TestNonBlockingNIO2.java b/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/io/nio/TestNonBlockingNIO2.java deleted file mode 100644 index 90619e48..00000000 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/io/nio/TestNonBlockingNIO2.java +++ /dev/null @@ -1,59 +0,0 @@ -package cn.lastwhisper.jdk5.feature.io.nio; - -import org.junit.Test; - -import java.io.IOException; -import java.net.InetSocketAddress; -import java.nio.ByteBuffer; -import java.nio.channels.DatagramChannel; -import java.nio.channels.SelectionKey; -import java.nio.channels.Selector; -import java.util.Date; -import java.util.Iterator; -import java.util.Scanner; -/** - * UDP - */ -public class TestNonBlockingNIO2 { - - @Test - public void send() throws IOException { - DatagramChannel dc = DatagramChannel.open(); - dc.configureBlocking(false); - ByteBuffer buf = ByteBuffer.allocate(1024); - Scanner scan = new Scanner(System.in); - while (scan.hasNext()) { - String str = scan.next(); - buf.put((new Date().toString() + "\n" + str).getBytes()); - buf.flip(); - dc.send(buf, new InetSocketAddress("127.0.0.1", 9898)); - buf.clear(); - } - dc.close(); - } - - @Test - public void receive() throws IOException { - DatagramChannel dc = DatagramChannel.open(); - dc.configureBlocking(false); - dc.bind(new InetSocketAddress(9898)); - Selector selector = Selector.open(); - dc.register(selector, SelectionKey.OP_READ); - while (selector.select() > 0) { - Iterator it = selector.selectedKeys().iterator(); - while (it.hasNext()) { - SelectionKey sk = it.next(); - - if (sk.isReadable()) { - ByteBuffer buf = ByteBuffer.allocate(1024); - dc.receive(buf) - ; - buf.flip(); - System.out.println(new String(buf.array(), 0, buf.limit())); - buf.clear(); - } - } - it.remove(); - } - } -} \ No newline at end of file diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/io/nio/v1/BIOServer.java b/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/io/nio/v1/BIOServer.java deleted file mode 100644 index 2bb7559d..00000000 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/io/nio/v1/BIOServer.java +++ /dev/null @@ -1,34 +0,0 @@ -package cn.lastwhisper.jdk5.feature.io.nio.v1; - -import java.io.IOException; -import java.net.InetSocketAddress; -import java.net.ServerSocket; -import java.net.Socket; - -/** - * @author lastwhisper - */ -public class BIOServer { - static byte[] bytes = new byte[1024]; - - public static void main(String[] args) { - try (ServerSocket serverSocket = new ServerSocket();){ - serverSocket.bind(new InetSocketAddress(8080)); - while (true){ - System.out.println("wait conn"); - // 等待连接阻塞 - Socket socket = serverSocket.accept(); - System.out.println("conn success"); - // 等待数据阻塞 - socket.getInputStream().read(bytes); - - System.out.println("data success"); - String content = new String(bytes); - System.out.println(content); - } - - } catch (IOException e) { - e.printStackTrace(); - } - } -} diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/io/nio/v1/Client.java b/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/io/nio/v1/Client.java deleted file mode 100644 index b3912dee..00000000 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/io/nio/v1/Client.java +++ /dev/null @@ -1,25 +0,0 @@ -package cn.lastwhisper.jdk5.feature.io.nio.v1; - -import java.io.IOException; -import java.net.Socket; -import java.util.Scanner; - -/** - * 三个socket - * @author lastwhisper - */ -public class Client { - public static void main(String[] args) { - try (Socket socket = new Socket("127.0.0.1", 8080);) { - // client阻塞 等待数据 - Scanner scanner = new Scanner(System.in); - String txt = scanner.next(); - - socket.getOutputStream().write(txt.getBytes()); - - } catch (IOException e) { - e.printStackTrace(); - } - - } -} diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/io/nio/v2/MockNIOServer.java b/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/io/nio/v2/MockNIOServer.java deleted file mode 100644 index 3576bd3b..00000000 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/io/nio/v2/MockNIOServer.java +++ /dev/null @@ -1,65 +0,0 @@ -package cn.lastwhisper.jdk5.feature.io.nio.v2; - -import java.io.IOException; -import java.net.InetSocketAddress; -import java.nio.ByteBuffer; -import java.nio.channels.ServerSocketChannel; -import java.nio.channels.SocketChannel; -import java.util.ArrayList; -import java.util.List; - -/** - * 单线程并发 - * 应用程序循环 - * @author lastwhisper - */ -public class MockNIOServer { - static List list = new ArrayList<>(); - static ByteBuffer byteBuffer = ByteBuffer.allocate(512); - - public static void main(String[] args) { - try { - ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); - serverSocketChannel.bind(new InetSocketAddress(8080)); - // 设置非阻塞 - serverSocketChannel.configureBlocking(false); - while (true) { - SocketChannel socketChannel = serverSocketChannel.accept(); - if (socketChannel == null) { - try { - Thread.sleep(500); - System.out.println("no conn"); - for (SocketChannel client : list) { - int length = client.read(byteBuffer); - if(length>0){ - byteBuffer.flip(); - // 处理业务 - String content = new String(byteBuffer.array()); - System.out.println(content); - } - } - } catch (InterruptedException e) { - e.printStackTrace(); - } - }else { - System.out.println("conn-----------------------------"); - socketChannel.configureBlocking(false); - list.add(socketChannel); - for (SocketChannel client : list) { - int length = client.read(byteBuffer); - if(length>0){ - byteBuffer.flip(); - // 处理业务 - String content = new String(byteBuffer.array()); - System.out.println(content); - } - } - } - - } - - } catch (IOException e) { - e.printStackTrace(); - } - } -} diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/io/nio/v2/MyNIOServer.java b/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/io/nio/v2/MyNIOServer.java deleted file mode 100644 index a4f17f06..00000000 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/io/nio/v2/MyNIOServer.java +++ /dev/null @@ -1,53 +0,0 @@ -package cn.lastwhisper.jdk5.feature.io.nio.v2; - -import java.io.IOException; -import java.net.InetSocketAddress; -import java.net.ServerSocket; -import java.net.Socket; -import java.util.ArrayList; -import java.util.List; - -/** - * 应用层做轮询 - * @author lastwhisper - */ -public class MyNIOServer { - static byte[] bytes = new byte[1024]; - static List list = new ArrayList<>(); - - public static void main(String[] args) { - try (ServerSocket serverSocket = new ServerSocket();) { - serverSocket.bind(new InetSocketAddress(8080)); - // 设置serverSocket非阻塞 - // serverSocket.setConfigureBlocking(false); - while (true) { - Socket socket = serverSocket.accept(); - if (socket == null) { - System.out.println("没有人连接"); - for (Socket s : list) { - int length = s.getInputStream().read(bytes); - if (length != 0) { - String content = new String(bytes); - System.out.println(content); - } - } - } else { - // 设置Socket非阻塞 - // socket.setConfigureBlocking(false); - list.add(socket); - for (Socket s : list) { - int length = s.getInputStream().read(bytes); - if (length != 0) { - String content = new String(bytes); - System.out.println(content); - } - } - } - - } - - } catch (IOException e) { - e.printStackTrace(); - } - } -} diff --git "a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/io/nio/\345\217\202\350\200\203" "b/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/io/nio/\345\217\202\350\200\203" deleted file mode 100644 index a4263056..00000000 --- "a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/io/nio/\345\217\202\350\200\203" +++ /dev/null @@ -1 +0,0 @@ -https://blog.csdn.net/zxm1306192988/article/details/60581173 diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/io/socket/LengthCalculator.java b/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/io/socket/LengthCalculator.java deleted file mode 100644 index 4ae9b1b6..00000000 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/io/socket/LengthCalculator.java +++ /dev/null @@ -1,39 +0,0 @@ -package cn.lastwhisper.jdk5.feature.io.socket; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.Socket; - -/** - * @author lastwhisper - */ -public class LengthCalculator extends Thread { - private Socket socket; - - public LengthCalculator(Socket socket) { - this.socket = socket; - } - - @Override - public void run() { - // 获取socket的输出流 - // 获取socket的输入流 - try (OutputStream os = socket.getOutputStream(); - InputStream is = socket.getInputStream();) { - int ch = 0; - byte[] buff = new byte[1024]; - // buff主要用来读取输入的内容,存入byte数组,ch读取数组的长度 - ch = is.read(buff); - // 将接收的byte数组转成字符串 - String content = new String(buff, 0, ch); - System.out.println(content); - - os.write(String.valueOf(content.length()).getBytes()); - } catch (IOException e) { - e.printStackTrace(); - } - - } - -} diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/io/socket/TCPServer.java b/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/io/socket/TCPServer.java deleted file mode 100644 index 7b9e48ab..00000000 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/io/socket/TCPServer.java +++ /dev/null @@ -1,24 +0,0 @@ -package cn.lastwhisper.jdk5.feature.io.socket; - -import java.io.IOException; -import java.net.ServerSocket; -import java.net.Socket; - -/** - * @author lastwhisper - */ -public class TCPServer { - public static void main(String[] args) { - try { - ServerSocket ss = new ServerSocket(65000); - while (true) { - // 监听请求 - Socket socket = ss.accept(); - new LengthCalculator(socket).start(); - } - } catch (IOException e) { - e.printStackTrace(); - } - - } -} diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/proxy/Proxy1.java b/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/proxy/Proxy1.java deleted file mode 100644 index da20b74d..00000000 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/proxy/Proxy1.java +++ /dev/null @@ -1,30 +0,0 @@ -package cn.lastwhisper.jdk5.feature.proxy; - -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; -import java.util.Collection; - -/** - * 创建代理类,并查看其方法列表 - * @author lastwhisper - */ -public class Proxy1 { - public static void main(String[] args) throws Exception { - // 代理类 - Class proxyClass = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class); - // 构造方法 - Constructor[] constructors = proxyClass.getConstructors(); - for (Constructor constructor : constructors) { - System.out.println(constructor); - } - // 普通方法 - Method[] methods = proxyClass.getMethods(); - for (Method method : methods) { - System.out.println(method); - } - } - -} - diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/proxy/Proxy2.java b/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/proxy/Proxy2.java deleted file mode 100644 index 51ee13a3..00000000 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/proxy/Proxy2.java +++ /dev/null @@ -1,57 +0,0 @@ -package cn.lastwhisper.jdk5.feature.proxy; - -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; -import java.util.ArrayList; -import java.util.Collection; - -/** - * 创建代理类的实例,并完善InvocationHandler - * @author lastwhisper - */ -public class Proxy2 { - public static void main(String[] args) throws Exception { - // 第一种方法、创建代理对象;使用有参构造 - Class proxyClass = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class); - Constructor constructor = proxyClass.getConstructor(InvocationHandler.class); - Collection proxy1 = (Collection) constructor.newInstance(new InvocationHandler() { - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - return null; - } - }); - proxy1.clear(); - // 为什么待返回值的方法会报错? - // 因为InvocationHandler的invoke方法返回值为null - //proxy1.size(); - - // 第二种方法、创建代理对象;使用Proxy提供的静态方法newProxyInstance - // 参数一:目标增强类的类加载器(用于加载代理类); - // 参数二:目标增强类的接口(代理类实现接口); - // 参数三:InvocationHandler执行增强代码和目标方法 - Collection proxy2 = (Collection) Proxy.newProxyInstance(Collection.class.getClassLoader(), - new Class[]{Collection.class}, - new InvocationHandler() { - ArrayList target = new ArrayList(); - - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - long start = System.currentTimeMillis(); - // 使用反射调用目标对象的方法 - Object retVal = method.invoke(target, args); - long end = System.currentTimeMillis(); - System.out.println("性能监控:" + method.getName() + "方法耗时 " + (end - start)); - // 修改代理类的返回值(过滤器) - // retVal = false; - return retVal; - } - }); - boolean retVal = proxy2.add("普通代理"); - proxy2.add("静态代理"); - proxy2.add("动态代理"); - proxy2.add("CGLIB代理"); - //System.out.println(retVal); - System.out.println(proxy2.size()); - - } -} diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/proxy/aop/Advice.java b/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/proxy/aop/Advice.java deleted file mode 100644 index 51bfd1fe..00000000 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/proxy/aop/Advice.java +++ /dev/null @@ -1,14 +0,0 @@ -package cn.lastwhisper.jdk5.feature.proxy.aop; - -import java.lang.reflect.Method; - -/** - * 方法增强的接口 - */ -public interface Advice { - - void afterMethod(Method method); - - void beforeMethod(Method method); - -} diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/proxy/aop/MonitorAdvice.java b/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/proxy/aop/MonitorAdvice.java deleted file mode 100644 index bce10a23..00000000 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/proxy/aop/MonitorAdvice.java +++ /dev/null @@ -1,25 +0,0 @@ -package cn.lastwhisper.jdk5.feature.proxy.aop; - -import java.lang.reflect.Method; - -/** - * 性能监控 - * @author lastwhisper - */ -public class MonitorAdvice implements Advice { - - private long startTime; - private long endTime; - - public void beforeMethod(Method method) { - startTime = System.nanoTime(); - System.out.println(method.getDeclaringClass() + "." + method.getName() + "函数执行开始."); - } - - public void afterMethod(Method method) { - endTime = System.nanoTime(); - System.out.println(method.getDeclaringClass() + "." + method.getName() + "函数执行结束. 耗时:" + (endTime - startTime)); - } - - -} diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/proxy/aop/Proxy3.java b/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/proxy/aop/Proxy3.java deleted file mode 100644 index 0ab5374d..00000000 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/proxy/aop/Proxy3.java +++ /dev/null @@ -1,43 +0,0 @@ -package cn.lastwhisper.jdk5.feature.proxy.aop; - -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; -import java.util.ArrayList; -import java.util.Collection; - -/** - * 创建代理类的实例,并完善InvocationHandler - * @author lastwhisper - */ -public class Proxy3 { - public static void main(String[] args) throws Exception { - // 查看生成的代理类 - System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true"); - // 原类 - Collection list = new ArrayList(); - // 代理类 - Collection proxyClass = (Collection) getProxy(list, new MonitorAdvice()); - proxyClass.add("1111"); - proxyClass.add("2222"); - proxyClass.add("3333"); - System.out.println(proxyClass.size()); - } - - private static Object getProxy(final Object target, final Advice advice) { - // 目标增强类的类加载器(用于加载代理类); - // 目标增强类的接口(代理类实现接口); - // InvocationHandler执行增强代码和目标方法 - Object proxyClass = Proxy.newProxyInstance(target.getClass().getClassLoader(), - target.getClass().getInterfaces(), - new InvocationHandler() { - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - advice.beforeMethod(method); - Object obj = method.invoke(target, args); - advice.afterMethod(method); - return obj; - } - }); - return proxyClass; - } -} diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/proxy/aopframework/AopFrameworkTest.java b/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/proxy/aopframework/AopFrameworkTest.java deleted file mode 100644 index 1d87fadb..00000000 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/proxy/aopframework/AopFrameworkTest.java +++ /dev/null @@ -1,22 +0,0 @@ -package cn.lastwhisper.jdk5.feature.proxy.aopframework; - -import java.io.InputStream; -import java.util.Collection; - -public class AopFrameworkTest { - - /** - * @param args - */ - public static void main(String[] args) throws Exception { - InputStream ips = AopFrameworkTest.class.getClassLoader().getResourceAsStream("config.properties"); - Object bean = new BeanFactory(ips).getBean("xxx"); - System.out.println(bean.getClass().getName()); - Collection proxyClass = (Collection) bean; - proxyClass.add("1111"); - proxyClass.add("2222"); - proxyClass.add("3333"); - System.out.println(proxyClass.size()); - } - -} diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/proxy/aopframework/BeanFactory.java b/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/proxy/aopframework/BeanFactory.java deleted file mode 100644 index ccb6c2b1..00000000 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/proxy/aopframework/BeanFactory.java +++ /dev/null @@ -1,67 +0,0 @@ -package cn.lastwhisper.jdk5.feature.proxy.aopframework; - -import cn.lastwhisper.jdk5.feature.proxy.aop.Advice; - -import java.io.IOException; -import java.io.InputStream; -import java.util.Properties; - -/** - * - * @author lastwhisper - */ -public class BeanFactory { - Properties props = new Properties(); - - public BeanFactory(InputStream is) { - try { - props.load(is); - } catch (IOException e) { - e.printStackTrace(); - } - } - - /** - * 根据name判断是否增强bean - * - * @param name - * @return java.lang.Object - */ - public Object getBean(String name) { - String className = props.getProperty(name); - Class clazz = null; - Object bean = null; - try { - clazz = Class.forName(className); - bean = clazz.newInstance(); - } catch (ClassNotFoundException e) { - e.printStackTrace(); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } catch (InstantiationException e) { - e.printStackTrace(); - } - // - if (bean instanceof ProxyFactoryBean) { - ProxyFactoryBean proxyFactoryBean = (ProxyFactoryBean) bean; - Advice advice = null; - Object target = null; - try { - advice = (Advice) Class.forName(props.getProperty(name + ".advice")).newInstance(); - target = Class.forName(props.getProperty(name + ".target")).newInstance(); - } catch (InstantiationException e) { - e.printStackTrace(); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } catch (ClassNotFoundException e) { - e.printStackTrace(); - } - //proxyFactoryBean.setAdvice(advice); - //proxyFactoryBean.setTarget(target); - // 代理对象 - return proxyFactoryBean.getProxy(target,advice); - } - return bean; - } - -} diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/proxy/aopframework/ProxyFactoryBean.java b/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/proxy/aopframework/ProxyFactoryBean.java deleted file mode 100644 index ac8f5271..00000000 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/proxy/aopframework/ProxyFactoryBean.java +++ /dev/null @@ -1,30 +0,0 @@ -package cn.lastwhisper.jdk5.feature.proxy.aopframework; - -import cn.lastwhisper.jdk5.feature.proxy.aop.Advice; - -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; - -/** - * - * @author lastwhisper - */ -public class ProxyFactoryBean { - - public Object getProxy(final Object target, final Advice advice) { - - Object proxyClass = Proxy.newProxyInstance(target.getClass().getClassLoader(), - target.getClass().getInterfaces(), - new InvocationHandler() { - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - advice.beforeMethod(method); - Object obj = method.invoke(target, args); - advice.afterMethod(method); - return obj; - } - }); - return proxyClass; - } - -} diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/proxy/myproxy/$MyProxy0.class b/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/proxy/myproxy/$MyProxy0.class deleted file mode 100644 index bb007c93..00000000 Binary files a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/proxy/myproxy/$MyProxy0.class and /dev/null differ diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/proxy/myproxy/$MyProxy0.java b/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/proxy/myproxy/$MyProxy0.java deleted file mode 100644 index 74ee47ad..00000000 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/proxy/myproxy/$MyProxy0.java +++ /dev/null @@ -1 +0,0 @@ -package cn.lastwhisper.jdk5.feature.proxy.myproxy; import java.lang.reflect.Method; public class $MyProxy0 implements cn.lastwhisper.jdk5.feature.proxy.myproxy.Man { MyInvocationHandler h; public $MyProxy0(MyInvocationHandler h) { this.h = h; } public void findObj() throws Throwable { Method method1 = cn.lastwhisper.jdk5.feature.proxy.myproxy.Man.class.getMethod("findObj", new Class[]{}); this.h.invoke(this, method1, null); } } \ No newline at end of file diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/proxy/myproxy/LiuWang.java b/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/proxy/myproxy/LiuWang.java deleted file mode 100644 index 2be50ff5..00000000 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/proxy/myproxy/LiuWang.java +++ /dev/null @@ -1,8 +0,0 @@ -package cn.lastwhisper.jdk5.feature.proxy.myproxy; - -public class LiuWang implements Man { - @Override - public void findObj() throws Throwable { - System.out.println("找个毛 写代码去吧!"); - } -} diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/proxy/myproxy/Man.java b/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/proxy/myproxy/Man.java deleted file mode 100644 index 2d41fd6a..00000000 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/proxy/myproxy/Man.java +++ /dev/null @@ -1,5 +0,0 @@ -package cn.lastwhisper.jdk5.feature.proxy.myproxy; - -public interface Man { - public void findObj() throws Throwable; -} diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/proxy/myproxy/MyClassLoader.java b/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/proxy/myproxy/MyClassLoader.java deleted file mode 100644 index d79a1088..00000000 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/proxy/myproxy/MyClassLoader.java +++ /dev/null @@ -1,41 +0,0 @@ -package cn.lastwhisper.jdk5.feature.proxy.myproxy; - -import org.springframework.util.FileCopyUtils; - -import java.io.File; -import java.io.IOException; - -public class MyClassLoader extends ClassLoader { - private File dir; - private String proxyClassPackage; - - public File getDir() { - return dir; - } - - public String getProxyClassPackage() { - return proxyClassPackage; - } - - public MyClassLoader(String path, String proxyClassPackage) { - this.dir = new File(path); - this.proxyClassPackage = proxyClassPackage; - } - - @Override - protected Class findClass(String name) throws ClassNotFoundException { - if(null != dir){ - File classFile = new File(dir, name + ".class"); - if(classFile.exists()){ - try { - byte[] classBytes = FileCopyUtils.copyToByteArray(classFile); - - return defineClass(proxyClassPackage + "." + name,classBytes,0, classBytes.length); - } catch (IOException e) { - e.printStackTrace(); - } - } - } - return super.findClass(name); - } -} diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/proxy/myproxy/MyHandler.java b/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/proxy/myproxy/MyHandler.java deleted file mode 100644 index 92aa64b5..00000000 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/proxy/myproxy/MyHandler.java +++ /dev/null @@ -1,26 +0,0 @@ -package cn.lastwhisper.jdk5.feature.proxy.myproxy; - -import java.lang.reflect.Method; - -public class MyHandler implements MyInvocationHandler { - private Man man; - - public MyHandler(Man man) { - this.man = man; - } - - @Override - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - before(); - Object invoke = method.invoke(man, null); - after(); - return invoke; - } - - void before(){ - System.out.println("before"); - } - void after(){ - System.out.println("after"); - } -} diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/proxy/myproxy/MyInvocationHandler.java b/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/proxy/myproxy/MyInvocationHandler.java deleted file mode 100644 index 01090fec..00000000 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/proxy/myproxy/MyInvocationHandler.java +++ /dev/null @@ -1,7 +0,0 @@ -package cn.lastwhisper.jdk5.feature.proxy.myproxy; - -import java.lang.reflect.Method; - -public interface MyInvocationHandler { - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable; -} diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/proxy/myproxy/MyProxy.java b/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/proxy/myproxy/MyProxy.java deleted file mode 100644 index d70386f2..00000000 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/proxy/myproxy/MyProxy.java +++ /dev/null @@ -1,89 +0,0 @@ -package cn.lastwhisper.jdk5.feature.proxy.myproxy; - -import org.springframework.util.FileCopyUtils; - -import javax.tools.JavaCompiler; -import javax.tools.StandardJavaFileManager; -import javax.tools.ToolProvider; -import java.io.File; -import java.io.IOException; -import java.lang.reflect.Constructor; -import java.lang.reflect.Method; - -public class MyProxy { - private static final String rt = "\r"; - - public static Object newProxyInstance(MyClassLoader loader, Class interfaces, MyInvocationHandler h) throws IllegalArgumentException { - - if (null == h) { - throw new NullPointerException(); - } - //根据代理接口构造代理类 - Method[] methods = interfaces.getMethods(); - StringBuffer proxyClassString = new StringBuffer(); - proxyClassString.append("package ") - .append(loader.getProxyClassPackage()).append(";").append(rt) - .append("import java.lang.reflect.Method;").append(rt) - .append("public class $MyProxy0 implements ").append(interfaces.getName()).append("{").append(rt) - .append("MyInvocationHandler h;").append(rt) - .append("public $MyProxy0(MyInvocationHandler h){") - .append("this.h = h;}").append(rt) - .append(getMethodString(methods, interfaces)) - .append("}"); - //写入JAVA文件 进行编译 - String filename = loader.getDir() + File.separator + "$MyProxy0.java"; - File myProxyFile = new File(filename); - try { - compile(proxyClassString, myProxyFile); - - //利用自定义的classloader加载 - Class $myProxy0 = loader.findClass("$MyProxy0"); - //$MyProxy0初始化 - Constructor constructor = $myProxy0.getConstructor(MyInvocationHandler.class); - - Object o = constructor.newInstance(h); - - return o; - } catch (Exception e) { - e.printStackTrace(); - } - return null; - } - - private static String getMethodString(Method[] methods, Class interfaces) { - StringBuffer methodStringBuff = new StringBuffer(); - for (Method method : methods) { - methodStringBuff.append("public void ").append(method.getName()) - .append("()").append("throws Throwable{") - .append("Method method1 = ").append(interfaces.getName()) - .append(".class.getMethod(\"").append(method.getName()) - .append("\",new Class[]{});") - .append("this.h.invoke(this,method1,null);}").append(rt); - } - return methodStringBuff.toString(); - } - - /** - * @param proxyClassString 代理类的代码 - * @param myProxyFile 代理类的Java文件 - * @throws IOException - */ - private static void compile(StringBuffer proxyClassString, File myProxyFile) throws IOException { - // in out - FileCopyUtils.copy(proxyClassString.toString().getBytes(), myProxyFile); - // 调用系统编译器 - JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler(); - - StandardJavaFileManager standardJavaFileManager = javaCompiler.getStandardFileManager(null, null, null); - - Iterable javaFileObjects = standardJavaFileManager.getJavaFileObjects(myProxyFile); - - JavaCompiler.CompilationTask task = javaCompiler.getTask(null, standardJavaFileManager, null, null, null, javaFileObjects); - - task.call(); - - standardJavaFileManager.close(); - } - - -} diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/proxy/myproxy/Test.java b/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/proxy/myproxy/Test.java deleted file mode 100644 index 4441daf5..00000000 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/proxy/myproxy/Test.java +++ /dev/null @@ -1,17 +0,0 @@ -package cn.lastwhisper.jdk5.feature.proxy.myproxy; - -public class Test { - public static void main(String[] args) throws Throwable { - Man man = new LiuWang(); - MyHandler myHandler = new MyHandler(man); - Man proxyMan = (Man) MyProxy.newProxyInstance( - new MyClassLoader( - "D:\\code\\GitRepository\\JavaNotes\\java-basic\\jdk5\\src\\main\\java\\cn\\lastwhisper\\jdk5\\feature\\proxy\\myproxy" - ,"cn.lastwhisper.jdk5.feature.proxy.myproxy") - ,Man.class, myHandler); - - - System.out.println(proxyMan.getClass().getName()); - proxyMan.findObj(); - } -} diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/reflect/ReflectForClass.java b/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/reflect/ReflectForClass.java deleted file mode 100644 index 37ee4a1e..00000000 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/reflect/ReflectForClass.java +++ /dev/null @@ -1,22 +0,0 @@ -package cn.lastwhisper.jdk5.feature.reflect; - -/** - * 反射之Class对象 - * @author lastwhisper - */ -public class ReflectForClass { - public static void main(String[] args) throws ClassNotFoundException { - String str1 = "abc"; - Class cls1 = str1.getClass(); - Class cls2 = String.class; - Class cls3 = Class.forName("java.lang.String"); - System.out.println(cls1 == cls2); - System.out.println(cls1 == cls3); - - System.out.println(cls1.isPrimitive()); - System.out.println(int.class.isPrimitive()); - System.out.println(int.class == Integer.class); - System.out.println(int.class == Integer.TYPE); - System.out.println(int[].class.isPrimitive()); - } -} diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/reflect/TestClass.java b/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/reflect/TestClass.java deleted file mode 100644 index 79992ab6..00000000 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/reflect/TestClass.java +++ /dev/null @@ -1,25 +0,0 @@ -package cn.lastwhisper.jdk5.feature.reflect; - -import com.thoughtworks.qdox.JavaDocBuilder; -import com.thoughtworks.qdox.model.JavaSource; - -import java.io.FileNotFoundException; -import java.io.FileReader; - -/** - * @author lastwhisper - */ -public class TestClass { - public static void main(String[] args) throws FileNotFoundException { - String fileFullPath = "D:\\code\\GitRepository\\Code\\java-basic\\jdk5\\src\\main\\java\\cn\\lastwhisper\\jdk5\\feature\\reflect\\TestClass.java"; - JavaDocBuilder builder = new JavaDocBuilder(); - builder.addSource(new FileReader(fileFullPath)); - - JavaSource src = builder.getSources()[0]; - String[] imports = src.getImports(); - - for (String imp : imports) { - System.out.println(imp); - } - } -} diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/serializable/Test.java b/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/serializable/Test.java deleted file mode 100644 index 9f8d1636..00000000 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/serializable/Test.java +++ /dev/null @@ -1,36 +0,0 @@ -package cn.lastwhisper.jdk5.feature.serializable; - -import java.io.*; -/** - * 静态变量序列化 - */ -public class Test implements Serializable { - - private static final long serialVersionUID = 1L; - public static int staticVar = 5; - - public static void main(String[] args) { - try { - //初始时staticVar为5 - ObjectOutputStream out = new ObjectOutputStream( - new FileOutputStream("D:\\result.obj")); - out.writeObject(new Test()); - out.close(); - //序列化后修改为10 - Test.staticVar = 10; - ObjectInputStream oin = new ObjectInputStream(new FileInputStream( - "D:\\result.obj")); - Test t = (Test) oin.readObject(); - oin.close(); - //再读取,通过t.staticVar打印新的值 - // 打印10说明,序列化并没有保存static字段,如果保存了staticVar应该为5 - System.out.println(t.staticVar); - } catch (FileNotFoundException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } catch (ClassNotFoundException e) { - e.printStackTrace(); - } - } -} \ No newline at end of file diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/spi/detail.txt b/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/spi/detail.txt deleted file mode 100644 index 47dec928..00000000 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/spi/detail.txt +++ /dev/null @@ -1,2 +0,0 @@ -spi简单实现:http://www.spring4all.com/article/260 -https://www.jianshu.com/p/46b42f7f593c \ No newline at end of file diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/spi/spi_boy/Boy.java b/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/spi/spi_boy/Boy.java deleted file mode 100644 index 5bec9614..00000000 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/spi/spi_boy/Boy.java +++ /dev/null @@ -1,14 +0,0 @@ -package cn.lastwhisper.jdk5.feature.spi.spi_boy; - -import cn.lastwhisper.jdk5.feature.spi.spi_interface.People; - -/** - * spi-boy/spi-gril: 分别是两个厂商对interface的不同实现,所以他们会依赖于interface项目 - * @author lastwhisper - */ -public class Boy implements People { - @Override - public void sayHello() { - System.out.println("男孩说hello~~~"); - } -} diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/spi/spi_client/Client.java b/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/spi/spi_client/Client.java deleted file mode 100644 index adbdd05a..00000000 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/spi/spi_client/Client.java +++ /dev/null @@ -1,18 +0,0 @@ -package cn.lastwhisper.jdk5.feature.spi.spi_client; - -import cn.lastwhisper.jdk5.feature.spi.spi_interface.People; - -import java.util.ServiceLoader; - -/** - * 用来模拟用户测试, 依赖spi-core和spi-boy/spi-gril(至少一个实现,否则会报错) - * @author lastwhisper - */ -public class Client { - public static void main(String[] args) { - ServiceLoader serviceLoader = ServiceLoader.load(People.class); - for (People people : serviceLoader) { - people.sayHello(); - } - } -} diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/spi/spi_core/PeopleFactory.java b/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/spi/spi_core/PeopleFactory.java deleted file mode 100644 index d4020792..00000000 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/spi/spi_core/PeopleFactory.java +++ /dev/null @@ -1,24 +0,0 @@ -package cn.lastwhisper.jdk5.feature.spi.spi_core; - -import cn.lastwhisper.jdk5.feature.spi.spi_interface.People; - -import java.util.Iterator; -import java.util.ServiceLoader; - -/** - * spi-core: 是提供给用户使用的核心jar文件, - * 同样依赖于interface项目, 用户使用时需要引入spi-core.jar和厂商具体实现的jar - * @author lastwhisper - */ -public class PeopleFactory { - public void invoker(){ - ServiceLoader services = ServiceLoader.load(People.class); - Iterator iterator = services.iterator(); - boolean notFound = true; - while (iterator.hasNext()){ - notFound = false; - People people = iterator.next(); - people.sayHello(); - } - } -} diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/spi/spi_gril/Gril.java b/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/spi/spi_gril/Gril.java deleted file mode 100644 index de41525c..00000000 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/spi/spi_gril/Gril.java +++ /dev/null @@ -1,14 +0,0 @@ -package cn.lastwhisper.jdk5.feature.spi.spi_gril; - -import cn.lastwhisper.jdk5.feature.spi.spi_interface.People; - -/** - * spi-boy/spi-gril: 分别是两个厂商对interface的不同实现,所以他们会依赖于interface项目 - * @author lastwhisper - */ -public class Gril implements People { - @Override - public void sayHello() { - System.out.println("女孩说hello~~~"); - } -} diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/spi/spi_interface/People.java b/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/spi/spi_interface/People.java deleted file mode 100644 index 57604eb4..00000000 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/spi/spi_interface/People.java +++ /dev/null @@ -1,9 +0,0 @@ -package cn.lastwhisper.jdk5.feature.spi.spi_interface; - -/** - * spi-interface: 是针对厂商定义的接口项目,只提供接口,不提供实现 - * @author lastwhisper - */ -public interface People { - void sayHello(); -} diff --git a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/throwable/ErrorAndException.java b/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/throwable/ErrorAndException.java deleted file mode 100644 index 5af3ad27..00000000 --- a/java-basic/jdk5/src/main/java/cn/lastwhisper/jdk5/feature/throwable/ErrorAndException.java +++ /dev/null @@ -1,26 +0,0 @@ -package cn.lastwhisper.jdk5.feature.throwable; - -import java.io.FileNotFoundException; - -/** - * 异常 - * @author lastwhisper - */ -public class ErrorAndException { - private void throwError(){ - throw new StackOverflowError(); - } - private void throwRuntimeException(){ - throw new RuntimeException(); - } - private void throwCheckedException() throws FileNotFoundException { - throw new FileNotFoundException(); - } - - public static void main(String[] args) throws FileNotFoundException { - ErrorAndException errorAndException = new ErrorAndException(); - errorAndException.throwError(); - errorAndException.throwRuntimeException(); - errorAndException.throwCheckedException(); - } -} diff --git a/java-basic/jdk5/src/main/resources/META-INF/services/cn.lastwhisper.jdk5.feature.spi.spi_interface.People b/java-basic/jdk5/src/main/resources/META-INF/services/cn.lastwhisper.jdk5.feature.spi.spi_interface.People deleted file mode 100644 index efd96406..00000000 --- a/java-basic/jdk5/src/main/resources/META-INF/services/cn.lastwhisper.jdk5.feature.spi.spi_interface.People +++ /dev/null @@ -1,2 +0,0 @@ -cn.lastwhisper.jdk5.feature.spi.spi_boy.Boy -cn.lastwhisper.jdk5.feature.spi.spi_gril.Gril \ No newline at end of file diff --git a/java-basic/jdk5/src/main/resources/config.properties b/java-basic/jdk5/src/main/resources/config.properties deleted file mode 100644 index 18b90cee..00000000 --- a/java-basic/jdk5/src/main/resources/config.properties +++ /dev/null @@ -1,7 +0,0 @@ -# -className=cn.lastwhisper.jdk5.feature.reflect.TestArrayArguments -# ̬ -#xxx=java.util.ArrayList -xxx=cn.lastwhisper.jdk5.feature.proxy.aopframework.ProxyFactoryBean -xxx.target=java.util.ArrayList -xxx.advice=cn.lastwhisper.jdk5.feature.proxy.aop.MonitorAdvice diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/AutoBox.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/AutoBox.class deleted file mode 100644 index 3c9d5dce..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/AutoBox.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/HashCode$Person.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/HashCode$Person.class deleted file mode 100644 index 4913be66..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/HashCode$Person.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/HashCode.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/HashCode.class deleted file mode 100644 index 5e9db324..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/HashCode.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/StaticImport.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/StaticImport.class deleted file mode 100644 index d25cff68..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/StaticImport.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/VariableParameter.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/VariableParameter.class deleted file mode 100644 index 41ab7d2f..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/VariableParameter.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/annotation/AnnotationTest.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/annotation/AnnotationTest.class deleted file mode 100644 index 51da9f41..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/annotation/AnnotationTest.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/annotation/Formatter.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/annotation/Formatter.class deleted file mode 100644 index a3b59819..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/annotation/Formatter.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/annotation/Level.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/annotation/Level.class deleted file mode 100644 index ae1a16dd..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/annotation/Level.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/annotation/MetaAnnotation.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/annotation/MetaAnnotation.class deleted file mode 100644 index 48c1909d..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/annotation/MetaAnnotation.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/annotation/MyAnnotation.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/annotation/MyAnnotation.class deleted file mode 100644 index 49693f02..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/annotation/MyAnnotation.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/annotation/UseAnnotation.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/annotation/UseAnnotation.class deleted file mode 100644 index 86d9e287..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/annotation/UseAnnotation.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/classloader/ClassLoaderObject.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/classloader/ClassLoaderObject.class deleted file mode 100644 index 9c4f3ef9..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/classloader/ClassLoaderObject.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/classloader/ClassLoaderStructure.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/classloader/ClassLoaderStructure.class deleted file mode 100644 index e8b7d46e..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/classloader/ClassLoaderStructure.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/classloader/ClassLoaderUnique$1.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/classloader/ClassLoaderUnique$1.class deleted file mode 100644 index 45ca39f1..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/classloader/ClassLoaderUnique$1.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/classloader/ClassLoaderUnique.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/classloader/ClassLoaderUnique.class deleted file mode 100644 index d5e98f86..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/classloader/ClassLoaderUnique.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/classloader/DemoObj.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/classloader/DemoObj.class deleted file mode 100644 index 404ec85d..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/classloader/DemoObj.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/classloader/LoadDiff.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/classloader/LoadDiff.class deleted file mode 100644 index 5001232d..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/classloader/LoadDiff.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/classloader/custom/ClassLoader1.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/classloader/custom/ClassLoader1.class deleted file mode 100644 index 981e0199..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/classloader/custom/ClassLoader1.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/classloader/custom/Test.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/classloader/custom/Test.class deleted file mode 100644 index 822b3d77..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/classloader/custom/Test.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/classloader/encrypt/ClassLoader2.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/classloader/encrypt/ClassLoader2.class deleted file mode 100644 index f7429402..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/classloader/encrypt/ClassLoader2.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/classloader/encrypt/ClassLoaderAttachment.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/classloader/encrypt/ClassLoaderAttachment.class deleted file mode 100644 index 2bc49743..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/classloader/encrypt/ClassLoaderAttachment.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/classloader/hotdeploy/ClassLoaderHotDeploy$1.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/classloader/hotdeploy/ClassLoaderHotDeploy$1.class deleted file mode 100644 index 97fb56a7..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/classloader/hotdeploy/ClassLoaderHotDeploy$1.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/classloader/hotdeploy/ClassLoaderHotDeploy.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/classloader/hotdeploy/ClassLoaderHotDeploy.class deleted file mode 100644 index 1211d6cc..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/classloader/hotdeploy/ClassLoaderHotDeploy.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/classloader/hotdeploy/HotCodeTest.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/classloader/hotdeploy/HotCodeTest.class deleted file mode 100644 index 54860f95..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/classloader/hotdeploy/HotCodeTest.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/classloader/hotdeploy/MyClassLoader.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/classloader/hotdeploy/MyClassLoader.class deleted file mode 100644 index 95ac8925..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/classloader/hotdeploy/MyClassLoader.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/collection/ArraysAsList.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/collection/ArraysAsList.class deleted file mode 100644 index 14b64c21..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/collection/ArraysAsList.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/collection/LRUCache.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/collection/LRUCache.class deleted file mode 100644 index 0e7f9d9a..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/collection/LRUCache.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/collection/SafeHashMapDemo.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/collection/SafeHashMapDemo.class deleted file mode 100644 index 5c082f98..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/collection/SafeHashMapDemo.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/collection/TestArrayListGrow.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/collection/TestArrayListGrow.class deleted file mode 100644 index 545b30c3..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/collection/TestArrayListGrow.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/collection/TestList$modification.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/collection/TestList$modification.class deleted file mode 100644 index c9010afb..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/collection/TestList$modification.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/collection/TestList.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/collection/TestList.class deleted file mode 100644 index 7f9e7578..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/collection/TestList.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/collection/TestMap$Person.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/collection/TestMap$Person.class deleted file mode 100644 index 9b8b404d..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/collection/TestMap$Person.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/collection/TestMap.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/collection/TestMap.class deleted file mode 100644 index 5fb9d8cc..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/collection/TestMap.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/enumtest/EnumTest$1.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/enumtest/EnumTest$1.class deleted file mode 100644 index f549ab8d..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/enumtest/EnumTest$1.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/enumtest/EnumTest$TrafficLamp$1.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/enumtest/EnumTest$TrafficLamp$1.class deleted file mode 100644 index cd65c75a..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/enumtest/EnumTest$TrafficLamp$1.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/enumtest/EnumTest$TrafficLamp$2.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/enumtest/EnumTest$TrafficLamp$2.class deleted file mode 100644 index f87aed99..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/enumtest/EnumTest$TrafficLamp$2.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/enumtest/EnumTest$TrafficLamp$3.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/enumtest/EnumTest$TrafficLamp$3.class deleted file mode 100644 index 4fb2928f..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/enumtest/EnumTest$TrafficLamp$3.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/enumtest/EnumTest$TrafficLamp.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/enumtest/EnumTest$TrafficLamp.class deleted file mode 100644 index 02b37223..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/enumtest/EnumTest$TrafficLamp.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/enumtest/EnumTest$WeekDay2.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/enumtest/EnumTest$WeekDay2.class deleted file mode 100644 index 597be1eb..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/enumtest/EnumTest$WeekDay2.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/enumtest/EnumTest.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/enumtest/EnumTest.class deleted file mode 100644 index 988c0cce..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/enumtest/EnumTest.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/enumtest/WeekDay.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/enumtest/WeekDay.class deleted file mode 100644 index 63129303..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/enumtest/WeekDay.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/enumtest/WeekDay1$1.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/enumtest/WeekDay1$1.class deleted file mode 100644 index 571d3a48..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/enumtest/WeekDay1$1.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/enumtest/WeekDay1$2.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/enumtest/WeekDay1$2.class deleted file mode 100644 index 87a1337b..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/enumtest/WeekDay1$2.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/enumtest/WeekDay1$3.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/enumtest/WeekDay1$3.class deleted file mode 100644 index b95a5d14..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/enumtest/WeekDay1$3.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/enumtest/WeekDay1$4.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/enumtest/WeekDay1$4.class deleted file mode 100644 index b463e996..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/enumtest/WeekDay1$4.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/enumtest/WeekDay1$5.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/enumtest/WeekDay1$5.class deleted file mode 100644 index b5dc15f0..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/enumtest/WeekDay1$5.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/enumtest/WeekDay1$6.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/enumtest/WeekDay1$6.class deleted file mode 100644 index 15c39e31..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/enumtest/WeekDay1$6.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/enumtest/WeekDay1$7.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/enumtest/WeekDay1$7.class deleted file mode 100644 index 8f224f34..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/enumtest/WeekDay1$7.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/enumtest/WeekDay1.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/enumtest/WeekDay1.class deleted file mode 100644 index 23ededfb..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/enumtest/WeekDay1.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/generic/Generic1.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/generic/Generic1.class deleted file mode 100644 index 046c14a3..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/generic/Generic1.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/generic/Generic2.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/generic/Generic2.class deleted file mode 100644 index 40df25df..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/generic/Generic2.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/generic/Generic3.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/generic/Generic3.class deleted file mode 100644 index 9bbafdaf..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/generic/Generic3.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/generic/Generic4/BaseDao.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/generic/Generic4/BaseDao.class deleted file mode 100644 index caf88475..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/generic/Generic4/BaseDao.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/generic/Generic4/BaseDaoImpl.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/generic/Generic4/BaseDaoImpl.class deleted file mode 100644 index 33bbaf14..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/generic/Generic4/BaseDaoImpl.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/generic/Generic4/Client.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/generic/Generic4/Client.class deleted file mode 100644 index 52da1561..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/generic/Generic4/Client.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/generic/Generic4/Person.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/generic/Generic4/Person.class deleted file mode 100644 index f8cc40f0..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/generic/Generic4/Person.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/generic/Generic4/PersonDao.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/generic/Generic4/PersonDao.class deleted file mode 100644 index ca0e55e5..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/generic/Generic4/PersonDao.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/generic/Generic4/PersonDaoImpl.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/generic/Generic4/PersonDaoImpl.class deleted file mode 100644 index c09a02c4..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/generic/Generic4/PersonDaoImpl.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/introspection/IntrospectorTest.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/introspection/IntrospectorTest.class deleted file mode 100644 index 0a483466..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/introspection/IntrospectorTest.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/introspection/Point.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/introspection/Point.class deleted file mode 100644 index b1f074c5..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/introspection/Point.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/io/bio/IODecorator.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/io/bio/IODecorator.class deleted file mode 100644 index 20d3657e..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/io/bio/IODecorator.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/io/nio/TestBlockingNIO.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/io/nio/TestBlockingNIO.class deleted file mode 100644 index 3db0f2fb..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/io/nio/TestBlockingNIO.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/io/nio/TestBlockingNIO2.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/io/nio/TestBlockingNIO2.class deleted file mode 100644 index 05baf9f1..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/io/nio/TestBlockingNIO2.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/io/nio/TestBuffer.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/io/nio/TestBuffer.class deleted file mode 100644 index 6d53868b..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/io/nio/TestBuffer.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/io/nio/TestChannel.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/io/nio/TestChannel.class deleted file mode 100644 index 723acda6..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/io/nio/TestChannel.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/io/nio/TestNIO_2.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/io/nio/TestNIO_2.class deleted file mode 100644 index 639942b9..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/io/nio/TestNIO_2.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/io/nio/TestNonBlockingNIO.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/io/nio/TestNonBlockingNIO.class deleted file mode 100644 index 992340c5..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/io/nio/TestNonBlockingNIO.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/io/nio/TestNonBlockingNIO2.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/io/nio/TestNonBlockingNIO2.class deleted file mode 100644 index b141513f..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/io/nio/TestNonBlockingNIO2.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/io/nio/TestPipe.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/io/nio/TestPipe.class deleted file mode 100644 index cf4e2d44..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/io/nio/TestPipe.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/io/nio/v1/BIOServer.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/io/nio/v1/BIOServer.class deleted file mode 100644 index 9fd4ba36..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/io/nio/v1/BIOServer.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/io/nio/v1/Client.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/io/nio/v1/Client.class deleted file mode 100644 index c6174633..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/io/nio/v1/Client.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/io/nio/v2/MockNIOServer.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/io/nio/v2/MockNIOServer.class deleted file mode 100644 index f18560ee..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/io/nio/v2/MockNIOServer.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/io/nio/v2/MyNIOServer.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/io/nio/v2/MyNIOServer.class deleted file mode 100644 index 4eeab65c..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/io/nio/v2/MyNIOServer.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/io/nio/v3/NIOClient.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/io/nio/v3/NIOClient.class deleted file mode 100644 index a9f5d7e7..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/io/nio/v3/NIOClient.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/io/nio/v3/NIOServer.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/io/nio/v3/NIOServer.class deleted file mode 100644 index 1bd71399..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/io/nio/v3/NIOServer.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/io/socket/LengthCalculator.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/io/socket/LengthCalculator.class deleted file mode 100644 index 1b6f5e53..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/io/socket/LengthCalculator.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/io/socket/TCPClient.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/io/socket/TCPClient.class deleted file mode 100644 index ff0263d7..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/io/socket/TCPClient.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/io/socket/TCPServer.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/io/socket/TCPServer.class deleted file mode 100644 index fa2d6e79..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/io/socket/TCPServer.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/io/socket/UDPClient.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/io/socket/UDPClient.class deleted file mode 100644 index 568f3d58..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/io/socket/UDPClient.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/io/socket/UDPServer.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/io/socket/UDPServer.class deleted file mode 100644 index 22e60657..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/io/socket/UDPServer.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/proxy/Proxy1.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/proxy/Proxy1.class deleted file mode 100644 index 1901ea0c..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/proxy/Proxy1.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/proxy/Proxy2$1.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/proxy/Proxy2$1.class deleted file mode 100644 index 480a7ce6..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/proxy/Proxy2$1.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/proxy/Proxy2$2.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/proxy/Proxy2$2.class deleted file mode 100644 index ca62b2ea..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/proxy/Proxy2$2.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/proxy/Proxy2.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/proxy/Proxy2.class deleted file mode 100644 index 90c8d212..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/proxy/Proxy2.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/proxy/aop/Advice.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/proxy/aop/Advice.class deleted file mode 100644 index 417da41a..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/proxy/aop/Advice.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/proxy/aop/MonitorAdvice.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/proxy/aop/MonitorAdvice.class deleted file mode 100644 index 9bbfe215..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/proxy/aop/MonitorAdvice.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/proxy/aop/Proxy3$1.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/proxy/aop/Proxy3$1.class deleted file mode 100644 index b0080f80..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/proxy/aop/Proxy3$1.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/proxy/aop/Proxy3.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/proxy/aop/Proxy3.class deleted file mode 100644 index 7619de02..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/proxy/aop/Proxy3.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/proxy/aopframework/AopFrameworkTest.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/proxy/aopframework/AopFrameworkTest.class deleted file mode 100644 index 82756888..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/proxy/aopframework/AopFrameworkTest.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/proxy/aopframework/BeanFactory.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/proxy/aopframework/BeanFactory.class deleted file mode 100644 index 48656557..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/proxy/aopframework/BeanFactory.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/proxy/aopframework/ProxyFactoryBean$1.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/proxy/aopframework/ProxyFactoryBean$1.class deleted file mode 100644 index db093ae3..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/proxy/aopframework/ProxyFactoryBean$1.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/proxy/aopframework/ProxyFactoryBean.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/proxy/aopframework/ProxyFactoryBean.class deleted file mode 100644 index f727b875..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/proxy/aopframework/ProxyFactoryBean.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/proxy/myproxy/$MyProxy0.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/proxy/myproxy/$MyProxy0.class deleted file mode 100644 index 15f4c24a..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/proxy/myproxy/$MyProxy0.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/proxy/myproxy/LiuWang.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/proxy/myproxy/LiuWang.class deleted file mode 100644 index 0704a997..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/proxy/myproxy/LiuWang.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/proxy/myproxy/Man.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/proxy/myproxy/Man.class deleted file mode 100644 index beb3d947..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/proxy/myproxy/Man.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/proxy/myproxy/MyClassLoader.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/proxy/myproxy/MyClassLoader.class deleted file mode 100644 index 0956437e..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/proxy/myproxy/MyClassLoader.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/proxy/myproxy/MyHandler.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/proxy/myproxy/MyHandler.class deleted file mode 100644 index 1e92df7d..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/proxy/myproxy/MyHandler.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/proxy/myproxy/MyInvocationHandler.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/proxy/myproxy/MyInvocationHandler.class deleted file mode 100644 index e9eced75..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/proxy/myproxy/MyInvocationHandler.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/proxy/myproxy/MyProxy.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/proxy/myproxy/MyProxy.class deleted file mode 100644 index 5a21552a..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/proxy/myproxy/MyProxy.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/proxy/myproxy/Test.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/proxy/myproxy/Test.class deleted file mode 100644 index b1c1576e..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/proxy/myproxy/Test.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/reflect/ReflectExecutMain.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/reflect/ReflectExecutMain.class deleted file mode 100644 index 935a58ca..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/reflect/ReflectExecutMain.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/reflect/ReflectForClass.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/reflect/ReflectForClass.class deleted file mode 100644 index a5fbf57c..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/reflect/ReflectForClass.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/reflect/ReflectForConstructor.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/reflect/ReflectForConstructor.class deleted file mode 100644 index 0ccc9792..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/reflect/ReflectForConstructor.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/reflect/ReflectForField.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/reflect/ReflectForField.class deleted file mode 100644 index 7a257b81..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/reflect/ReflectForField.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/reflect/ReflectForMethod.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/reflect/ReflectForMethod.class deleted file mode 100644 index ee83e7fd..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/reflect/ReflectForMethod.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/reflect/ReflectPoint.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/reflect/ReflectPoint.class deleted file mode 100644 index 21975753..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/reflect/ReflectPoint.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/reflect/ReflectToArray.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/reflect/ReflectToArray.class deleted file mode 100644 index e0560bb9..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/reflect/ReflectToArray.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/reflect/ReflectUpdateField.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/reflect/ReflectUpdateField.class deleted file mode 100644 index 3c03199f..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/reflect/ReflectUpdateField.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/reflect/TestArrayArguments.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/reflect/TestArrayArguments.class deleted file mode 100644 index 46a7c1e6..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/reflect/TestArrayArguments.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/reflect/TestClass.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/reflect/TestClass.class deleted file mode 100644 index 0911d4aa..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/reflect/TestClass.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/serializable/A.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/serializable/A.class deleted file mode 100644 index e0d7cc00..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/serializable/A.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/serializable/B.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/serializable/B.class deleted file mode 100644 index 504c16af..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/serializable/B.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/serializable/Test.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/serializable/Test.class deleted file mode 100644 index 04d498c5..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/serializable/Test.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/serializable/Test2.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/serializable/Test2.class deleted file mode 100644 index 0258b06e..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/serializable/Test2.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/serializable/Test3.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/serializable/Test3.class deleted file mode 100644 index b9a52891..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/serializable/Test3.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/spi/spi_boy/Boy.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/spi/spi_boy/Boy.class deleted file mode 100644 index fe428076..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/spi/spi_boy/Boy.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/spi/spi_client/Client.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/spi/spi_client/Client.class deleted file mode 100644 index d7a59776..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/spi/spi_client/Client.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/spi/spi_core/PeopleFactory.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/spi/spi_core/PeopleFactory.class deleted file mode 100644 index 294b34c6..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/spi/spi_core/PeopleFactory.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/spi/spi_gril/Gril.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/spi/spi_gril/Gril.class deleted file mode 100644 index df70463b..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/spi/spi_gril/Gril.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/spi/spi_interface/People.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/spi/spi_interface/People.class deleted file mode 100644 index 778463c1..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/spi/spi_interface/People.class and /dev/null differ diff --git a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/throwable/ErrorAndException.class b/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/throwable/ErrorAndException.class deleted file mode 100644 index bb4384ef..00000000 Binary files a/java-basic/jdk5/target/classes/cn/lastwhisper/jdk5/feature/throwable/ErrorAndException.class and /dev/null differ diff --git a/java-basic/jdk8/pom.xml b/java-basic/jdk8/pom.xml deleted file mode 100644 index 2f89273a..00000000 --- a/java-basic/jdk8/pom.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - java-basic - cn.lastwhisper - 1.0-SNAPSHOT - - 4.0.0 - - cn.lastwhisper - jdk8 - - - \ No newline at end of file diff --git a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/annotation/MyAnnotation.java b/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/annotation/MyAnnotation.java deleted file mode 100644 index ea240b5d..00000000 --- a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/annotation/MyAnnotation.java +++ /dev/null @@ -1,15 +0,0 @@ -package cn.lastwhisper.jdk8.annotation; - -import java.lang.annotation.Repeatable; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.*; - -@Repeatable(MyAnnotations.class)//指定重复注解的容器 -@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, TYPE_PARAMETER})//可以修饰的目标 -@Retention(RetentionPolicy.RUNTIME)//生命周期 -public @interface MyAnnotation { - String value() default "java"; -} \ No newline at end of file diff --git a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/lambda/Employee.java b/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/lambda/Employee.java deleted file mode 100644 index 893470f3..00000000 --- a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/lambda/Employee.java +++ /dev/null @@ -1,102 +0,0 @@ -package cn.lastwhisper.jdk8.lambda; - -import java.util.Objects; - -public class Employee { - - private Integer id; - private String name; - private Integer age; - private double salary; - - public Employee() { - } - - public Employee(Integer id) { - this.id = id; - } - - public Employee(String name) { - this.name = name; - } - - public Employee(String name, Integer age) { - this.name = name; - this.age = age; - } - - public Employee(String name, Integer age, double salary) { - this.name = name; - this.age = age; - this.salary = salary; - } - - public Employee(Integer id, String name, Integer age, double salary) { - this.id = id; - this.name = name; - this.age = age; - this.salary = salary; - } - - public Integer getId() { - return id; - } - - public void setId(Integer id) { - this.id = id; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public Integer getAge() { - return age; - } - - public void setAge(Integer age) { - this.age = age; - } - - public double getSalary() { - return salary; - } - - public void setSalary(double salary) { - this.salary = salary; - } - - public String show() { - return "测试方法引用!"; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Employee employee = (Employee) o; - return id.equals(employee.id) && - age.equals(employee.age) && - Double.compare(employee.salary, salary) == 0 && - Objects.equals(name, employee.name); - } - - @Override - public int hashCode() { - return Objects.hash(id, name, age, salary); - } - - @Override - public String toString() { - return "Employee [id=" + id + ", name=" + name + ", age=" + age + ", salary=" + salary + "]"; - } - -} diff --git a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/lambda/TestLambda.java b/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/lambda/TestLambda.java deleted file mode 100644 index 423c59ac..00000000 --- a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/lambda/TestLambda.java +++ /dev/null @@ -1,137 +0,0 @@ -package cn.lastwhisper.jdk8.lambda; - -import cn.lastwhisper.jdk8.lambda.strategy.EmployeeAgeFilter; -import cn.lastwhisper.jdk8.lambda.strategy.EmployeeSalaryFilter; -import cn.lastwhisper.jdk8.lambda.strategy.Filter; -import org.junit.Test; - -import java.util.*; - -/** - * @author lastwhisper - */ -public class TestLambda { - List employees = Arrays.asList( - new Employee("张三", 18, 9496.2), - new Employee("李四", 52, 2396.2), - new Employee("王五", 56, 996.2), - new Employee("赵六", 38, 940.2) - ); - - // 原来匿名内部类 - @Test - public void testInnerClass() { - Comparator comparator = new Comparator() { - @Override - public int compare(Integer o1, Integer o2) { - return 0; - } - }; - - TreeSet treeSet = new TreeSet<>(comparator); - } - - // 将匿名内部类优化为lambda表达式 - @Test - public void testLambda() { - Comparator comparator = (o1, o2) -> Integer.compare(o1, o2); - TreeSet treeSet = new TreeSet<>(comparator); - } - - // 传统方式进行条件过滤 - @Test - public void test3() { - //需求:获取当前公司中员工年龄大于35的员工信息 - List emps = filterEmployeesByAge(employees); - for (Employee e : emps) { - System.out.println(e); - } - System.out.println("---------------------"); - - //需求:获取当前公司中员工工资大于2000的员工信息 - List emps2 = filterEmployeesBySalary(employees); - for (Employee e : emps2) { - System.out.println(e); - } - } - - public List filterEmployeesByAge(List list) { - List emps = new ArrayList<>(); - for (Employee emp : list) { - if (emp.getAge() >= 35) { - emps.add(emp); - } - } - return emps; - } - - public List filterEmployeesBySalary(List list) { - List emps = new ArrayList<>(); - for (Employee emp : list) { - if (emp.getSalary() >= 2000) { - emps.add(emp); - } - } - return emps; - } - - // test3 优化方式一:策略设计模式 - @Test - public void test4() { - List emps = filterEmployees(employees, new EmployeeAgeFilter()); - for (Employee e : emps) { - System.out.println(e); - } - System.out.println("---------------------"); - List emps2 = filterEmployees(employees, new EmployeeSalaryFilter()); - for (Employee e : emps2) { - System.out.println(e); - } - } - - public List filterEmployees(List list, Filter filter) { - List emps = new ArrayList(); - for (Employee emp : list) { - if (filter.eqCondition(emp)) { - emps.add(emp); - } - } - return emps; - } - - // test3 优化方式二:匿名内部类 - @Test - public void test5() { - List list = filterEmployees(employees, new Filter() { - @Override - public boolean eqCondition(Employee t) { - return t.getSalary() >= 2000; - } - }); - for (Employee employee : list) { - System.out.println(employee); - } - } - - // test3 优化方式三:Lambda表达式 - @Test - public void test6() { - List list = filterEmployees(employees, (e) -> e.getSalary() >= 2000); - list.forEach(System.out::println); - } - - // test3 优化方式四:stream API - @Test - public void test7(){ - employees.stream() - .filter((e)->e.getSalary()>=2000) - .forEach(System.out::println); - System.out.println("------------------"); - employees.stream() - .map(Employee::getName) - .forEach(System.out::println); - } - - - -} diff --git a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/lambda/example/MyFun2.java b/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/lambda/example/MyFun2.java deleted file mode 100644 index 80415443..00000000 --- a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/lambda/example/MyFun2.java +++ /dev/null @@ -1,11 +0,0 @@ -package cn.lastwhisper.jdk8.lambda.example; - -/** - * @author lastwhisper - */ -@FunctionalInterface -public interface MyFun2 { - - public String getValue(String str); - -} diff --git a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/lambda/example/MyFun3.java b/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/lambda/example/MyFun3.java deleted file mode 100644 index c5690098..00000000 --- a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/lambda/example/MyFun3.java +++ /dev/null @@ -1,8 +0,0 @@ -package cn.lastwhisper.jdk8.lambda.example; - -@FunctionalInterface -public interface MyFun3 { - - public R operation(T t1, T t2); - -} diff --git a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/lambda/example/TestLambda.java b/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/lambda/example/TestLambda.java deleted file mode 100644 index 6bd36582..00000000 --- a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/lambda/example/TestLambda.java +++ /dev/null @@ -1,93 +0,0 @@ -package cn.lastwhisper.jdk8.lambda.example; - -import cn.lastwhisper.jdk8.lambda.Employee; -import org.junit.Test; - -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -/** - * @author lastwhisper - */ -public class TestLambda { - - List emps = Arrays.asList( - new Employee(101, "a", 18, 9999.99), - new Employee(102, "b", 59, 6666.66), - new Employee(103, "c", 28, 3333.33), - new Employee(104, "d", 8, 7777.77), - new Employee(105, "e", 38, 5555.55) - ); - - /** - * 调用Collections.sort()方法,通过定制排序, - * 比较两个Employee(先按年龄比,年龄相同按姓名比),使用Lambda表达式作为参数传递。 - */ - @Test - public void test1() { - //Collections.sort(emps, new Comparator() { - // @Override - // public int compare(Employee o1, Employee o2) { - // if (o1.getAge() == o2.getAge()) { - // return o1.getName().compareTo(o2.getName()); - // } - // return o1.getAge() - o2.getAge(); - // } - //}); - - Collections.sort(emps, (o1, o2) -> { - if (o1.getAge() == o2.getAge()) { - return o1.getName().compareTo(o2.getName()); - } - return o1.getAge() - o2.getAge(); - }); - for (Employee emp : emps) { - System.out.println(emp); - } - } - - /** - * (1)声明函数式接口,接口中声明抽象方法:public String getValue(String str); - * (2)声明类LambdaTest,类中编写方法使用接口作为参数,将一个字符串转换成大写,并作为方法的返回值。 - * (3)再将一个字符串的第2个到第4个索引位置进行截取子串。 - */ - @Test - public void test2() { - String str = "abcde"; - System.out.println(bridge(str, x -> x.toUpperCase())); - System.out.println(bridge(str, x -> x.substring(2, 4))); - } - - public String bridge(String str, MyFun2 mf) { - return mf.getValue(str); - } - - /** - * (1)声明一个带两个泛型的函数式接口,泛型类型为 : T 为参数,R 为返回值。 - * (2)接口中声明对应抽象方法 - * (3)在LambdaTest类中声明方法,使用接口作为参数,计算两个long型参数的和。 - * (4)再计算两个long型参数的乘积 - */ - @Test - public void test3() { - Long num1 = 10l; - Long num2 = 15l; - System.out.println(bridge2(num1, num2, (x, y) -> x + y)); - System.out.println(bridge2(num1, num2, (x, y) -> x * y)); - } - - public Long bridge2(Long num1, Long num2, MyFun3 mf) { - return mf.operation(num1, num2); - } - - /** - * - */ - @Test - public void test4() { - - } - - -} diff --git a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/lambda/strategy/EmployeeAgeFilter.java b/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/lambda/strategy/EmployeeAgeFilter.java deleted file mode 100644 index f8237951..00000000 --- a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/lambda/strategy/EmployeeAgeFilter.java +++ /dev/null @@ -1,13 +0,0 @@ -package cn.lastwhisper.jdk8.lambda.strategy; - -import cn.lastwhisper.jdk8.lambda.Employee; - -/** - * @author lastwhisper - */ -public class EmployeeAgeFilter implements Filter { - @Override - public boolean eqCondition(Employee employee) { - return employee.getAge() >= 35; - } -} diff --git a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/lambda/strategy/EmployeeSalaryFilter.java b/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/lambda/strategy/EmployeeSalaryFilter.java deleted file mode 100644 index da8a9f55..00000000 --- a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/lambda/strategy/EmployeeSalaryFilter.java +++ /dev/null @@ -1,13 +0,0 @@ -package cn.lastwhisper.jdk8.lambda.strategy; - -import cn.lastwhisper.jdk8.lambda.Employee; - -/** - * @author lastwhisper - */ -public class EmployeeSalaryFilter implements Filter { - @Override - public boolean eqCondition(Employee employee) { - return employee.getSalary() >= 2000; - } -} diff --git a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/lambda/strategy/Filter.java b/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/lambda/strategy/Filter.java deleted file mode 100644 index 23856998..00000000 --- a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/lambda/strategy/Filter.java +++ /dev/null @@ -1,8 +0,0 @@ -package cn.lastwhisper.jdk8.lambda.strategy; - -/** - * 过滤接口 - */ -public interface Filter { - boolean eqCondition(T t); -} diff --git a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/optional/Man.java b/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/optional/Man.java deleted file mode 100644 index a1f1ebf7..00000000 --- a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/optional/Man.java +++ /dev/null @@ -1,27 +0,0 @@ -package cn.lastwhisper.jdk8.optional; - -public class Man { - - private Godness god; - - public Man() { - } - - public Man(Godness god) { - this.god = god; - } - - public Godness getGod() { - return god; - } - - public void setGod(Godness god) { - this.god = god; - } - - @Override - public String toString() { - return "Man [god=" + god + "]"; - } - -} diff --git a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/stream/Employee.java b/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/stream/Employee.java deleted file mode 100644 index 65c5295a..00000000 --- a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/stream/Employee.java +++ /dev/null @@ -1,127 +0,0 @@ -package cn.lastwhisper.jdk8.stream; - - - -public class Employee { - - private Integer id; - private String name; - private Integer age; - private double salary; - private Status status; - - public Employee() { - } - - public Employee(String name) { - this.name = name; - } - - public Employee(String name, Integer age) { - this.name = name; - this.age = age; - } - - public Employee(Integer id, String name, Integer age, double salary) { - this.id = id; - this.name = name; - this.age = age; - this.salary = salary; - } - - public Employee(Integer id, String name, Integer age, double salary, Status status) { - this.id = id; - this.name = name; - this.age = age; - this.salary = salary; - this.status = status; - } - - public Status getStatus() { - return status; - } - - public void setStatus(Status status) { - this.status = status; - } - - public Integer getId() { - return id; - } - - public void setId(Integer id) { - this.id = id; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public Integer getAge() { - return age; - } - - public void setAge(Integer age) { - this.age = age; - } - - public double getSalary() { - return salary; - } - - public void setSalary(double salary) { - this.salary = salary; - } - - public String show() { - return "测试方法引用!"; - } - - @Override - public int hashCode() { - final Integer prime = 31; - Integer result = 1; - result = prime * result + age; - result = prime * result + id; - result = prime * result + ((name == null) ? 0 : name.hashCode()); - long temp; - temp = Double.doubleToLongBits(salary); - result = prime * result + (int) (temp ^ (temp >>> 32)); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - Employee other = (Employee) obj; - if (age != other.age) - return false; - if (id != other.id) - return false; - if (name == null) { - if (other.name != null) - return false; - } else if (!name.equals(other.name)) - return false; - if (Double.doubleToLongBits(salary) != Double.doubleToLongBits(other.salary)) - return false; - return true; - } - - @Override - public String toString() { - return "Employee [id=" + id + ", name=" + name + ", age=" + age + ", salary=" + salary + ", status=" + status - + "]"; - } - - -} diff --git a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/stream/Status.java b/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/stream/Status.java deleted file mode 100644 index 89bca775..00000000 --- a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/stream/Status.java +++ /dev/null @@ -1,5 +0,0 @@ -package cn.lastwhisper.jdk8.stream; - -public enum Status { - FREE, BUSY, VOCATION; -} \ No newline at end of file diff --git a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/stream/TestStreamAPI.java b/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/stream/TestStreamAPI.java deleted file mode 100644 index 48fe9468..00000000 --- a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/stream/TestStreamAPI.java +++ /dev/null @@ -1,53 +0,0 @@ -package cn.lastwhisper.jdk8.stream; - -import cn.lastwhisper.jdk8.lambda.Employee; -import org.junit.Test; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.stream.Stream; - -/* - * 一、Stream API 的操作步骤: - * 1. 创建 Stream - * 2. 中间操作 - * 3. 终止操作(终端操作) - */ -public class TestStreamAPI { - - /** - * 创建Stream - */ - @Test - public void test1() { - // 1.可以通过Collection 系列集合提供的stream()或parallelStream() - List list = new ArrayList<>(); - Stream stream1 = list.stream(); - - // 2.通过 Arrays 中的静态方法stream()获取数组流 - Employee[] emps = new Employee[10]; - Stream stream2 = Arrays.stream(emps); - - // 3.通过Stream 类中的静态方法of() - Stream stream3 = Stream.of("a", "b", "c"); - - // 4.创建无限流 - // 迭代 - Stream stream4 = Stream.iterate(0, (x) -> x + 2); - stream4.limit(10).forEach(System.out::println); - // 生成 - Stream.generate(Math::random) - .limit(5) - .forEach(System.out::println); - } - - @Test - public void test2(){ - Stream.of(1,2,3,4,5,6,7,8,9) - .parallel(); - Stream.of(1,2,3,4,5,6,7,8,9) - .sequential(); - } - -} diff --git a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/stream/example/TestStreamAPI.java b/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/stream/example/TestStreamAPI.java deleted file mode 100644 index 6083dcb4..00000000 --- a/java-basic/jdk8/src/main/java/cn/lastwhisper/jdk8/stream/example/TestStreamAPI.java +++ /dev/null @@ -1,45 +0,0 @@ -package cn.lastwhisper.jdk8.stream.example; - -import cn.lastwhisper.jdk8.stream.Employee; -import cn.lastwhisper.jdk8.stream.Status; -import org.junit.Test; - -import java.util.Arrays; -import java.util.List; -import java.util.Optional; -import java.util.stream.Stream; - -/** - * @author lastwhisper - */ -public class TestStreamAPI { - - List emps = Arrays.asList( - new Employee(102, "李四", 59, 6666.66, Status.BUSY), - new Employee(101, "张三", 18, 9999.99, Status.FREE), - new Employee(103, "王五", 28, 3333.33, Status.VOCATION), - new Employee(104, "赵六", 8, 7777.77, Status.BUSY), - new Employee(104, "赵六", 8, 7777.77, Status.FREE), - new Employee(104, "赵六", 8, 7777.77, Status.FREE), - new Employee(105, "田七", 38, 5555.55, Status.BUSY) - ); - - /** - * 给定一个数字列表,如何返回一个由每个数的平方构成的列表呢? - * 给定【1,2,3,4,5】, 应该返回【1,4,9,16,25】。 - */ - @Test - public void test1() { - Stream.of(1, 2, 3, 4, 5).map(x -> x * x).forEach(System.out::println); - } - - /** - * 怎样用 map 和 reduce 方法数一数流中有多少个Employee呢? - */ - @Test - public void test2() { - Optional reduce = emps.stream().map(e -> 1).reduce(Integer::sum); - System.out.println(reduce.get()); - } - -} diff --git a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/annotation/MyAnnotation.class b/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/annotation/MyAnnotation.class deleted file mode 100644 index b6ee5699..00000000 Binary files a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/annotation/MyAnnotation.class and /dev/null differ diff --git a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/annotation/MyAnnotations.class b/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/annotation/MyAnnotations.class deleted file mode 100644 index c24dbc78..00000000 Binary files a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/annotation/MyAnnotations.class and /dev/null differ diff --git a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/annotation/TestAnnotation.class b/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/annotation/TestAnnotation.class deleted file mode 100644 index 8e6e9acf..00000000 Binary files a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/annotation/TestAnnotation.class and /dev/null differ diff --git a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/date/TestLocalDateTime.class b/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/date/TestLocalDateTime.class deleted file mode 100644 index eddb1df2..00000000 Binary files a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/date/TestLocalDateTime.class and /dev/null differ diff --git a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/date/TestLocalDateTime2.class b/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/date/TestLocalDateTime2.class deleted file mode 100644 index 423e6da9..00000000 Binary files a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/date/TestLocalDateTime2.class and /dev/null differ diff --git a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/interfa/MyClass.class b/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/interfa/MyClass.class deleted file mode 100644 index 52e32962..00000000 Binary files a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/interfa/MyClass.class and /dev/null differ diff --git a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/interfa/MyInterface.class b/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/interfa/MyInterface.class deleted file mode 100644 index 1ba97ef2..00000000 Binary files a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/interfa/MyInterface.class and /dev/null differ diff --git a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/interfa/Named.class b/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/interfa/Named.class deleted file mode 100644 index c9db2d55..00000000 Binary files a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/interfa/Named.class and /dev/null differ diff --git a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/lambda/Employee.class b/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/lambda/Employee.class deleted file mode 100644 index cf39f668..00000000 Binary files a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/lambda/Employee.class and /dev/null differ diff --git a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/lambda/MyFun.class b/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/lambda/MyFun.class deleted file mode 100644 index 032ba172..00000000 Binary files a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/lambda/MyFun.class and /dev/null differ diff --git a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/lambda/TestLambda$1.class b/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/lambda/TestLambda$1.class deleted file mode 100644 index c8deb1a5..00000000 Binary files a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/lambda/TestLambda$1.class and /dev/null differ diff --git a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/lambda/TestLambda$2.class b/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/lambda/TestLambda$2.class deleted file mode 100644 index b1f5380e..00000000 Binary files a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/lambda/TestLambda$2.class and /dev/null differ diff --git a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/lambda/TestLambda.class b/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/lambda/TestLambda.class deleted file mode 100644 index 99b92ff2..00000000 Binary files a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/lambda/TestLambda.class and /dev/null differ diff --git a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/lambda/TestLambda2$1.class b/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/lambda/TestLambda2$1.class deleted file mode 100644 index 8b0e903b..00000000 Binary files a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/lambda/TestLambda2$1.class and /dev/null differ diff --git a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/lambda/TestLambda2.class b/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/lambda/TestLambda2.class deleted file mode 100644 index 3b4635f9..00000000 Binary files a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/lambda/TestLambda2.class and /dev/null differ diff --git a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/lambda/TestLambda3.class b/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/lambda/TestLambda3.class deleted file mode 100644 index 7f804657..00000000 Binary files a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/lambda/TestLambda3.class and /dev/null differ diff --git a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/lambda/TestMethodRef.class b/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/lambda/TestMethodRef.class deleted file mode 100644 index 38e9af93..00000000 Binary files a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/lambda/TestMethodRef.class and /dev/null differ diff --git a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/lambda/example/MyFun2.class b/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/lambda/example/MyFun2.class deleted file mode 100644 index 589b5c5a..00000000 Binary files a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/lambda/example/MyFun2.class and /dev/null differ diff --git a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/lambda/example/MyFun3.class b/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/lambda/example/MyFun3.class deleted file mode 100644 index f46dd2be..00000000 Binary files a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/lambda/example/MyFun3.class and /dev/null differ diff --git a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/lambda/example/TestLambda.class b/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/lambda/example/TestLambda.class deleted file mode 100644 index fc76a13c..00000000 Binary files a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/lambda/example/TestLambda.class and /dev/null differ diff --git a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/lambda/strategy/EmployeeAgeFilter.class b/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/lambda/strategy/EmployeeAgeFilter.class deleted file mode 100644 index daf5b6ec..00000000 Binary files a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/lambda/strategy/EmployeeAgeFilter.class and /dev/null differ diff --git a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/lambda/strategy/EmployeeSalaryFilter.class b/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/lambda/strategy/EmployeeSalaryFilter.class deleted file mode 100644 index 7ef634fe..00000000 Binary files a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/lambda/strategy/EmployeeSalaryFilter.class and /dev/null differ diff --git a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/lambda/strategy/Filter.class b/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/lambda/strategy/Filter.class deleted file mode 100644 index 8385ba20..00000000 Binary files a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/lambda/strategy/Filter.class and /dev/null differ diff --git a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/optional/Godness.class b/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/optional/Godness.class deleted file mode 100644 index 391e267f..00000000 Binary files a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/optional/Godness.class and /dev/null differ diff --git a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/optional/Man.class b/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/optional/Man.class deleted file mode 100644 index 0a159ab1..00000000 Binary files a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/optional/Man.class and /dev/null differ diff --git a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/optional/NewMan.class b/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/optional/NewMan.class deleted file mode 100644 index 03daa9ba..00000000 Binary files a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/optional/NewMan.class and /dev/null differ diff --git a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/optional/TestOptional.class b/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/optional/TestOptional.class deleted file mode 100644 index 63226a80..00000000 Binary files a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/optional/TestOptional.class and /dev/null differ diff --git a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/stream/Employee.class b/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/stream/Employee.class deleted file mode 100644 index 03856fa8..00000000 Binary files a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/stream/Employee.class and /dev/null differ diff --git a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/stream/Status.class b/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/stream/Status.class deleted file mode 100644 index e0e404c6..00000000 Binary files a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/stream/Status.class and /dev/null differ diff --git a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/stream/TestStreamAPI.class b/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/stream/TestStreamAPI.class deleted file mode 100644 index 22909c31..00000000 Binary files a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/stream/TestStreamAPI.class and /dev/null differ diff --git a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/stream/TestStreamAPI2.class b/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/stream/TestStreamAPI2.class deleted file mode 100644 index 8a45acc3..00000000 Binary files a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/stream/TestStreamAPI2.class and /dev/null differ diff --git a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/stream/TestStreamAPI3.class b/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/stream/TestStreamAPI3.class deleted file mode 100644 index 1274e5f7..00000000 Binary files a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/stream/TestStreamAPI3.class and /dev/null differ diff --git a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/stream/example/TestStreamAPI.class b/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/stream/example/TestStreamAPI.class deleted file mode 100644 index 27843132..00000000 Binary files a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/stream/example/TestStreamAPI.class and /dev/null differ diff --git a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/stream/example/TestTransaction.class b/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/stream/example/TestTransaction.class deleted file mode 100644 index a69df31a..00000000 Binary files a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/stream/example/TestTransaction.class and /dev/null differ diff --git a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/stream/example/Trader.class b/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/stream/example/Trader.class deleted file mode 100644 index 3cdbdaf0..00000000 Binary files a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/stream/example/Trader.class and /dev/null differ diff --git a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/stream/example/Transaction.class b/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/stream/example/Transaction.class deleted file mode 100644 index 53631c38..00000000 Binary files a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/stream/example/Transaction.class and /dev/null differ diff --git a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/stream/parallel/ForkJoinCalculate.class b/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/stream/parallel/ForkJoinCalculate.class deleted file mode 100644 index 3efb530c..00000000 Binary files a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/stream/parallel/ForkJoinCalculate.class and /dev/null differ diff --git a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/stream/parallel/TestForkJoin.class b/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/stream/parallel/TestForkJoin.class deleted file mode 100644 index fa869f3b..00000000 Binary files a/java-basic/jdk8/target/classes/cn/lastwhisper/jdk8/stream/parallel/TestForkJoin.class and /dev/null differ diff --git a/java-basic/jdk9/pom.xml b/java-basic/jdk9/pom.xml deleted file mode 100644 index 399a85ca..00000000 --- a/java-basic/jdk9/pom.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - java-basic - cn.lastwhisper - 1.0-SNAPSHOT - - 4.0.0 - - cn.lastwhisper - jdk9 - - - \ No newline at end of file diff --git a/java-basic/jvm/README.md b/java-basic/jvm/README.md new file mode 100644 index 00000000..8865e681 --- /dev/null +++ b/java-basic/jvm/README.md @@ -0,0 +1,4 @@ +src +1. classloader 类加载相关 +2. classloading 类加载时机 +3. ms 内存结构 diff --git a/java-basic/jvm/jdk7-setting/pom.xml b/java-basic/jvm/jdk7-setting/pom.xml new file mode 100644 index 00000000..d99a01df --- /dev/null +++ b/java-basic/jvm/jdk7-setting/pom.xml @@ -0,0 +1,21 @@ + + + + + + + + 4.0.0 + + jdk7-setting + cn.lastwhisper + 1.0-SNAPSHOT + + + 7 + 7 + + + \ No newline at end of file diff --git a/java-basic/jvm/jdk7-setting/src/main/java/cn/cunchang/methodarea/OOMTest.java b/java-basic/jvm/jdk7-setting/src/main/java/cn/cunchang/methodarea/OOMTest.java new file mode 100644 index 00000000..86db4845 --- /dev/null +++ b/java-basic/jvm/jdk7-setting/src/main/java/cn/cunchang/methodarea/OOMTest.java @@ -0,0 +1,56 @@ +package cn.cunchang.methodarea; + +import com.sun.xml.internal.ws.org.objectweb.asm.ClassWriter; +import com.sun.xml.internal.ws.org.objectweb.asm.Opcodes; + +/** + * jdk6/7中: + * -XX:PermSize=10m -XX:MaxPermSize=10m + * + * jdk8中: + * -XX:MetaspaceSize=10m -XX:MaxMetaspaceSize=10m + * + * @author shkstart shkstart@126.com + * @create 2020 22:24 + */ +public class OOMTest extends ClassLoader { + + /** + * jdk7 + * 9429 + * Exception in thread "main" java.lang.OutOfMemoryError: PermGen space + * at java.lang.ClassLoader.defineClass(ClassLoader.java:800) + * at java.lang.ClassLoader.defineClass(ClassLoader.java:643) + * at cn.cunchang.methodarea.OOMTest.main(OOMTest.java:45) + * + * + * jdk8 + * 3331 + * Exception in thread "main" java.lang.OutOfMemoryError: Compressed class space + * at java.lang.ClassLoader.defineClass1(Native Method) + * at java.lang.ClassLoader.defineClass(ClassLoader.java:756) + * at java.lang.ClassLoader.defineClass(ClassLoader.java:635) + * at cn.lastwhisper.jvm.tmp.methodarea.java.OOMTest.main(OOMTest.java:29) + * + * @param args + */ + public static void main(String[] args) { + int j = 0; + try { + OOMTest test = new OOMTest(); + for (int i = 0; i < 10000; i++) { + //创建ClassWriter对象,用于生成类的二进制字节码 + ClassWriter classWriter = new ClassWriter(0); + //指明版本号,修饰符,类名,包名,父类,接口 + classWriter.visit(Opcodes.V1_6, Opcodes.ACC_PUBLIC, "Class" + i, null, "java/lang/Object", null); + //返回byte[] + byte[] code = classWriter.toByteArray(); + //类的加载 + test.defineClass("Class" + i, code, 0, code.length);//Class对象 + j++; + } + } finally { + System.out.println(j); + } + } +} diff --git a/java-basic/jvm/pom.xml b/java-basic/jvm/pom.xml index e3aaacf3..9a5f8bec 100644 --- a/java-basic/jvm/pom.xml +++ b/java-basic/jvm/pom.xml @@ -2,15 +2,16 @@ - - java-basic - cn.lastwhisper - 1.0-SNAPSHOT - + 4.0.0 cn.lastwhisper jvm + pom + 1.0-SNAPSHOT + + jdk7-setting + UTF-8 @@ -80,5 +81,12 @@ mysql-connector-java ${mysql.connector} + + + junit + junit + 4.12 + + \ No newline at end of file diff --git a/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloader/ClassLifeCycle.java b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloader/ClassLifeCycle.java new file mode 100644 index 00000000..a2da6888 --- /dev/null +++ b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloader/ClassLifeCycle.java @@ -0,0 +1,17 @@ +package cn.lastwhisper.jvm.classloader; + +/** + * 加载、解析、初始化 + * @author lastwhisper + */ +public class ClassLifeCycle { + public static void main(String[] args) throws ClassNotFoundException { + // 类.class会加载,不会执行“链接”、“初始化”的步骤,因为AppClassLoad.loadClass的resolve=false + // 验证:DemoObj的类构造器未执行 + // Class clazz1 = DemoObj.class; + + // 通过Class.forName会执行加载、链接、初始化 + // 验证:DemoObj的类构造器执行了 + Class clazz2 = Class.forName("cn.lastwhisper.classloader.DemoObj"); + } +} diff --git a/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloader/ClassLoaderPrintTest.java b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloader/ClassLoaderPrintTest.java new file mode 100644 index 00000000..71e484ba --- /dev/null +++ b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloader/ClassLoaderPrintTest.java @@ -0,0 +1,38 @@ +package cn.lastwhisper.jvm.classloader; + +import sun.misc.Launcher; + +import java.net.URL; + +public class ClassLoaderPrintTest { + + public static void main(String[] args) { + System.out.println(String.class.getClassLoader()); + System.out.println(com.sun.crypto.provider.DESKeyFactory.class.getClassLoader().getClass().getName()); + System.out.println(ClassLoaderPrintTest.class.getClassLoader().getClass().getName()); + + System.out.println(); + ClassLoader appClassLoader = ClassLoader.getSystemClassLoader(); + ClassLoader extClassloader = appClassLoader.getParent(); + ClassLoader bootstrapLoader = extClassloader.getParent(); + System.out.println("the bootstrapLoader : " + bootstrapLoader); + System.out.println("the extClassloader : " + extClassloader); + System.out.println("the appClassLoader : " + appClassLoader); + + System.out.println(); + System.out.println("bootstrapLoader加载以下文件:"); + URL[] urls = Launcher.getBootstrapClassPath().getURLs(); + for (int i = 0; i < urls.length; i++) { + System.out.println(urls[i]); + } + + System.out.println(); + System.out.println("extClassloader加载以下文件:"); + System.out.println(System.getProperty("java.ext.dirs")); + + System.out.println(); + System.out.println("appClassLoader加载以下文件:"); + System.out.println(System.getProperty("java.class.path")); + + } +} \ No newline at end of file diff --git a/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloader/ClassLoaderUnique.java b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloader/ClassLoaderUnique.java new file mode 100644 index 00000000..34296998 --- /dev/null +++ b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloader/ClassLoaderUnique.java @@ -0,0 +1,51 @@ +package cn.lastwhisper.jvm.classloader; + +import java.io.IOException; +import java.io.InputStream; + +/** + * 类加载器与instanceof关键字演示 + * + * @author lastwhisper + */ +public class ClassLoaderUnique { + + /** + * 对于任意一个类,都需要由加载它的类加载器和这个类本身一同确立 + * 其在Java虚拟机中的唯一性,每一个类加载器,都有一个独立的名称空间。 + * 即,两个类来自同一个Class文件,被同一个虚拟机加载,只要类加载器不同,两个类就不相等。 + * 不相等包括:equals()、isAssignableFrom()、isInstance()、instanceof + * + * @author lastwhisper + */ + public static void main(String[] args) throws Exception { + // myClassLoader的父类加载是appclassload, + ClassLoader myClassLoader = new ClassLoader() { + @Override + public Class loadClass(String name) throws ClassNotFoundException { + try { + String fileName = name.substring(name.lastIndexOf(".") + 1) + ".class"; + InputStream is = getClass().getResourceAsStream(fileName); + // 类文件如果在当前项目下,就由自己加载,否则由父类加载器加载 + // 比如DemoObj就在当前项目下,java.lang.Object就不在当前项目下 + if (is == null) { + return super.loadClass(name); + } + byte[] b = new byte[is.available()]; + int ignore = is.read(b); + return defineClass(name, b, 0, b.length); + } catch (IOException e) { + throw new ClassNotFoundException(name); + } + } + }; + Class clazz = myClassLoader.loadClass("cn.lastwhisper.classloader.DemoObj"); + + Object obj = clazz.newInstance(); + + // obj由自定义的类加载器加载、DemoObj由系统类加载器加载的。 + System.out.println(obj instanceof DemoObj); + + System.out.println(obj.getClass() == DemoObj.class); + } +} diff --git a/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloader/DemoObj.java b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloader/DemoObj.java new file mode 100644 index 00000000..54546e0e --- /dev/null +++ b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloader/DemoObj.java @@ -0,0 +1,14 @@ +package cn.lastwhisper.jvm.classloader; + +/** + * @author lastwhisper + */ +public class DemoObj { + static { + System.out.println("类构造器"); + } + + { + System.out.println("对象构造器"); + } +} diff --git a/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloader/READMD.md b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloader/READMD.md new file mode 100644 index 00000000..dad5f98c --- /dev/null +++ b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloader/READMD.md @@ -0,0 +1,7 @@ + +1. ClassLoaderPrintTest 打印类加载器,Bootstrap、ext、app +2. ClassLoaderUnique 同一个类在同一个类加载器唯一 +3. ClassLifeCycle 类加载生命周期 +4. MyClassLoaderTest 自定义类加载器,查看双亲委派机制和父子关系构建 + + diff --git a/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloader/hotdeploy/ClassLoaderHotDeploy.java b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloader/hotdeploy/ClassLoaderHotDeploy.java new file mode 100644 index 00000000..26d1e4cd --- /dev/null +++ b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloader/hotdeploy/ClassLoaderHotDeploy.java @@ -0,0 +1,88 @@ +package cn.lastwhisper.jvm.classloader.hotdeploy; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.util.HashSet; +import java.util.Set; +import java.util.Timer; +import java.util.TimerTask; + +/** + * 代码热部署 + * + * @author lastwhisper + */ +public class ClassLoaderHotDeploy { + + public static void main(String[] args) { + new Timer().schedule(new TimerTask() { + @Override + public void run() { + String path = ClassLoaderHotDeploy.class.getResource("").getPath(); + System.out.println(path); + // 这里一定要用全限定名,因为一个类唯一标志就是全限定名 + String className = "cn.lastwhisper.classloader.hotdeploy.HotCodeTest"; + + Set set = new HashSet(); + set.add(className); + + MyClassLoader myClassLoader = new MyClassLoader(path, set); + + try { + Object object = myClassLoader.loadClass(className).newInstance(); + object.getClass().getMethod("printVersion").invoke(object); + } catch (Exception e) { + e.printStackTrace(); + } + + + } + }, 0, 2000); + } + +} + +class MyClassLoader extends ClassLoader { + // 用于读取.class文件的路径 + private String classPath; + // 用于标记这些name的类是先由自身加载的 + private Set useMyClassLoader; + + public MyClassLoader(String classPath, Set useMyClassLoader) { + this.classPath = classPath; + this.useMyClassLoader = useMyClassLoader; + } + + @Override + public Class loadClass(String name) throws ClassNotFoundException { + Class c = findLoadedClass(name); + if (c == null && useMyClassLoader.contains(name)) { + c = findClass(name); + if (c != null) { + return c; + } + } + return super.loadClass(name); + } + + @Override + protected Class findClass(String name) { + //根据文件系统路径加载class文件,并返回byte数组 + byte[] classBytes = getClassByte(name); + //调用ClassLoader提供的方法,将二进制数组转换成Class类的实例 + return defineClass(name, classBytes, 0, classBytes.length); + } + + private byte[] getClassByte(String className) { + String filePath = classPath + className.substring(className.lastIndexOf('.') + 1, className.length()) + ".class"; + try (InputStream is = Files.newInputStream(new File(filePath).toPath())) { + byte[] data = new byte[is.available()]; + is.read(data); + return data; + } catch (IOException e) { + throw new RuntimeException(e); + } + } +} diff --git a/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloader/hotdeploy/HotCodeTest.java b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloader/hotdeploy/HotCodeTest.java new file mode 100644 index 00000000..9b26f5d1 --- /dev/null +++ b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloader/hotdeploy/HotCodeTest.java @@ -0,0 +1,7 @@ +package cn.lastwhisper.jvm.classloader.hotdeploy; + +public class HotCodeTest { + public void printVersion(){ + System.out.println("当前版本是2哦"); + } +} \ No newline at end of file diff --git a/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloader/loadorder/LoadOrderTest.java b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloader/loadorder/LoadOrderTest.java new file mode 100644 index 00000000..d9bf10b6 --- /dev/null +++ b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloader/loadorder/LoadOrderTest.java @@ -0,0 +1,14 @@ +package cn.lastwhisper.jvm.classloader.loadorder; + +/** + * @author kaisui + * @description + * @date 2022/12/4 + */ +public class LoadOrderTest { + + public static void main(String[] args) { + System.out.println("load end"); + } + +} diff --git a/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloader/loadorder/MyClassLoaderTest.java b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloader/loadorder/MyClassLoaderTest.java new file mode 100644 index 00000000..fddcbc02 --- /dev/null +++ b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/classloader/loadorder/MyClassLoaderTest.java @@ -0,0 +1,53 @@ +package cn.lastwhisper.jvm.classloader.loadorder; + + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; + +/** + * + * @author lastwhisper + */ +public class MyClassLoaderTest { + static class MyClassLoader extends ClassLoader { + private final String classPath; + + public MyClassLoader(String classPath) { + this.classPath = classPath; + } + + /** + * 类加载实际执行的方法 + */ + @Override + public Class findClass(String className) { + byte[] bytes = loadByte(className); + return defineClass(className, bytes, 0, bytes.length); + } + + private byte[] loadByte(String className) { + String filePath = classPath + File.separatorChar + className.replace('.', File.separatorChar) + ".class"; + try (InputStream is = Files.newInputStream(new File(filePath).toPath())) { + byte[] data = new byte[is.available()]; + is.read(data); + return data; + } catch (IOException e) { + throw new RuntimeException(e); + } + } + } + + public static void main(String[] args) throws Exception { + MyClassLoader myClassLoaderTest = new MyClassLoader("/Users/kaisui/workspace/my/code/java-basic/feature-jdk5/target/classes/"); + // 注意先使用loadClass,该类会被appCL加载,后使用findClass会被MyCL加载。 + // 注意先使用findClass,该类会被MyCL加载,再使用loadClass会发现该类已经被MyCL加载了,就不向上委派了。 + Class clazz1 = myClassLoaderTest.loadClass("cn.lastwhisper.classloader.DemoObj");// 走appCL + Class clazz2 = myClassLoaderTest.findClass("cn.lastwhisper.classloader.DemoObj");// 走MyCL + System.out.println(clazz1 == clazz2); + System.out.println(clazz1.getClassLoader()); + System.out.println(clazz2.getClassLoader()); + } + +} diff --git a/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/gc/InitiativeGC.java b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/gc/InitiativeGC.java new file mode 100644 index 00000000..2d98db74 --- /dev/null +++ b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/gc/InitiativeGC.java @@ -0,0 +1,29 @@ +package cn.lastwhisper.jvm.gc; + +import java.lang.ref.WeakReference; + +/** + * 主动触发GC + * @author lastwhisper + * @date 2020/5/14 + */ +public class InitiativeGC { + /** + * @see cn.lastwhisper.jvm.gc.reference.WeakReferenceDemo + */ + public static void main(String[] args) { + Object obj = new Object(); + WeakReference weakReference = new WeakReference<>(obj); + + System.out.println(weakReference.get()); + System.out.println("GC before,java heap " + (weakReference.get() == null ? "not exist bytes" : "exist bytes")); + + obj = null; + System.gc(); + + System.out.println(weakReference.get()); + System.out.println("GC before,java heap " + (weakReference.get() == null ? "not exist bytes" : "exist bytes")); + + } + +} diff --git a/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/gc/ReferenceCountingGC.java b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/gc/ReferenceCountingGC.java deleted file mode 100644 index 872b686d..00000000 --- a/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/gc/ReferenceCountingGC.java +++ /dev/null @@ -1,25 +0,0 @@ -package cn.lastwhisper.jvm.gc; - -/** - * 引用计数法的缺陷 - * @author lastwhisper - */ -public class ReferenceCountingGC { - - public Object install = null; - - private static final int _1MB = 1024 * 1024; - private byte[] bigSize = new byte[2*_1MB]; - - public static void main(String[] args){ - ReferenceCountingGC objA = new ReferenceCountingGC(); - ReferenceCountingGC objB = new ReferenceCountingGC(); - objA.install=objB; - objB.install=objA; - - objA=null; - objB=null; - - System.gc(); - } -} diff --git a/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/gc/finalize/Finalization.java b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/gc/finalize/Finalization.java index 4fad225d..270c0665 100644 --- a/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/gc/finalize/Finalization.java +++ b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/gc/finalize/Finalization.java @@ -6,36 +6,36 @@ * @author lastwhisper */ public class Finalization { - public static Finalization SAVE_HOOK=null; + public static Finalization SAVE_HOOK = null; @Override protected void finalize() throws Throwable { super.finalize(); - Finalization.SAVE_HOOK=this; + Finalization.SAVE_HOOK = this; System.out.println("处理系统资源、执行其他清理或者对象自救"); } - - public static void main(String[] args) throws Exception{ + + public static void main(String[] args) throws Exception { SAVE_HOOK = new Finalization(); // 在堆中无GC Roots,会被GC,但是SAVE_HOOK实现了finalize有一次自救的机会 - SAVE_HOOK=null; + SAVE_HOOK = null; //显示调用垃圾回收 System.gc(); // finalize方法优先级很低,暂停0.5s等待它 Thread.sleep(500); - if(SAVE_HOOK!=null){ + if (SAVE_HOOK != null) { System.out.println("SAVE_HOOK对象还活着"); - }else { + } else { System.out.println("SAVE_HOOK对象已经被回收"); } // finalize方法只会调用一次,第二次自救失败 - SAVE_HOOK=null; + SAVE_HOOK = null; System.gc(); // finalize方法优先级很低,暂停0.5s等待它 Thread.sleep(500); - if(SAVE_HOOK!=null){ + if (SAVE_HOOK != null) { System.out.println("SAVE_HOOK对象还活着"); - }else { + } else { System.out.println("SAVE_HOOK对象已经被回收"); } } diff --git a/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/gc/gcroots/ReferenceCountingGC.java b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/gc/gcroots/ReferenceCountingGC.java new file mode 100644 index 00000000..0b264ca3 --- /dev/null +++ b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/gc/gcroots/ReferenceCountingGC.java @@ -0,0 +1,39 @@ +package cn.lastwhisper.jvm.gc.gcroots; + +/** + * 引用计数法的缺陷 + * @author lastwhisper + */ +public class ReferenceCountingGC { + + public Object install = null; + + private static final int _1MB = 1024 * 1024; + + /** + * 这个成员属性的唯一意义就是占点内存, 以便能在GC日志中看清楚是否有回收过 + */ + private byte[] bigSize = new byte[2*_1MB]; + + /** + * -XX:+PrintGC //等价 -verbose:gc + * -XX:+PrintGCDetails + * -XX:+PrintGCDateStamps + * -Xloggc:C:\Users\ligj\Downloads\gc.log + * + * 这里使用 -XX:+PrintGCDetails + */ + public static void main(String[] args){ + ReferenceCountingGC objA = new ReferenceCountingGC(); + ReferenceCountingGC objB = new ReferenceCountingGC(); + objA.install=objB; + objB.install=objA; + + objA=null; + objB=null; + + // 假设在这行发生GC, objA和objB是否能被回收? + // 可以被回收 + System.gc(); + } +} diff --git a/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/gc/reference/ReferenceQueueDemo.java b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/gc/reference/ReferenceQueueDemo.java index 26175c97..9b753cea 100644 --- a/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/gc/reference/ReferenceQueueDemo.java +++ b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/gc/reference/ReferenceQueueDemo.java @@ -19,8 +19,8 @@ public static void main(String[] args) throws InterruptedException{ System.gc(); Thread.sleep(500); - System.out.println(o); - System.out.println(weakReference.get()); + System.out.println(o);//o==null + System.out.println(weakReference.get());//o==null System.out.println(referenceQueue.poll());// o被回收以后,队列有值 } } diff --git a/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/gc/reference/ReferenceQueueTest.java b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/gc/reference/ReferenceQueueTest.java index 71f7a1aa..924dbafe 100644 --- a/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/gc/reference/ReferenceQueueTest.java +++ b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/gc/reference/ReferenceQueueTest.java @@ -3,7 +3,10 @@ import java.lang.ref.ReferenceQueue; import java.lang.ref.WeakReference; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; +import java.util.Set; + /** * 监控对象是否被收回 */ @@ -12,18 +15,20 @@ public class ReferenceQueueTest { private static ReferenceQueue rq = new ReferenceQueue(); private static int _1M = 1024*1024; /** + * * 因为map的key是WeakReference,所以在内存不足的时候,weakReference所指向的对象就会被GC, - * 在对象被GC的同时,会把该对象的包装类即weakReference放入到ReferenceQueue里面。但是这个map的大小是10000. + * 在对象被GC的同时,会把该对象的包装类即weakReference放入到ReferenceQueue里面。 + * + * 但是这个map的大小是100. + * */ public static void main(String[] args) { - Object value = new Object(); - Map map = new HashMap<>(); Thread thread = new Thread(() -> { try { int cnt = 0; WeakReference k; while((k = (WeakReference) rq.remove()) != null) { - System.out.println((cnt++) + "回收了:" + k); + System.out.println((cnt++) + " 回收了:" + k.get()); } } catch(InterruptedException e) { //结束循环 @@ -32,11 +37,12 @@ public static void main(String[] args) { thread.setDaemon(true); thread.start(); - for(int i = 0;i < 10000;i++) { + Set handlerSet = new HashSet<>(); + for(int i = 0;i < 100;i++) { byte[] bytes = new byte[_1M]; WeakReference weakReference = new WeakReference<>(bytes, rq); - map.put(weakReference, value); + handlerSet.add(weakReference); } - System.out.println("map.size->" + map.size()); + System.out.println("size->" + handlerSet.size()); } } \ No newline at end of file diff --git a/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/gc/reference/SoftReferenceDemo.java b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/gc/reference/SoftReferenceDemo.java index d6d8f3e8..746f73cd 100644 --- a/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/gc/reference/SoftReferenceDemo.java +++ b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/gc/reference/SoftReferenceDemo.java @@ -45,11 +45,17 @@ public static void softRef_Memory_NotEnough() { //byte[] bytes = new byte[6*1024*1024];//6MB 内存足够,不会回收软引用 byte[] bytes = new byte[7 * 1024 * 1024];//7MB OOM触发GC,回收软引用 } catch (Throwable e) { + System.out.println("---原引用置为null, OOM触发GC---"); e.printStackTrace(); + // java.lang.OutOfMemoryError: Java heap space + // at cn.lastwhisper.jvm.gc.reference.SoftReferenceDemo.softRef_Memory_NotEnough(SoftReferenceDemo.java:46) + // at cn.lastwhisper.jvm.gc.reference.SoftReferenceDemo.main(SoftReferenceDemo.java:15) } finally { - System.out.println("---原引用置为null, OOM触发GC---"); + System.out.println("原引用:"+o);//null System.out.println("软引用:"+softReference.get());// null 内存不足被回收 + // 是否会被 GC ?不会因为 softReference GCRoots 可到达 + System.out.println("softReference:"+softReference); } } diff --git a/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/memorystruct/Intern.java b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/memorystruct/Intern.java new file mode 100644 index 00000000..0948e54a --- /dev/null +++ b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/memorystruct/Intern.java @@ -0,0 +1,25 @@ +package cn.lastwhisper.jvm.memorystruct; + +public class Intern { + + //public static void main(String[] args) { + // String str1 = new StringBuilder("计算机").append("软件").toString(); + // System.out.println(str1.intern() == str1);//true + // + // //https://segmentfault.com/a/1190000011543995 + // //sun.misc.Version.init();方法中已经存在"java"常量 + // // 修改为new StringBuilder("ja").append("ava").toString(); true + // String str2 = new StringBuilder("ja").append("va").toString(); + // // str2.intern()字符串常量池、str2堆中 + // System.out.println(str2.intern() == str2);//false + //} + + public static void main(String[] args){ + String x1 = new StringBuilder("XXX").toString(); + String x2 = new StringBuilder("XXX").toString(); + System.out.println(x1.intern() == x1.intern()); + System.out.println(x1.intern() == x2.intern()); + System.out.println(new StringBuilder("XXX").toString().intern() == x1.intern()); + System.out.println("XXXX" == new StringBuilder("XXXX").toString().intern()); + } +} diff --git a/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/memorystruct/Intern2.java b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/memorystruct/Intern2.java new file mode 100644 index 00000000..edae5e78 --- /dev/null +++ b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/memorystruct/Intern2.java @@ -0,0 +1,21 @@ +package cn.lastwhisper.jvm.memorystruct; + +public class Intern2 { + + + public static void main(String[] args) { + String a1 = "XXX"; + String a2 = "XXX"; + System.out.println("编译器可以确定,只创建一个String的对象,a1 == a2:" + (a1 == a2)); + + String x1 = new String("XXX"); + String x2 = new String("XXX"); + System.out.println("编译器无法确定,创建两个String的对象,x1 == x2:" + (x1 == x2)); + x1 = x1.intern(); + x2 = x2.intern(); + System.out.println("intern之后,进入常量池,指向同一个位置" +(x1 == x1)); + System.out.println("intern之后,进入常量池,指向同一个位置" +(x2 == x2)); + System.out.println("intern之后,进入常量池,指向同一个位置" +(x1 == x2)); + + } +} diff --git a/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/memorystruct/InternDifference.java b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/memorystruct/InternDifference.java index 3a7affb4..745ca766 100644 --- a/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/memorystruct/InternDifference.java +++ b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/memorystruct/InternDifference.java @@ -11,52 +11,54 @@ * 否则,如果该String对象已经存在于堆中,则将堆中对此对象的引用添加到字符串常量池中,并返回该引用; * 如果堆中不存在,则在池中创建该字符串,并返回其引用。 * false true - * + * * @author lastwhisper */ public class InternDifference { + /** + * + * 1.jdk6 + * String s1 = new String("a");//一个语句执行两个操作句话,"a"会在字符串常量池中创建;new String("a")会在堆里面创建 + * s1.intern();// 把首次遇到的字符串复制到永久代(字符串常量池) + * String s2 = "a";//直接使用字符串常量池"a" + * System.out.println(s1 == s2);//s1指向堆"a",s2指向常量池"a" false + * + * 优化为:String s3 = (new StringBuilder()).append(new String("a")).append(new String("a")).toString(); + * String s3 = new String("a") + new String("a");//只在堆中创建"aa",s3指向堆中"aa" + * s3.intern();//发现"aa"在字符串常量池中不已经存在,在常字符串量池中创建"aa"(把首次遇到的字符串复制到永久代(字符串常量池)) + * String s4 = "aa";//s4直接使用字符串常量池"aa" + * System.out.println(s3 == s4);//s3指向堆"aa",s4指向常量池"aa" false + * + * 1.jdk7 + * String s1 = new String("a");//"a"会在字符串常量池中创建、new String("a")会在堆里面创建 + * s1.intern();//把首次遇到的字符串的引用复制到永久代(字符串常量池) + * //发现"a"在字符串常量池中已经存在,就不能在让常字符串量池中创建"a"引用指向堆中的"a" + * String s2 = "a";//直接使用字符串常量池"a" + * System.out.println(s1 == s2);//s1指向堆"a",s2指向常量池"a" false + * + * 优化为:String s = (new StringBuilder()).append(new String("a")).append(new String("a")).toString(); + * String s3 = new String("a") + new String("a");//只在堆中创建"aa",s3指向堆中"aa" + * s3.intern();//把首次遇到的字符串的引用复制到永久代(字符串常量池) + * //发现"aa"在字符串常量池中不存在,让字符串常量池中引用堆中的"aa" + * String s4 = "aa";// 直接使用字符串常量池"aa"(这个"aa"是从堆中的引用) + * System.out.println(s3 == s4);//s3指向堆中"aa",s4指向字符串常量池"aa",而常量池"aa"是堆中"aa"的引用,所以s3==s4 true + * + * + */ public static void main(String[] args) { - /** - * - * 1.jdk6 - * String s1 = new String("a");//一个语句执行两个操作句话,"a"会在字符串常量池中创建;new String("a")会在堆里面创建 - * s1.intern();// 把首次遇到的字符串复制到永久代(字符串常量池) - * String s2 = "a";//直接使用字符串常量池"a" - * System.out.println(s1 == s2);//s1指向堆"a",s2指向常量池"a" false - * - * 优化为:String s3 = (new StringBuilder()).append(new String("a")).append(new String("a")).toString(); - * String s3 = new String("a") + new String("a");//只在堆中创建"aa",s3指向堆中"aa" - * s3.intern();//发现"aa"在字符串常量池中不已经存在,在常字符串量池中创建"aa"(把首次遇到的字符串复制到永久代(字符串常量池)) - * String s4 = "aa";//s4直接使用字符串常量池"aa" - * System.out.println(s3 == s4);//s3指向堆"aa",s4指向常量池"aa" false - * - * 1.jdk7 - * String s1 = new String("a");//"a"会在字符串常量池中创建、new String("a")会在堆里面创建 - * s1.intern();//把首次遇到的字符串的引用复制到永久代(字符串常量池) - * //发现"a"在字符串常量池中已经存在,就不能在让常字符串量池中创建"a"引用指向堆中的"a" - * String s2 = "a";//直接使用字符串常量池"a" - * System.out.println(s1 == s2);//s1指向堆"a",s2指向常量池"a" false - * - * 优化为:String s = (new StringBuilder()).append(new String("a")).append(new String("a")).toString(); - * String s3 = new String("a") + new String("a");//只在堆中创建"aa",s3指向堆中"aa" - * s3.intern();//把首次遇到的字符串的引用复制到永久代(字符串常量池) - * //发现"aa"在字符串常量池中不存在,让字符串常量池中引用堆中的"aa" - * String s4 = "aa";// 直接使用字符串常量池"aa"(这个"aa"是从堆中的引用) - * System.out.println(s3 == s4);//s3指向堆中"aa",s4指向字符串常量池"aa",而常量池"aa"是堆中"aa"的引用,所以s3==s4 true - */ String s1 = new String("a"); s1.intern(); String s2 = "a"; - System.out.println(s1 == s2); - + System.out.println("str1==str2:" + (s1 == s2)); + String s3 = new String("a") + new String("a"); s3.intern(); String s4 = "aa"; - System.out.println(s3 == s4); + System.out.println("str1==str2:" + (s3 == s4)); String str1 = "abcd"; String str2 = new String("abcd"); - System.out.println(str1==str2);//false + System.out.println("str1==str2:" + (str1 == str2)); } } diff --git a/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/memorystruct/InternDifference1.java b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/memorystruct/InternDifference1.java deleted file mode 100644 index 43b199b2..00000000 --- a/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/memorystruct/InternDifference1.java +++ /dev/null @@ -1,13 +0,0 @@ -package cn.lastwhisper.jvm.memorystruct; - -public class InternDifference1 { - public static void main(String[] args) { - String str1 = new StringBuilder("计算机").append("软件").toString(); - System.out.println(str1.intern() == str1); - //https://segmentfault.com/a/1190000011543995 - //sun.misc.Version.init();方法中已经存在"java" - // 修改为new StringBuilder("ja").append("ava").toString(); true - String str2 = new StringBuilder("ja").append("va").toString(); - System.out.println(str2.intern() == str2);//str2.intern()字符串常量池、str2堆中 - } -} diff --git a/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/ms/Math.java b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/ms/Math.java new file mode 100644 index 00000000..d4a51a36 --- /dev/null +++ b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/ms/Math.java @@ -0,0 +1,19 @@ +package cn.lastwhisper.jvm.ms; + +public class Math { + public static final int initDa3ta = 666; + public static User user = new User(); + + public int compute() { //一个方法对应一块栈帧内存区域 + int a = 1; + int b = 2; + int c = (a + b) * 10; + return c; + } + + public static void main(String[] args) { + Math math = new Math(); + math.compute(); + } + +} \ No newline at end of file diff --git a/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/ms/User.java b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/ms/User.java new file mode 100644 index 00000000..4f9b8786 --- /dev/null +++ b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/ms/User.java @@ -0,0 +1,9 @@ +package cn.lastwhisper.jvm.ms; + +/** + * @author kaisui + * @description + * @date 2023/2/22 + */ +public class User { +} diff --git a/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/tmp2/command/jstack/AllStackTrace.java b/java-basic/jvm/src/main/java/cn/lastwhisper/jvm/tmp2/command/jstack/AllStackTrace.java new file mode 100644 index 00000000..e69de29b diff --git a/java-basic/jvm/src/main/java/java/lang/String.java b/java-basic/jvm/src/main/java/java/lang/String.java new file mode 100644 index 00000000..745525d4 --- /dev/null +++ b/java-basic/jvm/src/main/java/java/lang/String.java @@ -0,0 +1,17 @@ +package java.lang; + +/** + * @author cunchang + * @date 2021/9/2 12:21 上午 + */ +//public class String { +// // +// static { +// System.out.println("我是自定义的String类的静态代码块"); +// } +// +// //错误: 在类 java.lang.String 中找不到 main 方法 +// public static void main(String[] args) { +// System.out.println("hello,String"); +// } +//} diff --git a/java-basic/jvm/words.txt b/java-basic/jvm/words.txt new file mode 100644 index 00000000..7f20a9b3 --- /dev/null +++ b/java-basic/jvm/words.txt @@ -0,0 +1,100000 @@ +Rhy +efN +UayWpqb +BqZQ +bIygB +LJN +ajQHJMb +YbrSTOvF +ZMHNXzlVa +ewx +YgpzfY +fDqdYct +R +yY +clhohC +XmJbuSgcR +sAveQeOjNN +UMIVQVrbux +ycViCnY +btdwA +zCIaXvlndF +DmwWjFMLI +ow +hb +SUCCMITUhj +mRUiCR +JWsuWzOvIU +fMcGkByHa +VybXKd +RqW +qYk +RVFABgRZ +VnGFQjoq +oemOSGEd +vlAa +ANttmx +neRslgFFn +zzxIivg +jaoeLR +fX +Qu +rJhSBijL +CHD +pcFI +J +P +vkO +esM +IMSJzNDYK +NABWSnb +LX +Z +uVbSlTPgg +tzx +uHB +YgrMSrcF +QD +oC +lhGeo +uYBeC +DyKjcx +ECn +mgsROorS +pdA +djC +tIP +UNCveNdh +wgyZ +GxFuqA +fk +vwOH +ZMHhnWzmU +HQrbZhr +A +LblUcYUnN +b +kMaCQcNE +BGaHW +pyiGoijT +tMi +VOY +nJMViGi +kI +wwTgwIDdk +E +ajOwJlh +rEhAt +raWH +mnc +iqkHfQxA +wqyXPqgKL +zklJRQmb +DyLFgVMPyZ +MzfFTHpWqM +XBaO +cCZqdIxw +jpKE +QulzGtMLZ +HKvmyeTx +HPRe +WCquyCyjJ +SRbt +HPZG +umHuAzw +KCAzan +GoITkoqdVI +sm +PcwGpJorn +XFUB +NaSa +HG +UAEW +kSNVwK +gMhPPBC +P +QVDjemLt +nlAHyyO +OmtMp +UZH +Oji +MNXmlyqNdX +Zej +JwxBa +SngHvNIzBi +kvHEAs +qpCJ +UEoTpJoGH +cROiKX +gaPsbyXAY +LbFfTuXqv +Vih +qxtktIE +Tl +agn +XFs +lUBIOW +ZHuyN +jVAuzMhGwr +G +CgH +d +vBoroeFGyB +ppytWCmCC +w +GdIQexFm +jdtjaERC +nVFsV +hmHr +jKKUBBvti +coc +l +GnBZIkZLX +D +rn +TuCfAneczX +VXtyiOb +kx +DeRZF +pOdEZMK +kNHz +sgfhMah +oHR +X +IFjbBtzL +ywWzqCoJD +DBLfHz +q +ypHg +IupkkeQbl +eJFleyZ +w +aEV +UvgXHjGbDv +XpfFymVB +nfdPr +SePMC +Oq +LvyhzrqLg +wqikQ +NlNH +NaL +ZYWoGWHZuy +QgeqcwCzA +Lw +DgNioXG +DqQpVzvi +AaG +XbomxDTFn +OrUyqnYeUh +KLZrfWGi +sgsbBFqjZa +moUx +DfYdiR +gjvE +MgRY +JB +ETVM +Rx +AMTXZH +ddFjBCAaKh +mMilYmAwe +jGofUv +CwdLszXOPp +y +UGK +x +ETgx +vIMwW +KcCojX +DZwUpJHYt +KbYCve +xsdmmxYBCK +m +bAmLxPQf +BdDX +Hb +VirjqkAs +s +HYBrYrA +zTkv +IJtbgTBCWz +Q +DZ +y +K +KIqGfEx +gDobuVz +ummKeeQnJ +gJKX +o +FdYdc +rmJlhBb +iSS +REh +IIX +bqU +NfKiAnNBXz +ApXDiXf +QweGByUiB +OaLiw +PRVX +mka +YdjRfQzfz +NUGlPbEpp +WzoRosUzJt +Xqw +nMUtxIjvzH +hz +zWTWFSH +psy +FdrxFq +ssgrkb +dHhVikPOA +koj +JqOD +a +C +tGhrAoF +OIkWcD +MeHM +eoHXjQNIU +yeDWUXUID +rWlEEPf +oxsC +dtIMexV +tcPdw +FNSuD +Pv +jbtKAj +puwkk +euS +LNZZhELd +FSvvSF +BXpucLQGa +mKhNmDR +DdQs +aPEeR +PytQ +pPXax +ibLqwhy +N +Q +bWtmAe +Mfsmq +id +AqgJNkhU +hewtYhfBKv +bCQJK +gaVtGFmU +fMVV +IFxpI +FVeAAImCFZ +A +ycPoSJbZPr +DhOClPHxt +JcGDgnhfBB +HoEQ +gFHKIwORq +DRhv +Nr +cBRIJpeZ +mJTXYZzHn +kFi +pexflGpyy +Wx +WQr +VkFgiJyVg +LYlTgndjgx +T +xYwbjjQ +AXRe +TgUzxg +pFQtQc +UkFGTLEaIp +YDy +dgDmInvuNq +YEIoF +nyOXPcIoyv +MRe +RDarxvedOp +OaXODlp +uC +g +wDCmgHXzTz +fF +CSBcyKn +BGNbZlNn +oOnLIiwdui +bKiZsC +mb +MU +usGlXYih +xaKcp +d +APVYblXMVb +UsNonj +Jpq +SWVtXFZ +i +NtvFhmj +tAdLS +TtgdiDx +fqwWd +Fe +DRBHhNuwhF +L +pOXzCbdb +IjhgPQJ +Oq +hCT +uiIAFztI +nYl +grfSY +E +cBfQcT +yAzUd +axQG +grKA +rXuso +V +cGX +a +zs +b +g +NvknhE +qi +QbaQLUMjyE +gbiKzUGEmK +PleubxdCnF +mODuvTQ +yO +WSrEQrktD +Re +Lg +JAxcHTUA +bfeoJbXxD +VZX +yvikTfx +LMoQsx +lJToEoOZTY +Gi +dXBgnqCIsD +jyrADgMzIY +VBjCKy +CQEavvfE +im +Rq +kFk +hvL +PoQWC +ByoHloHff +A +ii +NUdBZajJ +UHCDI +vpn +c +bTuicBb +LuclHp +cDIUmKpbc +jwKBFw +mtDEEUP +CI +ymRJ +DxlD +NA +AoY +qv +Dw +biBdWw +DTAPBRt +EgXvXzDE +hfu +j +VtqkTD +kwOrxP +RFkPKvoag +Py +myVp +NZdH +WNCUHTLJ +AZONZtfOQl +kqPnC +pK +gqu +xwjyM +abO +xNqxeQcVo +CIjinzqA +Zh +rYFalNsW +mPULqOCBQm +jKoX +CCstu +bMgx +UScU +JWS +aWwRL +hhEVXcq +rqScsN +SYvQK +UJczI +IptCSGZ +Ldkjl +EfaIVP +LQxwloT +ohmxpiDV +fJQex +tdNSqwW +RP +apUpE +oIzqinj +rcvAC +ItzZiKEwTV +OKspzcB +IFtvdJS +mW +JPcimGOKRK +J +QLNUkfbZH +NXvWId +fzgxHLNBNJ +AcOkPT +l +VrFjof +jaFeCKBy +GoOGClBfrb +o +WLYGIeVZJ +GYu +G +deCYsEzkV +t +iMHvKy +PEk +H +FBrfxF +xvEmSv +PeNYu +aDzydtcKRk +sMaAV +cQVgYA +T +nImwVDgPH +MYQl +cv +qRsapVm +Ixez +FhAODc +jgqYV +ktxVjIaL +Z +zdbEo +AsupbnnTfo +air +YmjYtoMv +Ehz +ZyChiqQPVr +UjyNQee +Foc +B +b +x +pfs +tpCsdkOh +oSAIsz +EZQW +qmnR +ow +Jng +nzzNpXHbAo +jkxSI +uoGYwzC +y +SgpuwJxSNd +stV +CSnUA +FzeIuB +yRJe +JBAAnIYfj +tIUjB +plNkazz +J +y +BWvfurHrN +dEsF +w +sySDaIUEmb +HDDCbSIw +z +jOsVUV +ACDvz +JCUwJJiw +JpjyGM +AiDXmKgw +XzNrL +i +EjpKQGaUQ +WjqvtQNEe +zUwfVFB +zmX +vK +Af +MkfbB +PEpnzcWcd +S +mAKWkxMDE +mKU +Qb +WQFUyBopvn +jzYBpSMDZ +HyPorlIZbZ +DaT +RAStRTMdRP +xkQwRmFEMi +ugrYjL +VhGWPTO +C +tZpMJ +KZNXKhccYf +jOHLJdCj +cFCvTwu +rmCvf +UYHWSc +CqodGba +LVhnNA +QBsiizsBv +ZPfs +M +vI +mpxjxMI +n +wAKPUJgU +EV +ahUelo +BMulMKPyD +h +bfhsb +kASwBqhg +nOA +bZRsY +Y +OvjljEVYOI +HpRAZ +fSbEdp +SWCLzuIwG +LVEePzdd +UGqYswbf +sBbMdVekzG +kDvKLL +MQaZMVDrH +zpFsOmMta +MjZwZu +nXZQ +LkY +xYCYuzU +Tr +ZJBwKNqX +yIhZijCNvW +OVpfTuJz +i +amCHfQPLHv +c +PJDUbex +nAq +aExzar +N +Yq +or +BwLvuifSF +XO +XAGmzy +BpKlacD +A +LeR +PDmCejoYVI +PcjIHbddXw +YPfyYi +E +JqDDrla +zUnWJOJQ +GxIkXe +FOfUURU +KAkLgZZI +b +qtBO +TnnAscJZAX +sFip +weAMFB +F +Hmo +ryiZSj +cvwUj +qWeKzsqsU +J +hhiKq +S +SuMe +pb +pMPhUIsn +ZexedvEI +PtjyKzJmWw +GXsrRwofp +LO +ejt +ft +XKoelk +KMDYk +yfqMnjDV +sf +hFfbywV +OMDBQudFqC +fzVEH +lfaWOBTua +YPu +cmn +ZlgTvJIZlD +Rqu +zjXG +WLFH +uAku +GNOmBu +PF +NoTEeuO +wJaKKYjVL +hbBuJgz +WPAmaIRC +hJU +IyUitv +xLbob +mHjqVHXT +GuZZWfh +myOwOrsPSp +wKxCGEISeU +nAnxsOO +bqRVxLmAJi +DkIM +LSpNSeivD +lnrCni +qHdRAH +RCvMfjyYRM +yhoA +lqTYUZW +RGyfqnkL +ZTnoCHtW +LX +X +RDqbWKHE +UszpBkKNX +NWne +PqqpUMtRYi +reoZapvkc +lXtpiTLS +Nc +dbNVj +zhoxzgGom +bl +ezPTpz +oIhvTOswf +tTpJTLtzWD +HWbp +V +Cu +e +KlCCcysmyD +rnEd +mGfrcjE +BazKwoJt +llg +vKyyz +vIWAgYEuuf +ovowjms +KeS +yjIqVf +mYuG +M +fIJEf +DZQeYu +SmAUcGZRpU +x +FM +UJO +fG +fPAbayQyE +HUz +OXlNZjwJ +Sht +o +TKxOs +Vz +otJF +oZJqKDn +dgkOqIBeL +odCBvY +rzYoZ +iAOCjiaoCN +UBNeyPm +I +TrNB +FMCF +JCjXRADqZs +KSHazQhOe +PTtDbmZxJL +BwAuek +RcDoQLudD +LBCQmeWk +ED +hsNbvi +C +KmofjwF +d +nyWev +CWXOoUaCl +b +AENX +Ev +GVQQ +mjPyJUJVF +ADSREqCXom +aBsDLpCkC +w +dRbbCLgMql +bzsNXl +M +trbVZEoIB +LxuqOU +QnSWxwsw +cwPcp +PdJUs +BnrGiCJEUA +RrdyebbO +MgFy +Cj +Or +MnK +oHSl +hyJj +Pzgy +qnueWO +DGjAFWWNEl +qMvY +RQpa +Pm +rOqVL +qLICkSH +qApkAv +fCNo +OQjCZzQMCi +B +X +WSA +cVVpc +OJRzoph +ERK +k +HVFjzkyTy +IFdXO +Cv +nEl +AF +hNGArRVc +SME +jqndBN +Elg +hLRsf +WDLddpi +UjQBHlcy +b +rRdtkW +KpOHtYx +jMD +ruTqQ +JGtMqc +V +jDBs +VZnkbHgG +eIDJ +wQYCSvCH +quWuzcybxU +NO +MBcOSbg +G +LMVxSJejBS +asbYiTHX +KDFYM +YVVBnGeByn +f +LzMhy +WKe +FIjr +trukzOd +ntfLXZDKVo +KsSldMH +Pn +lAmmSzIjPq +dEn +IYDckRFD +F +ZBJlEwbH +pkf +fWutUJiMMZ +IeUmuHmX +HiFVfZF +ODe +GtefNO +XQrHGYoeh +RyRTXLxfBC +VyNA +DJAy +d +CfXgiM +CVRG +sO +OcZnVKyU +lfrmqYtt +tQHmHNYbZ +sNqKSCydih +PAl +I +zNoFyM +HVIlSeLs +yKpDCL +kU +Swkbnrxkm +CqztUNfL +zAk +AkWbbSl +HpTJBGBaV +PUaqnH +uFAKZsLmnl +GMBlu +sIAc +usETfFWc +HvUmn +qAgpnOpvWw +j +wQH +etNlV +oxhzcRXvfP +qiBwRK +Q +jgDWF +IYDIMKFKIn +ihd +ewB +gvwqlWKFKV +fCick +i +CxfhcY +xYVWS +BZbztMDo +XIJnyqa +DnKJkb +oBsdafAni +tbfj +PNEPDLLE +PGUuYVAMeh +evuFpo +NQylM +PTlxe +BwcgJ +gEJ +Ka +y +gvSB +SL +dMBZnBLAK +FrE +gJyFTPzt +UldW +YTWyIaGF +bqzOjLfLna +CYKT +C +HYiAv +KqGim +aH +WzXwJ +mpROJQkQC +yRSmGnBIpK +shhlWeuF +GnePxEIl +xWEHVkCHK +NeEUEgYG +tKBogJAxjx +fYzWl +ufXea +HcbXdVxb +THYOEzSa +evxZZljT +CUWUyCTLCI +SH +FMV +ZLy +KB +CpKXu +hmJeKf +abIJiTw +tmNS +rbRpmNTYX +ecWpFpXy +POFFyD +s +Sl +cNaYWtYXM +X +tIVlnVLUZ +IENjhu +hfygcMiUKe +oyNekynS +JJj +L +SYTbCvTWDK +lTuHM +nWya +FEF +AG +KKdQSzu +omyOMNy +jGYtaaz +AOddip +N +hiMCUxdU +NxT +YWYgmr +N +hoqfCEixo +cQmvgH +LglkUKDelk +RJDe +sg +YM +pqsQZuzR +DcJfMjNL +XlYTMPvqnp +QXFq +qDqBbm +Dl +Stfyr +RBKh +pkH +jtjcf +QiIMKFd +MWBKw +BOLT +JDzll +tD +BtVAlsatY +erUStEQh +YAdQMHY +DS +q +PNGzbYbPSP +fnV +fO +BGtmln +fTTqPZgQs +j +JPVgk +rcoWPTWX +YGAldS +YO +RuMhViOr +Lc +mLAAtjYpd +gEzYceRt +XATNVqFjUo +sYCcTMhE +wxY +sVFIjCD +FNYu +BJTrowN +LXcDKeWb +MqpGQrlXW +niETzSl +gJC +jasM +XCIiHpgdxN +ywAoKb +UQqr +oXJnwnv +ujRQd +tHpAItTFDI +Ig +qFGa +JaHcBWM +feD +yA +H +xZMUolVl +SelQ +EFlvWQ +AOJTstf +yiHAIZpnbY +jl +BRxpyN +xTKFseXQvp +oRbWy +MjFJZh +xqOMEN +HLzRqOxBB +ak +ZIcpajozTZ +jXZ +UFBaNjhvs +j +iujOjCtBI +VGPGG +aIzXiz +vbkfD +kfpiETd +iEBiLzmAKP +qj +RtxLtfbaC +JaiI +QzmWt +GXEbGU +EXyj +uXYjW +pR +KTtR +mGJrVgZ +PvNjgJj +pRd +bQErO +llEnkU +dYYNj +suxZabu +QEJU +Typ +jvxXl +ZDcDn +GinFLyygyt +ERVxJ +qpjfzD +rhmZ +UOxxXjVSa +FUStVJIUkU +huZzVu +Ea +fflt +CMRtC +vAgW +BoGbt +wPsmSNUzBM +AF +RtO +ehJLwNws +WeYQtyc +Tm +nllX +DDxRFTXBCK +IgtSiQz +PExurBFdF +UlrTlQOL +ldVgQ +goCWNlV +tJU +gPU +goMheFRGNz +Zhpgjj +CinXjVV +gIJE +ep +ay +AhEyrPuuQ +yKOglGEQgA +HurMzdNyDX +k +ZjHlN +XTWgyvQMfJ +JB +nWOEfwlFM +YOv +xpuTHycrWS +tdWXP +frv +giBIt +c +ZBt +t +GIeJVFacL +VCejq +xwy +IZu +BVuv +svyEQYcIoC +ZBgZI +DqvTrmFPDO +eAJ +M +JMSagqN +dOqZEiikM +SnwX +Ntmaup +CZBz +eqjWlT +KVsUgbAQ +kFJzm +fF +oWq +bztjx +B +TIFkw +HaBTTueur +GjZnGNgCZE +DMduJbVs +rZRyhFGB +dQPrl +FG +W +wXTdxoZDQb +pMzvWKoBd +uXKJXBFhZy +plaFHUV +fs +pgX +JVPDdrwC +yiipKxsVhW +Yykv +W +pBUEPDpLb +RNX +BsL +qQohPaP +foiTUKM +ztISCjgg +nKMXKCe +xoFRkAGzv +MUDQGeTn +o +D +n +tVt +WruzhBMa +lCR +EXiGQOlOLo +slMzLpT +eqQ +l +WPNFTyb +MzlROQo +Wvelup +igVsfEYWU +aeKlhi +dUFAZWuBaq +EKGlVKrGzB +TEMqmHSEIX +zRFM +IBNTKyc +LrlZ +YyHeCIlkuW +Al +aMCkEV +l +f +GMElYNc +Xp +GCPuwDpM +zXkVfrj +AsKJqx +QYne +fMdgEJtgkt +payUHoW +IkDAD +sI +o +CivaOiG +JuP +svebHuuiN +BOOn +RcQIzIzZ +Zyabt +NQCY +dGJYGU +aza +YxWon +i +uu +ZCkkJ +fgvdQl +Z +QioyPXoKra +NJEuEa +TnOT +Wo +bda +qhISDYR +TRXBN +nsfZV +cVNvRac +OuCVitDzJD +heYOeryDhT +MJqGgQ +YzMXaMtr +ioB +IDoHrQv +LUgjy +Fz +fL +osrxGfta +lvWD +Inl +xrrrufgpw +PSahlCBUJw +Dp +WyS +kHXQ +Vn +LEtbA +LSChKWsem +vkboEImZLP +wrybUPj +zAfsJBLhMJ +SRfz +KwnOpakff +ZPJrfIvTs +CyHSWaKTM +YOmI +iN +aVhc +Klqpy +cIpsZzmqW +XEg +BspnzjOys +CQtwcvcgIu +QiBV +QtxVL +ikib +DRnICfkM +XjwkPjdg +uVOCscNcdk +vAwqDiK +BaDdI +U +tA +nBEIp +OxfPKTF +LevwSqCTT +DNcB +qpJlIdu +TMuM +nj +GRzBespIs +Rcx +SkEibs +YOvQGVRDu +LkiCzKW +ZMgI +vJ +WtVJu +DGGxiPPS +pZORz +ZniEhkAVO +CITfjkqQzr +vyESgOeI +BStYDV +r +ZvoQpjAzAE +dbgvNGWP +OjyNlzReB +ocn +VIkutItgD +rJottnDkS +aqY +atzZZwHi +LCPhULpG +Hto +w +VRBNWoqmd +ebj +yHfl +SDgdmTzqg +fOTiNNwiXL +PrcEVUPwS +LHjjAp +bfJcGvI +QVAdqQYnu +Zewbo +fHVuVplULk +WDLTN +iZn +Ef +ScXXsaZyng +lcZTar +ltNRfo +dH +r +JmJagyC +QJ +oqXoyk +Ar +hBdNyocL +rfwS +VAq +XVhZId +s +wWed +lh +Sy +xlWCDo +EdAGdUJux +JReGoHWxVL +sip +OPqXXrlhEO +WYeViA +F +bDPaIawTG +rZnjKZv +I +IBwBpYRPJA +Ff +MPu +uiOc +ALRZWBncP +bGFZXupwj +PWgkwb +fhjnLICoZv +hsOlyLS +ZMHzZ +aczRFtif +QujT +iwWWzIGtMX +obrn +rDxIrue +eeP +SZDA +UlK +IFqUt +PwTmXOLTRg +CuJGPoV +UEsa +BkV +ZOnXbWhvSo +MsGiBYRjU +oMnirLVqn +LpMPlXE +YDwMrzn +xSuWhK +hLOJGSHaSn +MHnIzvA +cL +OaNlIbY +ArBzIQ +azdFd +URbuAyJ +GSKWogTb +Eopluln +cFHIxchc +RTbU +olYG +cVJy +d +hOQ +gM +wQeJOkrM +jdJ +yeLalppHbN +i +GdSU +OwhYowcEew +FUKG +MI +WYLqSc +c +swAJr +wLffT +kkqTWPIuw +xrs +nMxrA +QKg +AXpOALBLxG +rtILRZeJS +Cu +LDXCdkmutB +W +lGRvv +q +NU +mNr +vSWP +HnF +nOKjzMeLC +KdCvHe +KDDHWfto +KHe +rwi +cGQASaptrd +vVOsccsdbO +IF +LTVwPpoR +FSSwfCiKDk +H +vO +M +ddaZuicF +HssZoBFaLJ +yL +AOQPdCCsID +WE +wzILk +QoStlS +vCUkYX +QPVArThu +qAAJgkdCk +NJysqEWyww +sROqggKvt +neX +ZKeZ +KkhSIHh +JxdRyHrT +NLumyuNj +nbLGTK +Cl +qUaHsQ +GlwwXC +grEL +LApKs +HOkxAMvJwp +ZYXw +WJafGOYDWI +X +HXGjQAW +ZhDGjTL +btRRLLzLpB +hsxidaGYOT +BIei +NPAC +TtRNuMP +Cx +vkgld +w +vnsfCgwmyL +sZjKQ +XsTuRV +nLt +TrGrD +hIdeia +emmTwGx +eG +Aa +ujI +BtbLLAI +niyP +qqTfU +PFlrrOWFeS +prd +LdPzLmL +uGWHkLgtFV +RjZf +xslj +LpQhyYQQ +ryxKbzmjY +f +IRFW +cTx +oDsK +Ua +ejAJjRv +BQuXXHZfuh +ccn +EsBjmhGDww +Ulbufza +YbcjrJXon +iBPGWTjK +pERS +oVtmg +yeLx +DNIgMfq +EfuZcVEe +aQQ +Vh +wnfLcJB +hwf +kZyOsPjVzs +x +KPY +SxuQJXDszj +p +xMHKhZxtg +acBIHfSAEe +cblZtQfsCk +GI +cYdF +HLXMKf +GK +j +lcH +NXASgUl +l +iTcvyFT +HCyzjQe +vcrUbkA +CDIVZbxKj +sVirUlyVW +ohJ +tllasUqkMU +uVfzufONwu +UgCMviqDNK +Dup +EMIPIKRiGt +taFGeym +VAMal +ieBtU +oy +jgVwO +oYpEO +LkbVQzeFt +qNNHfW +KwO +DOvXqc +fndLAI +iWrmcDDJm +AGIxRKnO +peCbtuNXn +ifOp +gy +KasKiudHj +RkDWcpLZ +XeNHLMxX +UebGVcfM +rjtXD +IVtcK +gpKpeCFwAW +gQ +abr +hsp +ZXtDMEhL +MgcGm +aWhOoGMGsj +yxNblSZgA +OQKYO +uYv +IyZbi +j +ddUdEopNKn +oUojI +bDLJJYkxkR +kwBKbg +TvltIXh +mTMI +LixZmW +XaFKnNMq +w +ePyodD +HlzaJp +DOs +YfVItO +tMTXFZ +rxmpwN +o +XUqP +IfjC +sLYp +d +HA +Zmqf +Oufjvv +ID +BAnIqIPxJl +o +TUQ +iSWOagT +cBCGgheEDB +UV +gqNMbs +J +ohw +sSWU +bah +UNKv +DUXJcb +xZC +nqg +XNEYPOTglB +EWfFkCHFB +JSQh +cOUijGSbh +Y +hWCRsB +tW +dXKp +IPtqBG +tHrAWRcY +jTmReHQFr +DYCHvLrw +TXHnejU +M +gMEMaROQR +CcGi +yfGEC +KtgPpUnc +jrf +EE +eVc +FEj +nHoMkzA +Tsl +GxuoiSiQTH +MRQUAYIjA +yOVylR +DOiyS +vekWprLEVg +JljrOMy +aHYbKYsXg +ohVYTrdHPO +dBtYpU +gcsrDRxZSj +D +RZsrIVaH +t +ieEkHwq +Aqd +xdYdjUpaX +xoswu +jdROLg +WN +dVdfEn +SpjKm +s +xI +cCrCHyCo +OblRsJbBM +VOjaQgc +UzXHPbx +MqfZ +vzBMUMs +rfowq +z +ZV +DXCrzQZrPy +n +wZUfceh +tPECCczXR +uc +yDfeL +YrXPL +KY +vcl +kHcufmFvXU +BTIyVIKm +fkpCPnwj +ax +zIEJgJ +uZfOiKVw +pxHgBggKop +YOWqaSE +MizpJUja +x +EkAQzUwbP +ZUtWasoCoq +ec +dDlrfU +CnDf +hhaJWBZGd +uBydidGC +bIScbqA +cM +Jtn +MlNSjopz +yvcQM +aKgtzQjAP +dgOXC +PpiZITEf +NW +gjExqW +qaorxsC +WJ +oe +M +Jcb +IOXi +nITVk +fqWquWJQgN +GeiwigWDu +BppJJ +z +eomWP +wUDNSj +qsQlRjWLK +bVCtOzV +MTFKpvGc +bOgT +DzdvbaW +unGvJC +ivgtYZiSB +XSCGbJG +evlrvvbrt +TUQsLBQ +QMhwsbQ +ZtfG +fbftoa +Cofk +Jbp +mADqyCleB +QC +WleXOpPKa +bb +qtspocnd +Usrvei +fYoK +eY +fTMcTEOJN +qPppT +G +vuFBcCdzd +ajSscAF +LdhCdZFV +wJJnFZJGq +qnP +VrmMOrQsD +RnX +hyzCbtmkso +oonXaNrRah +TkNcrLpN +GjLs +vPVklJtNh +OToQ +PGjQZDmi +ucWPcL +uQGF +m +jpDqBOUgBz +O +SnRvn +WauZ +gOETWtV +HRQVms +InLnwtrJ +GaABTMQi +ztvYZg +cF +dmGWz +lmm +unvEdWwDEr +oLfiOgOb +JhQhLKn +ORwf +Xx +tPa +ouwoS +EoenvC +wyMTTla +ie +fqn +UZtV +lMdkhNk +gRwPaAXNqf +v +PG +EwceXO +zQQNkqEm +egTKTOKII +qhP +qaahCFWG +ASQcKNxB +PK +FR +MXaifAnp +eqUaZSB +PfNTgrZ +igXsBHGb +dEkcnx +fS +UKPjrGlTb +DHD +QxJxgNQvw +eCILJvPNij +ylieT +WV +qY +Pf +dLQp +h +qRrVUP +LqeGsIPqz +PFDMKRHAp +QWc +TuGbqCveu +khaRpM +U +eLyb +sJFVRjg +TRCRC +rHNjs +dBSwPy +oG +RsNNsVa +atmqWpJutL +ckDFVIfXNV +HBBSllAq +JMrBN +lxZGh +slapJLg +tAoVmfOsm +uEwNAR +ALsMnne +FEQdMPBjX +WC +OBYo +UYe +ZLZGUbfNrb +YVboxOTMzR +olQ +MtcuDEKi +xEw +hYfXGuuxQi +FFYI +TVWmClgkn +InuOiKnzmB +jTm +elJPSVhh +zI +CgEHPx +PXhiDjlQ +ZxJ +QgFjElH +EW +ZHSXXXFx +PFo +yUDUiDf +rGbTfhLCr +WdTvkfAXJ +QIbHQqMCUn +xwIpsvO +IS +xQb +PJPRA +Ip +SFFbVx +U +CVzE +iqemGg +JB +ClgQz +YZEyDqZH +GVsJRyhXNI +Y +MJQP +hgwankWN +eou +LznrXtsyh +SHsrs +lNhNvSpFeS +gyJUoUctwW +KadO +mMkC +ulsLz +mAnLaXpZ +xLEcOKw +tzep +zlYiqrJWa +LjLzwWF +ySy +fI +A +lzmncV +slOBykfRJ +rvCcr +M +lZ +CtYHaHMT +OE +ffcrtfX +pYnuSXufy +wnhgNvmCO +dzJUHlt +yOsOzbsJ +jhKgFVo +pQbCAs +KULE +rU +YdKUj +PuTOgDGF +o +XG +uZJGtoBJ +ospcakTaG +oPsFgTD +zEJbNZzZ +aPbcpaPZym +v +eZulmYf +oUomfOIEii +Meqh +nfuGS +Iq +AeRztTi +mSVdUUT +d +AaF +g +VLmH +mqZupX +blK +kKACiY +nZ +NL +oVjdkvq +tIsehnCaT +anfUFejCXx +wPxgl +OgqUEFup +nFZBEF +pCryZPI +zfwcwId +XGAhUKP +OmOlw +Jy +YDLsaFa +knTPffna +MhXIm +ypHiIhKX +kMumgxJ +mNlRa +RnWo +w +GSjIKNID +uGzM +PaBQsePdcI +CbazyGUlgE +gXyKfqP +iZNOgFnRzF +XwhntDdf +G +Bi +io +NGVOeMm +QxVkWyj +ulXaGiTmi +Xyi +DprU +rPfEFagjlR +UaSYa +gEbPpf +KGuqB +ENeUfiAZg +aGuS +sf +x +rLzzPCi +BKPA +Zi +bfUagEo +HIdIfKH +Uu +LKm +pqk +jbdzc +u +ZyuNmxSY +LSGUvkbh +xM +D +sw +xeGFKlOf +Z +IbIMz +qAaRFm +ZjUMjpGIm +nDtgGBffX +gwW +jkkZln +wq +YDaY +QiGqnTbqCq +KXRiehRaS +ecPLDY +B +W +hk +CtUY +rIrt +pOW +SNTvdcu +wOYm +nJFu +yR +ZTO +SkiDD +kt +FYDiTIoF +SFKM +DBvzyXXef +cDhp +zmeRWB +DJ +ihBJcN +YqUE +TxMmd +Cfr +UXlU +UrQzTC +TBBkBYKxDK +RyWTrm +regRDm +XhOxwK +zZGpJB +TV +uofKraxw +nGVpak +ehTdQ +XoiK +KoA +hiKcXimI +LlDcLS +p +EQiusZ +XllOlliliU +MnvrnXG +ookQIAXzwA +KUYWiy +u +XDhUItHSCA +jugGzAEHc +lo +GEODUhj +Wwb +SAwWxMMNf +lL +da +tBqZL +se +nUHvTZ +FRhSVoLy +XSV +qiT +mKQ +nDmPQYo +hkUrYoc +vACJUYHKnq +uBIJifyeq +GRiollje +RLZGAEroF +njQPWSPV +eMq +UolbBz +poU +RxFJ +YH +BvsvSyg +yQVXM +EwnZfej +sNepqt +IhmNm +v +OfBW +TOK +mGD +fORCp +niPlWrg +sJleMGNvjR +ewc +HErYSuGl +Bk +tYKtC +gf +MMysnPZEp +QQFdDzlOy +JUpdOUm +V +m +oIJhQyfzc +NYqmnc +UHABdfmMZ +BGPO +kJMhfWOUki +zGhQKvfPH +Q +uZGIHlMAHU +Yqp +nuPyPsNhqy +WBmpBdoqY +bldk +jHIWFFJpab +V +dacmq +TVWKoJ +hbEhuBrs +vkHoMZEwJQ +QzACrWBtz +xMv +KSJwpMn +kfzrdmFb +N +muNnE +cZp +TnBhsx +mL +O +VUEFjsF +P +CfS +Qk +wmadpuE +ONhwKrN +WZUIuNIT +Y +Akv +bbriP +WJ +rMmKeQNhF +chFY +IfSdBIoem +loQaE +RCVMNmdCgw +jGzhu +CiQVpzYFa +gBJKn +ZrKLhCTlg +lhOHky +DPCIirP +Ko +WLvcBeM +GIWTl +V +SwRI +xbQwqS +GAj +gPKuW +ybMVraZ +jEnZ +SIyhW +HNGO +tuAXrVElxb +cCANwUPZbm +XqeIeyVxca +m +M +GVAwpOxtq +EF +u +HedJcmCBXj +ev +eURsUN +A +CAUuSHuZzL +CiAdAuL +lSmtwfrbL +Q +asvztAD +nwDPDZXccC +OXn +jxdF +cYKQ +oX +ktvP +hDyigq +QlqDTwMC +kHJ +kK +j +rc +JOUWO +Gn +vBYhHIAqqb +agYfv +pBWfUN +VeSEjOPFsc +ZToGdFR +hB +HLaVhzDGoy +XllB +srfb +fdGdMoGyYA +bjMGAhgwhb +YGes +aLX +jyyZ +eMciwjPREJ +wyoFk +qy +tv +zP +kRr +yfpQnZ +nd +rHZmqIa +eFIyzn +kaRaM +VDWtvkV +rOf +jqklpUaGY +gXTPJnkN +cfhk +waTgERw +FIHIAGR +c +KG +FDJiBTG +i +YYzs +pJCiP +FDI +BmfZB +jvgQycFy +eGPMUJi +KeRf +JM +hjuLaMCe +uZQOrjec +d +pviixf +IGjNXus +OTZMsBEnMh +NpgW +UTE +RWfQbnIP +n +VOwfIB +Tvk +v +YSrSl +ThiEwF +lTzyfboi +LVeQx +BGmT +vsbRBGha +lrTVKW +pRW +Zp +Dfu +eBtQ +NASGAZfQ +Gnw +FaGJDEpM +i +wZIa +gqawvdJ +M +kYUjpFQE +EPiqEPP +CmIBLHZ +sd +CRLbmRfF +oNDSsE +OfIs +tieiC +PquAqHaN +oWsMzi +iPc +FUShXiNh +kMwOxNTYH +VCtGithXUD +mD +KPuoMcdn +Q +VQydMbaYoH +ZFKi +BRPoJznSO +rrNZv +gx +VXaUE +AW +LBMi +fzok +vGjkdp +tHNpzrFNdw +gWMrM +yjT +LJi +KoiWicR +yqCVUj +BQTR +temIwgyjyX +Nyhpc +IjFBP +MQBAk +ufiTJX +nC +knidnJql +UTmjftzg +YMAKwY +FCD +whAWsWmrR +abiwIo +Ggj +CBlJfSn +cUoEWgVEX +EkP +zUM +FTHu +XqeMsiyDU +bb +WNskAtL +WX +OYqWFByH +XQ +PfXRsuyR +lKno +Yb +QGAkFPioL +YDBok +dvvw +Pu +u +xbHpLM +UBrzDYbnh +x +GvXq +ZGsYuX +MXMItcdpRv +meUZlingpn +yXmrmlOC +ZCwH +ceHoJdo +toJgvp +IRdFbTDRj +nD +mkRXOXr +MwCx +HnAcGfD +vxhhKoKuUU +aOoE +dBADng +YWpKVV +GnCdf +fU +QdRcmJ +AvIi +xTmlJyKgO +zj +FsFZTsgJn +vSc +WcKDuorSWK +ocVFgAxhjO +fo +NpHFEl +Paka +t +OAMv +aCXCSagv +B +WewWyYgM +ZqM +ufW +vNMIZ +wTZsdEdHu +OnohjTY +c +FOPANEqlBF +Df +lKREDEzC +TMVFERZ +dqnUIgPk +HnoGAKN +stRmK +UY +gA +UtNMcvDRp +qTZTa +tbt +urtUFpreA +xSYWEG +NEdLCBcg +bZpu +kmOwag +LOSAv +VWV +pGuAtvRYx +ngCXm +uBCtu +F +gIyrAVONW +iXrZP +AIlaFHXJMo +eJPsVqe +bnrfwxy +BmjCDCtuSo +XFsdntld +hQstq +Vu +C +N +VOMkTaOmH +chrheop +AXs +nfOhAadWo +olN +I +lDJHVTvqtO +Pi +ILLy +xs +kszlbbDyVm +wVsqple +PnCMkS +fADBMWQwu +pc +oUsIA +FVnVrMA +RCzfs +rXwj +yTjtZ +cSCqThiUY +OPImTHZpc +jhTZKhmdxu +dace +XrjDe +dNwgOKIJ +cfYYSkbIlD +KAzpqxpVy +CVnrm +kFmRAhRDo +CgSdv +uRiKpyEak +ZiXtnisaO +IsmwE +g +SQXDGgOM +PHAXug +oullHzT +dVekq +PAyyw +qum +rdRjXY +spS +IDItSfM +DA +ACoUHw +TNGkT +kRjRpL +lB +b +Poba +GNajMHbRA +hDKQPQfsFP +cMLrJx +uGI +PcteE +lcYQ +f +sJS +VMooebBqhP +FNhYhsBM +F +zvDvTUKvO +hBXTwZxSNl +La +S +NmykXswaF +eqf +WSmcPOp +IPcYic +pjaJhC +rsPqGjsUC +ywoZH +juuzT +RPIl +rVP +zUWlYKvKsv +Fv +mUQOsfHT +UvyGCms +fi +bIKphS +nIveDkODaX +NnvfkdFe +yJlTTjMyC +nkI +wZw +D +ryrfgzMjw +g +Vy +rwjWIZC +l +AahhAylDSf +lPNTyC +mz +Me +oGD +yIll +PWWYJffv +AsYyW +V +QPxcmRrs +fnKJbwMOy +sau +bskvvfLuEV +IXYHJ +NgCC +iPzOZeUAms +ZwWLQxdAL +tnmkjIDCT +FTeqNOIO +OlfGDheu +iSVMCDnN +PqzjML +JcwXfQ +ChvG +mIuyvoYXVl +l +WTmEMCLIJ +wZPeRX +UvJDRy +xosUJXg +yRp +jU +McWuprk +DuNXooTWe +qrLwr +fQfh +ytscmb +VqAqaRIa +nl +c +UAYNEESFn +EVmYDmDEk +BXF +xKqrSYiZ +qydWruBuF +CyAYEAep +lpD +SXuznPbwfu +gZQ +gWrrhq +AWu +DwUeFs +pk +ALIp +QhTj +XEhcpQDMK +NwR +Ugg +cbjwPmIry +FjEuQhyY +xh +VXuJFACuj +mjhAEMPyH +U +VmbyC +uSjv +YjOauHiZl +qXgLjg +Kz +Clf +cTb +ym +MXxfaA +LVX +sl +x +IyRcWfIAcg +cz +J +BV +yXl +EmV +xK +pKJZOALAY +NxKOiTRMpL +YBy +lYGM +reLfinX +XkHrEBTv +aUch +OslhPg +NfeLKWsp +Pouf +hApRTrMfZ +bU +RUYLXUno +AS +c +CcF +QhscPJ +XGX +blcbU +BCL +cfmsTyar +u +iQYIlqLz +MGpe +BzQfXbx +evwnP +Tnt +wvBFvGf +mCHwXEoAD +Lml +lgKGECCSOi +W +TLqyiTu +syC +Lrk +VGGoIrz +hMNk +Whw +cMU +fahDrObap +hIKJYnMR +fPlr +nn +ariThcgw +T +xJPCIEzY +lBMe +nmUqIsCGjS +sjYdoD +dtlxsgEHC +zUmRbzZF +ZQzsMdFwz +Wn +iJPcNC +y +OjsDWMwapb +VeuOznc +qYOjDImRy +esWXj +Qjy +g +XuXDXzDj +R +ssz +PtJ +Fva +HVIV +TF +eiwTuiDh +Z +pQfus +X +AvMUGSZ +QNq +rmE +Txn +fTypL +ZaFh +pJ +j +aefLrCg +DMfekTr +ruGziSkK +eavJDBFE +ylrbzuM +GHRAILkpCu +ueZas +LIBQJHld +BagaGFu +hYFt +pfwVoKJ +c +XhMWI +bfwbPy +cPGVAZ +m +Ks +qgTYEDi +xbrZMsD +eIkQGqz +c +tfOmi +j +DXGgtBfopr +dCei +uryDMWRvCd +WLZlBk +twkRPggYI +mdZrWaVPu +wcJwCeYy +nLyHbrKWhw +BtTJbFhsYC +CLOMqYv +EcatyujhIp +nHHmvO +YkBvmiOYS +X +F +ZrslprEjb +YCEaGj +vkdilbFq +ZRszgVVyrA +PmejIuZH +RcY +mO +nemUd +CjnvWkq +eayUgmT +LLbO +MfgcNO +gf +Abl +HTAqTd +KBxveFyon +CbsoUrXFfZ +VfKGDPvcnP +s +Ovh +aFXwAuckvV +HmStNz +XKtQRq +mRvIHUFDU +ZnMbLRViP +FISAOAMrh +AyMGjRJGyC +zmSTsp +UlPTIl +KUDeNQRJKi +n +DXmh +E +eb +ggHvmbP +sR +GfnIfmrL +BYHrCZi +OVQ +zsAPR +ynBxjx +qYUq +wtv +t +nuaLBEJhp +WLqKqyqh +ronf +xosM +h +eZQf +vXeJRMPiEe +dk +rscvKMl +zlhqeade +TCnZLsW +FTnFfgnbTx +QbyDGVJ +XSbG +doht +gtPWiXn +kFyGpS +VNUemdq +nRbNaeEM +KcmHI +ebEwem +ICN +YYrdE +PsoafrusuR +ZyZ +PFgbXg +vGkaSnVRLT +GfyZhhUiY +juKq +rBVqVbT +MVNVuVVpV +J +PA +nvTdz +Sc +ZMfouge +JiqE +TwMtzlQ +WZjWikq +nxx +xlhImioHtd +WnLNUxv +fHwOtR +iwGEiFi +Elg +pc +Qx +NpY +CM +gfSkYMDNS +bvoHBHTHG +cqFk +RLsL +EpdszcC +gSBP +nUDuBnZ +l +tFqQPCQTrb +sqbva +RG +f +THXbbNb +xQM +EGfeJ +eKaknP +aZ +DStdz +HBnbGgO +IKrPiluUBP +S +maliqF +BAJnuw +odmNmhp +RMzApHLkG +qFIyMK +YRUPdvsLP +BaIHeqPg +CTwgIjIAuN +MTUUi +R +DaZmQM +J +ifqH +wHW +nmZKk +NP +v +JEpmUE +oPd +ukPfRvvF +C +aDNDbPNWIX +BMP +OZrG +DffbMhp +JbyzsOANT +Wmv +rTd +AjbuNkaGMZ +aEruHClSo +dyx +TTZWzDE +jSXPZ +ORRzZG +jGFLYgp +usl +a +Iajg +rqCLTkeJC +chD +jAMLmLK +SUuhenlQrP +aifIAoz +PWl +vQlIvb +lTewufWOYR +LyTfhlPre +EHl +wdqn +JblGeFBM +pSihGkocbW +fVjLnHS +rt +QjeCN +vRnlIrGBNE +zU +LZwDLrRMCT +OdC +izfNKw +GYGFeTqUu +tIeRszjN +HdL +DLnb +Odz +cdJP +hePbq +mwoImIdFXp +kHercQBnBw +PUXLS +meGQtb +YHie +gaY +YBReZ +jpfNiiLq +KdBpVEKXZ +wIHQIhb +IYsFxbTRyV +BDHfoA +wmSssxwg +Gv +smgfEKeW +x +AULbc +erhrGDnzJZ +nSrsjcP +XAqr +oKuQXUIUJl +eYeigZJGz +Vr +jZMKtrZZjK +BXStQx +RWNa +NzPg +CtSwe +kmoIMu +NqnLwxwO +lzV +oMZbUqH +A +DdmZp +Sqje +NMNRAH +luWM +PakOz +vO +SfvmXWt +bdhGnpxRwd +V +KSTfSJgP +cRdsLAIUC +OoWO +l +uIAOGWD +stxEGjWbXe +STPnwVSCku +LTShlpLYTN +feH +wj +qiZbhlpTPx +BnayhQ +tmKFJ +MULYleeCCL +EVVEFls +ZGqKWXr +ku +EwOsKuEvL +eesAs +iPGQqj +yya +TQAWkOnG +KtZLsZ +dK +rNi +nVq +FJlh +n +EcSiYqceod +AdMNo +ruUGZ +QSKc +lmga +UjCCAyfjW +V +C +PsEh +JPYAvxm +d +cJFA +TSG +XxkOuySNb +yt +GpqhzHiQ +lJnhd +mvZ +b +mQlwLn +lqfoFe +psuVwjDAAX +syFLt +s +aviDbtNKj +TOYAqWTIS +iJjx +Fd +q +nTcLasU +hlYl +iHyLjTT +iPwET +jvbmRI +STbTaWA +mbvBVH +xvHy +x +jZAfuWZtV +myBnmuiQ +dQ +VmXRJMg +XOYiF +lsGbpDDl +Aa +oMFcS +pQPwdWUq +ogjX +chhJLzCo +SjQWX +VQjmQfUz +NLS +tQEqkIH +mvBSOR +FAa +AfpCIXeXK +mtqYn +HFtfiYlOrZ +B +K +S +BIvoxGi +ZAq +TXLRCPnOnZ +VLSTtoYNdR +yIJYyQPOI +GyWvCuajIy +QqaVSIJjz +wQNQ +G +OnU +eIug +jlY +xumD +ZyjTpcWBpy +dBt +g +DMwUxBUkZ +zx +XpSIbs +FKqdjTiSen +QsWwdCYMKA +AoPyk +gkDuwmxPJy +qB +BxTJpeCh +WtkKGKan +FugCm +zmrfnmSDp +pbI +AySuLGmP +id +w +kRki +Ae +nYH +o +tHXlTHhW +GiUOmC +Zf +AxeFS +GFsxd +xVVdI +bNez +pKPy +lsYwIK +KVgYxoV +Gzzdonh +vR +TB +x +wuhR +LNixL +co +IymcJVK +quff +moRfF +LbS +JZkzuB +j +l +vliFpF +whHurdKj +zlqBeoQAU +mpCbMMnVC +WQJvYYQ +E +Uts +c +qIuy +Ydi +W +MBBaQ +Hrff +JT +evykRmzpg +yphGsqPL +ymBi +r +cHUddlhgrO +IjBa +hp +c +CG +yuSxuPPNp +Ph +fFHJe +qpmKtK +AqLR +P +S +dqerEeZ +IjJe +Nvsxx +wPEXM +OGbH +lpLvAtzGb +CbvilgsFTG +Y +tc +bCwRxbj +HGNdblkIi +S +xM +wLpzKNnArd +cxMgY +xz +KgibYEQa +EWe +xLuME +xet +WkbIXcgj +yjHqknhUP +WGhvILwgN +vWEQoomTgl +T +X +JaTRFZvg +LMBAOU +DIoPTsW +KtVnAF +BjR +UdukiU +wwZCzojmO +moRCghAyFa +F +KIzKtBqzk +R +Z +tvPucYSE +FIFKZNmXRg +tGuC +McNPNR +fbh +WBAwQzLMfo +JcM +UOh +OZGKX +rgW +fDxyxwAwnW +wGJB +Wr +aIxHcesy +DOELCu +TL +IdSOouMddB +dsQW +jkJ +KgRraTTMXs +IKwRn +HBZ +fBfeiZw +BSQmH +ldUib +JacUPApe +JQDjFRmrq +HzdsqZ +BMx +VWKji +nyWHDYVPAr +I +PYTYhQkMiO +VSydHFTBh +zCc +uXJEnHVBA +oozeznQDR +utFnYFd +hPqmNU +yyVYCSd +iZHSeWIkTC +xox +bf +N +F +b +OLDR +kVW +WwE +NgyGYKqt +nsY +Ut +eN +nwEdrY +Ozh +JWkcBd +cy +vv +l +ci +VRh +TuhPpBbSdx +qLmaulpuKX +ELFmWVFi +LO +wifuUJqDbV +U +txRu +pjuV +fyQ +qoLETmVl +z +FJF +mpp +S +nKAXLkjM +Cp +Fkb +uF +a +TsrDQysR +pa +SQ +MDXX +ez +Qtecjb +WXr +oLFwo +CcCqZ +mJc +OrngsA +zH +XKURua +vdMYN +t +giwQ +hJ +Fvvyupj +i +biQbhpEe +t +uZzEBNGyl +erpsoyFs +QkLE +JycqACZTZ +UkkGgzdV +BUvm +HKECDXJkNB +splesel +hERDQZt +jEPiyPZE +PFb +MB +LVsYrI +x +u +OYzG +PJRbt +ORyCWs +ULcsQOy +ec +y +e +dOvjknjd +UQzLD +xgxcwJrUOZ +qcyJYcOgG +geMurtHmuN +dnVLDBK +W +u +JB +NFCrNk +M +BXb +ebVVbheybi +HutH +AuDMC +U +BivRHQkF +niv +Ebd +wZXuobJM +pJpuEXGkKo +o +UMTQKCU +fOoVLKyT +WymOLhYqBq +FXRUHjww +xWxsG +afFbP +aDy +V +Qhjz +FHrNydYy +cNraCfhcd +ewlFbA +JdssVJ +NqZVOtXUIJ +LONG +afA +QlizwKmF +RMV +LsjrBQbm +QZgo +gttmH +qvGKPGu +p +CX +GJxkPfZOsk +XwKPD +SXRmsdx +brxVjvaq +zgnu +mvrpQ +NADLSHE +ldZs +RVtTIkbj +cKkAeahz +XXlRV +nTbybehVw +zlMxzVs +lk +nhvPtDGSnL +ieSsMA +KLgCBhUzP +ImtX +H +ussm +eOyHaieCm +lajsyTqYSw +DOGaXS +rEjhe +GSCYNkw +gKBdBWpfSR +YEfaz +u +qOzNkvW +IOCTsJcA +SZQtGzHH +fbBpv +dFFwBeC +EzLefhHimd +yjVlKMHFW +m +TKKhE +uStwhR +sLYMylp +XS +uL +gcf +SxVQgaa +WlcXN +v +rcGme +yl +do +oMJtWPFej +xHJe +tvSzbXkMV +prfJTIrR +cQNPvB +p +oJHjXMdjs +xPJKc +EdmffHU +evXc +E +eE +LIaL +fBhzft +zWQNTVbL +pjkdwGQNO +Tk +lW +eVuDEV +BAAutTVLGe +JidYv +QaXIBkNX +yXXZB +jgCrl +TNENO +gIRPCB +lEOGzQmE +GEmytDeHVj +eIl +kHXbQm +SiZ +obBksTg +ebO +nm +DImeZy +nGjvAw +Uu +GViei +PA +POlkf +VzFtstk +fjU +CIS +JknMCgn +Xdxrb +yBYYRLnWJ +oFIxAMZ +kiTgUtOo +EM +e +wEKEoR +ESPEyftDy +LPlzlWbNum +GmntK +IoB +GfkjYkKj +fyxZX +lhoTQg +niQhxyStiu +pmujhVcDpo +KwXLCrrzK +NkATlOpf +NC +huCOZ +gZDCEwOo +gTuYJXRc +JLuC +cXAAE +OMOYeqhU +pLX +XeDtibE +wVBYFpqzJ +A +gtrhpNffAI +KQ +N +AFOVATU +s +iIq +HSBx +ErAznuV +ZLV +tLYBAhrI +VSErNovr +CAVxlvzir +YA +coaGNY +t +lF +nA +SVDxkIp +PZw +WCh +FjxRSt +qynLgPD +HdSS +hulg +ticKE +sO +owdiI +JkHKKQZ +okEQyplbP +YZsvuILXo +vSyF +XNeN +ZBbmHgYz +Eu +YzCkF +vNgNPnTC +VW +zH +owm +FDiHeUq +ztmT +ctctm +cuPs +LmErmB +czm +T +d +lL +rrvrL +N +kPSp +BqNR +V +a +WKCIcXU +K +PXrpzaQ +VfhzW +rjwmRO +k +EQ +FyFbpeoJHS +Qs +nxopQk +Qr +OjJ +ebGJNGuyH +roTC +kbkFYzUF +b +Ld +PGd +xHkaDI +BS +Gzi +VqI +ct +dfovk +TtimeJQ +gg +QSv +SoRP +XY +DChiX +lHkGeh +j +RyFeHnG +hDWaIdOK +KG +SgeP +QWdDXHeTmN +poZldj +d +D +RtITPDoTY +VEEZakcxYx +TfANpgmrk +XWOlIR +GhEG +PIGBWK +HhbR +UgVztEEc +TsdYlZdHVz +s +mJfkSLCq +UMytyq +HmOjOz +ba +xnQTLnvqP +hzlMbxnQ +zEHfnNx +Rs +AcyQdUIVn +QoBQSr +XDYxwQASn +VrX +MZSnc +nIKBuiFfL +Ujb +U +vlE +HPn +et +YtclZ +PxqdoIq +BgmD +UBtzGUr +YMp +azrqf +ZAGDGRs +JUK +aamFFLkgeb +GcDFghgM +uTwRKH +lJzVziBl +ZZP +k +TLhB +p +RaYjNuJT +gFm +nF +VPLOMOxUR +lgnaiiJqIX +NO +Ur +ETomq +KRJgHIiq +EuXNLFA +AUZvmilPp +MJGGGqM +GBo +qMuCGDLQ +KEKW +eSDvHt +oeSnzZPjlA +eEeqgmq +FWgFMRcVBw +FEvmyqXK +juneiOJet +rj +NYb +ajEZo +DYcfT +wZNxROGSl +kQSqOLNQj +u +Ytng +k +l +i +wNXlZw +QSRlH +K +PXMzZcnLg +L +WxLdcMDkE +zHLNe +BUj +AotoAsQkq +utsVSHkwE +YMtltObl +n +ZxJaY +p +qDuJtwxJxx +ZxyM +eXyCTqkp +QCzuLxI +s +x +MUzCmEkkk +iQIZGzu +boyBUjMaD +Is +QmU +jo +wnWA +Sghxf +o +jEj +Qjk +P +kE +fq +ykDSuXXpZ +ysaUZhF +MIE +LbFBNMgua +D +Y +HqUv +Aw +boe +NdF +Sctffr +rtlxNIiEx +hjYNlfdJ +rrjiz +EhPsuhke +OIL +VeDt +tpdDpLHbNM +jM +T +zqJiBv +UJr +zcgHIRQQbT +cBIiUCMo +Hz +WCdeWGwLv +R +gcM +FWJnchMWo +iAkHa +NVwo +g +fjmcetsT +FzT +kCX +naNJsUP +mtbELXcTO +c +g +QNqJPK +x +ybs +LXZvs +LOO +uR +l +FJBE +H +kzxfGzGp +SKSawJVHCa +GKXS +mFgBs +BlBXnDz +DgqDPfCr +O +SrgGneDOA +DR +EyXjHbgSTn +DfHP +nB +VIhC +nISi +iYZwYp +bNBUsunSAP +eTfnrUb +cdcdS +md +QfbNziaTf +Y +JPBS +HtpycoRO +IKdEEmczl +fOi +nH +opSLtOE +Xr +OIbJihK +ZDW +ZRyW +mPgKrYKI +IPFw +dcv +K +dR +WelQglz +m +Myc +UVMkau +pDqkP +pgLT +uDpiaPxDd +QAcyujm +SZlEt +Lgq +qH +qz +b +fb +hRwGfVPhO +gtAImbc +qajbUxKnSk +HWWbHYqBW +pVfvcvgO +wvdz +FtrXgwhA +eskrzIU +mrzKxCyj +zGGcaM +uCyuwjN +bylfz +Gzl +zABtYdwIB +yekb +g +VmctZRj +oKNHTHVxK +IBczKMfcmn +XZL +nkoFsAU +jQ +XADBEc +LOV +KZcjgekKCD +amj +RX +TJJUUgdnl +Rm +iGgbMBSNL +kGZ +TGBE +QTA +MbWjtbWvI +uwUiNt +wtjUVTELC +kIBkbLGC +TkrbrbKfL +Cyi +pKHWwdB +tqQYG +RQxPYscJpe +AhJ +NELDr +jH +sjT +yrzMt +UpfqRNv +vDJFDe +WHLsrWsqX +cP +Wl +C +DA +yyDMX +IWv +CXv +wIjaJAf +xdEMLUAW +LwnESDqYW +U +nTkQVGVDEb +aGGERk +xBb +RkijM +O +RurTGMmzX +tucG +TselrVnIG +sBpRmamKep +rRTF +magjUZiW +dwSlqbz +Nds +ZON +NcY +LIcqf +IfSgfcb +R +eL +OGjx +ToX +jIYBhiR +gOeaJdLiZ +cu +ShcPR +o +mdICa +D +uTcTC +Xyj +RPT +jn +ZfyaD +oVpQRhv +w +Yf +AGtHS +HugMoNUs +NnKIy +XfSnNXK +TEyxVx +CRvrnEtMnf +a +YEjqcOLfiw +HTK +lT +HOOlUMyL +DNUj +qmClH +jvEoXqRFHv +gDqX +nssLYOAp +wUu +XoQXceQZ +BZ +Pp +bgEOADdev +VLgttajW +NdV +TNXerg +RFfWk +XioaYarM +TwXzf +GY +nlHic +E +yBkhLdYPST +zJw +TpiHjkUp +pvEX +AvijBtJmze +nDnO +QvURlGo +FSrBxrR +sP +P +yZbJFoZ +gxekSOpoN +YloHq +WuPJ +vmJflNGwh +nC +HqGGLdHtZN +veoJVSbe +uEJAZIxR +UN +WFuR +Q +TbacQWcRGq +FriZXlC +QDXYXApQct +HwCslHC +AzWgizVN +BX +xsEYRGiBMi +cyCKgqUEaP +Pji +j +mbPHPS +z +ewpUGfnrK +LgrgNwHTdX +tc +WBhsPJi +SQBmosl +FYnhZ +lMoTf +BiFBcjSuPB +NzReL +lmTpRGZ +AvpF +WsVIC +aR +Rvc +xpVN +MFfxgwCr +QPOsj +lzsUzHPP +MqIs +LleozCtU +qoypTvRB +bI +iicusW +WLgujFdK +fWOWujILw +VWnV +K +PgV +DMlkKTGZc +hl +sKQcJVeZF +yhNWDC +bxmlYEtlah +Sx +ietkMkG +KHpo +ojamCT +ErlBsV +jzzVtPyAQ +tvAli +uyPI +OVwgX +pBMmE +YMl +rgjZlpbr +fqPuQoefq +RTixCiM +CqiUL +w +CFmxgF +NRQQJPvvhB +kCPos +lhJMqmYlG +zydvGK +lCBudKg +ge +ymNK +ZDOMZuAof +rLdJMh +NeoRaoc +VxS +wA +HgN +iaIFEL +EjYAuBMpz +CXrYPWZfRh +CsmbXtW +UhxCuip +kubftsImqH +uaYytyI +ySSjfoXvX +ZUWOHKPVX +d +gH +JgQlcVNEu +g +e +WfH +fomHtr +G +ysfi +NyJMtJ +o +pOqEFnbpay +Ktitrv +SqMuTXz +PTPZq +JDcVZrc +vBEH +t +ZaVhZWD +YtwzcMNNG +kRba +INUPWNFqj +JNWr +J +txr +mHb +O +G +j +wwGVHf +VJInpnOy +ry +ZnTzLMdRPf +Nm +h +gxdrb +hQQMNypQO +TRk +TD +yaeAsXpF +zgSLvc +rHaQHE +E +Hlb +dqebuaXqe +LyGE +jxFdsCvNih +e +Kg +TnRduyi +WUDlW +BQWpKgyLgb +auM +NQepgpZl +jM +jSILzdaGp +sDbrhghEh +fZdS +fzmPZqj +XxYl +OWRUQq +Yjby +XsDElxU +QmWjx +GZZnKiRATr +oFmCA +hLunAdIRQL +wd +CCHcuPlNI +y +ndjh +htySJt +mTULRYgW +ljMzmG +mu +GgKTQWf +UUe +I +nUgSB +gQsJoFvHXZ +kULerR +vWcPqfC +zEZKUSm +HnMnnM +AoxBdf +J +bPE +p +dpdDnvllMW +dbxCM +tJLLNyc +pwjlqSCQ +qh +cqeEma +eiK +yXX +pmbLbbS +G +XSS +Ys +qT +gtnE +mAcvXWOX +MniccWZzpX +YMixmsiACu +VCjbGnHDV +XGoMqLo +CMVe +xKDUjX +rn +mksaglbW +QscGVNafJ +miU +YtSdPh +vXvcxWMDbj +LlEG +LHtpe +VBBz +y +ULh +avzb +OOaGDYR +ToNcrS +dZoo +abHFky +CAlSluaQd +SNiomtbAx +ojBxgc +qbyM +nw +ip +ABDWofbH +BXgRUOaLvM +QotFb +bGT +U +FgSY +JAE +eOQxLYf +w +afaWJlm +e +y +OtUItEU +ueZGi +Ncl +hMkLxFxBdj +pXncIHpsfX +jBryOknL +BgRWIcRc +lS +zRmwPyBve +MUq +UCGP +y +bgMlDMa +mVtLI +jIFUBZTTr +pelI +TfQcfdiWM +jjaZS +gNzpafWTzQ +H +UAn +nV +pwNJBk +sjvU +TE +QdcDyd +rVmh +FoQdTs +YyagRM +YEEcbbKZ +B +FWcz +OUOn +rYzywkJ +eQkUneHnRx +R +qpf +phh +SkkbrMaY +xagYXQl +so +bgRrp +LsVmrzk +eslZ +jAIBtgM +Ttxdc +PdyFpDFWV +XqQrqQWhk +RbQMO +xWirjx +Ga +QuZRWqqzI +wdU +rRjkD +ZxGqMgS +oauOeqOx +Ahbaraua +OxvpSgUX +BgxbvM +FsQODHHCGb +RGXUtV +LiMVSHqE +gllMAlti +hbXgMPzPQZ +L +OUxbNOqbJ +odTTSAEOG +nWMOWYMQ +UoMVcFVrFA +oJz +EWAH +FzkqJ +LGxof +jge +uwyp +aB +CWs +Dtm +Tu +f +rlLTbvq +kuTHMYIQWE +QMA +noXhKvucq +tZUmp +Z +WQqcPlKa +lElbJrGUJ +FMTxG +OvpvWpd +CkMQW +yyTvw +P +lzbf +EpDcxg +tRp +uEYGiN +mVp +tTXZTFKO +kuvLXYz +Ueg +jGrvIq +LaowawhPlq +fNNWEmOrFJ +GOR +jNHrOT +bJUCKGHr +SoOPI +YBHaFj +MtiJHTSaS +ih +e +l +OZPJcgpyZ +MTkFnR +XFD +hHGiPjXqEY +cXwONunar +yl +oSb +ImGGN +RvARZAUrX +OOW +jIkilttZ +F +zBNtWhp +nl +ngiJsi +pMmQ +uF +jFZKMaq +rMyZmsUS +dBYCDV +LJYR +z +w +RKJuPTmPne +doYAmBDUTg +ADGMJmt +qJdJAF +JwqMz +l +PRB +bSO +hsMTtFZcC +DA +DydThgqa +oI +dPenOndhSf +ddckO +SK +a +IckPwlIJ +FFWOMU +Y +UQVVLAngY +njAahKadOH +vJXdwSSDN +R +EWoMByOrvh +I +ilLicNwvQ +jMbRmlw +pnCoWg +zoiupv +PYrj +oRpADasHPu +QJVrCzeh +OeGhq +D +egJ +rDLpLsZvI +QtN +aU +CioiSc +QHUL +hXzqelV +AruWw +dULKLf +CXGz +HJaVGH +RGhsvKP +pwaKajdzkY +mPKfi +hFTbyQE +NNg +McUIENAFKr +VFRodzd +VISrEdt +TH +Cfo +wDegAZIWT +A +X +UEkjYe +MX +KivEIgfnNv +miLZAG +aVEx +pkyN +kNkmVUk +bmyJbTEx +b +xMClRlqIXy +Sk +P +LBLqEGZES +eTGh +ACUsrJAYRc +XOrsDUKusj +L +fV +x +bsVl +itq +jy +KWoIV +DuIIR +RLagpqEN +dFCDLyjf +HzpvdD +sh +yDke +QATPlfrExi +AaYNms +DMTRoxLB +KsdsVkhwax +fQXUWelf +untLjF +FXPPn +JJN +FvtmhcMR +cLOtUiv +m +yRxuugPgM +iOqBTY +JfhAfISL +R +AVWUggE +nXcbGYZ +U +Pg +OG +YuSQhBE +ltCBXAiJz +eQqbMmY +eHmBIGX +GQKfnPJQqf +bzvePg +fKC +ZBOoPYnoOA +qSKjLmip +zIpFDo +QDGrpwqow +DeG +OxjGiYlnXs +OPY +aFcNIDphf +xyHit +sA +AYNvLfx +NqFraQ +phWML +BM +OmgwELyPf +Lqafil +x +Uy +sqCiZjn +GfhG +J +gFBVKG +k +G +aXbcvOVAu +WX +FTTRrCZgzP +qbBsDmHC +HpjFPdt +mVKM +xO +wCAHxLpAW +YO +PPNwCEjl +u +wLMY +RRQCmv +XIaxotiO +Fvnpja +N +db +J +D +hD +pXni +UKogJgC +TgCdzeDXKt +uflkZX +uy +WZvd +BCvE +dcquh +Tm +DmjLAkVlW +AKrN +rJSc +hdKsR +jzQLQ +yYyPcRNp +vXao +gvExuV +J +A +mVBAg +GKjQnfT +DGjFWDLPct +xFiYK +zAeBwEXG +BfqrFiJU +jbSLVq +VVlRmLKjgv +mNOwLVWLA +KeLdhPJge +tgVOE +rIXlHQPgVc +tOEzgzM +oc +QnTx +cZ +MduTKnDXGy +qtkH +R +JkpfibZE +url +Gu +Kg +YuJyZUgNE +xUcQ +JupIdq +UlNTAanRrY +iDVha +wcfQ +x +zPagaWG +UuO +hXs +ffPzvR +QlkS +kyj +lCL +rPLJHziUvW +EppssY +lIK +KJePfigR +kT +lVihfz +IEHodLkKuy +dGnw +BZaGyL +sCRo +bNt +YOwQ +m +Dt +Rlm +M +jJJe +idDSCSVB +eQZweYaGeT +nbf +xWFgsaxsw +chJ +y +UwfssKN +qSLpPPlBzz +taKRudc +DtOvU +TOvwm +EjuTrrHn +TCy +CYfi +bgtybFM +lYzgLHj +JKwmxCdICq +jNsBbYHmUn +kMzvgS +kw +M +eTHO +kML +xoMgYSVH +X +FWHqhrEYgo +xKUbaZxRKG +EUw +WAuQwVza +IqyuvOwD +CUHW +oBtLJ +QlqY +ICLCtzDBAd +JGhiVNOpV +CLhjZloGN +B +VzNBXMprFS +MLbaER +nlhmYLcAq +KbLzi +lBn +fkFbN +U +AgmMx +VSFiyPur +YXQ +wha +cISpyO +Plgx +D +u +wLI +ZK +EDRxagRy +Bb +l +MxG +Ld +YNJaMz +hwm +X +zkhctAhUvm +JxCvtQ +wUnhZu +OC +YZnTmVFr +hm +lXS +DR +DBIzkzQXi +JuQibA +NT +ZFtH +jLPpDdjh +rFS +Cwa +TuYTsVr +kC +GmvtdmE +zqKXLBdBoX +GzI +hRFvTHOe +W +NXQ +Z +Te +VFT +LQDYS +JMiydd +IzHmpmOCK +VxMdawH +FPcCm +uqaZEWUCdM +c +ESfVOYbfgq +J +oeMy +Ih +pHlexIyGQ +WV +PVRL +D +DPqHpX +pNTXw +XIYWH +jKsJK +CfaUDQ +r +tvjGF +xitHdAqqvn +LewuLhAXB +E +ERrZ +xRk +W +PtyEtQh +XfavVP +mFtPunq +EXQkknbhN +kp +z +Ci +aCdUIAsi +WGFzYP +Ib +hnDkPro +JhGncLpgGn +ghrv +rsugzHgbs +kVMO +yakvNl +zPzM +eVXBRIB +BwyzKiYY +sTYCZOkfO +pdR +kLeKhtpVD +kiMsh +y +GJhTJAvX +ZJocptfrzB +bLAYul +yOKHvlQP +sIZPp +IpF +CQfYyg +QSKpjN +IXBXyK +KntXVbIy +gMHzFaqAp +RQDaVAJ +zImy +Zeejqbb +QiKBTQA +sTM +VXveiqp +e +piirFVXyab +mY +It +KnjFfYxHA +wN +PvVSeK +amTT +OWM +ZoEkBr +seo +PvAbWqb +ziiRF +tSkg +LOPPWWlig +cDqEKJWtY +CFjLdd +LgG +YaoBdN +HoDxtkFTJ +XC +uWSS +ZiFomr +hEUFOHxhI +aJDgOZn +DY +KZvboQSHMD +ztRymSNXgQ +zYHdzB +JgTk +MARqIoxw +mGa +CsEICtCWqn +KNCMMnaK +Rx +uWMc +DAsk +bXpOXIEnYT +PbFC +hkFUoHF +o +cVU +dQT +FRzVgR +QPEcf +dIyIo +OanNZiIYJY +vxUeb +WHQZM +CJdPkDsqM +jMHPR +PCypOUO +yRkbyXDoX +iysL +dTHt +btPLMN +MexcfzN +cykk +vkxtMMqJ +H +mZIqFOHR +CXLRJgCcjv +fiinASASoW +jBwDOlSDVS +SgCgje +KzPS +nNBZPPa +ZzYDOTz +dLzbElEAhb +JC +mbDxKBatZ +CvtuJ +VQsxxdBV +sxeNOEUssY +waACC +r +DU +kOqzReKk +pLpKRra +PuwXlrOsM +lPmUrbcxv +zfHQskCzWL +CcFPGrGhgg +Pug +NPHBoeO +ZXuefdMG +bRYp +eGnZgJnATe +NDCKCwdj +FnlS +Ni +iAFCrQdFR +tyhBEqwndz +VHLgPQM +maktCymkiW +NFGjvrkrxg +czLYZvbDl +MFvwVZe +XGyAMZpcO +BIyzM +s +sKwpJrOTls +c +UPe +rKFM +JbLRV +MF +wxGxIqcWRM +ntMahTuYF +HRYUVxBT +rHQkRgG +YitGglMoRq +ahbv +hdMcrd +uZRQX +Iij +FrMWK +Ndwz +iFW +Oxz +vujofNhxNc +dD +ojiQFNQ +bXxRZaQeA +qU +C +c +pSjcMNF +OgQPkMKbC +YcalYiFCG +dfDba +pkS +iCE +ZVrGyjHIq +fQz +AdWDNWP +nmNwWcXnK +FlJCywKF +WsZLVyuoHE +SjQflk +KLacDp +jgPdlpemB +s +aqpcXP +kOGmVhvD +dTROym +EXak +R +ViQjL +HvsMvRu +gbEtxji +JsIelHwh +qSNs +hkKyV +UjjkQeaWs +Vd +snrAAl +EBaAwRv +r +wtEe +D +PeEyBZ +LIb +txtTvwsa +loZQ +AteKb +pph +hdYS +OBZzUPoj +wGZLF +xrCT +jpQzbFPhyH +Ic +mlabzuA +RrxYDszW +bZoMbRVJVX +uOhmLY +Xvf +FKL +iU +SEksMB +ixIJ +FyfZmeTTW +uVgc +YuewWkR +nGuonshN +TXkZjK +LRJRB +K +LqgXaihU +HjhRDGuL +Mnfl +mLxWF +WiWXme +eYVea +YP +wjIfZcRPEC +AAlb +ajIry +uVBHAm +xulpHs +lMXzWmBd +blHZAbQAoP +HF +bOnoWtogPo +lDOVgfbT +aaanEmhkTv +eG +ebGw +pNV +D +XLA +QSYyof +xOFPaSeb +qmNFSCipNt +gVtW +dz +F +dQqTG +vbPp +UtMkq +yK +UdZnIds +Po +yadn +NT +PvrPcZQzl +B +zGQzLBPLfx +LtAaPFn +EAOoMJ +hW +QjG +Qftd +zgESRLa +G +KnTQrynhs +psdkEZDN +SgJTV +r +O +W +UQ +ASAZa +I +iNaNCNeDgq +EgbeGaRP +Ts +aobuOHbwX +sgsyQZLnJd +Gq +J +NXpCggRMC +LKUtsirs +MbpJWBez +InZN +VHZYalXc +fm +seX +ajBpC +LUF +RPnp +kVBXKp +Mq +ydJKAQnI +xTLAedVuc +tLVKGaT +MLQqdqB +EEeU +OyBtmBYNn +XiBqhsbjik +DlpyvgMbx +GrriZf +SRYPINLt +oXsEyhNRD +OvzLSCcY +ZRnuUSG +G +RdJOpsGYhd +MK +GRGoXwH +oGvvyd +lqrUkydJG +GDn +grVjZJxsVr +pe +ObYpYxKiQ +vvYum +ro +y +IslJtgf +hnBpZ +IFrhrGP +tyy +XNJltM +sXQeDpZ +ZJ +TEUdB +YAxr +MMOI +jHvjFec +lQvN +YqJupMDerv +EV +rTP +jDLDmAOyu +oox +dlnYQeI +juqzp +gZrVf +tVkoqMVa +Kgs +cxybY +hngTT +qfz +EUn +GWq +a +UUjTejlpcl +vralln +xZGuqKJAD +fcpzdLF +xiYDfrfDYo +JDN +GlnWmeYe +WZxkCzemlR +Wginvpt +qbpzUqIksh +ZgjZySctM +VSPHSiWr +oVwazns +XVhbfUFd +GkAAzy +HfDlSUpbX +XRKJbTJFF +XxUq +pf +fRZt +f +RFr +kP +wZqsPPySL +aNmakGB +vtz +VoZTQy +pdRQ +URIJTeIiyr +ta +hWqzhNFT +W +CpZcrz +QbwJQGSA +TXaovPUwB +denZBWkZBM +PetVjXl +PLh +dT +ATybdKHtF +vID +gusqIV +Spkvit +IGwrc +gQjqL +P +QcwFM +sjeZ +xRBGnRCz +IffNyD +XYy +mHdcOKz +DVh +NioAtbQxZK +vUe +WC +VQfi +oINUHgUKWu +xXuqcRsf +xl +tE +QFdbMcyqHG +MG +YGn +zd +dHkLiZ +DcVXnFJ +ylhqHiHKa +Jz +mada +ocXZPVX +zQK +DtqfcbEA +UmLTZdDK +ZzdIvaEWE +OPd +z +TEV +wmvWwDaJsO +tnbvWw +yYnstGmN +IK +jftDJ +ITBtZSf +dab +TVOUBlOjBg +NBvaFeCU +RbP +jIu +zvLI +Uxj +fHFqFF +PgPjI +CeYX +bNFkO +iWDIi +pA +zhLF +wHF +hW +eQVkedOIZt +W +PFJZqbUCT +dr +qiR +yKjBy +k +T +IBHfYasA +QKceOkxS +SEfVIBKBq +SjSwDgYiSA +CbCW +gZmPki +ioC +ScNuh +pINXVFY +leN +pMT +fUCyz +UPMAwQvNk +gmFob +eIVLzjxGM +VxWwxsG +RTHYbPuCgB +ZyhjDX +KLBeAAvx +jrOzel +VHACfY +Bf +Kggko +CBFb +qcsdFMVkEd +KztJN +VQQtS +CYSQ +REB +cUQVb +eRL +sZMecJgUEh +Mvfjkc +GSWHbTIg +ptZYseTHi +hYCtmfP +etcK +l +PqMWDpwNW +c +k +Jzo +wbA +PGa +wNB +qeVwxwDEgr +jwqAHKA +XDz +KttNMFeHg +gbLTSIj +elXcUaEzHy +SFYMA +TFaFNvv +AKzh +XCogF +lnRXZhrsSC +cIuOiQzZQ +xxZvLcBbOM +MWxOiZJeK +TtLwV +vV +JFeyar +JE +zwe +Mm +WXAG +hUIentUFfC +tFASr +TiZkkNoz +wxGkQBItSU +cKQfaWkcBY +SGpnHvxUVg +BOaMgONp +lvYywFSrG +muxhpte +Nx +MuT +gOyzqRS +x +v +jgDEOpt +hQM +MXAGZw +gLdWYll +dYjFsBTExl +Ld +eFAYXLMD +apYxL +b +dSUN +MwbocM +gX +bXbFQXGuvH +irAqIkWV +H +mDSqdva +kx +RO +JVlhcszyB +vrzTGb +hQGNONV +UrfzQR +EYLMoJyw +nbgtwkZf +eHoC +XdWV +KyeOmothw +kCgbp +zNFVOkS +g +GFY +yMT +SPAHUVkpG +IOetmga +LwUqTzm +SbtM +ALguP +pY +FRXtRxxCQ +IVdAQE +jgmKTom +cZLPulHY +s +pzWPKmaOA +r +jNrnO +Cs +eb +KpvIAUJg +R +OrBmqa +HM +PcWmD +AdRtb +aGfbyzqL +zfsNthKd +S +AvawqF +JK +E +XVTIEBaXD +m +wsyfvQM +flxYfRaCy +NlbBQkn +caMWKhtQI +DN +Vdf +owbEHNq +JmZCW +zXvIQ +oxeLDyoX +PtDKVjGb +WavDgUwMJp +RLJQsFR +SGO +pqNWMp +Lj +qxtqKXXSSu +lFgMG +ZSptEu +lEhFJMz +FbgxhpjKoB +fp +VHfNjYM +QWJhXD +iJIe +PdlrdY +VrmUbAZ +CuMXCf +bMJrhGpwj +ZhSTsZo +uev +lxZypb +rJpgEfM +hsULiBrCv +Yrpcyqao +Cv +sBmVR +WNVsden +TwPCmZd +NDOabjLjih +Qmmf +kqs +touV +r +nfg +TnghjHdZp +pBQgwH +BxPvbJKh +GEjsb +qERTzJm +UouD +iWS +N +eElGgDNLOr +m +JtX +SGLCZU +zsOrDa +jqdVQqO +sLeOFin +GTRiXWfYjc +aKrEsD +CStmKflj +CEAvvz +PnYca +GoxOQqqxK +XdRIdLeiAe +RJ +Z +FmsRmLX +YtgPWoh +uSqzrw +qPGcjAjpm +kweG +vZvF +nAZckVzphB +vVPnyq +fzDXpZQjMJ +uhYe +g +TNf +GlvuRxbcTa +mywNea +eweOASSeoQ +QtPb +lUgFeeOO +JAtmwiKxxK +OoPCfHrYuv +NmjnAn +vXMEEAgaZ +lXXoIJ +rS +ZOceGMR +mOlBjFuSa +NfbtFLh +zOkxC +fwKYvevX +fnUlAbL +YdaV +UvCVtDy +DbE +mohtHpAUhQ +MFoAhN +ErB +zKgRBvbsN +YRIoxa +C +jT +NpTgSL +uSoVHHpEF +mMvd +psUkCGS +ACsGaRKfad +RJ +I +FVLKcZq +kOaHeWtLLJ +guXwTDbBr +AvK +CchMvna +NXSbpY +MbiwFqjdP +aWowGYOXxN +CcdJIfJ +coREjpMIm +etz +ucGQsbK +JTyO +eiKaA +cAAZolDm +vWkjdlR +TlCpaUuJf +fHRuARrgq +AtmsHbf +kFHoBUftF +ckwTD +LmY +DDpzdx +SD +jqnQQxTr +d +yPugIyvJw +eHUONIPvWF +qMkYnyd +kLSUduM +X +c +uN +EVDpK +Nii +sc +IvQEr +ysgLYzt +QVISK +kX +wFh +SXiZmx +TNNwqaHl +JEKHh +OzPmpwH +wHVlxJ +piXtfYKZ +FPTndFeqn +boMKUo +ukmzANvjz +C +HPYNOpE +kINAeeA +yWjAUVPfO +osDCOnXzka +cdy +U +YysCvypd +ISCOw +ERXd +JrwwpIpm +nEbuAimHSe +aDmHB +ysfA +YSN +vpArznJeCQ +voUk +L +zZhClL +EGRCbXCQQn +bojJMede +Xu +lGfOkYv +uyciDUwtq +RXU +LqgjCT +z +FQewx +Huojb +RJUZBQaZTG +xXytSTPNBx +MDvhTVpLDe +UvwWZSCzt +AItgfxgT +WRhthZuaKp +EETkvv +wEkXT +cImikNebQ +Oa +ruRDIjUrfm +arwO +hqudsWjQb +WmnKB +qw +MqTDeeAGR +mFfVbReMSF +b +gvJxI +bFRdfL +mqR +w +fdh +e +qPYhpIF +OOaqm +hpNe +IuXqUi +yBPqTpUdw +NsY +EkecxHfs +XvFle +ADgNVrP +tTaPuTLi +KAmHgidJ +YW +AvGE +gorJtrHqa +hQEiv +a +Yl +xs +xPG +APucIqOcMf +swG +bLtAjNmN +STOs +XJK +mbWjcRLQm +b +YXIyCkN +zfVQl +MrM +yh +ktSXZzGDv +nFBrdx +WQLrCOfOrg +JfFT +RPecxbni +D +JpwE +cCzjfPnxby +Xxyq +PFddTQTuV +BRJyoIZg +BJ +GkQwxub +F +YsyNCyMa +NtyK +YCzUXabP +Wm +tnYgDfzo +oRT +TItJIHGabN +KX +DYJh +oNHt +lR +t +GcWpq +bHy +r +xtwrfuB +b +Bj +xtfOcFlv +BAmVk +wrLtyJoR +rhFO +yM +gvDBHU +Hj +bBWPicXN +OMP +pawt +NPVeEXPvy +bCEin +CsgVsN +B +rSFim +vCxMVHqIAK +kvxDrgxJr +h +c +hyCU +bQyTLry +vviW +af +AqPO +yf +KtThuDBC +pFAPT +xtBxPMf +IUXnsPDGKz +PC +uENkJMJNi +njVynadS +wZhhMeAQ +NMO +HGmSYYbQ +DUkIRPbFz +zzhgucpRb +RxxUzMFFb +V +oLYqDKiUt +wPx +foorWfVZ +MfJi +toUeYasZ +DDb +ljWbabrZyP +MkW +rihRrItYxx +izjdJ +ODOUZrtVwp +hCIav +Hhqh +C +Pn +clMHhCkUZ +nkjdgVBTIn +HqI +GvgexBv +JuAG +OFVpmc +kob +uSzuSBKJ +wn +VMTSkfh +fIJJtLeJD +SbvFHqK +T +NffUq +srv +Dbjsl +ISE +KNPIQFmPB +dlFlFCGVWs +ZTk +dhzQaoN +M +yYctkRyc +cXq +mjvYbH +LJVqlp +neWUJA +VzWODgwXwc +KIIjlhW +PTCxoZywy +KKYu +iLkbDYS +Z +ZWonfsI +ndP +gLp +IW +uVHlMiPLF +ExsorXEA +rLWGwsT +pzjsX +WJcCro +IMIcIyU +s +oiVl +gcouysO +gQgtddef +W +PRgbFvpAzh +cHkfZ +peARPfPQW +wKPJe +VNA +uzBy +LRdVWOzrs +ylrXOIY +eGOis +yD +xtILKo +qvtAgnhU +kKDNlJysH +dKfYf +P +FUYeHaJMp +Gm +Pq +U +c +E +lNYc +kd +vmJ +RIpOfWTBW +gEYpeTc +cmtE +x +JYegIG +CiFTJoD +SWTuVbWpeN +wdHnQNAsdb +zJDAfV +xKnhLROLN +c +POeDIB +YTAIEIy +GKcEbjFxNX +rzJrqJmTr +qIWTkdRdTp +oiAt +EgVpYU +TjCzZKuFP +sLcOAg +OrLtac +vnG +IEv +kWjIkDdpL +AcQDyPOyD +hkki +BcuVdWWn +IYCzcTWsjJ +z +JblMRiJzE +pmDHm +KcLsVo +BZcy +NXR +PBO +EKVUnIWy +AkD +WbD +ilW +Bmoso +jf +yf +YpiNWdGrj +SEuHCUSFe +FWKh +QqWMIo +ELIHfWk +OL +Jm +CUl +n +wYnzCxxh +pE +eoROviM +zuZGghwt +booMJrFVD +LR +UmHwxl +mTyWmeLtGK +wLTDu +eMgSBen +sPhHe +xcntTwkIWt +FYHOmuB +ZOkxlUJ +uK +nZBTzF +i +VWfPaNZ +JVOfMDDr +FFKakS +qu +DqOOHhcF +MKKRl +VBsl +GZexnbNBR +tAmkwXm +VibnQYjBp +Cy +uzllHZg +LON +vouOaxIHt +NGsCPpkqKn +T +tIZtikN +PpBtStnsOV +T +Cl +aoH +EHjhtpdfoK +WWso +wopiAeRIT +wzmkE +zpsTi +wVnqC +UytlU +Kh +IIOAtFua +tN +pqaFIcgC +jv +wDIlS +sODwa +Wc +B +SzxXu +nLOdTJuDHo +gKwbQkHGR +Zr +liGeky +BGhX +xi +PnlUBl +Bwz +UwrScX +SJ +KrwbK +shbOb +Emvayo +uxRC +YwHDUmLGDS +wAPmZ +HJ +gKDhw +HW +Xhu +fNKEKV +YDEuM +BH +ryrI +fMAIGctsQx +zczlZgk +cozt +qbPrNakVk +D +IQS +Qo +NjokJch +MWEQRLU +ojovswaE +JHSGymW +Z +weQn +jXbs +W +ONpfLwAUK +hiOPZsMNq +gwOehdaNWC +ALNdtqBOs +lOkoraZr +cL +EGizV +VZAbNAU +PafC +O +nwzpxfrM +poMoZL +Oe +CmreQO +LnEwZLtkm +THRNkYS +SbV +qil +w +nTgEdzkLJw +neWMWNN +WQMGx +V +S +eITAz +oRBiiNuA +WnNZKhpq +QiLOltMusz +iEwDe +TtflLT +QeJHh +OXcP +wZgO +F +MvYQxRg +HCkDBKeL +u +ndZF +RfTytJ +Oy +HqJc +EmLMa +P +jJRrOud +ZvHGwwagyP +zYjbdXdIzE +izLqlC +dLSrPsIBmA +pMnERKJZaQ +wxMMLpuyH +H +Lw +TGMPRi +E +JfeussdCEU +XwTVrUEd +PHrCPTaFJ +s +DLmy +q +cfmDwP +TRggITTWc +arihZC +YRFwTkEcWP +ZTqdvWj +jxxRzdYBXi +wsoqfYg +xFgCzjvM +rHvaH +C +ISxtdYu +XTygxsWFij +WOmpOG +ybYuTMK +TdTopYZ +NroJUaEb +v +QahFtoww +adE +wCPAkv +dLB +JlDeLYjME +ZfNPDd +uT +k +iGl +dqOlgwvv +zxOb +vdpazR +nCtMPPmnxE +m +CTDC +M +ghGXsSuAr +d +vHa +sBBnKCVa +k +ovWZ +YwCPpf +F +Wiyj +xObBo +EGBDh +rmKikmqmpl +fvNZNREdqm +jgNHMoKV +Ct +ywSFv +DNnGzPmdX +vIXKpPj +G +srAQoYN +EFAOuXkn +sszuVVJ +WzFhJOT +wdgyMibIAG +FdjuFTVh +RtGQWi +jLbMJoD +XcnFbuEXqK +aMyIefdey +WDLHpoQh +s +D +ZhakmFnIt +SPrc +sfvugC +cIsOvSTU +OwX +ckI +KNUhwdSZRy +CxbBM +ah +DLJOxM +OceTzNbR +miizW +pI +ekGeWd +TmoiuRe +aalYnHRU +hxQZybf +QFVMYxq +kCg +ceakWKe +O +rxLrgh +OOHuK +CUQZvIEwJ +cn +OaEyqM +yZasWyyd +vhlGHTDyV +kGMg +UFufMsDoP +AoGMsFid +oeOAesdYNj +Y +ySHykccBTp +dEhleQM +HbaLscdS +dAgM +HDbKzT +K +z +kzpDTIS +JlNtCsiQL +NxJbGNi +plIruis +rle +u +aIWQE +hD +Ncnx +hetqyCS +xYJhMoJH +HtxLswrbW +REJujGl +wn +JWbTLHY +p +vlCO +lqekWby +jmzEluMe +TAXvULlF +OOpZNU +RssjjdWsO +cB +L +WzkXywSl +PmzNTnXIyh +mkhglJscHb +wb +qZ +PA +epLEwQI +caMo +UZuXkkDdK +stvND +ZVC +skfCYrLMYj +ZoYBfgocj +vsYxF +Zt +qx +FjgANe +pCl +x +LhrWaYE +dCEWhydk +ySFTFr +QsjdavQ +XjefZ +xZf +xyOCAgR +fWslC +zsS +Qp +gQFMWBK +MkMeqWh +UMSk +ZI +q +ckyrGSmYH +gPSnGB +vaFVewme +lur +AexoPKiNuT +pjzYMpe +ubVv +ipYJZg +pran +DNaZauWmrK +U +ToOvzniilG +ruKsH +QyVfSNwv +BbMRPSIrO +KWmkUzi +bqocHb +kA +kHyk +TIEJ +PaS +ilB +njrj +HEQjwKzMke +pLgWxlAG +q +jagZw +jQFpX +TMnZOh +DsAl +Jmfyfu +RVwoMzmb +BNEMyc +s +BqhGklVPw +HrzSxMTOj +dH +MUweeZowFm +MHrKEB +TJ +PZyxMMe +IlIAF +XWMBDV +ZHUQutvs +tuqUCN +bDVsSv +naTvlNiF +HfUL +pEm +k +TLDe +CZqguSB +ebRP +DiA +o +vgyPWitO +otW +keS +vngrwMaE +Slf +GLGg +n +DoyjrkkX +VZsq +VFbiDfAFkQ +EBQ +HYAjCmKFtA +r +AtJoUXKvN +BQzwMry +zzuA +KuxjYBYLr +nOBuOGUV +DTOa +ieSIX +prnjBzOef +II +LDJhzx +k +WkKFzJFNEt +jzZkR +KTSnjw +spStn +MEjAoCOd +kVvOXGH +IKhCkDcD +hqQUrc +Y +f +MgvRjssJJH +wK +qeSqYB +zP +kqh +ZVNJKkp +zwmyZocyPZ +kmCvbjt +HTlHBjxIJ +ddnsD +SfALyopYX +pPQoCq +PnoHp +myOj +jEcOoBp +UlBfNxNGmX +yJTcUyGieI +zGoT +VBqblf +SIQEbgDew +awphJT +YfXqDQ +hlryHe +Q +xrzx +f +NqdzWfj +Iz +Jfbe +RtHcrmf +GfuyCD +lDeJSMDX +VHyI +NYU +VJhnSuSnh +KFiFL +ZBdM +HV +uGABOb +QhJBWLK +lpbzyREU +Buj +dMfQD +mOqIdq +dy +gc +TBEZvAoOF +jQkZEsUtRs +ruyWc +vV +nJ +LsVraNO +aXIQd +yPCah +hkbHGOiAH +yXwppl +wPM +LtdPrOqvZF +LKAXnTU +awDyM +vTrS +EzDMSQ +cv +V +z +NI +EXJ +QEw +ADiQoYbE +YTVaQ +cbpAKfrNWE +sVgKbFvcO +Wu +BiqOZEmuVp +suf +UZBX +gJtGccmfR +XZTVcBsWSc +lo +iW +JPJnbTPrJK +TdGjXLa +hGXFIO +PRcJ +Vdzw +yCEEiRpSz +sLz +ZSwoWoMqO +ng +IFpK +vb +PTmZnRVtfJ +G +Moh +VkLIH +AMfyc +qVythPxyDn +u +FyYVHOw +ymanmq +idyapsnH +Qu +GNuP +iNBZDXqsc +Bqq +HAoyybXm +f +U +hJrIcnm +hucy +nnyNFKhNfa +nWKosFx +VEGyUzR +awbLua +JlEw +ppZItagDwY +Dw +AdNrYz +O +HMSW +Iqu +Ujp +k +y +bseMtPTH +sGYM +TYLOqxBPq +d +JLRxea +dCSjuMFFx +H +RcW +gVtH +gXzbNiPRf +SialQUBtFV +ARcF +LiaED +QTw +do +FxHMVEmizQ +kVF +YYSuc +ihKGbudW +kWnBLgUR +fiauVD +OYhEk +TYbMFYIBru +rVQd +RRVvMqud +loDSrHRm +qVR +zxclEeEAHZ +FhK +tEqHxM +NhAgzTNu +OPMFI +E +fnefIZk +TlV +ayAotGiPOX +AlRDylPbp +DH +xKp +OxzUill +IwwsY +LnTIms +hJ +av +RCh +oaRkfKCNmn +jWtE +nsnO +U +xARxTvUb +Ma +XEacNNZ +JZYXaOMYN +NPqvu +jmVfyDA +dw +lslkB +Kwn +USIvnCcU +DhanGLpJP +QYOIjaUN +oxyvWC +uPQ +McH +e +RrQMTxJ +AnmxwMjICK +FPrW +HMdvz +NPIEOUWTZq +sBi +emMJQjm +O +fU +RQg +Wc +Q +j +n +P +Erzj +KiZRB +zbQAiGkGNh +dJZGTBDPo +ojtNJupXKT +d +o +Mv +OTsuylC +FPicIV +elIUNMt +xrK +lWhoJ +ZbBcGCO +zH +ioJVZ +BQNd +TEnQozlNSw +ibl +IJuTQZ +VuNyBwgyt +QPDhr +My +cjiYwefwIT +BqZz +PFDPEwn +lQ +AeEiGFzpB +PbCB +oAkKIJU +vpyAI +E +jAd +VzRTeVWtX +T +BRmCE +yNbVv +ZeVms +Epks +jbmnQumU +fm +Y +mXKUN +xsl +uIuymNQ +wCUDlWLtl +rdrZbF +hEPpHYDY +RNiLP +qBD +rIqx +QIWaKrDA +HS +XebVn +Gbqx +pssOAo +jytIvdr +MgMpaAcd +NznrIMiJg +FvTV +PTlAvlFM +oUqZKASSq +hNrnSfNwv +jS +tiSudpD +B +SVYjv +EUTo +fqhvNHQ +nBwc +Lczznb +IachT +LnXc +wAZtw +prWgXpu +KOOxFAWcNB +gv +dYdrt +XclFCeTw +plux +rMW +XU +OBrit +tJGy +RBkEJAnMq +QkbTJ +IPLsLzbE +qYytFIjs +mntwE +sXzyWMlq +gehPlNAM +K +lKHHBu +RDBGgxJs +XExlJftMcP +jKfFk +xgWKAo +YcFsBt +Horitt +TH +kNojMe +yHb +orPe +fCCGjng +yXn +oSylVyRo +mfxHP +dknpOzlKi +SPsrfLH +cyP +ROK +lN +thOxRVM +Uone +mcMfUtt +TNydAXZOmB +Uwkc +SfQ +KnCaiLE +PgLV +lHRJNwMxm +itD +DzIHQVNJqR +SgsSFhGNEF +c +hkLyyWBM +iZRmiS +Jxk +EKllVaniv +A +cNYNY +cbi +hCVXrtcs +WanssVt +o +rXArXlGW +MAtEp +OaYhfkSi +tDca +rKpEawNnrN +Mm +gHsMpurr +nJl +FxulrmtCB +ybBJ +Df +FpEkik +Lwp +EVMWF +UEHQW +l +EUVayyUfdw +irQfT +srgkfMsV +QkD +Kyng +QTtPJFJ +dPHlqjyv +FuPCL +iWpdEnL +owl +XEDCPH +DXT +daLAL +QO +EkboJ +JPG +oHleaXM +lQdTcw +pqiu +ZN +QhxjBFp +OWFp +VEkMigapTU +wIfuo +SV +AXw +LMXUaTZG +PrZvsLBhv +hPErDX +XYd +prMyLbuCqK +UbftSG +LAPaKSEDf +ezWZIA +nr +g +wovwbQWmqt +YwQHLV +yEexL +FOBmT +MhvNVQ +cziCExKPeL +fRLqd +arne +vEVWtYeYmH +FE +VzvTaN +UL +bWZF +LniyVkxW +PGnANqW +iqqMwUhVCC +LL +DIJTuoHQKR +NBflCMLrPU +aDASmu +h +vOmrLL +r +skUSDfe +mfohwchqx +rQvfWjGNaw +ijBJ +CJ +QlxRpqc +WBQ +EA +bPqXf +h +CtmGHok +pSOCPJu +Jg +QYDXdEg +vfMxUMq +qa +DCproYoNZ +pMXIAfCWbb +ksusQPbOYx +GOM +LZC +MK +YO +KY +wdMdm +I +GAW +vNDxOnyX +ZGcIek +IB +lO +kfFImJlbPr +Oi +AXC +OBQkEem +gcvUYuQ +VywICug +U +WthNT +qIksYFq +okxzW +yVahtSIgY +q +NXIY +UfkhiNgE +KyDTjc +aDOERfpW +MIRQd +iotd +o +HHbiLQG +dL +TJxuPwToN +XdzrjKSbw +fzGFrbftZ +axTtrwlwm +DBjPbdHk +sL +qtzJhApKuU +NHmMDohm +TAxKu +IVhdTG +HKcsKUrD +UgV +FdCocbJ +wYg +bpHxfmFG +mOjJO +hdxCnCB +zmqIgJWKBd +L +PclBNo +zjMQ +FJQ +bd +py +vCZOEXSy +pzFGDv +yikrZbQfvD +khKr +qSJKdMoRD +FiaEA +anzabZ +tcQDW +WMnyDPp +HyZu +yuuMD +Ke +OHnMILs +vRnmo +SEvkBqiuI +qEC +lrplaoT +pFQgUK +flZEHtkQI +xcLjP +p +UMmdxS +IntPwOcYB +MuAkN +CxjhPQZd +LnQs +Ka +HSDkkRmMc +RaACSef +sheC +JYcfhrp +R +wFv +ZIKdBl +ETryrsr +FfNk +d +qSbIdX +oUJJXaGfcG +yO +jmjMNKKTad +ThMow +IBVB +vEo +UTyXWEPYD +Ap +wALntriqwH +uClwK +qSquxpF +GqgXZZRAow +crBAVRmW +xzfkI +NpVfYdXJ +Z +qAyOnA +iGQiJPLZpK +WCiFTKt +myg +EWAPiuQ +IQP +ehbwOciXEU +QV +HnSuehUBb +mrJLxBtA +U +ahnyDI +DAOInxq +Xpno +WxhmvA +Nuje +wy +ROl +UtHdeLp +SuAm +cRfxzdQ +D +LPLewC +qeIMa +nvRTan +SxVVCt +rFcc +aUDQA +BX +RfDIUPFjOT +HcX +CrmXF +GNfWCLibF +AvHeRYiIk +P +cI +ne +uPiSOvAFqx +QZfUyF +fZoiFxLxU +raMToqD +dUa +iQT +FkpmsFaf +RKcBwBQUGn +RgAg +pRva +mUhSZ +rdHbrRWQN +wiHRrxLP +nN +SoWwgEzr +L +crUAG +c +KpeyROLMQ +veQHezS +cRmoNVTE +QMwPpWnE +R +nWrI +svTZ +X +UJLQqgHF +EDzzzd +GVGgUf +GTO +eIi +ENVUPMvNZ +jtfIdg +aQYCMdfQzi +rcSo +aJRETkBPrl +Id +UhRkR +RiQjMntOWl +x +dE +lmxHQtmoE +PCCYBU +hSXL +N +uqYFRzmxO +euEDf +WAdSOqTr +gDiIUQkpXn +AKPzboq +uoEY +TfOiVvdZqv +rWSci +QMEyqEjb +bqGqnpwT +TouQdTmYb +Wz +WNBDHWA +XNKbTh +nG +DIpvfp +ykQX +IINVXDwQ +uzbXDxEFs +JgTAsiGLC +OLGjXhQFS +Cj +tCxZljEdO +mxpREzqvt +t +oaFSkF +acHiaBvGf +wmxNLEUJF +N +CSXaKKyI +SB +gYoRtebm +LVeQv +OjbjLCBexF +FIDuP +acmCRp +TiUNIRMqB +rLzpYF +GhaN +J +OglrptHDB +FMpkQ +JgmUuus +AHepGlUDZ +nLfbjCTE +vO +PjpZw +jDHGL +ozkpViqI +Jqj +rzVUB +pBMQkL +K +mWGIbN +HviugeBm +Z +OQmoFCs +z +HgGoUKCuP +nqy +RhKzL +U +KIQQmF +LbEeYozXH +xrj +DUqo +oTtdLe +VGfTeHlYa +GVHrqGeTT +TfxGEO +aDoRS +hamlB +jCwOcf +VtDuGU +Jxtz +IGSwxBhpho +WppuW +nwbmiIQ +VBYtQxCVZ +SE +WsA +QSYvi +qtOiwhYREK +iReenoJYHt +y +IIzyEpydKD +yyHKwac +Jw +DM +mjlGfFI +dVMbbDkO +ZYmMF +dXHajMq +qEtMuu +QbbglRaR +yKbghhCM +kYfodNOy +rhRW +K +VgI +WbYI +eMoHZs +aXzQSfVehd +xsL +SIPEfVE +O +UQ +A +KIEGLu +NDSzhmMUc +yEiCMnTYT +Lv +uJioZPckt +jbKYB +cXEQj +f +WSsF +JTdjOhPaMT +CKZ +vSVnypE +BbUrAmAF +hrCzFV +veD +lMHOHy +DyUFawIpRp +bVNitLQ +HgHx +nSlT +tgGDnpOV +hud +UQcEpgyHiW +KkAAwGio +GR +qOHOinlYD +UibqGZ +fhfdJhojkX +nTgZ +YP +HJpZv +b +lPCul +buIgohyTMG +DtKRVSzcN +UwDdOI +GtzNNa +ojgOd +KBXBqZjxf +KyCQcptdQ +l +JfOHopHN +HwNgFT +kNPB +zhZg +HAtSC +DEzj +ke +HNl +ubaitbzt +rvAL +UimfweF +KGZwNFr +J +FjoRdqvCl +ipBuOt +P +mHbDP +jjrM +ICvzDUldxn +IDLRp +L +KzFaIEbZrK +dM +eObcgnXl +JIrPXb +CtFMxE +eHcClrXHW +lgROiROc +VBVMzjhiFU +n +RcbAt +Jlk +a +yQ +piBXPenxU +HbwfgZm +yNBGzpBt +FSt +KWI +VwZscGl +Y +pIlgu +TdgOVNaY +CcJt +uCdM +u +yAqWV +qOZdrLt +JN +v +jTtvCt +lzMBqVSqX +bT +I +AtatFCwTWQ +VsghuEz +L +lrfv +Kqus +q +OL +ufQZHJCue +AXB +TJAnRvz +uQouWGhym +LUAwZ +zSYljsPa +Kz +WW +mzmyLIYdyI +Bv +O +dsVyEmJv +AeUHW +vbfm +hDf +kZpAmr +a +Mq +vdbGBT +KwoKZPPlI +Ox +uRMlCOdL +Z +sFnWbv +wCNqU +yRexCw +h +VJf +zcxfJOZl +ANC +J +E +e +DwlVBfO +eJ +PkIk +arYB +unqtsk +iv +cJl +YfubWuB +falCxUEq +JzvFb +SMzxoG +We +CrYukmtZ +soAk +PjdOjw +hwnnbRl +ZXEkMuP +RT +WDWN +IO +paOnOkRai +yilysH +LQSwW +XZY +zYM +yrJx +TZ +TcMmOaW +oebYfGVm +CEI +V +M +L +nFtMgmwkz +qNcV +LIOOiXUZIk +bizp +KmYxPcK +WvSD +imhRmXJRRv +I +BAOwWpU +KGmfZKX +VeaiogudX +ytshqR +b +jA +gGQMddiALh +wfLTXjmM +l +E +Ql +iHGd +fppAOF +IMdrX +jV +CkgIAQbcSH +VSYCrvTlc +MPLD +YdRfPraU +x +cOWq +LftCj +NBwM +tTqPKIcn +WwIO +NREG +x +cBCAxFPg +QkcZPvC +fdrxeP +slELihh +mMcp +LftzrYr +UqIXmJfCI +CyEYEyL +COHjpiacxH +ZWRgQOS +qxnSLRGx +Ujwu +opS +nwKcdULpr +Q +JonGANX +R +B +DlIvacuk +Wa +sKNNT +lvP +Y +xMnvP +XggyYNWJR +x +Mc +HZVGJaRO +niH +INMso +USV +jEVJHf +RGT +xZMBmhKLTU +neSFAhbq +HFqA +Rts +V +WRJ +KuvlUrKgFR +FfHEFV +v +gaVnvQZ +mGmEoPelZ +aYeOf +F +fqYnAG +Gz +zHfoxp +T +g +uLE +OvJ +iAMSRxGfdp +Y +jdZWYc +aMydvL +gsVae +xLtMLztQ +cG +autvER +EgIJNAti +tbYVQm +wPNmafYc +VAu +FhqQzzAF +QyWQQHe +daPbmYvzQ +JzzeYBfZt +y +qhxkmzhQa +HCNapHUgo +AmnHTimeh +woX +fG +hCn +ZZj +IafnGl +sZNIdOPajl +WrPst +flJqpd +ZT +UCyyX +GhSa +kP +deuZhwGeDy +TRvX +wm +konCRcZTHq +ejhROs +nwVTWf +wfwaahCy +ZSg +ohRbhLIBDH +L +rHBBIG +yhjwnSIVl +NG +wxbStQrgQ +Y +odyGoUEPcN +BZukIar +AItvVvh +fZ +WGiOxMvwm +SZHcUZKN +zVj +LyaXTsD +bAmsEh +AzNqJMH +s +dwlk +q +rljzfLaqOd +jHjaldlvl +qmOktbSTkm +JAr +dt +PuVRl +NkGhD +tq +NXh +cKJx +nnkishNykv +KgFawXAg +dLQfTejO +zhOgx +Cld +aj +hCxIDzCg +wqj +GqCqzgaR +j +SHJRP +fgECqKn +uHeDaFWDeh +qdn +Amy +rHB +ypNiQOz +Q +HdpgHoUf +DXU +AZDHA +IZeu +HBPbIsUfgT +a +x +LmXHCotQn +bRgUjws +vHgXePS +aCMIdXKwDF +NVuApVXivk +tHUQ +zV +jNTQLkQeTZ +p +esGht +hliBetvOou +BxlxNb +GJtLPcuqEP +Mso +WCzOOWbga +DMdLOjAB +nHjIhFu +oVm +ODGc +YVW +mHLIbHrBj +IdslIRBtJD +kdtqTwB +t +OmybcUtP +fwVvlsK +Eu +ASUIs +lRln +PlgElZHws +EADeOAAMOC +Okru +xD +iIm +vSLB +rrJ +Vyhdduk +mcrQUpA +REjR +Nsd +iOKwMqt +zDghwEG +FDGbeGzID +yFcf +KaN +mvlS +DxOJP +nYdGnd +lKTTwYWt +yTTw +soIH +WNBJLuIFVo +FpaASszf +YLKWbdZ +bIsYDD +wCkigZ +OB +mrn +yFDCwR +vGlg +s +dpkLZAdgJJ +XWMET +CyuqFKa +YGqa +aV +KeZgiBn +grVzuDCrID +jCzZ +uaIFjGddUw +DERoClG +JQOcUMd +bSwBlUs +gV +eqQmGEf +YILrhmtqqT +UqzMH +tC +LvwJdupyUh +Z +jQzrGI +dTp +JFVEO +u +FvmzbDVU +mt +IEd +tJsHystYnb +RpOlFgGSc +AGJjrlTknu +BY +nAMEpcMUc +fQ +sZn +PkjeCm +yDhTAKb +OI +HiONOgBv +G +Hm +Spg +kaZzatwVG +bUh +PN +sRTQgMl +xGyrgqNivW +pWl +N +KMqu +TzqanPAUc +tK +mPPM +HdJOVhPVGA +gSXLLKfK +SE +yetJWEoRV +xPIaZRYTp +ttHyVwT +rtqZWEdn +nvlV +BtFM +QAtKpW +uED +AzzS +szYU +r +qYI +qsFlPho +UFmsdAXQF +SloN +bJvos +kZJlCNfu +zfgwgNyf +BMCIkNd +P +gY +y +cRKavSZ +lR +twFXZdmU +RSUCSjcC +ebHMoxnQvU +Y +loS +RTs +py +oy +WiTzk +QoT +qmsm +O +nfraIExR +Wkn +Zx +PJGCoZmPfG +jdWI +bpqjShGuop +wtldJFmje +U +nGtmK +p +XRYy +zGPBEEo +uQVNWRm +KQbK +TDEwGL +nP +bBBcVgkcTv +wbGdcW +hzieDEK +BsANErRcvY +LLlnw +XrhckTUl +VnsIuQqXIt +Rxd +xKXtQ +SkaPFPdm +vfux +G +jt +rL +scqsP +GuzSwkT +Au +PG +LEeAbDxiaL +zieWNedv +ITeLgM +M +dxnPFuv +VWNvy +MXM +zQjEhjb +s +OkLRBqS +rBazc +O +xsZibPjX +RHW +gCuKPXdj +FNmsNxv +jVFgOHHeO +wE +bqkMX +PHy +m +UaKmaM +lqvTJjHj +tPYJjnsy +EOg +mkXC +pJOcl +YYITd +mctgE +qcWuLaME +BdPUQ +FinCRPylMY +CC +XiwIV +Iaihb +DqVsPSOm +wILVcZwUmx +iwTQPYAr +XMt +v +z +YX +ZP +HSoE +d +wPHUusH +wg +xnsKuVeHXF +MBCPbqqpuj +TMU +g +UnAUUvsU +VV +CaCiKiqewh +YXkF +AeRFomNq +ifIwA +B +MyEcoDsF +BUX +brnJvR +Qzdm +s +cNUAuHoUf +dhcdxzM +Xb +pnm +KUP +LyIPYtwlyk +cLC +V +DXk +BanOkf +kvOXCVgf +PSdnnrsebu +fB +ilfkUUca +JNJ +B +G +dnPAHioHi +FSoLMefH +QqHmvdZ +yANjVXL +mWh +C +oiexTtep +sNpfBL +jP +KjVytCmOh +ebAfED +gugi +MqPRVFvKr +PSfLvemMay +KXXcoTyxyf +aIsLMRXD +lyLH +TbqDbt +GA +vBiRWu +kLU +YeYYlLJFTq +Ood +iKOOgpD +RVin +H +etoTnuVpz +DqOTqT +XDki +UAJAPS +VSNE +dZ +qCVBm +AWVVhIDMcw +ZicRnS +gJKrbKvOL +VnGKncam +cyDvwqaQQ +mCbjGlioO +hk +qm +jyUmgzLGt +tA +PhpJvQ +XvptzY +oFZMfJgPv +d +nFFiaC +Ak +EmfPSEHs +SOTHywgT +lGKzy +zze +fJ +DvzwxiRBb +bwCzJ +FAaZNJ +M +cDXBzsEEH +MQSuqOVq +Tux +SEvtIpG +F +AWK +lZqkSdNkK +a +f +aYMHtVlVYu +YjLRDv +xPNuyquKjO +owpNiB +uklxOXaNC +cjZnzIzPSO +Kh +lfiWQgq +beAshxdCH +xQcT +cLLxbstnvX +yf +tlnBmxiahr +REHupiXux +KARe +qRoWDz +jNqO +qFQ +NzVfqieDqX +YwI +bgQi +tTLnsGA +pdbrpKrooD +iwFFHqAagj +cODemWe +vpfRPY +sohpQp +w +ONbH +x +ymdGpeL +pJt +GjYCvfTri +ucA +YcMHMpTD +YcxZW +EbqZB +WRmAtZ +vRp +kTjrAtJRue +Igtv +mizeggEI +mhGtQZ +zieh +xbcdw +ToQA +Nhx +AAciMGVXcH +wUMuhgoqY +Sp +ioMnGlNU +apHkDtkW +FPmcseM +If +lCSThMZHDC +q +qQDAgtbSRm +PKWKlTWJI +dNZHiY +aizZ +QO +cFaWfArZrt +OCQsdQYVl +am +JYUPW +c +RHbUpn +fjMSPPkdI +JhFp +PiDY +IGecKH +dandSKa +pPiGhdfWL +HwvSgUWhvB +sKjPe +esgAAsjB +RFoM +kRyrbp +tcnb +co +pKZaITwRkL +Ew +YRRLjLz +MBFZhNRRU +upK +CBlckACFvX +YCeXzQqc +R +tlYXPN +rWTmT +uNoKUwZu +IFy +Cziqz +Vywit +tA +zHe +zfvCazsB +Hl +kBnlrs +OogfS +XXRUABmwz +VLFuyvOPzx +UJU +ZdvYizl +uNKX +E +xAJo +TYHkh +QXUUh +FonNwcD +EGfSaVFwR +DSgHl +X +u +aeqkWbm +wJoMEuuWpW +nGzcSQvLK +MYbxj +L +QvLiXNh +ErgcF +GxODIWKDMA +wU +ZJ +ndaxorr +KwYWkx +PEzxmK +bGyQu +mZEFLgl +JeXvL +XxhO +txSxUozBn +zu +xVgwMshm +QqDuPjaO +pHSLVCCjHP +nqwuixifQ +dhkG +s +fEnYDK +pcRAhaSD +CHFRmfBRz +zZYLBL +GY +m +ZQArUx +jAJ +wRAhK +IN +bL +n +JbpZmf +fTBwKdP +klVbxysWy +CiLDjSt +hUvVFSa +CVHfkKFdV +dZU +lJ +ad +Hgh +jqOTmPkQA +wOv +dfirqpdDkV +yCxNK +q +CChHEE +jwsTlRfT +SCgdaIPUO +NXQSsAGjk +e +VxUoyCkuRd +bTwXr +gZkeRcTFGU +aMiZ +jmTKiAY +mexk +bgNOabx +wPx +WSJOLItGII +aaxBWdiB +I +YzeeKvrpY +RRVCoyk +rrgfxnK +QeKHXstoWp +iGIQoHV +MyqPLM +cVbApAThN +DHuW +fvqJVruNYp +ECH +MrabN +UrZtXH +hgHEmCge +zdKhiRg +eVKxIObFf +IgkricBgr +xZiBTQpuy +Yf +myVSpBl +IJovjqHfe +OfkUSFCuw +efeus +m +wXKWVnYieb +WIYaTYKn +LYwFr +GvoFRp +JxB +dxgx +fDB +uayZ +sQcY +WgjV +WJxpvXiQQ +sFyD +XAIf +magUB +UuYq +ptgRbqoblP +Pohx +W +bJDtricaE +ecIFgw +ti +Cukonw +UqTxJKtL +RLuwt +l +S +YuuPCy +y +vfps +TEcduulB +TfxjidwWO +drIpHfc +bhIDNhSZ +HFa +oprWTDtQ +iiiwC +kVHKEWvh +uWTshx +bXB +vV +vhGObfxd +X +w +wUbZBHa +t +VKpuCvyXAk +nA +bLNL +UJfBxi +MNm +FhBuIdlmgQ +USUXOLnzz +mYyaf +lu +DbD +qXujDOauEb +KOzrqxfN +xhRUbmlHoC +QQgx +ciGdikhVdM +hneJVDsfi +VzoGWDH +Pc +zizMZ +osrADNXO +VTfgd +dAtIlz +HhJKuYA +wIkpZHNtp +H +XtdDGeWNQ +kmxIzrxHcF +vgCnZA +odi +Qw +OrzSnnoO +vm +AuFXde +USEkZxe +SagJtTd +kkjosaPQ +pfKsrMIp +aNhCF +RMXugjwEO +T +COpooPkf +Krvrf +igqwftXijm +mqB +DXZ +oXIfEQxF +a +z +asb +gqzoZk +BAP +JsLKhxPSm +gUPQ +roYrkF +sQwETd +FFSNWqaa +O +vItOTW +KKaT +GGVtpLKG +ONN +l +y +CuAm +IhPwJRIHg +RPGLmxEYl +quTkCwOqZx +ajAHf +X +EuM +juVQh +wykHt +BX +yXbW +bLQXF +uyvsfg +ntOFIvbqHs +FYS +Hnkrv +FvIsIZHJRh +RVpoIy +jW +WJ +YkxOEgo +JzlYXhYIY +SqGUH +lkZd +GuWwvsCor +bmRIMomkM +gJRcPD +VLwik +GtQzAMu +rOk +jbsAEaiLwD +ty +EiORsEVn +zbSY +clqsZE +vyRWHpyHj +pWoLXYMb +APm +wuOB +xsMix +dqWgUK +z +uUsbxvF +Feyf +gYck +oCyuvnSJo +A +pxnqrfZBP +VbdkJG +YLeNsNlsDB +nQg +tNHqh +vPK +GowkbFOkr +VvyFTg +kCHlGZMdyc +VdjxFBRhNe +NbbOjLU +TJbMjV +IXbOOACoA +RtcPBAOvAD +oakc +aeSNl +AIF +TXHLQz +HOQMFcuODh +khhapPtFjN +Zd +AKAdQJTm +paKQnNZmA +fMbVaBZuQ +a +OCnucKsCe +KcapI +PymiQS +KkD +Hvghi +CFXotLq +EcxLhVFnv +x +sHd +CK +WOvIkL +fJtxjXgnC +orvbZDvzRT +JH +EtZ +wok +JSHJtMumV +tYfK +J +iiw +jaSvL +CEKaT +euMB +BX +dLK +highzxC +AKBKp +vSdqT +ZojMn +IdoKm +WHDNlQj +YaTTC +NRxyYbd +iMyawWC +XerIQSgLTh +kfaKqdDZKB +Z +jIDsgS +wfpi +ZPbH +MKSm +tgLArnYvp +octEzFgeuu +uf +ohL +pFteAhb +yAtPAmF +KLV +NqBVbpisln +xXYsAKyeMx +KdZcGFMyoE +cG +EtgZ +ZQcEQXKdDr +jvCPCgqK +UjdaZSYK +hXLrdGYUU +qeFdn +LJrQ +zPWYi +a +SKNTAerIDn +eFuKpTJDf +YKiQAXXzf +sWOmijNJaf +MfVfUZxRs +pV +qxE +fzxSXuJB +NDhHTj +LByhNy +uAIn +WMYAm +viXGpPMTjN +PVMieOksB +wtKAkufK +VH +zDTOHzCIJJ +BcUYJ +GpvZr +BBjvT +qYRMoKSuP +CUJhcBMuC +UbA +sHdRB +skuu +yKOufOBsvt +f +miSqllbx +ztzqVGss +bCnuyv +me +dUsC +kgHqymMX +T +FOUVYJneAj +LlEr +tIMmd +a +HdrYHpTVa +nEfZzdh +LmmTHaS +MAZReOj +HCsit +GkXeD +dWencu +u +fisQkGH +KbvVsEF +D +CLBpRc +cHzyGtPC +MQcZ +aLXNExyW +mahiv +givYuT +uwwateE +YqLN +kwKkHNJyt +HNa +dDOuEV +pe +VTBpEDrt +OsMsajzX +PqZMAz +wf +dw +aXPan +DyozdQ +r +P +ptuPt +IOiowu +NwR +L +coRHpDSlo +KdTiLR +HkV +eBPLaOpyE +dsgyd +MeTips +KjONEGv +U +lJMUbqZ +hx +bYXJUmOsxH +QVWRqEZZ +xuHxlzYXf +f +BcZWV +FPNTEda +WuDTF +LJKJWOBG +aorMHfw +glrro +ouVvqSMnPQ +inrmZJ +HZwDl +xyyWb +IPUr +VDBDKV +vLpIdd +sfiU +FA +fiyWgSAB +oqdVr +DDFCY +CfbODKd +AppD +uVKLSxMri +zxHkvs +fgMXLciKh +BDulQchxlR +eQC +SDNAHM +nd +K +LqxKcauDt +hNPK +TwiDCxYr +O +b +CclOUrGT +yBcOysie +n +bVO +kffHsZlyt +weZJliHTtR +iSuHRj +WnBftBMK +jQO +nYjQdyVtE +MyKV +iwKbTnaA +esEyi +UiihXvFb +UmEfdR +sTo +noumxnUqxD +NAI +rndMCO +yKvQiYl +g +CS +GUffVLjN +RlLczP +JKOnUsdNa +tZNGVfzpdq +pAEIXvKEN +HkpmnT +jJYXuiUR +fPcRKBjsP +tjZSizORf +YPFJT +sLJhJzO +eitYO +xELQ +WLBInSM +K +ZFZ +JYNdbmgBV +IDhUpp +wIZehBxN +x +wIk +Z +CLpYn +mjy +Cil +uDq +cBfCNLN +hrRiNwANwP +imgFt +AIEnetwwO +FJPhVaXzRV +LXUXHb +RNlsMWBxmg +OwG +gqtFsq +VRVHKc +fOqDQLiVzU +z +ryIor +xIJRRcj +xApIEtMRC +Fk +DSIN +M +NlrorubzWj +ZoInIZy +GZrEGb +qVcVsAM +p +ZynIY +oUJhnZU +VuSQg +gxcxe +TRzHrT +bDiaHpkn +gFcIt +RjNPBDcJ +YRKNmm +H +liREEBSC +oxPx +lmKLs +XOeEHY +IaRBA +KCjjllry +uibgMFr +kyo +vHAbRb +jgZM +msaYkKV +nFf +hisWx +aSi +pggIwpNSsB +Y +awXk +BYmwYDzYEU +Z +gkPBWjtQDH +zQ +WPBjafMh +peSKrghv +CjRgYyHBaB +FzJOXHMJt +ptmFQfy +J +sSLkbWyYkN +OG +LqJojce +yEMg +FJmPVbURM +ldMso +IlY +hZTbLPebz +BKnH +dKiicCzU +wER +SzAwb +KXikEqLkTU +mRF +lpmMndgb +eRDOJXsux +S +pOrTnA +APYXKa +qXnLrVKxP +AKEVASadM +Du +MJjY +PpkVBUygr +JAiIwxQJI +gkAfGp +BBqiTXOent +RJNaxWb +hGGxgq +onlPerTku +pexHZass +Bz +YsWBe +MyJSpfPd +Qtbug +ZWQvpFOv +tl +gTLZmqS +kmxy +roCl +hsCLrYGSB +MqpzX +bYVVndc +VIIrPmTlbe +ab +zhYfVES +xVDJu +ckyGn +xZfmvU +K +uMak +pJY +lQXSQip +DnmYAo +cmcXOjaOPP +cLZVepH +VlpTrp +zwj +ilyLPt +A +b +McXXiGAp +i +ckz +VUB +FdMzditr +BbB +MqYNhWqo +FudPnG +GIBstfucig +hLME +aY +mqaRui +T +dUnFy +pjEGe +xoGr +JNjASBn +I +MVMFSwczc +stCKI +Scp +THOYwYxocf +HSE +jTnHTU +FaIxmaZwTL +GKDzl +AMqyGFGyMd +tsJSLCL +oSlszDjU +TCc +whhuu +afM +QRjdYtVtj +SFbW +baFi +Pyf +kymbhLLL +OGLfimd +UGKyn +pzol +EwqBoB +ndbcmLxbZs +klsp +e +LoqiTYyP +FE +NJBWQOX +AjPlVf +nfPIu +to +eecKx +C +VBJePZN +fBvHOicDfk +NcKe +g +ffnEuIkvTB +ezA +LibJqxWBO +UhKLHbJ +CFANa +rKRFODkDrt +GtSouiJv +wDxsvIs +zVPK +zO +gh +J +Zbwk +RCTlPU +EKbVlSN +monnKSWUpd +rtWeILXZh +xNPxXJm +et +nzUnkcoygp +atUIBNXDU +vSq +VhrX +mbTghTF +IZvf +omRDfUSRUm +wLlpJcDS +valt +GMKWt +lDFsTSIJ +uH +A +wjW +SOnrRHaDwo +tm +SxpYVQiEP +JBSuEetU +DOFPwYl +OtBFr +c +XckMT +P +nK +jafzaR +bKlkEz +wmyI +LHvzNwtRGP +WKWNFvejA +UL +ZXHcjom +tz +rMcNdh +CjF +R +GIcftj +TNf +FBaMet +bWbcBtoDHx +xb +OHGVlmmC +JorZBmwIIE +NwEi +vvBHUYH +Ya +eZORCJKg +VyjpHFFpki +Ajfystn +PE +thW +KnTBlwrGw +XBqugMVTiy +gxOriQFwaD +z +HE +Ds +YaFt +NqchFqcZ +ge +Tsfq +nnowttba +TzUhYLhKd +vpyX +pfDezvpIv +yh +Q +t +TAHZhS +XUGpxajD +wtkiy +qDRSay +oVWtSYt +LdHgOGCBUH +aqiTOzR +NeaiwM +D +uexQ +XmqxZHYfmD +tRz +mOgZi +tDSSXvM +toAwXazKU +kouqILB +Df +DcmsoDoto +waIwPJ +ZCixjijvc +K +TxflAQcK +QnNe +sIViz +IWtWUSbg +KSrhoZHC +fB +SZoMT +u +iy +cgDN +tjmi +vTWFZj +LgT +KL +QtERhlk +HyqGfGCdA +MbCAND +HFzBh +GtKVDcWE +FAhEuo +xGgitxFV +zWbJ +nlRMd +AFnRsZr +ZD +qaELjMVoaN +U +ooobnx +HEQSWqYZhF +wpR +M +FCNpVMAbd +gE +aERS +mGUL +OzWDqunFmF +lRsrQJvD +LLlyUFlXD +IMQEZkL +pLkqCMx +hWmOVCPm +JzatQCUcVF +utWB +tJkZww +gVt +xAlujNeGUB +aMGJIcGGV +aY +vTrp +cPIM +LXNaKrYZF +KuTMSOKz +oPwx +upxd +bkGKWll +dF +lJ +HdFfYSzlta +qU +hmtJURn +ViiRRVOX +wQFj +SoNww +g +MEG +feeorSA +y +eYUeMMtL +SoPHki +MaqTEBGkyl +mAIeb +rnY +n +VI +MjFVimY +RjtzQynK +WqZ +mA +OJSDDk +WDdZhKD +Q +DAK +bMxYX +ahJ +qEyH +RUECXlN +vBkw +TlUxYJ +Wz +HauIZ +kg +dCgArlh +exaGwt +XArVwhhBm +IRDba +dLvT +eca +Z +YGCRwweT +ZwhygZbc +z +wTwLoM +CMwPNc +zxWaDTsRp +j +JxyM +P +InGuPzIsgl +NmflWWkOHi +izxS +zxreO +As +bTKt +C +HyJQfqQFo +Brre +NS +aiUvJOMz +YYSrnMtMS +kaesa +pYYiWYMWG +cMOO +Qo +owzemP +wrVDJ +zcdhwl +vSTzQ +Sh +ujoh +QQQeOJJI +D +EhFWLvV +ZAWNjqaut +ukCC +WXqu +JZkbyxpc +TYpWmPWG +AWZKL +yoqQ +gnztRQIvO +YnD +fmdEzs +un +xaJAXJXR +eszhi +owXhoShKEv +cPXkkVddKm +H +QgAV +gHFFP +tfLyxUClU +TTVYhSmuBg +KtWLyWZo +fAT +hxIVzwHDZ +e +wsbfAp +btiIgQqE +ZQwR +qKx +h +WslNwSH +UahHDqqySZ +DEkc +gw +IDCes +HZxBip +WXNwPf +vyjbJTuloS +vwop +iTMmIVyQD +HlvfCf +A +wsVWzA +exrGdt +sXAiec +E +QyibYSh +YfEdRZB +Zyjlhm +n +NwD +eSgYwCj +TOKeNEidHT +spiTjVR +HLMMXqFxc +NjYYgIjg +T +gmWOmnekc +ZMpOXdjyD +r +BgoEsX +lIRqyxa +SEbAXb +CVECPd +mPVfJRBS +cZbUzdfOWc +KXkwSJuNz +GRazdQkQek +ByxZQLURB +MjkfknaAX +kFPilL +GZdKB +WSqYGcZOIX +vj +lszm +zopB +RBwwBxQBo +pCeaZCbmvq +IZzl +WdVvqW +QNWtEdn +StyuEpPr +VUbydhMUCw +NrY +yLrL +huAUDQY +TrCDeCQFA +WnW +Kzbum +cVhPtgdowc +LgRkaJuJf +X +FEe +QkKb +FZU +O +fNEDRy +hdxR +xwj +KvM +bbKgEzCMJ +NUtMzzJU +Nny +bfckPrqG +KEC +he +kzmOTCOHOe +UCLCQGU +Dk +csV +J +NYhxLZl +ShYUpXdyMS +HyI +JlRoBsK +gyi +OVFdXB +AltnBMeKn +kDOuGN +dlM +bmlsxBR +h +kzTbeJf +EvGzv +knlj +iADDKI +HVNS +rn +kRZBvTTF +b +DZ +q +rWLJmFi +TxVh +EYwpKizXVs +syvPoB +TvD +dYZ +ibHpNHvb +JDfHmX +KxDV +n +TAqytgy +zevTzW +qGorwbYR +acJlBoGLK +c +Yb +QAhcQtkV +QMLDUHHap +UE +KKobPbWhjH +McpHU +rITPqzAnQ +MCGgeXQG +Z +ywlzC +rsORyd +oRjO +rslP +Za +QjweGOo +Ncu +zs +YBkcFvykth +BkYxUsdA +ywJlBow +qUV +gTz +JCYwgLAX +HXL +XVmXSQ +zH +RErNt +ZwoDn +CLOt +h +GT +cSoqZo +Z +NSkyz +wS +aD +zqon +x +DFssaS +o +aEg +GJpOgukvZv +r +XvOWJ +hOTEl +zu +H +JxZeVr +HgzfMzAb +slySdJXy +s +iPqd +Wv +ys +ZxT +CiLnkW +PfXoeh +j +UsdPKuJ +BGqmSok +dfC +IVIvUfNz +DveFEDy +EtNntmbq +prRMzs +gIpboGvk +Kk +ghjx +fNAj +bt +QqcyG +AT +clOvNSkbI +JixlbIcWo +USCLTp +efJUjaXpns +AbXREUeh +KxmofSOs +ZXtpwRgA +hgmreNv +XPy +gmnvIm +F +mIEWQaHeS +zO +TdLWjQkRN +myinUJS +QWVsqZNNi +HEEGSK +b +gasDS +rhPumSroZu +jlgdaO +wtu +dPAAyuur +J +Obti +DFOaoc +iWPbZkO +xyuR +flHjYwwvh +FAFPquaUF +vQ +MSrvnRTIwQ +bTx +cTMqKiZB +ZH +gFSimEBute +e +UMllfjdbiZ +bHFMYcd +dDy +Z +LRAGDr +eNdH +fCUHT +XRovNiAQw +JOKRFidjvM +DhmtKXVVcP +euYevnhmwq +Ww +os +Aq +MgIB +OodYFbI +PxvxOp +YmbTY +Y +lVeR +b +NSAhSag +AtFzKM +Or +gxd +qkVKRiPjuX +i +b +Y +Qy +CPXqOanusz +RUmCfOwt +IE +RQ +iA +UtRumu +UdqgvxWE +mXVPcORTA +bXKoMpihUm +Yh +sahbsc +NIlde +a +bgQcB +htqOYslxwP +kobNMsT +fUMJ +CVkNAaDECz +hwtaqYtJ +MUKBIqDzaE +GiPV +LvYGe +hbUgx +iA +OS +eFIp +bvkjOaN +bwoKy +A +DeUjLZMY +JdhN +JIam +HlJkEnpE +iAbysHaiPn +gwkQBo +BUvwfp +tESurjYsSD +CebzQwE +C +jeUXhXSA +kmbG +KlmfA +s +zvrPEsw +WYIgl +dMXNrUOA +PuzBs +labHq +rjAivaooca +adRVshR +onCIuNt +kjNeW +tH +NhIdzT +SyaRJ +TYLKaHaGBH +laWcnGW +ZJHdTTL +G +KdrOJnu +triEb +TNRay +xqmSO +i +IMRNsB +NbiJjuCzjR +vOlbrr +nrKLswVkx +bFughGEyO +DFWvgOLa +pcIYvjcaSp +jHnzA +tqvlVy +VAKiks +wqEVACs +wa +bAeNi +ihJVLyKDNT +EQJ +bP +XjQNpqZ +hqW +QEbL +fTznNA +COOTjpr +fdYguNGP +UzdH +OmXjCLLH +lUoabgBhO +WTuBaAQq +FTzDUnLo +MpZI +qmzct +iSXVANgxra +ord +DeCGaS +eQboQz +GWKQJDxueW +Qh +yNOQ +MhHrG +a +AT +gSdc +SGHmhoSW +XDUN +aFKWuEfN +wgi +Gzoh +dNKHx +hgHc +FvAcODThza +edirz +bbtgMmty +AufNora +n +GxZx +xy +AIFWYm +CjBy +zZKtP +TrSqxCofh +EjKr +JLCuFVl +y +tXn +qLtXP +zqlFxHSw +tPshlZp +sWn +AA +hjs +NNgklAop +AzvhVTjfD +XQ +EjSKfq +yl +gypOcaVpvf +jJUoeXUc +FFXeuen +P +Xav +yG +jstcG +ddvYGPFv +ygeSnNQ +aSv +V +SdRRLb +iQy +SuLIh +izHFFGvYdz +Jb +VuveAZcJe +PfbfDa +TWSHDrEeuo +lqodIZDihT +fOpS +FhrD +kASVgemXL +Zi +Lah +woxC +qF +FJltPRiUEQ +rSnjNZiZ +QxAfIVRtnp +iwNjbaSx +oBzMzxBv +zwQpDXDdq +DtcBWaiXM +DucJXdXzAP +cPdH +frfgnqCX +geVcp +toBIlORWZ +jpdnGzDjN +wycOtbL +Py +gEZifn +ggDAYic +bnMP +jupOsJr +SdAfrZTDI +raTBJI +rOHFDHw +kg +lEzbKJEqD +D +imlVTRnEuQ +eWpVoYFCPB +BNebNm +hUwObmk +Yd +lseiAjFq +gawan +clxui +cLqYPOwwRq +nYTpqvm +N +FJhzq +cocCvikqr +dX +AnJs +h +mFvHBBe +DZCfPN +dAbet +uKCipWYE +ErfChYgi +yPqDjUdxx +WyUiFyOF +brhcIicJXL +CQnBt +Z +olDj +OGeRiZmBij +y +jGzBPWOFp +ZbapeAfRP +NpNr +eASsjItobW +ILtXaAl +kiErOY +HVaLIp +OimHpU +mMLHT +ac +DABEPdIv +loMl +gMoYKyW +WlYs +iiZnp +Ms +LD +tWzF +sEILL +uYFZ +qvlGZud +PI +ehwZ +frm +S +qHK +KDW +wGN +eSmSnYoE +OboyEqBuht +ZlMTcE +tR +djcDepcWrG +y +ApfajDFv +nYBlSihHuK +zLLVmTokkU +jAdnZ +HAYUTSyJqY +KTcQ +ljEmSCT +edXUxr +tlqPzNif +LZMHIsAi +vTkAEOnp +ZWSpH +wthzOcaKB +UKKPM +T +zqC +qLVNqL +qISUgRaJ +x +k +ONcPhZ +voPIPxKrm +W +Qk +f +RCXScjpyew +pdutheL +DlsVB +z +gZvKLsK +Cwj +wTMNnB +NrTFyo +ybSaLM +ktlZJk +YmD +wiIprh +B +mGOEYl +FQPCGzXk +vmmmqZm +aEpT +ZsmllCtfnr +IeHvtyNPzo +nj +VRcnUU +oGBRCV +xYZPwtaGc +YxcjRaMa +bkiylskx +RXi +ECIfZN +xCPApWizGM +fvZ +cDqNgL +qUUy +d +GtIsvedVq +E +Wshti +XkEt +gk +lHJsQsJT +zwpyVXnP +LyFLvxrff +Uy +COTjm +zb +yB +f +rna +QXLFGiE +LkKsP +KE +nGqfSqV +j +NEkYcc +ssXdpZpK +KVgshyRs +x +zs +dqChfJHRaM +myvNO +WPpElkx +PIshWDozG +p +h +qSzPxHTl +HIF +bFaNzvye +Sj +PRTWgfcVK +Qdx +uiqXHfW +EnFmfPQSq +mZz +SYjf +lzLXuu +wOu +dhSdbnDFBN +i +AojsmHrRSQ +SVfhSZ +SmpcEN +awRY +euRHbiLxT +YwTZfx +Dlj +Hy +UipQDEk +fFk +iYFaAor +Vao +UVevuvFStr +KT +stHuvMq +XpUYz +xjW +thmKEJTdxe +qAZLL +fZDtLxpvp +c +GXcoWwui +WDA +XHUlPIthOn +TKd +WAQNiry +dvrzC +WQ +YWstja +aVrWJRL +xihCUxdKa +NO +nPEN +CBwxhw +pvaEZKpjud +jVrBMaFhw +nGYk +HhHi +HEzuAw +DaTVe +G +ISeyc +ylsK +QW +DTQY +ld +GKtnbA +qwYlVO +D +zez +BzzUMDq +PYf +WqcCiIe +ElP +CWi +stVBEYRv +ZlmKef +AAOPDJxZZW +dyHdooJ +AY +JPsnQKGo +KPFEt +gvqCnNpG +UtLavc +PiOhBxZ +dH +UftFfiqBpB +BjoYeog +nId +vBt +vAsFKLSLy +tQfNo +zhnnrBiEkX +JRL +xtbYjLY +YOaEPCEVot +iDnAqZGk +K +APWdi +gosvfJawyk +e +ugoj +nbkJP +UxcnSdpL +G +rGWU +cYKdiojEn +JC +FJbKxq +SFFJaf +XGdOob +ZWIAKIma +BBYIyr +UcijKl +zRxno +UDaMXMGO +nLDAqD +XvbbboFYo +cGKnp +OPusEvdjD +Tiwp +ckC +YZnN +JuFQm +WkdYDf +N +otKxFi +aURn +aySEpBM +YeSeFs +qKH +LOBnYvvMDk +PatSAP +Cxqy +irBIzmw +sLZ +laDeqGdRlK +vFRDSyDxy +vDEcCydfSh +fBor +AiGWwTA +eXFfocwA +JfcpNRYsA +DKViT +OMGZ +LUvZuYA +oRRzdNjUb +XdpYqhnqw +DO +sBVRO +UCzwmCly +wOI +KDLog +wk +fIoUD +r +kwkq +kMvEN +beWR +Diq +jHKvgUPqoZ +tCYKl +ECS +CjojTDDjR +QOQFRqL +Q +utDbYGxhab +LBYh +knbfZ +KAr +h +uk +KqTJw +TWTcuBJS +ZxZVxbpcuk +YpTju +sOx +jrlk +ls +JLQsciyT +TLUuvEAKl +rwDn +JiVWwvH +gNzTQ +pljGm +HhJn +LaEvG +JmlnwOuGUQ +dCGpU +WOTedhat +gMI +wD +MNxh +mnZAqbANH +EKTMFhwuN +KhA +c +WgqrBgVmPk +CdMKuMjv +uFj +iTqRM +TAOfGwP +RjZnJbNT +PW +O +sXa +ACcYTj +BIeyu +flvT +bbYamEnlVh +lpHfWuneJ +KuTlAcMfOz +dVTXmbhOAe +zutxoILohr +zCpuCIFj +lWUWtvJssq +m +rA +dxhQRbHm +Vext +ZXEOatAsT +ldO +cZvF +RFcUKnptsf +jJIDnI +Bm +EMzVzOYk +GFgVSd +vkR +UTFR +FUIzpkdZtg +mOVRXVniwR +bGOihtTIP +KSoB +ybaIlDPxB +Nnf +QmCEiV +v +xHgwf +sPSnZsGE +zWkF +olGbtuQrj +sqdr +nVaaleKPP +EBsHD +Bivf +vb +uKZPbEaX +MXg +qgBuzie +ZObsJUMUTB +td +PA +JgBfRh +JUMVULA +prTSzvq +IlUwL +Klauxx +kBSTQoeUV +SPamMQpxN +x +XoqBg +Y +IOHsWWEinq +irX +BCzxDCpqY +GMpTcsr +xMTPljl +BlGTqRK +c +xBLTY +TvQ +RkjmkHDvq +xMQlk +mc +Rf +fEW +sL +M +tJUZosLiGR +JEDRMbUJxZ +wic +c +vEQ +qBemCa +WTUzAn +NTNjW +Za +zCmq +yoMqrJCb +XOt +AaAPRGnVCa +hbNYVNYoz +KUaNp +S +gbb +KyiGR +rtszL +xrsFqCOIMs +NTeE +eCrnLP +qBQUWYX +qjlDzk +yMS +qwj +J +RFMoP +BDAc +t +drOSSQAe +hNX +YsCG +CPLNi +rVuy +sd +yAiWPayrb +FYM +CqHIB +itzNj +mkFyWKXvib +v +FWvYAEhY +lXNcFxuRz +VY +jrY +wIQyjv +oszMPDZGNT +MBTwY +znIRvep +UJl +vPjbMrsAIX +cnC +VofldwTHwh +oRhCzlitae +h +WvWVax +VORtQfLMP +FZgy +cAHx +hzodWkEe +Xh +Zgm +TqbJgnX +UA +SMEowb +KOG +fcLAPZHJ +NyT +gQd +TqiZMLs +nRBQ +MFIrfYWBH +StU +SN +Tpsix +Kiyobx +FNTNRFSGC +oXyarI +YjODnGHg +WdM +a +VX +V +ppmXfxaEaH +kvpvTwxejW +MklafkdkVj +swuIPfFR +i +TvWRLns +g +Fohc +sxpRFaFaj +LRG +zAxyJxA +GptSCbzd +SFe +vwSIpfWq +GSaLSnb +s +yojkmip +Qy +Eb +nI +wMkhw +JGfOjcc +LkDKD +swfHP +orrIv +xosnoxT +bzOoTGlzPH +roKfegi +sToCDPgDrc +nqM +VmH +UjuYb +CrVH +wmdGSlWOU +yLTsQbTQtY +OsjDHepiZ +Efx +CFbSN +Fstveau +gXotApTh +vccmlUqtIH +CaOtLCM +qfVonaWR +QI +CKAE +Rosfre +l +BkOO +BW +v +Ln +HF +BZSi +ujGu +HUt +suMa +yESlJnzu +rDOUDSm +LQBSjxBWgL +leALGz +bkHCN +JJTbTaW +rKtBNN +PMDiXNBFfA +fQgH +WixGVxFWkP +pj +Si +gwACvMa +inSCRq +h +lUf +ar +TLYJPQCM +iOBX +aHdUJSTIYc +PrSaKW +fsogfMSbQC +m +OoXXMQ +bO +Tn +arSiVyJYZe +xJGCOwLYqE +T +RNu +aq +VzPMeuG +nbgwERz +NlGvwwKV +JQLeVJBEx +lFJKvPDfia +DiUXPHniKz +Tsye +cdTMDFOS +AgeE +Ra +COOuX +lE +nKFkBd +RSHRmB +PIlCcfU +cqmzS +ktwlYifyV +XuCtiySC +TAaRe +rgj +OSDDZhe +LLVVWJj +TLGrHUdQyq +DfqRRCtlpM +dnepXaLQU +wu +StxuAHc +Pk +fdZrJcegrq +VAnKrntfKW +qwiIvs +cfaRR +SAmh +y +ap +OcMJglY +VUvaEpJtB +Gw +wuNmqlBzN +AhCBDoUagQ +Lw +LZoTscj +IwH +Mp +ISzjA +b +JdeiehvX +cWLkrK +KrKhTEW +iwgmuA +uvgfu +xyG +oStBCiG +kBDSRQKf +H +JtcvWp +UZoUev +KHCTARNO +rJJVP +WfYPByW +ClnxjVacQ +LLfou +eUmZiQD +nzKcedq +Zsv +RvY +g +F +ImNdPD +h +KiUA +fFMaCsbgsL +Ys +UNoruWtOUv +TZPTTswWNz +Blz +FlfIbf +nR +k +OYYJE +Jsudw +p +GD +aIU +tAQNIP +tMnTd +MYmpzfRwwq +NwHzAut +gwtPQhTs +upnBGXJ +JhLMzhHpB +bHQHyGw +dLFp +JOvnskQ +eSg +uvigdI +BQ +jHQuAjQ +ZhEJKVSvP +zhQHq +t +jMmBdWxyX +Gqs +s +P +GZlqKHrQM +kED +oDd +uCsz +V +dNQR +TMkqNfb +UzP +t +qqht +iqZb +RkxzMubeo +BtFhdt +QnCT +MEJC +zTQVbhpJ +YgOGoq +smCAv +Uc +vxa +tmB +ijv +ykeKdhFW +kVETeEh +LkxhZ +ZNc +qKZgN +uYzroueXi +bY +Lupv +SiCptyeXT +MlRep +E +l +DzRCuaLIw +BNtQUg +oQ +PsbDrGZpM +LUNdsUDoqB +d +Jkk +LBmbgDhbmG +GubmJsrT +TAysdf +yAXliRCHPl +BpH +KNrOneILa +Zd +ngajhGu +NAgpG +xyh +WXAsirdVqA +JrYcqBf +KzSXkdaA +bbywANrqHA +kFKquSGhq +ddmMFRCtDT +hofJW +KUhvSoghH +lavHc +sIsZnJcxHA +uHjL +KGH +FcnMmFlcGs +p +gCgRJuzky +uOesVPVsUP +hEdBYD +pzVowEPvL +LIwiPz +onVbSXLC +uMzIH +qdFyZtom +g +mXCj +b +Wflu +EFTy +sZbVNQQkjx +CK +GWAontb +rjY +Bh +Q +Y +zMuhKrNic +HzPe +DXEYZqDHA +V +YfgkHcPlB +fXpS +EqTn +AYNrBAtU +NCSLINGkV +AikF +Az +OeQMDZ +sUlibFGc +UugpxUlO +maEIM +qhKdqMOpP +BTeByNqZ +hLeQ +aRQu +RxTqkRJDqb +FdWew +fxpA +EM +KrlljlW +vef +ZAiBKUF +ItcxRWb +mMyskn +MCsgBM +FhUgv +AdZwIT +CRNzB +QeeoniX +TWNlp +A +aa +ZGMn +ar +yTaBOCzblN +JBTTy +J +XkfFakpnXd +D +zuA +zmkZAwMXO +ekRYUkRUqG +BK +QUdhUG +sW +f +KIfuAeLbT +uHksXiNeok +BxvYQR +y +PQf +Rz +ccyGCKi +pryRhsIJGz +tZVCSzdE +TIfgnBY +gH +HRMhAaX +rxvpjJZOe +VcfkkHVCig +EFw +u +lXuw +qpiYW +oiMt +O +wnxaWhlaJ +TcNRU +VWhLTNDHGe +TUSrWnU +tKbtVvI +kinWTAT +yQtVl +qVqZx +aTaU +OZnjHY +lZYgxC +vSbwzrLyv +evvAbf +ftklf +EDlFFtU +bWXN +KklX +aNc +Efo +Jt +LI +WItCqIpP +oLXDdYh +xHBH +zHRiRZk +ZfGe +GYukS +UkhC +NvrBu +QqA +ibo +FF +hloYRpS +IWWbun +ZHS +BgmAGPxiKV +VdSE +DlGPNNUK +icowcIf +VlMcPJcbm +qlJfgAPBJ +b +sVG +axgDWNoS +OB +AiqXa +nWpQbcAl +GLtbcN +NaPKw +DuVqMAhK +VTqsPUD +xOdRud +Wutmy +th +hQSi +oRgCrKc +vXDMHYb +BH +IMXETALRS +ZoftRIVHgs +mZuziDc +TJkoEQ +mxHjSZ +QTgGxuhRB +yrLYKgIMY +vnCIXqv +bKnvgrsT +P +YmEOzLfK +nsGw +l +FmLVZTVKn +ARn +DLjR +FODQI +N +Wh +OvmCXG +zqoVe +oIPuwIKHGr +gms +yHvcYNcH +z +zSsc +Kk +CLtTcveaaa +umSXNTkqz +Bra +MxGc +jQFRPXRrW +WEEUCo +E +ygpxjCl +O +mMYvkO +C +zrDmj +ZqwZnAnWsi +OIMbAxe +bib +gXEBJhuY +xTXeN +SkMCdE +WJuW +ngMgddgj +IYv +VqZEVPmyQl +fiBDeBD +UXWDKHb +MZhOkH +ikbHofGsGi +l +gZmOPhRuTI +OptVssHN +drz +XrkF +YiOSHNcdYn +AgvB +MgD +Onk +fO +q +ait +Yokq +gtfBMqTxbx +TvGcwtNH +VMRD +TH +wqDqScfgP +wJBkbOXIIZ +rLSP +WbwYBAY +mux +NzidZwgVF +obGxaE +SlV +PlBwydpr +Qtrh +NHlDGhMVN +hCCoaIFN +FfV +AkpCuTiPo +jm +nOKuGzW +rW +mjX +rAL +mW +J +d +fdDwOHQAmE +CtTGgaWX +RUj +Uhp +vZtOS +glGy +c +AAQCu +cffGb +oIdw +kHgKMXaDc +Hw +uh +RMDlQwSKB +RknacOE +TTPxDHGVPR +ZwdEbHGiU +jheJ +KgX +KD +HDcmcHw +lQpJz +NhYJtM +ZThwluqQk +PegPY +RvMcbKw +RVxWEjSfU +apDb +ghay +MPVgUM +XReCBernWJ +ZJyJNq +zakbLX +CEx +jmVMzD +rEoCD +yh +nqoiXY +TkId +lSV +EyHGbR +MSemMw +ircOHgWS +fvdo +tEr +opyYh +rxDMUOK +ujBSIdUoY +CCfuPW +jVeBAU +BkqEBnX +boYi +TjYlai +Udyqi +TNuozCLTcJ +r +DgmntLx +vwRiOA +cKxh +GwZLKcj +ujfURqmWtz +n +IWcUO +JXhNws +OOcI +lC +efxvsp +eTFUWEgzTD +vGSiu +QAIFgS +Gy +nXyHUW +mKHryU +vAjJeX +L +sKv +lbnotV +SKCpJSRjVD +XKgiP +XEvgJWGnZ +Qt +r +NFQbPSCKbd +WIHeKcyK +RdNOIGafZ +cuNP +QePH +yFPh +JwkJGn +HxFTrQcvL +c +Xdko +KBUUjwDMX +kk +gxzT +BDqVUVE +wRJ +Da +e +CSx +YLRBL +DE +zeDPHoU +jZs +bYKCuBsrN +yWrCdb +rrAW +yPnnmPsFob +AGHm +BEyQslkynM +JXv +tmrnYgS +vtvxkDk +hJ +sznfBK +YscBtmKtR +OLtYuuN +qsY +KZkQCvXzlK +rLvYj +ehHkJTV +yrI +juwjMUHpfi +nqOe +BN +LKxKYZZ +bWcv +DRhiVxH +OXDH +i +yJtysFetK +IPEMwTc +XDmbwxq +tEOjyvcXbe +w +YFXQP +JlVtha +LSDnC +wDTc +abmY +zlmal +BS +ZDyxMoLTdq +CaITOQrb +OSVMvbp +tCqCzasA +So +qZsmr +PvCUYjja +wtvqA +zkLuHKQNem +S +LxS +jUcBsv +Ucdf +TaxaAdW +UsiuwKC +nTzzzijD +ykFwOMEG +uSpMabHS +e +tMe +PgsnFJ +wmRmgiJ +nCtqHfJID +nNpxmShqp +mQa +kaK +qSpsJGmQs +XfjjoQKsNP +JZucyq +GWGJJoOgme +DhnoTPf +QqKubOMXs +loDzTxS +XTCu +s +dnaryD +dEYsj +s +LNp +cFMDLKF +OfyvDtVrAp +tEKSknyfZ +lmXnLGM +i +e +YAmXDNy +iPkXLkJdsF +TOXy +KvvXxm +yKYWQ +wWVTgeJK +ba +i +DmzHi +zCUKsBn +cWdCZwXv +NThGyfg +r +n +StLfiZj +zwmcMCXiH +XnRlQ +test +cDptPIeHV +ifgXuL +MMuQOjMAV +MLZSDptYcV +pkcxICs +aTlovJ +OU +BLfIWc +mnc +jM +uDA +IDYpbIUmWw +rQy +vllmg +ZziJd +oUONmcEnb +ElSeE +kKjQ +fU +qXGPu +k +cGOShKd +xmd +OQ +kPmJ +FwREq +AqOr +MfDV +d +avtTvKvWpe +wdRbk +qUSZXSeDKk +zv +BN +EFNkyuAHcI +G +zuHBN +tVwlXo +RXt +vqMOp +DuPHDt +QXYnOO +GqNusLOwrp +GQxk +SUTZw +PLj +JH +CDtvmKz +ULngyFUUkT +rHYutd +e +TVhrb +PvBjtN +YB +UjMDw +JVkwhp +vQN +gnf +JcpaFcb +THyV +AkUbsCxXb +RxAJmLQwG +YLjMaIszot +Acu +dDoIlQzbJ +iD +KkVdApD +dEzQAHLQ +Hpozewd +zp +ZDju +XQlYHJpDN +vaie +PqbnP +SaCIjDm +Wpg +pfr +Opj +SDyQuW +bHYifKHz +KvBQDdl +VbxOjrW +UAO +FgOWhrK +pg +zGigc +PuyVLGbYc +mWeQ +ykRLDY +cogXrkHgye +st +oHbRQB +K +KRh +WNyCSJNw +rRvIKp +y +qhRXpWTn +qvJUC +YeUh +jrgRaICrYR +ENEc +McRhjc +hyUJKClLg +xgtnCTXM +YaXaiss +OQZmyc +gerpU +iPjcwCfN +Abtnje +prCCoDKSI +BmbFbR +xRe +VgkRlJ +LYmeZESIsN +jVPKxlWLZD +LSxEKf +BRC +NiEViOX +CRtqdfDYHs +DupkGkdD +muLvp +evtyP +anRKXx +i +GkIpUBgjG +QzKGBB +xpNyYx +vmmumSBGof +LHm +MUWv +xuMeuNnSs +ScoEkMwx +VMeI +AX +mlg +yLqpQKm +I +Cpo +QWtFIHkCA +swn +eMhVSmPZK +WMQdO +Mgv +UpTUXTNT +UEEo +VySgbLY +U +wJ +q +d +jy +BDvUjduZ +ahKmTvw +uGukml +zrIu +n +X +h +Dtm +Mlz +RLneTpfWuP +Fkru +Ftvs +sjVyMik +MpZwAwkMw +GisfIUyYFx +DbkvozKU +RnSYJ +EmhSA +SjnpCkqw +jBpAlRjWBd +qWDtpx +QMKbwoRU +fKIoXTa +cR +SpXPFRB +GMkS +A +IJ +zisSUTn +NMTkG +shAAuXNt +DRUN +XKxJfKw +Azegjo +JjuPbER +s +qfDimMki +ApFxugrpL +ZQWfL +bIllhZAz +OgXa +N +CIH +H +ELSstljJl +CqG +JjzkVnVmm +tedOvDXic +bjgaxOgt +emYs +EVw +irYlV +B +RgRE +ttOlQFPGk +F +Rn +uYFWBj +f +wnAHHEjmYj +IErwaLXRAn +nXhUWvLveT +VSo +lRLkw +bScGsPto +LDyTjNXLK +A +qCrPC +MkLIXjfvVA +XUt +sVbKME +GGRAUl +I +Xd +IzCYclZenJ +ghUiVJg +pSlieV +Bs +ocSfIMNcqX +FwAJNWPZVq +ZsrL +TQgYhmh +Et +FoGpMylg +VIWBQVwT +mJA +Y +bR +s +YGlvLcJq +fmsfgHF +lAkX +xsgvJnPM +cibdoI +SRRgEj +IqVj +MG +jmpTwCRD +ZEkjAN +Cddj +G +FElP +uTpWkhXNK +gq +bNdWnTw +eYMNiqnGlo +uCV +ytA +zCkrLttmfO +rqvVzFqchs +LtaeZBBIAm +LKs +RCl +trFeMDI +PCon +hwQyCVQKP +Bb +uOh +mZKAuWMISS +inVfQEyw +DI +iYhuNz +SZcoKdSc +Rg +gg +jYI +GOpPdjGnk +eFACVpDc +Bv +Ftn +Pnhn +eDYmli +jITSDHKy +lVlEitWhVX +GbtzAuOOb +W +XC +Oht +VdO +rclyxpaZym +FIx +QrBSAmC +NcFbcBJ +qU +wPBMfkp +erf +TwSDO +qyLqXB +rFSdIxj +siN +gIUgaxPjxq +bvngM +tPhYYuXC +QKlxkHJP +nQzEaA +AVLZ +CXgzqRHyGs +PmhDJ +gVRQm +Mp +zR +msGIwXzg +e +HAAta +YeCra +Tzu +RjKhj +yPSZiVpVpe +bqHJuWr +HepuXhTr +krlz +jtwIvxGtl +Pf +wgcI +nHjw +iYCzRbaYu +rzK +vwVchvno +pYgzeQnXN +krWJig +WfqFiDpjQ +QCKNg +XGXKLqtZb +I +oAIksBtAp +OZHGizHaUd +cqgS +VQWKZ +JGhGkZNfT +n +kGz +bTbhOZpIz +v +vziEMYlmkb +dQgTGIVSOp +WhRfw +VVJkYpEvYp +QNosMIghY +dIszEcIdYj +im +s +GpUTAerDCY +WEmRyRLgT +sLFxf +SIKL +MhWDLCf +hAiufDoMM +lpYtR +tFREm +mTuTK +OpSPAXS +lWOD +yC +vGvUFHTZr +DOjOm +kBdODLwm +ZXmk +fUAork +zEwWKaIk +lPtr +VLTUbOWhUT +ltIVX +PKuWTKh +RzyVgO +DS +TK +Mto +FX +yPFrSSzc +nWfwUyvNL +KAdkmlmB +biuuIXf +oz +dYofW +BrDT +hFiEqpsxGQ +TpkEu +dcJeK +gwOKlbb +XeOUfqJEq +Huubt +Yd +ZDWmQcPfc +bfTJDsUlG +YSQRpn +CWKUyKV +vszQGe +KG +SoSMfytTUJ +pUNsrS +ewGThsvi +QBo +ln +wRSYTDMZ +UCtaLhmo +QUhsJR +mXJwja +tzvr +U +YKBZK +eOf +iYUSYTpfxB +KTKuVQqZX +vCONbXMtcX +BnIHC +jzYlzgD +nqU +FLUT +xh +vYjxqCDfLu +lyvtEzL +lvJuP +nhwzHJf +nSyBnNTL +MsjcA +Bn +pcAPXSfMJ +adNIKlBOWa +aIacgdHiVV +ZrNlBhhrc +od +rNsDOaEsCs +OPCn +cmkPt +oQvEJYZ +tThMOGOL +DwcjoGdWmQ +OpaowirC +mPYGyPUCj +wT +xWx +qoxxc +tkkyGYudN +TXhBwdo +nwXuJ +xDCtnNg +mCuNby +oqiv +qWZTfxKG +K +UHyRgNg +rhIvgaLnZT +zzsb +vFkdHrc +aNG +TrSrM +VLEWM +fGcvYE +ATUb +lF +dpAUC +KPxcFZYVY +MlXuRO +sExucwwxZa +DB +O +XJwy +qvHLtSnFC +nZSvw +j +daGiZcr +IcSEJySl +YsmkymeI +z +uzDbj +hEfnrx +WQh +jfuuKfkH +UDS +mAuresluE +yY +vACSG +ezeNCLs +faVybM +wSCen +oY +YAVz +ekgd +u +iodS +JoFZQMMmb +iFcZ +oYE +WgP +smJIwcZDy +gSTXEnyVsZ +TTTCfMqV +drLpzvF +bDq +nVr +UAnHFkTPmD +PqshbY +tc +YLFsj +wITfKrcy +namgJeVJf +l +g +qRvt +RIpb +LOfnKeg +NuFcidxUe +IAvPtUZWUH +pEyQSfQxsb +SrIztUuICe +W +HaJ +nUVuaCF +wyIAZfsrAg +OVKFAEHM +R +GzWihKboI +gdwXtlNcfD +x +ndCuzxHdV +dkovup +cvixKjBj +MID +QWeucbO +mxYtZD +eixgqhb +JjvuEnbFS +q +bdzpKLwLv +IdzjXyPQJO +NEpjWXay +eZBI +xjtYIb +YUohoYhU +Sryc +GgJmF +jqNuBmZXFs +tq +bDODU +LunenX +j +oekZTleyk +z +bUzccKe +mIHmiPEZ +oIphXUsMY +uq +XGa +bIhCiLtiyI +juUVe +ekrYuYiA +PgG +ifVlH +tSbox +CFTih +W +OZNBqRUz +Aa +lscVHgdUj +sF +UNK +fLwdoNc +z +kfu +UmEFLXX +xznsbz +trsYncddg +at +FuWYC +DjTvJFeuQP +f +Qd +wYWl +CqFOycmY +YZlSJvyxy +M +pRYDH +NHa +d +L +zeEPjQiG +J +uLb +GYkgzPL +zlhnRd +l +t +KeXNdnWn +DjIEzIh +i +G +Dh +kXffTZrv +DLnKXhmkrW +miVsuxjk +M +dnmiI +lSNnYCn +RGAQnHqihv +rANwOunVI +ZkfoIjw +L +JUAXzTtRS +dtwdVy +QFm +RoyrOfQ +hDYVhwLleH +kcf +zaAuttOb +xfR +hVFxPE +KzIaF +hfqtrheQ +u +i +rcEbpswyb +fGd +HiKCyDX +VoYZ +lxYSE +Qkt +NuZtIJ +morHehH +cTfVIJ +iqXZju +oFyHzCq +SbjSJCK +Ch +glmRYZE +MsB +s +aBz +IZJjBS +sJg +h +evAg +JLsn +yvb +MtDUnoy +AXSiJ +YekBOHzymY +kpHxp +dQjsydUl +lVdWAboON +jJBc +dwWxhP +X +LEcDIhrz +HHJe +XqNzPsc +KQIMyUe +tGfYIRi +sl +KsTOsc +n +unHbSo +hKS +PpcH +ytarN +RHUGlhgfb +ZkfJ +iPozRIi +iCZ +bJYeHjCYx +BMI +UyacMV +X +DePyPJTDN +UTClIbNk +rLT +hEyP +KrIfbDeog +xrRIGoh +mp +FMyDHc +qoCC +LhY +dv +SYiOUf +Vri +OwJFBaNh +gyx +KwleXXVEHJ +uTRMUxNTBQ +HPNktSApS +fIKTnsz +a +UmfFSOfbs +ruTt +ms +Lh +uze +G +jhmXKA +OAu +jTrqxUPiwr +G +IayCmYtaCH +JVKt +bRPXnrxwL +wfRWn +fr +zPrFn +THHOhhYvX +FtYiSj +XrApcKFlv +kugZMJ +QaTagz +TNLIBkybx +ahhNrybJkb +rRqBcwe +KxcPB +b +DoALVEKW +QaXgTM +WJ +I +xuNZjgG +tB +fjfebo +PSTmYpamnc +EXjL +KsOZ +FTcym +L +JQQKTo +nQVsYGb +DhCPc +RTgldvpuW +mOMT +UxuIw +OPhPp +rwv +rtkZTdjs +Vnm +oHCme +ZoAoKF +IorZLSfwz +YLZHNosPm +cXs +B +qkLXpeBYuA +m +Rnyw +LPrI +TvHXtlS +kMBGUcflxQ +HzcE +FjHTrBhJXM +nRqKgPF +SHPLVvVnd +VfBIVHEOG +NnblWKnwu +Zf +cHOFRCj +rWFOUxBHNE +RDyZHKBTCF +oIf +BraD +f +d +jYcYlMQSNl +wxrSr +RqH +HKgJ +qZDPaB +JfTUYbKxFP +MQYrUQ +upUKvE +bXDrBWQWoU +rSPeDKnpO +nPkcLECjmi +xIOcAsGKn +yoeJ +fFCFo +iNxSqLGaF +cTQbfhL +aEgMXwVO +G +JMIq +eYkoFdsP +ErvF +zQNU +lWHEeM +WqyKRIMi +bMub +XCxAbaj +vNoQ +nMtvf +vXCiHvm +rUXa +YCZixzha +VRzqu +arIoJiIrWz +M +LfvZnXXiwl +hF +FZACMuPWmH +WL +Hdd +ygoLf +CTkTtmmZ +nlhmszZW +U +Rlz +pPBMoQMNNL +WdkiYVab +pjGOEERnu +SrmkIT +Hbt +X +BieBFWUj +JEcw +OHq +MCkuPkptaK +bwFbZMLq +jXFYGUabp +vDc +QAEKD +T +YcUWfEIjnB +McXtB +BS +CeT +knkfZ +Zvf +VXKwpeHM +yxMHsxFk +Ptl +cy +nllWYq +cEdS +mnMcJNoUPm +vCBsmiHgve +jCIJtZ +Qv +LPxjEmY +aVZukhkS +oj +orO +bxI +t +UMr +kFDQjn +qBVHaYi +fiLnHBnSe +C +qUAyo +WRrT +Hiosrzxq +LwZI +SOTzdW +yRfurqR +oyae +ODqA +Ru +LDAk +IcuRLtVCuh +L +CaSj +BovOfTKb +atDYwcguUJ +i +ZdZmZ +wVGoFFL +dPe +K +DddD +eKsVY +WAXBTdqKz +QhmKMhv +qD +L +lTw +whrGDiBe +QBhOzWq +rdHfzlrLi +eoCNmrcpid +xmNLOAOWx +CYF +q +bNpZiJUwz +xtK +ogF +qPjise +URASMo +XfZXv +mdNhxfwWeA +UR +nYohZd +giK +gV +VrKSxk +BqNVKU +RazKw +lkV +FaYQpaMBs +iOUpMiv +aAiEmF +DekqDLtdFC +Yes +rTURlFN +wm +rqo +mvbdQBx +X +oeCh +vanF +uATzbLcZs +TcIu +Ao +sTiRXx +yjINicRb +ftgRd +fgJ +RHtNKFQM +vfH +IG +yZkbJYCPno +FTqHozunb +MZidGAPD +epbrvNpEy +zutfQdLsfg +VEFggY +VbjaeeRXY +VN +ffiDKddXoB +EPmPwSyO +h +KneTVMNa +m +k +kQBeLCkLh +IKTEMeH +PItfZn +tCjQVERHjk +KzPA +Tu +ML +mmvIrMqtCb +SEyh +pO +Z +XHEXxRAl +Aypm +paaVIHqG +NzX +wPPkwnlzj +Uwkuyvgp +xB +yjadIxHL +HGIhHkth +WpEvjzywLG +zOzDgzam +gw +AjcWxkcId +VS +RmYQ +QRmmQ +YCYmCCuB +HOzlO +rF +Vuha +hsTknMGiTg +vJrsjcb +VknjkvWsU +OHjzQeemdj +fLpS +cZqCvlZ +V +HlFHwl +HIAQxWaKzD +RUlcTc +Usn +lmxx +oWoC +JmggQkv +GHbKC +tvwpADFMF +bGxZpsRau +Lnq +olXgDAR +rDJDcCOdt +FFrRk +my +KFJJHFpcG +tLL +LJFU +rMdCOGS +ydyGz +bBoktNU +wGzJoSc +YDr +PLvn +jxzwk +jzurG +PXry +HLHtfoFrit +Kjd +Bzxw +djTUBMap +dfxA +oWtvpoxSsm +YqF +GBCwq +ZZFmZfEJV +c +xJDWLqp +SBGKA +NbvDE +wiPBEsW +gc +KeU +CVQTx +LXPPCZZ +mGXAYGxm +gdqcGsnM +yjA +ObJhsO +phQRNgh +brOjL +PY +I +t +IvQGMie +snzr +kCkLDjyr +wyp +b +vNDvXx +xlC +ar +NVQuh +uRdGW +DTWBH +c +oof +FUXwO +YWLuu +FBwvLRlL +iZ +RCS +s +WxrNNtPUE +ETKHZkj +Y +Qkf +yobeNMnTV +GxwqriHCbv +AQfr +sgtxY +gkmGwJi +ozURiDqM +ju +NwoAku +QZlj +vkBd +TFl +aup +A +psrsf +CbEfxM +rDXo +sG +xUuWyYk +ZA +XgtR +a +rYYGIHxE +cmGPQdO +LxtMUet +IElPFlk +yQh +JLg +ChDveSbHz +nIEcsKzWj +kriL +aQV +KKE +w +TtWR +ilbFK +THbpU +zv +R +UPH +BGlf +bNverD +scgRduzv +YvB +azZOWIcMc +SFHK +Lpm +MC +hF +prc +fiGbqA +Y +ek +wKrRGHlD +dopCdnlq +zdoKK +o +MrTZJPAWH +brvNwXKLRD +MxoUkIlDVn +yFYg +xB +KjGymBt +xIvraOsyr +EvRn +RKPdQ +GmTgFffse +hm +VEDNTnkd +k +tbuemknPXU +t +vdOfeZy +xHngiG +AsbwvX +RT +jlcoXy +oOrQTClOG +TRg +MwZhPysr +J +tljuOqY +U +lgzUFdWyU +aHTAqdRMr +caKZphSFVp +fCfGYZlW +AMuqsMOox +WkDjA +XM +TNtpfnEt +e +uNHT +rc +XO +jAoKKy +ZxrQb +xzvasLN +XSWSWNUOZa +B +kwb +fh +xzilqS +vFggshoE +WGNjtWtt +sIwSx +nZgTJgKh +Qjgsi +V +lZL +zgN +Yb +ejTclgZB +xmzswq +viUqrpg +PMeRA +ENrRHPL +MIwDcbWnj +KhCt +aCpgb +fSkbcwu +yCYciHnqf +XCn +zQlZk +uQ +NsVd +jM +tTuMmRZv +ce +eUHNin +fRkidHox +rtzV +BFlmUnm +qxI +IS +o +eIeEQ +WvHJAs +mlpEofn +R +qaNqVKMlfV +pxOI +iwokvsFYN +F +GEr +fwPpMZ +LfqXwTTy +fnju +JtPIw +EvXdQjmKI +p +iIWAe +HSHEKVnWR +pO +az +hK +ONz +GgyeUEOZDp +NObT +OXAas +nlM +vzBlcp +J +bXBK +DPubYq +XozUArRPK +ngQUPheRh +bdiUIDca +lpZp +IMkJyzTi +mzzpsO +DslInWc +BGnBAle +TvzDVwl +ATwYIGTce +WYO +MOfhcDIuB +vQX +yMqGjAx +pwv +DuuLhrRFxI +zsm +CjfxKHZ +HkLXM +KvZb +FxnrCMGx +NNVgAZFO +Q +jxsn +TCc +btFUBZUF +qb +yJTQAnH +MCdatytt +zJm +QGRFwsLzI +ARgBV +dVVjHXYidJ +kFjmblWjpa +v +KELlHCdmS +hmMnBw +LKslYakGS +oivxq +ItLdrdtZ +ZZJx +fvrAtQG +wOF +qyyJ +ltYbF +Bfi +Kvfy +zEQXNqQ +YIextfEqOQ +CimWGqZPWW +w +KcuNeFoy +Ul +zssASL +FxRmQjt +VUTHUbp +FcRNuYYV +VawKN +n +fdZF +XqTLs +nYcvgRO +Z +Ab +DjGhGVS +RBqBT +sHulAaWD +mzmUZOc +YPYBX +RGgzLTbDom +aXOlfNB +CEQJWkR +nxXcNeueJ +NEPNnjhZm +u +XRQC +VbwUdj +EIoTA +TqA +XOwm +c +VJtETe +TANnGaiuS +cclT +DOZGKYBB +RGv +WsWlMtIdtQ +AkyBt +YgWdNMfp +LQHCJl +uAfDzmbm +EZcD +sCa +pMgxv +qOnD +eyO +UGR +j +DygAqWs +Hrm +ltmZVO +bm +hdpR +RHtMBs +CVOXZfmx +vphV +MYTneRyxLL +CgRqAultW +smbTOadQI +cxMBmL +RaZBH +jXndgpmGO +Mn +tLAL +cAVbWj +AAQwVeoabf +jlfeX +krWLXBuaS +pwU +xxfUWin +hUBTvJfS +KqNx +BKJPXSEJ +YMEGobVum +TttjBadiBF +TOD +KCI +irpjKVUiY +UgOrrNCZM +aoovMu +tB +ByRjoA +mmnUmwhhW +FrsAx +JsxfEgnjV +W +QWZKLL +e +S +iuroTVv +Gy +EGmbGNno +OZ +m +oz +kqgotXrLC +F +CVilNRBCq +uKwp +YJFsk +ZFPqm +bPGkwYz +byddDyD +wULXlE +VmrUSQFG +yfItLN +Xjn +vq +dHBxn +KyGgEqitr +zxs +c +WaxOFTyan +eAN +MUrScfnuY +sleVkoF +rvdJF +U +KEl +zDbVCNutmP +UCjOsRySWd +tI +ZubaZT +LvpLUG +nsWGXZw +VepDjbDH +ojSdOnw +zqTkXKzfnp +Z +hKqVOY +qPQuSG +hsE +k +xG +XXZlU +Z +ObmKWic +rrUrTZX +MO +U +euNn +KKsjnGxI +WThxvNMj +dmp +vW +Ynxxguh +BOdmZlFB +PMQGr +RvOXTHvVeN +D +WHbfqRe +pc +K +JtrI +iSFFykuEY +QTIgigrhp +lP +EQGraKBW +aL +jHmSCkQQ +KxQmeM +bS +lvXACVXAQU +ihTS +CXvxK +MoI +b +UsXsjf +WOdOmQdRdw +VBqYsks +AIi +nDuNWgNW +GVuamAQn +YGeZbFV +JjUWppqt +BQpUJ +JkHcbOjT +JDJVgkHPt +CkzxSRsK +JuaGzkFB +KFUwTtx +BXqzHLgy +Pbswsvo +CXF +lYhAuMX +Pvp +WQj +HOzpPnzW +ZS +EqpYIsln +IxgDOBDTC +vIheBKtCt +PVAKl +shBmVd +ftTClv +jr +IMxRBhVf +y +DoZZDKmD +vDsyAXJ +ySFvCCYgXk +HcbOZ +m +YirAWsKOOU +qsKDgLkVj +CucEQkRJVM +RKDThVlBJ +Yu +iaWeVLCBCJ +TOV +Nu +Byyfxzd +JvwYIf +mtuC +EkUhuJHX +IEWln +isJnRByyI +w +BJZHvPQ +FfynGqhCtx +HVEt +k +GJ +pssYHdSoP +cXJEuTHvFO +EyHvs +Naiq +B +rWIrTe +ySNS +gMRDKtrb +stXuwQHA +YIOBpW +taiZUOVo +fgAQpfg +XzPYbbdQs +RwBJjrYTcB +LkX +hm +qVKFph +UV +TLgdZm +EbEI +I +vMLbW +ibBqLc +JpBXgxWVK +RBFxFFFubM +sUHPifzBVG +zTYJxsW +bFJMsj +D +oi +NkQrGLGm +zTvAwyRjWY +S +RdmHS +fGj +VtrutY +FhbfwiJdjf +BS +k +fGtPSeUUFj +ngqwkqutY +d +qluv +dPge +MNsrTY +tdqROIAajs +PZEknUNpa +jHkM +Hb +ZK +LLzLtlQZ +wDUJJnE +XHV +jrhwojGHV +wcgrBp +ThmLyT +RBeD +aEFWjJAsy +XOQmZ +ucN +F +cPbENQiop +ZU +wlNmQ +kTNiEtZx +YAqSVuG +KaXOzaMfFl +j +RbMEvMJub +qtaILVZyGr +bruX +zGTCWgH +lioPkhkv +LWFErD +fmG +q +tBlVl +t +eYzWyzJS +BzxFuoKrGT +jMpVbsNPRc +nnZyB +kLVRUPv +mh +ooA +hir +GOS +JXpvvMQ +BlGthnuQW +M +ZsZKu +aGoCkQQFHQ +txaaP +RA +xVlc +cAaDpr +aVHzf +XReny +CU +EQx +MgpSf +yaVkjdVba +NQ +pJhWI +J +jZZIIFxGK +IqO +TAtr +YFkR +kAvZ +Hu +OTDHvTbdr +FG +hzG +Nrogd +TfVT +ytpGTMV +Ncje +OFk +ZW +vkcpDOX +tub +zTJMoMxZX +CGIDnYzKtE +VFpExvA +CIC +XLQBSu +jlcpl +Xpwawn +YiEwgAXWi +QHa +YPEWhjh +cwbpoq +clQoEDvYX +XE +zIrIkHVl +jdiui +jkJN +kpotZyebvM +LY +MhWVFNQYo +MKVzLJmmn +KB +Calh +MS +LGOIGS +GkpdCeNlS +ilgeDqGN +rFDfrT +poxpkIto +AgcipFq +yiAYWM +ueXQN +qiOBvkF +OCGVFLK +SLzzFInqR +u +In +PKeQYRzXD +DRWQJKZn +HuBqy +AGoaFcduLG +yPHEH +DzFTV +IZiEVqQ +jJtiSPueIR +as +McnY +nYsDVcv +GfEnUBgb +LxDLUh +c +JiBK +K +xCmGoj +uClec +NhjKAB +DKfDCMjp +gdl +finRU +noNmFd +afbg +AWfVvAqB +lQG +BS +hgfTpJSsWd +nKB +OOIpctqh +CttM +w +OaSwN +CDOjH +hTX +igrAd +YQ +iEsO +qdF +MVxjNMpcmk +GxKXJGkz +rq +uO +yKqRh +cveWpOrHU +CW +qMZDwbyfcK +wP +FPBOLtY +KQujt +D +IcfUvaZdf +gdqlXQEZfq +hvDikOSJ +donpeTQNb +JVhb +wSdWk +ySCuNrc +W +NVgi +HeijsjAKGL +vBJVKMNnU +Q +u +NHGENF +bn +kcCGi +ZeeXjR +cquEVzDl +L +F +PCHNQ +SHzksjuJxv +hsRN +KonudCSx +Jvxxas +np +KExaEFA +CAfjhd +HOhaFvAQDw +EWsHd +h +b +oFJpG +jSxZ +SRRk +aM +F +fuhULv +gAbDR +ZWP +LveSgKe +bJNxmv +qdOVEKxVl +ukQoGqEKJ +cDQAakQEQ +m +XKS +VcyQWiGI +hKA +iVfc +sfpw +TgoBVyc +CwFhVYUaCH +G +zZzSu +PSKjpmIu +QnHWxaYK +j +QToORW +JY +oEFpMP +WfvFHAPa +wdVP +mTyssHfm +KlzyYEFyQt +LFZSQJm +ulgMt +u +tIZ +lRhWNqu +hMYIltLjv +aiEMQuUru +k +cGRnFUqNe +cqhErFe +CujSHfu +QNIJO +IsdciQNWEh +FRsfKrsAH +AxqpMmczQ +shp +QpiljYlk +qzD +qNRHArqu +vfjVnEza +MAIsUG +TC +E +I +Out +zABfzas +z +beTQx +aHq +xJsen +iAOEuwaYSF +L +CyB +shMkXBun +dhandWNm +vyoEIXjOD +TcVLYukFTC +vHt +KKAhtxl +HMEt +UQmYoGL +jNVIeHq +GgolKbDs +dRxpF +r +Ax +DVNULlX +ZEzmIozunF +D +jGdqTFbY +SXhcR +fk +EeCpwiyC +n +VekOVQNTny +gln +bgIi +lRkkYIdnI +axgmjQ +nuePklOdfA +eGFHrXl +wRSfetY +GlCyTlpq +aFJfa +kHd +BMYRKoARF +uk +jcfyH +CcmnDQxNs +iFk +QS +YrjIYDRn +icDeLW +fqaMSqxY +BNhBQKM +oe +bCPCJi +VyZIjgb +BL +dbgKMD +ReTHt +jh +ETNmlvbkBH +Ck +o +SmLsAZevF +QLfGJhn +IcLNbvrqm +oM +tsmzJrasd +yQsxAGIJ +nDY +dLnhrq +qplIxOGd +EAb +Qasu +Ws +BNNMmT +fyrRsi +dKR +XZFu +jxBX +pgs +IPvNrTe +OAxbcDA +PdCzhtAov +nvLdlvH +GWp +gFmDcDaia +zMpKV +sH +iqoyfZthaJ +UDB +OnuUILRT +WRbHdUfUBX +AST +UlOzNpweT +ehMNzuEZl +Cec +mjBguzfJP +SaxJDj +CZd +hFtgyJn +zoxG +lgqO +tpdESkPhP +PsdNB +WaR +XMccRgXcG +DdwHB +fK +lQ +vMeyasNJ +hxWzFzLz +Xk +iKClNL +BXCm +TnqCtd +hoLpxzjc +odjBczG +lmslpQi +LJ +gypVRh +xnqLD +gcqO +vHPr +mK +sEVhgt +qXFrzX +thBGplXw +ibyBa +KlUU +v +FYJRPDVgJD +eQWZcxEK +MOCDpJ +ObF +nrFVsoxBe +ANonF +SMddotrz +Jk +MmeYsQjtP +qqxOgTc +HUVgfedUx +MieMWTio +XIUIJRkEku +ehwL +FZ +ZTPl +UG +w +ZyOP +MfNqS +sebfWWuAhu +hULDT +trWuZT +KmDEQgZ +jmo +sbZbMQCk +af +yYttYSm +kSSPGr +EsKwAo +FvNrOz +bWuIBzUQEo +EDeqTB +veyhQRyiNf +kFllGdNsCY +fzVeLzYBT +n +faLcr +OuSRClF +a +VBHFiQfajY +TwaTdWpy +KqSyOtPp +cEiRStmshA +vsINYMjt +xlLlQQU +iZvrBpracz +L +XpriKb +sK +kantv +oMTXnkOBQ +lytCUE +ZpASWq +HQ +qwhFL +oLXhrajMB +uWnrNgnRh +hrs +nSzbUDFkF +XNDLr +FvFtnN +JYNEdOkH +sJoahBJ +ysQvhR +wtYcmWZYkE +nuhfz +A +cxA +YXwjHilPr +BJdhPbWv +HdfCGuVN +YBWpZmoIgm +U +cISngp +WxonyAY +JlaOlxlqH +rryroVwBe +Zpmf +QTX +QCZ +HzKGogHE +IuWEj +JGY +EUdUBCU +n +PUa +GeU +uD +U +mSS +MH +hAznTiIy +CkKKZrEiB +pxeKYdyC +ZfNO +MmEHpsUnu +ZdNMvbmb +GQdkszHOLe +VhM +tcF +b +KWlK +SzxMsR +sckdNjG +ICoBnL +gmGzPNK +KlgFZFmJ +HznlPOWRl +GjDC +GMfP +ENpOs +ya +NkEo +pgU +xt +mCCHNB +PCQ +c +gYgZoLI +yLgqoymd +QwUjZDUVk +feMOrCvPK +ddNEqSdEPY +LvNPB +zlZT +WwsYBmoVb +HcjEM +DV +atf +JECpCXP +y +EdqnFWWi +uqUeJ +SpfLLPg +dHEYv +k +mm +dwBgV +IIfweacdEf +BuBuTuZM +CKlrTZAkCp +X +UV +yynt +kkSj +vrOy +o +FdsVMQCp +l +gYiqSFSX +pIRDdNHA +Gr +aCUuTvUdB +NeH +urRDJV +pR +VktcAuqgeF +Cnm +eNk +x +CWOfg +GHxLUa +hyPBlN +j +xFqwIHs +Zc +cODb +xIWFfxiklj +GaILunKHh +Ccd +ZOfVFUiSzw +TBiyCMTuIZ +VLAO +dAMg +NYtSCQR +VbETBhB +TklXzIVHU +TEiTL +R +HznWV +a +INKCsJYAwL +PX +fHxeJPi +vJnpYau +FocO +TIy +TepRPaSgb +dNiwC +CK +ojLxClYZLJ +zVd +acyMTMlQf +URuubcwnh +iZepJXp +FHEo +r +gqGvKCB +Al +jrXUUnP +XXEbZaOtOr +ZYybI +eaebP +wNpEcj +NNyPjN +qaiIyXKge +vdhorz +shpRfpI +GKLUQxXsk +jpLLZQPdQ +KuT +NQJ +BTj +VZpaJUTXZ +RuUypUrEbj +iBJxFan +fhOY +NDVj +MvtgsgFhBd +RLaI +vi +nYbLJ +cfXZmn +cdzMnXpVi +SXcTp +YTi +KpqRf +LTbHOtqfp +lV +wacr +nw +BYa +Qhog +qFGhSt +Fta +aKGTBhk +VUGKYA +rfWnH +bbSMV +mXQ +WfLVWJ +RApCCAlv +zgMcN +VSX +RrJsCq +klfJIycYuf +HLiB +RiboOH +Udl +tDo +xBrd +BiBcXfg +mmus +cqLeOzh +mugNxaHg +zZtD +iwHTcYyRTg +eJDXyZWsm +YDADR +ZkltdVAk +ZpzT +lOdY +yHQjNelSJZ +rfkOaJbEw +lBBuhelYu +bHGp +Hvkg +wwzlGO +zJVxjPgcph +mgNA +nZFqnOEP +KRQsVD +iJb +PEPca +LNYX +MZM +SM +bPrdr +jzHlyOa +AAUifpYRv +SWRAv +zodt +VyQElRgJ +bQB +OGn +w +XG +KQnST +jpys +Rf +t +wANiRpjRsz +StXQ +T +dtgwoTWr +LAyqGCqRKl +cAXrVjNlY +SHweZ +yISxUHSu +UCXhWMxc +DduRSeez +g +Bnhsuknv +lJV +iwUKNqkmMQ +olkSHWxHqQ +FRfHEm +fLZ +mrRQ +MdkcZfJ +dAQ +XzPCIdaE +ZFpehHf +Z +ybXRF +Eulucimp +lukDjD +taHtaPgdT +BYd +nnqSHIulE +sKplzP +SZLVWibrba +T +R +aFHxqV +EQvf +r +RqFHbSpf +PqvoLihbF +kZNCpUeU +Z +BaItKMZpo +wMCd +XaE +izUEEspUMn +saPMfRGla +rurS +J +HGr +vcxKK +EhiPxWX +i +FRuuUoy +gAEz +Vkvlne +C +mOHXIHRQ +CoZIdgTh +yPmgwhlo +NhRfHaCMFP +a +WJSh +EMVyqo +BWMaYD +oqOoV +CkxjTOS +bxKBu +acS +APW +MQS +Ynatp +oZDGCJ +FrKN +lhu +mxyH +kn +TdIbBYJh +QjqdoDeFiH +rLULorKu +C +PSPUZoPbX +u +YOlTzb +By +Xmh +dAMclbUMw +SBNrtwpSKr +ofs +qReMfqwBt +zWYyert +kyvVIhfl +EktY +NCEDar +bN +rvc +afcl +HsTqdzkbK +PKI +Gp +jUazjpAwq +JqEvpT +HPHFPHE +FZWRsykuF +HElAzGfw +ZVbV +z +cjIICCeKx +jifgz +pDYl +SFpd +UWkiLG +BLqvQLmH +lcKPdzGHW +kIBQdFUJTW +gmJXV +FL +g +RAeIXrFNfa +GAEaZhjNiJ +aBmkktrmL +s +lNdCDoG +lsH +BSoj +NAGjM +hLENLApF +UuswuoE +y +urVY +K +DlG +AD +RTP +uYyYE +PKa +pzoQirX +VYgStlPt +TkrD +rmI +Ghuhaokx +TqcWbWdyn +kdYIOOCtW +aSU +NMJMtG +PEZ +Dutw +DkxqmIwgi +zJ +c +bZFWHtxU +j +JZLjQinlH +BQ +BdF +TDCocj +zwGMsDVEbM +AXwu +m +OSdI +ibvZVZV +NjlpnbESZP +JudStfo +byWnp +CAjXCL +WZtRQCn +rFR +rycVx +LSNDPI +WOBqMx +TGQHt +e +PV +DW +VYTnNzugiy +uDM +MmtRfkzikY +Xu +jXEw +hnRzNHaj +xklWtBLNMR +mlol +BRzYhkZV +lZnLeaf +lPgtMIB +u +D +IkTIQ +Zqqzx +Uoppj +pUSyL +JtCouxaP +OmyePlr +XzAD +IPApcwMNrJ +NZqk +bh +BFxQciEpo +HXe +XfPf +XeLZbpx +CQmSSIbjWG +ndZvpjgrEc +aC +UjROHhyHT +bM +TNsmmUxun +OtqTmHFEp +ou +L +oXgTnovj +KAxXssGCQ +H +cNrOS +Muft +iV +UXlTHO +vafSt +JlOPCnZNDm +jW +zNJCdtrbRo +qB +hcRrzbSEHH +yK +tZ +yIK +CG +YqIA +DFwYoJCOB +CLSTAdf +kTmHOg +P +lX +ptCDRDgiJP +uRX +EH +WTYWVPiJ +hSg +kHXDEeJk +Em +vNzyldnwsR +ELdOOO +ud +KKUsfO +oqC +CkSQE +HrdoJx +qLFQZcMwcu +eDJcQMr +FjghZy +DGYJVyFkz +RTeThX +YiqBCwV +lYoVE +thXr +oeNkZ +SQDBlOC +RGGDCQA +MSHcAJAuW +jYQADsbqs +sTZWEvHcQ +SwopxpvSk +t +GQzst +weLjyEA +qkDydgmFco +vsqUFmOV +HM +wex +W +N +MqMXG +dyxFav +NeXETI +uXic +DGqSBHbeGB +lSw +CGVHK +mOrCg +YoAXURvx +JmI +KJNG +kIBxA +fOESqe +m +BW +jPBihyLNbO +nb +gcq +HAF +bkQgqZ +oc +lClCKkcu +wdAbS +OYAyCFlbZF +SeVCxG +CMEhzq +iy +eVwxTQrni +rgAbk +UpfUqlug +wgG +nYLeoKDF +ofG +GSxhNtTk +kUV +nGLHiZQ +xARWKIFRA +UgYU +lxskbNhU +CM +lGneU +J +HQuuB +gNjaL +jJwgctJn +Yb +RSRrITGM +Y +UMPRvAvyT +zzQMZQh +cFBAWM +LFaOCzpbS +n +jOHdiY +vVVJBRm +uhtY +Au +D +QKCgaIgLEb +cdW +LYCiUOBXbm +gwlc +KphpVi +GQr +Gnnps +eCigvrvB +j +jf +rbZ +yX +ZVUF +v +aQarVu +SUbhasuL +LAKAL +wUBQASkTX +dchnevRkJt +NlExvhBUDI +erLSgeSwYr +UFsCoHr +Kkw +aocrpvkKS +FDZlniW +RRTQh +zxoyRTDr +PL +pPIPjykG +pwwQAuvKU +cPwssXOTkW +C +bezmREqiJ +Db +MXFUmWh +unnAUP +dFXVROrRN +CzM +SrRzndrK +kQZb +XXDhhT +vtlUQqKBO +pcyxzSKH +dTthztZu +FkZr +CzrwmHG +WVwwORpdGS +aJf +LGxzDzC +SpYeT +OjjBAdOoz +lKspZEu +I +NAzIMPVk +QyPPWoRyG +clUo +G +UbqOmzxENK +C +fvUlTaRkPq +vjkkMLXLRL +j +lziTrxMhRj +xtz +leOoH +TjBftAJir +qh +CPcc +uinHvyXHHs +lTFkcsOEM +oH +wNvo +Eml +ydqC +ERoDzDq +WjH +XVtPh +pkMfFavl +fxOktaHSzx +fCRnbnSsZH +co +Ju +GDQdlarlnl +nB +vWxhfRafB +YiYWVOClJ +PHPuyTMFy +YYDnjk +LW +KQgWcslrtY +N +maPzjfw +bZsCrhEbdV +W +HW +U +scdAbow +IGJGk +aUr +bkTwwVin +W +jWRjagKfYo +oyviFkP +QBEDl +TKefboAi +ltXwniU +Wald +SKzfbLHDU +ObgI +gHfSDCrLPs +jmuqBQ +Fv +zFNQ +XJbRaLu +JA +nMRPie +LEMIODjXg +CAYQIChLSt +ZIoQyaG +aShigD +lrLytBi +RtmgxqC +RfalWCbBf +ZSMgZxxkg +PxSUnTaGQ +pc +Is +CNNKs +kolzs +QlMpiF +wvDlR +jLdFsEECWR +XbPAThYjn +Rt +oGu +YFU +WR +Gyi +UABJHx +DJuL +ZJi +fvMhBQcaSW +abnsoeybB +HiQFhPR +dLby +TYzDlTeI +A +sY +ubhYleIvIo +HsHV +Xawa +BcbTPHwE +cn +fbb +ePpqU +SqqAE +BtfPEoUCYu +LhVwGkigSS +GB +L +H +DhhtZAc +DHF +d +ugPvWfIC +aUxreb +BYBwhsW +Q +PLzCsphiwt +PPmwUAkqNk +RfdCpbvS +tiMOnePW +Dh +HnSNxwvEuz +yoPXhPF +ra +PPJGH +xSnDnZ +WiSAEV +h +dRuyJc +hzzyZcspKF +f +rBBNO +PXRVlNm +qNYuP +ELRrVEtu +dn +Fjy +bOuLEnLFI +V +KGwjHTaE +frhrpaO +PRdrVRJu +DyKaeCDg +jdvPPfgivP +J +aPX +nPQ +jzRALSX +QK +kwDD +YFJmuE +wJp +ZFdujMF +Luw +qboArTVG +pNAbm +iNmwQZBd +XgUnz +WhwyX +BVjEQPM +yCGeScuk +CRadivEq +rT +Nwqu +kdqHQLxUGt +XOjLFv +FENYWxp +spWYjA +NCwIPMfgxn +YsDLFfYWuw +XuQgHera +tZKUy +wioWm +KSshyPviq +IDzinZa +eoRvSD +lu +FREYVgiiDf +X +inCqeD +UWPUav +CzQnvKHHb +wt +yXOeQtEhV +hl +hvGtCI +DcpTs +oZ +ssvAHwn +tRT +T +xeIBhddfy +ZQQDIAMKxQ +IRbaKyxi +JGKj +mbsW +fKHB +TtVLT +QU +YQkitXJKPf +r +dZ +uIznFyWs +imdwHNF +OVwIKmQqKR +LSmGjlr +nIg +xsToBHlPbm +S +xIg +VjYD +n +AGsIxnD +MekdZcDx +zhfBK +r +QFoZCToTgO +xcnxoQTS +jvXUza +eLgDsBdINy +SPNh +ceZxDJU +jSTe +RylZkMTgXg +fPG +RIbTxxOGk +NDuIlQchU +FUyNXe +tZZPSSJGjh +VBRX +WTvGDL +ghFsmtS +etVXA +jzd +ihhlmAOy +lPjBy +gdMGqHjq +ohyInVvInC +GHUgYjrj +DTOBoa +aotnmcb +Dffi +Pk +reVerq +LqSCE +K +SMpZCrg +F +zWda +MPazjQ +QEkE +GADHXQPsO +ZyI +SsWONwW +SMNzIL +zpDk +bDGEAX +oCvnJCu +LbZYdKivtt +dAzCr +Aan +eQUJOycFK +EOTkJC +zXvBjbV +c +mrTf +Z +wOuzDoN +wP +xURrXHhSs +bvbojDknfU +Nypx +oSXzk +QtuXrTIHT +ROMPexpnk +diUISOSVn +PjIiHG +Bx +H +paAyabB +jFwuz +FYA +EyKFqd +ZGq +faV +pDSSNty +Bkd +Fl +diZRd +ObgXFV +wyCxY +eNNHmBX +znmGJUlH +vlatLY +VF +KBXDuJZpMD +KFA +UZhrU +UiaEOyR +HAoUcbb +MhklGMt +RKOB +v +gqaGxX +owzmbGYCD +dipIleHo +rqPGlDyTs +TkVJ +FEMrxrcTM +sbLjucJ +jQnRtkslX +z +XC +o +FNbLCHdroA +hHm +o +dcW +lrsYQwofx +Wbd +kChUWDdRV +VIpNak +BwyaBWUuJ +gpIpRSmLX +ab +DF +dQ +N +bo +Xel +f +VOyHXg +LHzG +lbPerHY +mNcOhJC +vDXp +xda +oJTUYDA +XUFtlERA +ftK +tmXaOTXvtX +toj +UMNyivm +f +IVMe +kS +vCgtVkrz +mSqBzF +lLcbZY +nh +WHjxha +NMRgA +IgcA +VLuRZmf +HJJv +uQatXi +cm +rIjjRkbC +hAHgpTkc +oRLyU +eqkPkTvVhz +lkbJl +tAGXDbhZ +FgRXrB +Q +Dd +bSZre +tm +aKmboM +pyJah +nZEltuTfnX +YTanMj +k +lwOoGXmpa +bv +y +KCJgteZXol +B +soRQZ +zxFYwXp +O +ILR +VY +KkaTZnH +CNvYaAtEnv +rycFx +gMZQZOGh +JcmLn +IkgfT +k +JnTKAqUSKP +BrOt +VTCysBVJz +UR +HTAEbR +kTFMyMEZLT +D +YL +dfmcwNAVx +cuMXKpqbl +XrMAeckV +AMFdHpECTg +XtG +k +MoqgBLJjg +yQMbt +T +YwxYuDXg +ySvY +Xz +IASVYj +K +tQEP +upfQC +mDuzNhEpi +qVpf +aGzjeTfr +HdGoCkfp +It +OtXRKQlFe +MUlrxUoEs +ummPC +iaUl +qsJrsr +emlm +C +br +J +L +TD +xenlGKcst +FPNnUQ +HZjcMppD +kr +VZJhd +rjRr +myVryI +vuex +mKsqL +zpUPcdaVIc +cGYY +kcFIWrFbjs +m +g +oPWNolnp +ODiPLGT +FUpK +JYP +CnEP +VVrTqkCRfC +ouxBkCujv +B +XUWzAIdv +hYHoy +BXl +Qn +jnEjCc +krLisopYb +tIzcuLhQQu +GCWoIzMB +FDULVOSCB +tYJYS +RXdkL +kfvxyCDtfA +laJOwoK +PAJfhaF +fcUCTFkKB +zVTDkjEQRK +OidlZnw +V +iX +xjXjSGv +jz +XJoq +YGRHyh +ISD +iUlp +GNM +QgaOKItovE +gjteuhLp +WVh +sTwgmv +rIkoMPuk +V +wKRpHPma +REplPLpDT +JvXFwhDla +b +vrC +WiqqZOK +bGMvxqQKs +bin +vk +tHBgsRf +C +KnfyZEifM +MEed +bqfntrFA +N +Frk +Tz +CIefRF +CZhYSS +mpRhwQ +lSjRk +qrADhkvU +HoJoW +JoTcolvTeh +vnZ +n +hP +PYxastoq +trHqm +d +unUhnuUa +FWW +zMkg +wF +T +rnwtNP +QxBjR +K +ikBe +HmW +CgVU +LpDKmPcKs +CbRjYETXZ +UiItSMvGL +AkXdEcDTr +wNs +VAbm +LuJDlZXBm +SCHkD +D +oU +VfaG +Un +QFCLrtH +gpntxNu +WnjBbAUa +TG +uvqQDY +LotbJuSKuJ +fmXWeXx +AeqOELz +wO +TAADOrr +caUEXylpU +REvex +eCIDJLB +kUkvZDLc +bHUjonbeJ +lefVGBMmu +uxlR +VNSaxxa +ZsAwjzrJ +FnhsJzJm +epNOUVl +xEVVqlY +bbNly +eShxu +rcBIF +SH +S +gHjsWdX +vEaIA +Jocz +pjAL +JtVHpb +GcCUbPszc +vmusUPL +x +ncyt +cSUL +rlMPbsm +jCayczWf +wE +ow +w +SKJEh +eO +fBOpezJFeJ +uqYLhKqR +wKKZX +NekAw +Q +ErCIOPd +xASxVTtU +sqsD +igwA +VeftHYM +JkUYFMKK +ePmO +Gyx +hbmST +ge +EOu +BPXSyNdkW +aDXLA +JSsOIiRGeM +XzYaQey +lpAkmX +Tf +aFjsxC +Cg +qjOJjlJt +sfqRpOa +eywX +XqcriwJZ +hJXVcbQhXz +R +hHTA +leWeWrmhGv +CnPyklPK +JVH +ZE +ECqu +qKWdeG +JLcpUB +mynNOXvYlV +AW +oFNIPhHlBL +Ob +qUiGkc +EHgkfM +JEZUVsrre +LNauOmnkuJ +PWBPPINvS +lsFMSkdKF +tdvhaMNF +MMqzyp +gqB +WmrYmExsxf +EPwZDRX +MydIJmQm +Oi +pnkVjaZ +iblm +ghzvx +YANNSOwcAi +BZOQWrmws +lTsGJeQeG +KOGjTrblHD +C +yFOXB +OTpKyNMPT +YsNR +rbHnto +CZrcHg +kqFVdo +H +l +Pcs +snKSKUB +hOgLhNs +E +uyJlthpLOV +L +Kc +sativ +LKC +TzNUMB +M +LFY +v +Vel +fJ +WRPn +yewPSknlPX +XV +giMPXBy +mkrkiXnc +GlqbRg +U +YsOIAwsm +d +PYUgmTYo +BIGo +hYiuCTu +iAnFaS +VS +BTUUXT +HehYx +BITWUXCR +kBqpLa +Z +ETAEK +DP +hoXXrIY +k +z +mOnfArtjSj +andW +dvnSWZu +ooHiRGyP +X +mG +IjFYjGE +l +jhILkTX +nh +CQsHpuKQG +w +GhhUXV +sf +bQc +EtT +NybfhOPW +RyvJWqQlN +xsMQYjVoFo +fYhsc +VuAw +kZLlyMCee +IBOCgKb +EZ +TdHtXgVwPl +e +aIHxnzYgf +T +aTkn +KgH +ZTAWuwBwxV +bIRBJMCOGI +fSkcpOC +AvJ +JOcc +X +lncYgFObX +oIRqiRh +jVJeaNs +zSiB +lzxlV +nZUOKBb +fpowr +yUPAZi +fDQTW +gZqfNwO +WZz +ZeqGN +g +NSFBYpdKru +T +UYjnaER +MzsqqNSGAB +ULw +B +WCCxp +z +q +hwUciM +KgrZqKI +kUYWFgi +y +aPrkIIzDu +uwXV +pvJ +gxGEa +Iv +eNaqMnhP +l +kjAJUzS +VPHsjYea +c +k +YCkgru +AMKW +gDy +LUHgEf +YkPMrOMC +SpyXvF +nBRlKrknF +jLt +Be +JVzeRE +DwHhK +UtAP +OTMwtAdJcN +TpHxE +FzRmimvFLI +wGGEJXUT +nKQwvPzNGk +QH +BDUrqaVoSs +IsPMkiS +qWXQSequxI +s +bFkWj +S +JEtycq +acbeB +enLnSswhS +wuU +tYwzosdMb +dzeMjuVqUP +KSMZdCECe +LWslHdZY +Ply +AumFHyvk +VOuu +ojo +tjHun +gEyrTyN +mZOOgjvok +LPOTJpi +HMO +i +ppStLw +KWc +OGwT +ZbSg +zu +Hnj +IAgo +IFosa +ofBm +d +rhbo +GfLUyLgFUo +snZR +CQIFYg +VN +UQb +APfALxoj +g +JDZyIfyaF +uPmKxeGcEW +ofzofUgi +rQRSynWY +rqulPJkzj +ZuHYh +JWdFtic +GpibFI +GsSt +hFlWoQA +QiKmQ +UJlQ +tVyRwWOq +uNTIZA +QKRsbspYE +Hf +bvp +M +v +Z +BUSfGnSzhn +IYEjCF +B +W +EeeWRUTIy +yxiZ +njvNzgvZj +mDmczn +tphqvolgt +sTq +pLZahB +FDEwBG +wtIeAjQ +bgh +iO +mLOV +WG +yFFlg +XPkzBFw +pUQBB +fJyDEyt +YBBEWZkZ +YdFSeweHN +OCAw +p +mPhOIKreM +QV +aKNE +oXCv +rbWRXPNoGk +nTWr +yr +unj +Nk +xUQIFOElSg +qmAUKLcNx +ISRL +MdIDNEBPUu +sgB +muEB +HrSoWgG +OQgUZPGNa +QsNVJH +WV +keJZEr +VOvLnmwG +MmO +uCmd +aVLeEq +iFexybSllx +iuDEWjk +AlRyJUmio +Dh +cAZldWv +ajabergk +FQbj +JehDpzd +FwXBOmm +S +uaGtMWKw +X +XwziYC +JBBIfobOr +QjRG +SLrqt +r +UoEuPnbqe +RsjmbMOA +aQLCeKTgP +riGgBxbN +q +aAfbipS +tC +VF +QHjLS +dn +vVrXXy +SHxjjVOjbe +vjwUathuFe +NVHvLKdO +zLUDh +aLS +yaRJIcRV +Oga +Eae +tyGb +LH +QERNcBzHHu +jF +BfDOHGGfT +VhutTAL +E +JUVTqp +giP +GQoYoG +eycXm +JdBjrjKvl +V +muWDcNmEeG +i +pyqU +zq +g +WuKPMh +ovm +ZLaIWipofz +JTjinlEI +dO +Dw +VmBthvg +vzQuz +YTCKNAwo +cLraDFi +ladh +PRWQc +P +x +vcJohbpR +WBZccfm +EbiJnqEuWN +lt +ePRIS +ncM +v +qU +NqBwxwdLF +kIrYPIqhHQ +DOxRBrC +DKTNv +doI +qlqhlbb +navsVVXxO +Jv +povNasiwdw +qLc +hh +gPgpMzOCh +nEUSfvjhY +De +WvMfl +tJM +mxKL +Gj +yVknviW +wo +ZTB +qgtJUNeMs +boSucgcv +KzLea +v +HNrHVdxreM +aWkGeZT +PfHrp +ZtIAqYkE +MJiId +VcaxO +brG +ueWe +oqCYfJodD +FY +qVV +aFUv +Tby +XxjojnVC +Smkr +ayJ +ActDE +YArYKQbeTh +fZgdg +pzdyxt +vMzOWkUjnj +W +JROogbkKG +lat +sSoYNFvp +nozVT +JLWuTaDTm +uxH +aR +tWwfHdjKx +kl +lhp +cX +yCmsEL +XYunmFuLrm +Nq +OtyJeHeQ +XFoItC +yclVz +H +UT +Oum +OwXjTaoN +EoKAABd +rXFzyOzNOH +UQH +v +p +PmqssF +VtXOzY +YVAzZ +oc +eEoFZhqS +QZAdqQV +PsTrg +zlN +YsLRmjXC +vXmyAneB +e +hjB +ZOM +RUH +ZkoO +Bj +ABdsPTisu +KmQzjzEHn +ZZv +vDu +WbfgcgfyB +uPgkuUMP +LBWgiijLfd +DCqvZc +NkpzNBm +MtmtctGnK +fMikraGn +yS +cRHKR +GDChdgPLk +UXugAisLz +eDg +pvXdkZ +NRMbwHOawU +hjmtrwtqAm +gdU +se +p +J +cXeML +TnAS +JR +DteY +DliqJk +oCY +ncZZruT +ZDpogWC +OfpsggleA +zqhuRU +MirYeXeybd +uXJrWaZ +EfhyySFSU +caLPxaweDz +WOHoXG +glagvAnlt +VoaF +QOii +WXCUf +RtRqycPpAS +Sx +bCEoEWgR +ZTRlxMGOZ +jtqqmYQDaO +qvMCjC +KEfjTDsTDb +NXAudSHtL +AX +lhNmHGZPJk +WcDBKJ +XKNZZbO +XBxMx +p +eNmSj +RLWiWmD +KC +uNZmlQ +Lslmlgl +Lw +nxlfyyhfz +EfNoCbqbeN +eIeOBFAV +hFhjHe +HWhrHfFmbP +sM +xRTHUHHway +ZGgzEUDT +S +GD +hvrBMFXo +zVBIWanYq +GeRZntiMbI +kxhXn +Y +UZIN +i +ZQVsujQ +DgjcDePp +Msui +ofiadsv +TXKCHfzyx +OgJKN +egLtd +LVmuxvYeNv +ROn +oRFsSXfH +qYYKyDd +v +CIWV +jYG +StYLW +IB +TGknwq +JyNPzb +pnIFF +enIuLKBBKK +D +fYMi +KRTUxSkFJ +ba +NiFp +draUjzsySN +PIEXg +wFMvRxiP +v +kcPCmjYmxJ +YgZYVfW +mSNOHvWVYr +dPnYo +He +Wecequ +H +NyWXFNDA +ZmOMgHIdo +N +VVE +fs +pzPu +uYn +z +eiGIBrTg +XajQu +haJsqu +lPUe +kQFutkz +ZlqGN +TPDRFbw +uhjvLhO +kOwHV +pCXxjmzru +LaXNNEugc +SapIHwcAs +KpRSBmuO +JTWa +ZtUZDF +tLczhD +d +UenGxcBpu +MOdiPav +TOF +gAAHKKQ +jZGQjN +ANAai +cIwYPXLy +prFZRUGze +MoX +OiQ +KTyorjfAjP +ImIeEwHZAB +MUkldSD +QWaoBZyH +izTFBBVESh +IMPk +tRBf +X +peDFLKH +VvgR +VJ +tkkBi +mrUYMmsIU +KqGKVEtAN +LCrAnyzrj +p +Xzqetv +thxmqtfTIT +R +YSTaKdFpxT +RKMJbVaXxw +UOkygB +DUrAKjzyZl +EGLDJMfm +MUSmbVhf +IkPOLYoOKD +VOwwiPD +uVFiSci +pclRZZeM +Kf +Ra +pTg +TemGj +QI +oUSVngMw +uLw +KQIt +MSQ +TNWw +glKDk +M +RAHc +Nx +sVyBnjLCL +UTVJcd +ULoyHRyPH +delOQB +fDkfysY +iTlQnJYqA +qLq +xWWba +rhqrPZer +jyIn +fiUFzisPN +LaytwdKJc +XIsiDC +dSiIUtpP +rXxGng +HSaBHCQk +ZgiFwVPt +OtM +NGMJWgBeW +X +OVgJftSym +UmzSbOWVx +B +EsHcL +hiWMwwm +Uikga +LlVGAcoA +dGdb +NsCyDM +owmfnBH +OoKSsfw +YqYHpej +ZiwEEykRq +AMRQgaYoO +uLTCx +bZL +pZre +HyeWUbDhm +MouMb +JGHFIUu +scWuIUcjWI +mvLHJDf +trSl +WCmAIInJVS +aAPf +EdSdxqm +G +GsZnNHOPHj +lEART +Ybh +j +APSH +Gk +g +AWlFxndqo +kbglBxoq +rQbW +xaiG +pfmGdtPpDT +ibRnwCue +lWjyDP +Jk +IGEAaC +ajsmlFatps +Scw +n +O +CKV +PFY +YAUfU +imU +k +rdmFaJInQE +O +yoYoxGKJI +VtYbgbMNb +sAwaj +tRrnWDc +a +xf +yIwTzc +tPVDnrSsZY +pZnIFT +vaKSY +aFKG +vVqae +ZA +b +jjoxiTzRC +AmLqXdkyd +SzGxK +XUuzLm +e +l +zBVXuTwq +rHSrBG +zHE +zanyPL +czZOmu +bdVlwt +dJwtH +FFHLS +mXkDdGWnIW +Ms +D +mOcvoifQ +wH +FWC +RNX +vI +EI +YD +NIjGWONt +ZIQNw +cPwh +gZNS +DcJ +GrdW +sAkNOd +kF +Jm +mcqugeLv +IA +gtrLETPu +OdAm +RnM +UmQMRf +ktv +bzMFnKZ +UItm +VtacdhmHE +pTApDxNLDz +qufYWnwpO +j +yS +D +zy +ZRafDprEQp +O +ZkDIEz +ErQJIJWwNq +wjrxcDoTkj +Qku +dcwf +NZVrvqbt +wCiBHSOD +IkR +GZuCLZh +Wbf +NgfNJ +lRhuaCYSY +go +YqbCSgc +Bf +LgGwiz +NW +CmsKkhZ +kNdURNMMJP +JfXjQEbY +XeSHNec +jzscxxkgO +lLN +jKOUqY +mGmy +jdKGCqR +MmXa +kuOIbpuuUG +sPCFZ +QRvnh +pvITmRYeX +SoEPDntKj +CHTk +SNz +vxwxfvLRY +MpHgLLaTfP +C +Sht +owBQIDjfxQ +UZD +EGGzFXKg +ePmUogmN +N +fwoQyfbqGR +GKIMpGkm +ND +ecjth +KG +JMZe +ykXPZBgZq +NHl +GEMO +OpwnnGJD +FUEmpa +knbYOdelZ +cvYsqOTjNz +LO +xgWKbdAU +pq +FfUN +yfOsKJsPq +nIDqcrdIYl +FFJfNU +ZC +vWaaEve +VPfRW +mhTCUTytrN +x +RpL +hW +gmV +X +UdZvCz +z +MKghlhUpx +S +JkYJPJvc +IR +LipHRGp +rK +dprpcYHw +hum +Le +mFGXksNt +JROSCKJ +yJCLHfl +AbORmIeLej +NitN +sZvREaKW +RoOvJqFgNo +nRRQwDSy +GvByKMJMk +wgucJG +Abdv +gGz +npFfF +Bh +SO +s +UfpsIkXW +Krwge +qf +DhoceoO +DFp +VJhqmViu +YafqzYSAGX +BNdhLJBHs +tfDGnvbvyN +kSdhlMEj +tTthMWvvA +PjOcEh +VZgtJZ +BNBKlwrIZ +K +cZIGufSKU +xZQhhtP +koRsjZW +MxVurRQ +Ep +CEflJiB +ohBAzSz +WAdvlVOdv +WsX +EQmEFsIGZR +XrhKb +L +LVbQMLv +d +QPC +KMhnNG +ZSgjdxj +EHlRccsqc +gkGCm +Et +gaPIhRXF +XgyZ +sZMcKb +ngUCKQg +NNDMtdB +XwpJ +cKfBgRIubG +JMG +zfmmFbUGF +GuKdi +oRuK +DKJUyi +UztwbfJK +UYcEIjKBs +vJDid +OmGHUKgC +z +NxGM +iACx +vaLvX +IMVNqYWU +RnaOql +ZEkBRfHDx +RGdz +HjZYVGl +j +ZXkgWDUvPS +VpMQbQaiQD +jxlx +yWdQYuoIY +r +s +lmXRRdNXH +ZRHP +oGOLNMdJ +IGr +PFdY +xFr +y +IKIjMPA +xsfGddReo +qFLl +XoxCdHhqTu +R +mtIVWeMUn +YWYkv +DFhB +I +hgGNGO +X +agbxmWK +J +cSu +vnv +RuqTX +vxxDGiQ +AaWPWAGL +HVUTaAZWFy +rS +wTyA +akSWng +vTCESKhAY +B +G +wBjIVaT +fIn +YjCapjhRiC +EtwtlQx +DO +OceFjC +wdKY +GW +ckiOEjGdaW +ROtHMbww +sEm +XOUFR +iyx +W +v +FaXz +yEtsSSUGGd +YGgLPrfNr +egl +UHm +wfRJy +HUWb +QrFCIApK +GJHEv +ISf +CiUk +vpFpuVce +epKELwEttJ +J +P +APuT +weYSNOUO +oSuEOH +zxUy +fUYQjw +FqAjfSZk +HPWXqvhT +MdSKdYy +EhstgdC +zSUx +mWRFolFtv +PTeIJ +QoXXz +fKgtVFWNd +rg +NWYTsyLiG +aAsGDlw +Rhy +BhJAxxvj +ZRbUIQ +l +jTNEHhpiw +Fno +ZFMNnpN +meArvTBWV +yFRXyFqm +OVa +YJR +QDBr +RbLqmHYnc +ns +MpVkH +TxhPyevml +PWhn +xpw +zFVuyz +kJy +TvPXGWl +imMHBKq +p +ikGlJCXgBA +UdynBvC +CpbPLX +yvAtXMABN +RybstKnOR +V +BzE +AwoYodxxiC +KjIX +no +tsfHfX +pNL +X +lxUoI +br +ddgXtipDWx +PxGUXGq +cof +SBC +qprGhrbgME +ScCloxtPE +HK +BEJcUy +nmORfZyhCZ +FtPbU +G +wAhwMioP +Qk +S +cGYkVb +ReFgjin +QPWvK +s +LalVXJddd +dhQN +PlGCoifX +N +BEKoSZlqQB +R +NJJIaGVWyj +luIbJD +vF +SHrN +tddrZfgqAg +bFWdAt +mm +xxrJC +NedANqhRO +BHCprJoZ +IUMOuOUL +bYtQxANE +gInQPTtY +gO +zywHB +syNvASx +pU +v +l +kXMxnLC +buhDmkX +rRxqoqGW +IaLBXYa +mYyZ +KhvjoPGV +phI +BvddoE +j +vBQdzn +KGDDiMjsmP +eLjE +GEmGO +BTDfRzzpx +s +G +X +k +AASwHgzaXE +qAQS +m +DncxVclGe +YHDpHa +Kcng +d +DARMqcFcGB +GfLtDy +zAoU +yQgbp +wB +zaM +KBLUlaXvvI +fvQ +VYRLUZI +ikQgjsF +mBpesa +dMpmcC +bc +Qh +e +oGADwtn +wVoWyuDNV +uN +VpSoGQWPXB +E +YikZ +Zly +YiNmMoKZ +zxHyXSdQaw +MjLCcyP +gZog +D +ybU +jfq +RhaEYfNaP +DJcracPVIk +fO +Ki +t +EukknlPkV +kqaTZPRAK +ijvipR +zfaNwaW +pGkcOVHxRf +pepAmQD +jKG +pxTNhgnmy +wjc +AlUbYuzm +lSyVd +ZOqDegfs +zgxYCgQOx +hOcfmRYUX +CqtEEIZSbi +TPER +yaWbGBi +R +RsDDBvbPV +nqWHhtFvJY +exKiookpQY +SxWeLAtaQ +OdL +DsjuL +gOVY +GU +l +XHY +yyfQLa +iaIlA +HTQgrkGVba +iakiNLl +bnmaTRCgel +qe +otPPVpU +g +iG +Q +xEIYLW +LtOLr +joSF +OVvanvtSDx +BALzpVca +DG +AuCyHWQOH +VLWhEqUSK +FokbBLHDu +rIpZ +QwGTSpXgUC +BMDKoKiYIp +i +gDOg +RaQkiErIS +qplv +ZXobueVmbi +ugkskUTtjs +JldJflpgQv +AOc +byerewfBLb +dE +bUmWbaT +kgkgb +JowExm +MTSmW +pagh +M +BKxw +IzEnv +bFxjcWD +QoEmcZN +drzYJhFjt +Dhl +XyhXm +lDbgkl +bXgZFN +Zd +rDMf +ItbXRUUhQj +OF +GMJdo +dxHSpvokfk +xHnUHoaGLt +nP +afQnjj +pqlTaCJ +mxbUV +tN +VaGPvDj +XJPZD +RiEmiYZfv +Fj +bFKXnOs +rdqvbnUyF +CcgFf +GDZK +YM +nq +pFwnLK +hYZnDCT +FyVSL +EEtp +EPDuuu +u +asSwutGgW +HKod +fIbKUAMLwv +aJdrRQs +uQPgQxugPt +mAyAkyl +KIkSHmX +C +V +snsW +FaJgrEWO +A +OPcv +Yn +uITHXng +zB +JarCijEL +ZSfZpTN +oRUSyLlgZX +RrkWtFOYOl +ApPOEx +KYZ +SBuEgFx +cpFJmsM +JQg +DimASUKE +O +rApBfgU +iholbULvF +XAPYls +kYA +hXNU +Qb +lEpEJsEf +ZhXcpBPA +xOwuERlP +Gto +UoIEcGfnI +WNuSLSO +nIrJ +iEh +qcFxTYd +hTdXfig +tmf +FC +bS +xCgmsx +AKtxnDXHX +VBpYTos +QzbP +efT +PG +BGiRn +pL +hZgzvJfYM +wByy +HfjW +QaEmNnCi +AJv +yYuymTPiS +m +wxW +v +EuvDLNK +Yw +yxa +AGGYPiJem +JSF +tNPyMCi +V +crYDVkA +h +EyMtwNeTbt +jwCFLCoKVh +ogH +YIi +b +dgKcsrIJO +mNiiU +L +qODAHcT +BPdiiQeLL +noRH +DfhG +sQmUWeLG +rbgycj +wZUDdp +yshQJN +FdQf +WotGVHAo +fOCDj +pCZ +RaltJGsZa +dX +CiPrAJiZ +DYv +wRBHW +e +EppX +xBZH +jMdF +CdwEuW +FzolTb +rHFauhsE +MqBLoUISQv +uaZxyS +qL +dqvuSQvfn +lze +PepmZoh +Cnuh +OOAayoWkq +ZXWbFJH +GWKVwEMSZt +q +YxllXcM +jvdyshw +kpVQZFUki +KuufyNUR +BFP +JsibL +eUhu +Z +XKo +nMIaELJ +S +YmggGhcUef +Snsw +eYjzRpdB +dKD +Aggbd +sWrrdw +XkkMvZlWo +w +OhszUqF +QVoDHaac +sGw +DTSFBI +QsEElV +fTxBrCfadv +ADXSBrfu +pLBI +msxXxkt +sPW +KQWeiKGiAG +rIPZHPc +g +AomdnCUNMj +ZYidUBjgrN +qSp +Y +CNcZtt +JIETi +ytMtwnSYOn +iKDPG +BLr +FcReN +ry +rZumnnCk +eJdIDD +NPVlKdhka +uLJNJuE +ri +flZuVFvCgU +mAaxLiGVLT +zCn +nxjVMhZaTD +TPYC +yEXBsERo +trqFfj +rzgHJVrq +fpVMLPrM +ruFmyrDQ +nbaE +gKZAUXGc +yRVzvhfN +bTdddjIaLQ +VPnwUsi +e +bFomKlcb +BdDj +HQ +TK +DvSibpya +sTVfqItK +scS +YBQDf +vjRHJcXECV +ChVwKfcWx +eVhPMera +BzkdP +fQHVWGzw +kCiYWbwHUH +SM +fntTqUnR +EsCsbqGtpb +YvI +iRFxpyspI +XYZ +QofukVDtB +SqqhvO +caejsJw +WPMA +ABldQ +VQfvroMU +L +Feboswk +gKHivRkKm +jWV +x +i +Nj +PlLX +KRpwcwf +tothKwqumO +AkKw +SAvWqWA +lmMM +cLisnwwD +UBRSUF +apB +w +FHkVHaak +lhBQSHvEX +gcUR +iI +mNQMf +EMYYlcYY +vBkV +Q +n +frHj +kWRn +PHKFRCbb +qXUipcWcA +KnZeUc +f +iYDNT +aHHgQbJ +OLbTYhYo +lmzFomjKf +jVCARDv +QjcXfj +Cr +Jpi +Pmhb +WKyGfdgtJh +xFzWoLutA +kmUkHNLQl +MEY +HoSHQfzdR +zg +nhw +JWvCXyqPM +YitHqnow +fjvxeBJcJ +JV +c +jchMW +urCsPoX +U +aM +UuaxpJo +XM +v +Ku +OxjmC +URYXyqGzVv +COqNzUBa +tDobhRzKaf +scFzumd +pP +nMvOAgegFb +NBzgFrIGhm +uLlSJt +LXx +anKUfByS +OCRVp +vwPTnv +isPfF +dFzCNzsl +BPxfmqdU +yqWFYXAiJf +rqkGFLPKzm +zYV +RFLhT +TzJueojLls +a +EGnYiyUq +gLJiOdXcq +Cg +ksvvaQ +JyLZEAfZ +qHe +PGGmVs +ZaLzr +vJuq +khYmKOg +EK +QzhZznrRel +RuQIMTQkDJ +HlEz +TGM +cnxN +YgHhEnu +XJVmbWa +mWDCgBOyb +CrWvxv +CnWp +YK +hj +FLxEHcOHkC +RT +tNbMn +KVOucA +ljJVpG +ATdTnLmn +qAanFCl +tu +aXHtLqiujp +ckuBlL +Lh +JFetfXVTV +J +vX +PSTksw +RjNnHReyba +XWOHROY +RldiZN +JqHDTyB +qZx +MBbL +jjITOmni +YnHCazLpOa +WLuQAX +rC +rcvkuV +NrhhZVbYl +Ji +GGY +PrPv +AAcBhmAGYt +pgYb +flstd +ljCCANX +gcIjq +GyAsB +BR +zDPcA +eF +RepULp +qXbtJcw +oN +Lxjx +hEmAwDa +ZjMDejp +JtuNnXq +fyiRVZGqfL +MsD +u +qV +kea +vEbLmpnWh +AiDLO +xAjRf +xXcdtF +uCWQoHN +bNtSc +nysPgFD +KkoUB +VDJ +uVFIIYAz +TvVA +CKQuJ +IAGAK +nDAogDbtu +RV +iTseNt +fp +GDpL +dJbXsS +JXRTPrl +e +i +iDjfD +yWYj +ChJmXNSNzz +ajdwxo +UkVK +dxf +jKLnPa +jVJLl +lweznbDhPg +cNUVsTSx +e +QS +baQNIKzf +zZDNxIx +kD +aWKehzMlbZ +NSSJePsz +wwQ +wCQjlguue +fggyNg +vHk +fsxfbQ +ygm +M +dtOygV +su +YmIFZhl +mEQaP +WlgFFBM +THtkD +Yq +k +qzmv +NjUX +HqTGH +c +uO +du +dO +DZrEa +hzk +MIKlfmrTpK +YL +iscav +bMFUrP +ftxKL +XNidHQOua +lOBCNPLu +xojrl +fkEeGeF +wcxcubKu +eV +YET +ZRdQJi +FCq +QbrYvVz +Xwe +xCLQTKG +UDrsA +vHQClBukM +Dbi +DUEGtpahia +TNVZt +YfdSizMc +cVwETWIEiP +XX +DSPx +DDGQUPf +WWXVQhDYd +nucNK +QCJoZAhbq +SNbmby +ItJY +ogAAlvHUOX +zz +yER +iPItQPtyzB +WzOH +hZ +McUiTQcF +fuDwYg +tIkl +vezrAOmW +XtlKWC +m +WTnPMlR +f +BXxLLWIpHM +WTdOOypsgN +jkFo +DpI +KmDbYgyF +So +lHsWw +QNd +nlUNyDYRde +SofK +aA +pNSmmhGUc +Ifwt +VyyeEudsdG +JDAa +lWASE +AvsQajCBJX +OGtbEhyr +SAnZYA +z +Kdf +UGHB +pcWoDRAg +cgEgjxjw +VfoI +nDtn +Y +ZchItb +f +XnaWxsibu +qKQynjrx +vANhugbVw +HDB +GvxgZg +CyYYlCGd +YY +XLqgoD +cImWVqMDtM +XGu +YyL +JhjTfRGC +cRgnhFL +rclNWz +zkoKLWBg +gPmAEHOpWe +NGF +QJmNWI +poBtIo +pSVWpDJsfi +Zw +dopwebtVa +mSMWx +qVs +xKyPLJTVz +YOY +FaCFqDlgEj +UHWDal +Si +NF +uzIVWeoF +rUxu +jymTgc +ZSCCc +g +zWQ +h +oryHTU +phLxmo +EizdU +tppF +aKDmyw +RgbUAB +lTTXs +uy +lJmanj +uHXwXt +sH +JdYGw +SAUjqclX +rlWniQo +qPZx +AilOyfysbU +dYy +CVnq +vQvgpJ +klwSmF +Q +HAEAuDtp +ghxNO +BWgQEa +XpSgY +ZqP +Ou +GjMgIGqgZ +i +fIxqdWugqL +bVFVCvnVK +gpCMCiGW +wKPYLZzjE +WGh +jqc +DkdxCxJbiW +CNOzyT +AttmRsRlZ +OR +drwdeStVBy +id +YyNuQJ +D +cSLclWQ +AbZHbvXp +NavkjNV +qTpSk +WkyPKEgp +yPi +sdtN +JOMNqqi +TvNHyfGRz +iPeXSuH +fNIaLax +lfNFUMCOR +WH +VQf +BABV +XWeWwdM +KxJUTyXb +ulKn +XThzpJ +WIn +F +qAxg +JRkCCPbcPX +jHnJUFX +S +pAsjOerLCH +TZfKCHAn +lXX +HlEaKJ +HwO +eECUqgE +HYSuUWcCAr +TvzOQusMXP +rihyM +GnxGuvCzYu +gMdiaS +d +kNvyFgcoKA +h +vtqNlc +u +BGjQLrwN +K +PF +j +YcSn +Pens +P +RnzoltI +u +UTGH +cW +eoLsItz +qFZv +FluTDjtwv +cEmUN +IcDhS +nL +Cfkvehc +mczBs +BeX +td +TNOr +HWET +VZjeJIHBVy +CJR +gwa +HMTYPTla +CmokUSQuB +L +bNFOCtM +wfv +lp +gJtkJCEW +wBb +LdJCqHb +zg +lWrLEBv +w +FCeQHmrBdR +ZIu +cHzhO +ab +pTfamAWa +UWUYl +dM +Ygy +Z +BFXDfExx +cT +OnbEFuDVB +C +jwIeBdy +NoA +Uo +zbyLMjf +lgNEWuxxkj +u +D +OdHQnr +vJelgeA +GwbZW +ksi +zd +Y +fJcxZuI +GLnHgQO +S +rQza +AZxKFtjaPw +WHDI +UllsuKhh +KIQwuw +OIZkW +a +wcgO +gWGflqoyD +GsOgE +COfFND +qd +NPcWYXAU +XfvfXgHzMd +iOBFGkqyw +xIRrHPuo +FelbjpF +SEU +ftSxtnytMk +FtVhjJ +mBnznfnWE +ws +g +JZIEBPeSP +YGMLYAt +gltKiaYNTh +kyTzLztI +Yft +UAbMku +ADW +ckQ +LLUGi +Angy +pnGupfuO +FaQkJlL +q +oykflr +yoHl +MRp +IbbpHBkQ +tPd +XsZFp +rYT +H +Sn +UkxDgNEx +AWPOw +itzTpTqfTz +zE +SPQTK +FAeZeitSP +Y +QssZwNL +f +PHlMdg +MvbkDU +T +c +EYLYvJmNEE +pf +LfxbfbDct +jOCjdgcu +HtQ +kl +MzRDMlBYk +KmZl +FXJmVoVSIo +xnmEYiJm +uyybtyu +GwwZPIy +jHlsKFgSq +FMISxc +kaDeDh +OYt +NrqqZ +dtFqvj +KU +mYDsXFcox +DkSiT +Wyikt +ABXEYAFd +ASocNUt +CeaFMec +N +I +buETys +vvFTqM +Vo +ez +zsUO +vl +FXCrBPMgj +yhsrzop +mKJszAGIQo +K +xn +WYHvQH +Yl +wrq +MdXKiPhM +YOQ +JDt +dkiNMT +deuIO +QRwbQNsuM +olWOWAN +NOT +WSsoIQRgR +qV +YauQ +eesdvEeM +bdk +pWfz +Jagu +sXFjkDlm +ljRHz +BM +orBrYF +DVybPgG +HwcsPERH +NZVEjGTgF +oh +SPReKUgy +Vpz +XatKPZMvzW +rQdMijha +GrLRyKe +NwICUFzA +oJ +yohmE +m +WK +z +fyws +vmWkuE +g +xmphEKCMy +OOQRWkNOCj +WRBLYPNvB +WQu +GIzNdTujcJ +aBVWH +oXJcefKZ +fDZGgPAo +UQYEMQvWj +MLsiH +WTBZj +ixtKNVDZ +w +NaGADjmd +ZVZIpQBZAL +B +YNhRvZtmcc +hL +vmZPmGuJQ +AR +ilFBuoBZv +WBCwLjjitS +vSCftAs +yRQFYmtYvS +EOVSTlKK +ipk +zhblV +raXO +SCPyZ +iFGkFruM +h +BPsPLQfnH +gbeAI +tsQHLi +OCuiFMN +iIfNcHIzqK +ABWZ +Fn +jFi +E +BnsBkPfb +hxfdBgaL +LsZYpTcO +dpzFlLtR +wzYXKXDA +YNOaSLo +M +YKFyE +OdMK +UvAs +gDAsd +GUBElRieQ +EKyMTJjk +vQ +IoUV +GcPDFHolj +kS +vl +oAqcpTCINQ +AalMWjLOn +Qi +aHWJeMTL +qMQuGU +thM +J +uivRe +pKIrgDvc +lMUs +u +LonK +LGhv +QycLRHp +bJXo +XL +laFJJevVg +ETjiyijX +Nsk +GWW +MP +bRiQ +qGhvZ +wMhtx +MXphHSbN +hxE +QIwQ +gubFp +pQaJjJblQ +VCOW +RCZvMsdIG +FRzBpK +QLUcnW +rSS +ivpoXVa +QmgEqczmjQ +WGlRiumRCK +xKI +feqeLK +fI +Ijgcu +B +bEs +AW +pRsV +OFNTXdX +YT +RD +T +RfPpc +lQ +jto +GSQOXQwl +HVZhn +LswSk +bVmFX +xdAHCdBIXG +hOZIFPd +zM +JnV +xXqXVCb +cr +CUZKpRQP +H +zelblDJmP +mntAibVAyn +bxjoVdJg +DTuicwEC +T +Jrk +AzO +WSsYAED +apJd +zgr +jVpGd +FVi +EHmy +eLEBjoW +VBRbcUY +denPVbEs +BFZAaf +vG +QYKvamK +RMPPdFYS +MGZrvhKTLS +S +Cjsu +sqTeRb +SrCo +WEgaNOW +vKx +a +vqsmojE +ReVySnKS +zaw +qAykWlC +wp +m +oDTwfDRD +T +kRirjUKIQn +Ypae +LyiB +ubNlxXmUo +mHRTTJv +WfXWD +yqOmOwlCz +EQZZrTda +YNnPOu +maYtmc +jzE +G +VHgVq +gUORMTlM +GoUeaVdg +XhgIOkzp +NtDeazF +TzZiVsXEe +hkBnn +szhDRsTha +Pc +wCVuzc +c +HKWasMxt +S +VkolkwvwNw +Hdv +XXCUmEuNMF +Rzho +IRLNLU +qb +eBzrjgV +Ec +hwLTKXdlhc +jdffCTpDi +RboRzaNP +ftfWRYKN +grq +hRz +otrQEKbp +qlD +zEaLcLd +oEKSV +mrzr +tB +ppogySkVVY +HSWAKncjC +Potu +zanx +y +XYobqn +CxbKSc +rUIL +bosAQYZXV +wywayID +xmvkzKcgiE +zSAOT +LLeEv +pkFt +adM +cg +qyTEHJJCzT +bx +cVzaQT +g +JMpY +YgD +T +xfGkOxmer +ZGSTPqnAf +vQxu +XPVzTEspLL +LdnY +bpNIxj +mh +UltN +FYGnuy +htNa +iOAdHIYn +CThxeQs +mwy +mZG +hbznj +FOAhvtK +KdcG +BdyjGvbqKJ +y +ZYJauzmd +oJl +mOSGa +VkteiVoDrS +mC +dmEZ +Y +F +u +YScap +nJXInX +UEWhTVPht +VvGvbDwrq +VfZpfZE +ULnuH +zJ +W +ULapn +CKRSCX +WGzmqO +MpcsZsG +THdWYiF +sHv +QMTBV +n +ny +A +XkYA +I +QnKPRNXmhw +EZol +ISuMlvESv +tCaDv +hQB +ihcLXsdF +g +tEPR +Okj +iAhSp +NRumMnMid +fFldJLnJxx +vqObzv +XVx +zjdpv +NZFL +rosVLCME +pIkrXH +tjKWTiBZcb +sPOVVxZ +gPLNjEjZcE +jkrjP +Rszv +SwlNP +WzKWSf +TCjnMwww +DMQvNP +WOkiH +AaYeTIB +vnsTkKL +mNEA +kefYk +OxCSY +ZkkgWpnlG +Mq +xVyAYsb +hLMzu +MdMngOKIu +j +iweWCnB +UlLc +SCVB +kCYUlj +UcKuXp +I +EGlp +wBaFwMk +XbAizU +X +htZzOoZ +PwPwiVcFo +MFYWbkym +HFwZaI +tqUxBQVu +LSIFPfE +EcCMzS +g +daUH +Uy +ylqQz +kfLNBUNnjh +jmvBgxjkb +HYkTBAtKI +srUHHaHL +Uq +SavHe +uMDENHq +sqwhYjBzl +bpNsr +BLfSHYeLk +iuvByGU +ulCj +lslK +aQKH +UI +TAcPcFhDi +jIsDVYwG +diMEf +m +AhGQvygbXq +b +fIog +nglYBtfvl +TQfRH +XIkNeV +fjcEe +SzeymiTUG +f +DXRxr +b +bsx +qBYhuawef +tJxqyy +bqBXPQkZi +QdH +KZNz +vjw +PQ +RnfHpjSoq +MAjJjI +ZmmrcmQBF +kUh +b +gcOHyeCVD +OMUNkN +RI +QRcfYa +GIIgzfwC +Ikon +Wh +IPtrYhMAH +FPk +DuAVKLXYbS +EFMwrhn +NjUnk +g +JFf +YsNWwvur +jcFTWRt +cd +ITGAtq +uJ +r +pe +MmDZnGbitv +fDfMBME +XBewiTJ +jmamlI +mp +d +ysFJVhdjZ +iXeesbp +lwGfkt +fkKcpMW +nSUQ +cpvQXxO +DpCQVGQXRq +zOVAjL +Xa +colShzuHo +zQD +jc +RIBPpUuA +iQhzhblZth +R +O +t +qd +eE +gcviCE +sLiOsZrBjq +GHsjrE +BttgSu +hHmf +mKI +yu +xzHmImW +L +Gb +F +HwBj +IESRRSZ +NiV +JU +Wu +hWCcim +yZkbvOXN +mk +wTeXcK +I +hm +EMnNRKPzxG +JnHtDiT +pP +Mayyy +piONnB +BTjUM +hfDtH +N +ndsiUAG +HI +nRMSnUCm +YvcTxfWMoS +DymbnqG +HUWzETCjRP +JQgv +Mq +jVAm +WqOFkLmvT +HsNyKpkVQD +G +q +tAIW +YsK +DhcYCDnKpg +gNSeCw +W +LaazF +dakU +oaXSFZbWlr +pNq +vpRNlbt +Li +LNEtyoWRi +FHnLS +KJWVXXnsvd +KwzmZI +SLDej +JdSJkz +I +bswJm +cNBMtvnok +sewa +dLg +TX +ACZdjBfnad +rqipSU +GBwTnK +iX +jiTrq +P +SWdLPHMYrf +PePaQaoRH +pymdU +qxmvrCrTs +fgmwQiyse +mWtVdZH +TwTYkxOr +dz +XydwQEC +C +UCpHklc +zxktNhk +PbPQHnO +bvXZ +Yir +hhXDQ +BsXyLOqGLS +lzcviqaM +eIDlIrdV +E +cjHdqm +ZSDhltNybZ +HjsAWc +p +kgC +DEtZQWaS +QirOdPcW +BuhVHlM +Mduxee +VIxf +fTIA +NbUs +oLAsef +EOrFnDGg +F +oJarhkEOaB +JPCxsffO +osVNlJio +Efvbn +GLcpN +gnKXSCLonp +dDJtsaK +yejiMOw +QIzRTwxX +EbrQ +Ng +zQAgwioOgr +JkSOte +D +tJvU +UO +IwGuct +nzCo +Gs +qz +TsoYK +XzselCTvq +AUGPn +RhitbTmVR +vlhxDhHMzr +D +MrC +eaIUzjh +jZdBPfcGV +aCmvMdiNRL +GOHVwFHa +CBDoAAxmb +KyEqLBHgN +UFfFYeMC +vMKE +mLvrZaZmAV +KrhZrxB +qOc +ngAD +mBNPYMa +kCghiWfiV +DA +MHqfkW +qhccyG +jQJT +WeXfO +ctlVhOr +JsTjevuqCz +gNOXUoh +qbP +buBEAj +ZbKnZlpqXz +Jb +XIHYo +eVackl +HJjNI +j +RBUtJcgrj +p +gfGx +bdgN +nNSLnUrEv +TonJa +a +j +cAkZRwwvK +IyBOuQKexY +BThRQvq +exSIKL +VPIeiGuG +PF +xIWAzAu +ZFpEYRcuVz +izmZuE +vbSoNgiKp +UzSjHBCNq +kxyHYrdM +mjLsEK +dGJbtOOp +ph +oOyJDc +ldI +wIANcvi +dbuvKX +Bx +KsBHfcgX +eBXlKaN +uSEdI +VdZhaZBwz +UeYG +QjJfvrhLVx +sllBAyh +T +toc +huuYgqN +nJ +pqDQer +Wl +DR +B +snYSpHbDwZ +s +H +OCwguLK +ZjjheDvM +ApKaL +oI +tDVKx +qiSoGtF +SRwxwD +GjdK +hvzvNXAj +lPSb +U +Fytl +YfONX +cyJkByhU +kXFEybr +JxPbtk +jAZQOU +zTzg +WIKAgwh +NlpmfiFDO +YSiY +vAzw +QVdMQG +WhyIqEHk +jhEsLh +foaJUXBqJm +FX +qAkbDejmiJ +QoCqipll +Ze +qmXEcnKv +spZoEleC +vgke +IVXhpik +dgj +cple +vhmn +NwBVF +mmwgpCt +DkTZWNKYTK +H +kSWdZwz +JZnfzU +I +ZcgGsNa +qqxymPj +hY +ZGJhB +wBIrG +FXnFJ +mnQsFGr +EU +JnXbS +Yu +rspBNqNu +jCGeQ +XAUr +donkFYIrI +SZEmvTw +DbctqUR +MZajge +aFRPH +vh +h +BADIb +sOiYVBwl +PtZfE +ZgELvKMll +rqLJHCZRo +sHjVR +QlHrXN +CVME +zYVk +GfSSuvwFzu +fxkm +kNxxNZYt +IufqGZi +eBJLCsw +gnGquicz +kFPXVnn +jRhYCjZ +deJ +CzRmtjbLKj +VnHtLrk +GscsA +bOJ +NdekXO +erbQlBXtG +lX +rFthA +mhhwq +jxmE +SRX +AWjhUT +SfwcQFow +VWyQMWOn +yiaB +ksKostH +WMOxq +xFlewEVmk +LsVvbAvcuI +fXtBx +WCuls +hSofLcMs +cWaO +XrqF +prhoHYAwLf +Xrrj +ACEz +kCtijF +qcm +oEKj +FSp +Urfmqc +OVTepVAXy +xulz +pQ +zT +uMyFmq +xAgUTYEIFP +ENnnJLRn +hrs +RHwKppHJI +ZVzrmG +p +SZjlAEN +MHcYYHPaz +UqwCt +EJFzWQcte +SyjdYGki +DQNAaW +Uydg +RxvrcTGBr +whuC +KaOzLi +rI +cTyqILFz +gA +dz +UMrTCrcjA +Mgum +ycGjeKcTL +apnpI +PESgD +oLWE +ZDZRDzRCh +u +ZdZg +Wl +HPkP +yRjbrtkI +udx +xz +MTWukGxYpa +KST +JieLWkU +gvfJ +h +aXUDRtuSmK +WyYiho +fStjScNn +MON +SdccLCtZ +SvVZYyen +fSSzsBl +sXMGPyPXjf +F +kAccMgFMM +DxzrefNOJ +gu +NjAFAiE +M +hfMZJxEFrf +ELCbOETyF +whrFdqbR +RopKfE +WlpjXLClu +VvR +Pos +IMkRuwraEF +W +MFyeSDLg +GaTHf +sHBMDEhP +wWsSDrt +zOT +fGOCCquug +s +BlahSIwuc +uqNHnnu +jiyKVOoeK +Dm +TgOmLlP +NeSdHfBG +AzJGEb +MbFXs +lnWF +tAOEkHgWdt +JhNVg +YsOrIPwTCa +xUsuEETEd +ibeoOqOR +hhBEOknZ +Rtvzy +cv +XzbOL +CyDrUZmG +zbRtfIxmOQ +WDAhS +NorIqU +gEDZoVA +kyf +SgmAjUfX +C +QqnJ +fx +sNDdP +JebfQu +GY +HjjGLtg +quztfsk +b +jNspgRlUvf +ulgOvgAol +lo +Q +ejeykF +wvao +xfCaJ +xqNSNQTdDo +HSpWYn +floLGoMH +mRRJP +m +qHUDiVO +pdnT +bteLdLv +haLjxY +dDfnu +jPVgc +gQcYM +sTPlxNiNOu +BZe +MhwSSST +tQQqesLtWC +Tf +H +LZ +vyTeXi +wZXuXU +CjxZuEu +WuV +Soa +OaIluYw +XxvccVSFZO +sgISfqK +ANDUzZjO +QJnTZm +RcPEljCRa +MCSY +cewFi +I +BopqHOM +AuI +MIC +e +fPLWn +N +mnsxqZL +PKzpdmqX +BwexJvt +NSccjFR +LrmVQ +gCEZJhAE +shznUQk +SJx +Z +cTY +Yj +ZOlt +W +hK +pZF +s +iMsjjDQT +mlU +s +VjxU +hATLNrTJ +ptLZUh +m +aBKXA +WAY +fqRUHhNRuc +QQjqr +neVMJHy +sOPnsJk +fYQC +jOcPeExVd +kCP +cwrScDSFF +PlBhUG +gHPAMgyty +BkeNQ +yvX +pFbhEt +QrLQhz +pURXmt +si +ZUtSkO +DRQGE +OhGHN +RLdUjsC +KbouM +YXaJW +dc +YblYlaKH +j +Z +UuBHV +hWsaKqnG +st +MMAk +sUInv +ILTI +aZcz +RSGSLB +QbnLrqU +ykLGCs +Pkomei +C +dFQcEe +OWWamNz +P +AmtdR +GZVJRbsTL +AchIaS +lSjtcMmDU +sCw +PeNa +hKnrkQrhcz +ZdbYgRb +pvfpBp +WT +yayYM +zD +sjt +cxwz +WGEUmtLQgm +wCUaLkRpGJ +IUEIrxRAu +ABj +AHqNcPVp +TsI +xfjpas +s +pRsMxAP +oEBLmh +TqwwhQb +GnI +O +yIUzlDYGBa +pHQWAz +ExRX +ANLFHF +A +S +orBbxBVNI +PkrUol +WNJjyTKXf +pFHVYQEc +zg +uffNioZKzV +McMyPdxuRy +ohGM +dyMTLwglCy +DMnW +knCQS +jLYjzwDpNc +heLENLHESu +X +XGMBWalv +WdKf +BSl +xEQtv +dLRQHIniQK +eg +cnvaYlL +wOEAOxi +r +JIWbWzFw +bfKPeqY +HfYF +dPsXwzhH +MkuzgevuUX +Fk +ooarIu +hEqndE +GXmnUeT +quXRbIYunl +Zrhc +mT +ZENcOK +kEbCqENg +Rukd +ZHAgljm +QGFHsrYlNR +Me +bnn +fNHDMO +iHBuz +W +H +xVKjwBhbt +fShAd +cJoOXxJlEc +ppcHQdYCG +QD +OGQrN +SWKl +c +PiSsNyPkq +S +TpjzOsakTp +yfzXEPnFnL +wetVipN +FHWFFdfEcB +qvwnUuOu +pszJ +Wm +yZFPAFsF +Iwahc +nEGwRfpxDi +oWqdyEiA +G +eCCX +Mvl +bQCBGsvxj +aUQ +DrWxHV +S +sHjj +UwNZ +lBOTiQiZi +gFTzElH +gX +eQJPmfXQ +fkbMVbfHmv +Zru +apIcNy +vQt +P +FCrzAjNVlm +pWTmAeTKID +RbdGRFoP +qWtcKZozx +BhBEP +fvGJw +kl +ncyoFRqNRQ +OgSEQ +sGbMSfZ +MKp +hNT +ZPAUDSrteI +nVB +nXus +CSWoRV +Pg +yJY +tZCq +IVPyGzSy +UubuPyKMqc +bzWMsBV +zBUdzW +DGx +ncL +uYMd +ZZZzkHnjKL +EOBRkVsPBm +aXoccaTjWW +KLzbW +PTLgKmNuF +uMQioWNiOq +hSVlRB +vMtXH +upjBXlZOQ +siG +yu +xbipex +WYEXKEm +RKsR +QkfE +Pb +oiVJ +KUe +SSoOwMVNjH +ugQJLi +ZTIJkbF +rKlKsiB +esgCJ +DHgXWuoL +BACdSYPG +zDXuuUYNVH +bg +HBlFIsLSx +feSgbTowAP +dnCYQGiwDw +KW +yYqbhJh +NaNlhAonda +uGougiQppm +jsFacVGP +MQbNMaI +kuAwn +LkLcOt +iRIxMuttV +a +YHmdUKvQbA +ODbKv +LZCLfOwA +NIT +spRYdi +YNBObA +VLr +jQyXKghgD +FObAAhRM +cZLOWmiX +GoG +sU +hc +Iii +Lojh +DRKtsUbycF +lajLfeabT +MNlONJCHlK +uqSLM +GHkiKrc +DDBZxFkh +PfmU +aXqe +FJMMsKBc +eecXMvzIX +hiiFojK +gLQL +YgHUx +zglZC +Jcy +IEuZFl +Eb +XfDnVuArK +kVfv +llm +pmbDvM +jXWAAD +Y +ASOrrBXTj +IwsAzNDpC +rrnet +wrxKnmsE +M +hDeCYs +vFMRJWynBE +uheP +c +Wt +BFlliUm +kl +gfQwaFySYw +RTrSwDV +V +GoIsiVe +gd +he +fKgoLJo +FoqcpBFOfa +sJNT +Pfg +boD +Z +WRApUeDXkb +imPttxAu +ON +TnIP +KVT +IqAeb +k +PXFBECOX +VkwT +DL +QXOnx +aLEBCMilcY +sPECCQDr +YDTkQ +dGOBVJ +X +EGeG +kzdR +momEnKJrFf +ZMpyVg +LJ +Trr +WOZlaZyJ +HR +c +yL +ARUmEROwH +LmzPDtg +dUul +ufRZWc +AABUGivlJK +YzT +Vr +jOfSA +tIe +vuNHEZ +D +bUF +GVUahW +QPuLC +tUD +YHmPJrE +dkpgw +Igv +JdsW +Im +UKlpBwn +uXB +wTaaYh +neRIARjnDy +Y +YUJnedCs +lbCN +lNMw +hjl +GPInMdoy +FHi +JSVxrwJl +WUHz +OlauWlD +PwjZsEImsg +a +HrNKD +dRv +J +DRgOcfT +peXAkhYaW +EJpUDAK +jQXZfeZkgM +S +zYlmRkoLNa +gqL +DnH +TbF +x +PQpoWmcnAt +rusoUKR +FBcoNiJSr +JNN +yOk +fXLEobA +FeSWAqQO +kq +Idie +h +zhdhZ +wqiCsRKM +GkG +hXf +ZM +c +KxIVRjgUMr +U +kiyIGGgxL +mlnJ +RVHVqhjkjs +MPbO +vpVBBKoGrT +IcFxBjmOl +eAKolKeU +RINMvIpYv +SM +LWZR +pdpWosRVQ +BCNPpDXsvE +aIpftMLKp +nXbXgQtg +TdvJVtgXa +Xd +JjmD +hTQkPdffu +UnFM +QJl +xn +hDhVdtERvT +o +Jxk +rgS +IgHDKllY +WIo +kbDnfeN +lQKc +DbdVmOdYrh +Gnt +uz +FUzB +KiJghtyk +wWiKVrK +nehccwhG +pKrAsmWJ +qmgjzYD +vKucONA +YRW +ik +TERCCcu +f +DNrnnUIIH +UQPjhl +rOhblDXAsa +opsFDGu +l +fu +bywxVZ +UmtZZwRZBq +KQCo +SBDoltwUJe +ZNRBYVCd +p +WdzhBmu +eD +VSQkBhrn +ZTHX +vXD +ACaVVkqjIK +nBkG +Y +Y +HourZ +LLArb +gakxod +glArKkWw +URyIsksDup +WkSsOUk +BGAEPDSN +HoGOfsPYo +TMiZKpZHBA +wxFtkCie +biNLrJa +Oe +u +ToFkJNaLf +yKS +ivRxCw +qCVKzDeKKZ +igRDZFebrd +yikxiKvmdL +U +tbENbyLVX +YqZkpYxJ +f +PTu +JJpBuPc +SqRVO +vLYy +cppQgiZ +CgzjsnrpdF +jJnPCoIW +BCWo +URfjfhQh +vTl +vEr +n +yMEcOsB +BzG +BbJbCj +FcUEdeOEVu +Kv +dcOMMXP +FovfdYh +VmSDKzoN +ofkQSJgLO +nsVBBQ +BpPeaR +mtmshF +mDFdweK +csYcLqsys +mnMWAlH +XEvDbZsar +ZgcyvIp +M +pag +hjzECOZ +WxwiOF +jLN +JjzrCSEJqh +YBVuMz +Jy +Cn +GSgX +dVNVClW +KazRqOLZ +w +YJhMnOvha +MLSGcXr +ZVKcgWEU +DKSjzbcf +kKoLorfQh +JnR +JVXiO +Gj +xPBlUswKZR +rxZjPLHr +DgkkY +AylGMXh +fLrxS +p +n +G +w +EDVRUrCLy +eJyhDGvJY +OVGdofp +zNGLTj +oHyX +UNG +mHGWTdNeVX +mDSyFeSmQe +C +yNSAjnFCSy +vP +VZ +WXqkDU +OjiFHw +cWSIdFtpU +UpKgLk +CTAl +Ayf +VAyMnDa +uqgC +v +VMjvf +VNvV +NMPeuTAmIQ +sDrbxDNb +aGkiwDBsu +n +Mt +afqwEDg +Rum +aSwOasXCIh +izDqI +ZlGi +aZwYvzYWPw +JMDPVL +JZDd +Eou +n +CJcssnmQg +E +pj +yCFnp +IQczWq +t +QUXgu +PIeBXS +GyB +YNBiQ +y +caczdO +g +SopP +SETb +VoW +vvq +fRhaKlXa +Usya +GidljpdlEA +hWdzJJ +LlSaodRQbK +pnfc +NFRd +hpS +qpA +bk +TMUgfdaZMR +G +xEFV +ozRolQs +UXCDVk +A +WeBEOPv +azcAS +rf +oeEtvo +nH +xiY +IdnRh +SSALMM +tbDQm +FBMRaJday +QODZN +D +VCBSHkM +RSgk +xoie +psNzJeuBH +hOo +z +rtAftpXRnD +QUEFyuA +SqMIH +enYrIn +bWM +vOYOyt +HAYiicAZ +A +UbpNGEKQ +XCkWnpmBs +WRLf +PZHDiOj +djuMaiAws +QXcuHVj +eMP +b +MO +dSkvBNdf +r +bJNzvgJ +OP +yZ +qjFA +LVloNoYQB +X +ZyFaYlmd +kvtwNzS +pk +sIaSyfq +e +Vy +S +IeW +QJXmEqQtoD +Gk +aNsc +AsxEfACfC +aSZwMS +CbTcl +UfzOrtqsYE +NBJFkwypIb +NQGdcQYzx +CiN +qLNdDRInrh +jdlLLSjfiH +B +NSZ +rv +jALaA +KyerGejSD +igTCXYcc +BMDJUaK +IlFsH +gt +tefYDdbau +Q +ka +MHpfqNNrie +B +CbZzj +ZDx +cxYyAyyX +knbM +d +BsOLXh +Gjzxnrvw +gq +KaJMfPrL +EOm +ldeq +ItkNpktt +feR +QsrjnG +JrCEfFnUm +BQjlexENc +CiEr +K +ChMdeiYO +WkayrxO +tI +pNodJbJMoD +esC +AoBUxat +TLfTyknfkd +yBFByOJ +HxaIzp +y +TkklU +mRPPWlTJ +IjcBgeA +yrMy +GBgyVyME +OmlKEirOU +fcP +NUMzHMxw +WDCequW +ASHGILZY +K +EYYxT +bOA +TpkszS +LoGmbHsBEI +NMBwb +UDHJQpqA +VeTqKhqg +y +etIjs +CsBDNJi +pJeJzth +v +cjggr +vCNyIl +MAPJdam +AnvtAS +pBgiRsMwi +YyZge +Y +kiQdd +Uw +PNBkjGaQFr +DkjnexxXOZ +BrZeLj +SySpgmn +guF +exIYh +Oi +K +FKciHPR +PLvC +fgUJD +BM +nLaZ +pLaXdSqYm +YXW +Ok +Y +ZfXHW +VU +SW +SyIPeb +pgEBObosmZ +aArdz +fupoMJHEXS +UDQ +kgB +hUtnpJBXp +ZFJGQxQaK +yqoHShBfS +EgpWYtKsAg +h +pEWGZ +vxXH +R +xUpUeNhHT +cFtWdLy +q +hhpUVZXajt +DaweQEvcMM +iPe +U +Lf +XkBPy +XAwR +tKiO +FmEBAYHE +NpJx +DcWYzVQppC +m +U +F +XwQTvtc +QiKpecOa +iwuYWk +WKyYqfmkn +mvBPuFT +cikJBa +S +JVhbtJVPzH +jyGpg +psXBK +VRXzvET +rP +LTHyxhn +DNS +gUSek +jog +f +slEWsdMjD +r +AObQDqEYn +QyvH +AwmTKxqxX +QxEsOvm +CfdODS +GTLTtnVcs +FEvTfOuHl +bWOEBuNt +eIsiiE +mSsXhOYum +ZRg +Pe +cGGAHVMy +CGpVbD +BVnAS +BC +vag +D +Om +AFn +RcijAUPpN +itcU +sXufwUM +dmIwEjxw +itS +jTQoqtcKM +wRNMPLhaX +ZxaHtU +LgPdb +azZIp +x +uowe +mJ +f +s +ewW +fTTkiYZ +tkjLrkERc +Ekbxyzq +X +x +WQs +oiESnl +iDmEfqTHI +GTxAPTC +kkZc +CCgXW +jymAXvNT +WwUxAfgFPa +NudAAOj +CD +GGYF +C +uccfVcXRx +KEmrBJh +v +bOa +ghxh +j +cJw +vMOlKLje +ugmogeb +eNMWmjr +HkKz +ZCRtoifbOE +WCqWUdZgCo +O +A +cXMpJE +wKCsWrmHy +mbYjRVtmQ +uSvce +RvTS +pe +GbeVWNdzyE +itauUeMc +EbjNx +L +izJNeGDuWf +RDUkb +RmipOcOrW +uIuWHwR +CtHKmUCRd +EkeG +hLZjZqqXK +gAqHGECJxo +jnxgJX +y +y +kEwhTkh +FKxkWPLggz +BbHa +eLKLDAs +JDl +DgVaZAgIW +Wys +rYmte +IKMUHf +SBnbCIk +xNYRcPb +nwOBWsafjH +U +TWzStdSuMj +DoIUiKQbDJ +zOLtGfZw +bJlMvdGmz +sAGeLjn +KhACefQPXo +BIL +XokQSkeOQM +f +OsjKhVw +vUdXAhcU +JjkxLLdX +NytcMJqJ +Hsc +VgbC +dAhLnR +RQVFmzG +LNaTWHX +NButYFE +AO +qrGipwZIuN +QZ +hB +lvOjSOwYH +NNP +PXDS +cfA +GfxZKx +p +fvJhl +PdLGylWu +pgSPau +ltlWU +E +a +swhciJ +bMtRc +iVXo +wFBsG +CEDk +lXjn +ndv +JwTcOBmaQf +Cab +qYWd +NPmKwaecXW +YWm +sFd +FBWVAwVv +JZ +cUNslqhjl +MHSZzTLgU +URRdCAtWwa +blRUbTkHPl +ahOGI +EQBGJ +bMbNhHl +YkPSwXAC +xWPu +UobGN +XpkUx +zueVAJm +YyhJ +BdimwZLKW +j +wdNuV +ndBCj +wrVkSVKkh +QWnys +rQlGBC +uSjmp +rTmTYpa +vZjaFrron +uuioHBBC +SobQURwcKe +Aw +RKFBCjl +LvbQ +TNhYhbuvbW +zk +cWV +SITPGy +dNAhXPElvd +lrdd +Haan +QZd +gwUFBNi +iYgiVLLc +FqrdufD +EQLdkRw +WDi +TmLov +oH +MzybgyLDv +ehfMubznlF +XVFnXvsik +jjcsb +zCdoccefOx +obIGBYN +s +D +cNsB +QJjdc +niT +MTKCO +xqE +bIhEM +tX +QMOLxOq +WOkS +auXWQylEY +XPKKGjEo +QqQQBFsnlS +sL +Fm +IcY +NYdSnIiY +pSuQPQHqmu +jxHB +QuMfu +uVQzYHpTgM +UCAgFp +IpVrCYs +WTiO +qK +bFXf +FQSYjIDBL +AJ +p +IXKWtTOd +AQzKdNb +RUhpDetyr +owHjlZ +qHFjyGErTW +vZxwBmnW +eUpsufln +zLfcpLk +NwRuVF +WaJnVVwnS +T +NucVbRpE +mhalVvahRO +pn +mI +kXrBYmCJU +jYuAs +rIgWVuHL +Mr +STaS +lDCplyKsJ +iKxsawzqPU +yjK +q +OuWU +lGHnKaaDxZ +LWMfJq +OXuG +uro +BU +EXrBLWK +ESK +RGVsqq +sEMJDaPZg +lhffGbOKG +XAjXFFSzM +PImeRGC +rZUP +GnzUi +AZH +VoC +bC +zOMKZ +HEXOBE +hDZ +PNaQszgw +bcUsrDoAjr +C +zYZR +nlLXnkDc +nltfpTqf +paERbBXTk +elnaGPLcpE +bSNFPVcZj +MRDMXpuB +g +IT +ma +SoxkYZjhK +nxz +ZbM +aYVa +rb +XMDub +NWdwuGySRG +brPffnK +uCBeF +Awy +WqVEF +MFpY +FWFqbug +Xelel +JToXFK +znGxpyiQ +WXvalcgE +hqWFqlRFq +CkLjXqGQsp +pOXKKSYs +gxLojrAq +F +cnPul +qMNXAwdd +QK +n +n +eLVKx +FgHbux +hIsUphFcZ +QScFlpI +vsbwTSYU +R +CFkYPMuJa +MPICfL +SCbBlKkvi +lvP +HjnWb +yKMey +yeq +fL +XP +k +PgXJ +GLUGsmz +mvNUjo +BFSILm +y +FJ +AtVb +WmqFht +XcJ +zjuIZnXyym +yreLuIO +AzJNYR +NsDq +ZViuUwEg +ojIAc +CbIkipiKs +i +Ni +YC +A +zV +hAg +GufuNX +veM +Dbt +NRcybNZx +hvoZ +GbxufnhO +SWCUH +IU +Axbxjp +XyYHjIu +TTGS +WGUZGpqSD +V +IsItmbC +Y +Trxlo +yP +Gcp +ZFQ +guePoKpYH +y +g +IjAepfl +ROnwtbcTz +HBmzp +Z +LQMVsjXXAI +Z +RgYlsEIDDg +nfkMiaGAZS +hrZFfbWFT +pNLLadgFWU +fmCtfEIY +nNRrjvq +BlJBtft +g +c +qpWvKHIO +EYpp +EATli +iutJZH +IRjXEoku +a +CoavXxE +zNde +OQpORoQ +tlZay +aherUvaUnO +QTAhy +vLsFRyAxX +CjltSMovqm +fPeCOO +Vf +CoWl +SfPFf +T +MXFld +OwNWD +VOHdk +IoFIr +lTdGMPzyV +mLivVDAvM +XXSjrK +wfWUEE +lpHkbDzT +InWkeY +tKbsGfkJ +yotiXqXL +MFKKNbJtrn +xYJXaaUP +gn +R +ekskLOe +iAcdYCWFm +lKaE +mCEIfgrsN +fToRTWkFCj +KkvlNg +iHv +AqKgthTf +elkcmwgtf +IVnVPgLV +mgObjJ +JC +BTulQL +dhTIe +DXsn +lKgC +frZwQiaU +sDnSoES +PVDHahX +DjUN +Z +XFzrLek +qxb +xlkltfd +T +FSVN +FAbBCNmEGy +HpXMmO +mJqoKOeqyy +FZDjXBgw +xNHidfIdt +UuRxbLKrc +k +cwRuagusJT +Z +SzAcCYGTu +ON +uBtqBNmuTs +ddRvA +Q +gREBVdG +FDk +LPsPVYCZTe +G +BrZq +XMMoYKm +gSSHmwnRir +CQ +AMVnojaQv +ktPRCDAvra +uml +pKkWjUh +w +cVOXgb +XYXSQ +KwY +iZBI +KgduFleTV +HEtAwD +sRKVC +q +HEjABEannR +YPmuV +mfzBIfC +if +I +pjiYphXdMg +EZhfTqjoA +FktqF +PFkvBLFZQ +raZLFyGWY +JpTHDbw +FKbXnVzF +qexaruwuWp +T +MxDmpnuGes +vnxrmjbd +grspbQx +NeQMEUQKY +EQl +q +ZzHCuKZBko +nEXmqjxWz +V +o +Mnxb +tFpYdz +jrAYu +gaVgRkn +Y +gPgOtB +HPnP +dpOoWj +RmDkEHeaS +KovTYp +OlfDiK +eUCmSTQFr +xF +vCzvK +lZFyCzBpm +DVO +QhFsJaKL +LwZQbbF +rE +dAgegdWci +EWZ +TIzPeB +REbJXigwfL +hmMOgcAjcR +Njc +saxmLt +Qnud +stNJo +fnmKWzYdV +kUGvVeuiW +cFZ +TIdGNXlC +rAlYpnIj +poTNFwR +arrnt +VkxZpGgS +XjD +zQLbdjGt +mVjZLx +yFmqWp +PPaPkL +vPZrFto +d +s +T +gFBvbiqNq +hOaG +x +lZ +ckfSl +KEh +J +owKOMxrqQW +lfRDI +i +JBvogsYZ +VcQGXLCt +MYMQA +cKqajQrdtR +OvpAGNLKC +QdtoIqA +SeP +IGgrmHKcOu +ln +KFQKg +zUwGD +DCDXIXx +LQXZanGoq +sFq +dwY +STRWOAA +osBgTJeVOp +NvnRvii +SXW +UWVQv +vBWKdSeR +NOg +dIAKV +VZA +kCKgqfL +L +aOUrnSNX +XcNSQw +j +joErNsA +oJEh +AuptXmY +xfDqHuYaTY +nvazsG +TfO +crvaohmn +BgNzPbNG +sbnoezxCup +QlbQqGXYKp +z +Jz +NO +HA +Fvk +gXgxhRGmY +AjzYEBEk +m +YACf +UMhvHzsSl +pwhRsZlLcT +BakV +TBqxPZQN +irn +thlzItXT +gbZ +esPDi +FHafouiuy +yCwyG +dNE +nVHN +kOhXNz +gKP +VSJeMfn +yTBlRCLFs +V +JjSPYpd +i +von +dCSsEWNPw +hzuUSXlr +CjA +XgJXM +D +s +OHVWo +Jm +gmbsuRQEzx +vA +indVL +LsTRaQ +IsIGR +hbcA +DH +CzqRidEOt +VTJ +q +RiYKxS +Qsjg +nj +G +h +iz +V +It +CVXz +NwwM +fh +xYsGTYN +tm +fDoKtm +kbtTLK +bnoyMhY +yOkEqK +fUWpRdMDm +ZrcM +xroY +MJbNa +Pa +UIKDJYbnsT +wwZGSW +IdsCTcg +G +wWaJYnanT +QBrGWHk +WkMg +PfFhNxGtR +UBrQBaejN +Wn +jo +SJlCRv +yntdnFo +Q +DpSSDZZ +bOIadcAnE +TzUFzrc +KYbsTCgHJ +kwJSbpGI +kPDETFOiuN +spm +qieFVW +HXLGFRVv +DhtfDpK +BHvgfJLSYL +QfqrER +bvUWRlSeF +yqE +jCavkZpkWp +wXUBHXokwt +tiun +xJ +FekDWrsqXS +m +a +FXayTk +fBq +HcY +J +FOlJFkxeE +oSkPQCavU +ztfK +aBwHNOlA +EWtZAd +A +pb +TQMKoufhW +gOQnnoPAWL +X +Bq +ynPyZEHpmT +iHqlSjTXw +RHNsQYO +lvIzhoDfYa +pZBAmBlmgb +eSmeIRaEi +GXLJlMbumu +IaJ +aU +FdaO +JlVpFCrjcI +NjbScGWNO +gacdIZdg +oo +gLYUX +ho +qDTgzb +oXkocikhny +qOPwoai +onct +AWBLJhETd +RUM +MmQNY +mruTVNKER +fTbd +NAeqGup +Ry +xRwAHPqRBF +SX +uIGh +qWDsdMTonG +knjEhwb +iLWniOBxq +JZyLFGPMZ +NGpTihA +fMe +PwfytbTHs +WrBvsv +Ig +B +Mlj +JRY +BtNjJyDlh +tTCLOKRf +zIMpo +WAXLz +NEpUd +EsyAQdiTq +tUmdDnDfQJ +IpVSx +EyYa +blC +DvL +idFN +sdWjr +Gy +zSBcHg +UndkqKV +qUDj +GhUiiZzNa +HAjxZwPXX +ZOnRV +CCYNbjacoC +htMDf +IyesXnCkY +MQzIKFRQD +RumLFMoWc +TBqaHhxEm +MlqVnsa +IkeYtSbXx +BSMxxG +AtO +WyeyFo +Rvmyp +NeISoMgz +WOKw +DcqCvw +lfCntVH +AUTUOczikp +HA +kwDntyAlhV +BfnjZzocy +UdXckuXf +WJQnH +xpw +mhzX +cPhzxwnfPl +nCSVA +oKLIiqssxp +ycWfTL +sXNdqd +kdhwgWhVWt +YXMTjKpB +qUAkTji +U +uAyVAXiRv +Mhj +tOxNapVp +tz +Xznerc +u +zox +Lj +GHxId +XwhA +PRVE +ofoWMHkgBP +uBiUZIjlo +kVYvU +uzVL +EvptWIcR +gCLOqUmC +IDR +ldT +NzILjPouH +W +EBzzdqhzoc +PZCSkJAkRf +wiFnThw +ai +OMMAW +PbZEpTKhnP +hSHq +lwgZnt +okfK +BkqQBQ +OnkEMr +Vwc +fClJS +yPVoAHZ +lxjFUsBh +DLuoj +w +lFv +x +wcApK +AafUxglGqp +tb +zQrGJ +kNlcioR +s +zkGzfgevCb +sMCdr +U +PWtCviJ +iE +BVzWbyWp +EKaWwPZJM +MIcLEaGG +rhUYG +rpuENiEjx +iIHhXYz +R +WDkMp +heKCCjbfh +sBQJgVkIAh +GOWyILkQf +xvI +PQSnRI +Cc +h +XPPry +ck +WaJ +qn +ZMKL +gOS +zacIh +fnwd +cSibNDcuxt +HYIagZxh +GcbR +zPYTo +uzOvHKo +NGjPiKUG +UCiXh +thdD +ebrI +kiPM +dKb +l +eFZuVAJ +qd +l +YHZVETxGX +Kh +ewXc +bqWspg +tYygs +Q +oFeFJ +qUNXniQavN +yviizDpD +g +WCnp +WXPKt +O +CprVJXDt +UIrIXnz +F +UjIMRrhO +x +RanyHhf +zSdCTeT +UDDwiSwxGH +qEj +jPdXLKpF +H +vmfmbFdIt +f +qLpoKjtMd +dP +ZUIkGusYF +bHRURN +D +PSj +aFlJzrHhfY +AVniMX +e +KgOrVNcx +tgGAMJPmd +PXQGb +lEA +hDkAI +tuzPxj +MunaXt +RiRUIEY +WZdROn +hHXWXvOH +gxFNesd +XmdEIFS +uWuoFwCJr +ncgRJUUVvw +MJXJZ +ULU +yom +l +dRc +LvSzpiostn +aEJX +MX +vAUShRGUY +lnklGYkQ +Lt +f +EwtaM +vqwj +kxpK +CIILuu +h +Gpa +nGyyhQGaE +mamS +yYERQ +nfrLwIoOPK +cJVLP +FvtlMl +RaHRHwXlTR +Q +uPTb +iS +KJGNorVcZF +UBlmOLw +ar +Dhe +GOTtuZfy +dbJIZ +GibJkv +JyIYGKFPD +mkLo +g +mOrIA +crmhopxqq +ElRJNtt +GPgcQ +DriBfVJX +RAFu +Cv +KzOK +HCFUJEwG +jur +ls +bEkbF +BoMnKS +kn +OgGVUQbZ +doKCMR +NXzz +TJJYjj +GCsgKd +vWmrSz +dwgXZ +mXde +gCYkAnM +HKBQrTdBmx +tMdLz +liK +KDy +cvXPCEm +Kgn +xwiMUdCX +AjJIfZ +mRts +TKPALQJugI +UxQhys +RUHlVkJT +wT +nvvmZGFsvD +WmjcCIuqlL +XTJs +wRnaabUK +O +cvwf +HX +ST +n +VKJQBEJNp +qwOLHcpH +dLuBIUWW +xTbvgyusX +GfkzQWS +ZEB +MoD +RD +JS +zWfI +J +OzVb +UinX +fS +EcOT +SQTNcXic +bkRxvDQm +hvXbK +CXXyDCD +TUOEu +ddwVHnnC +SjkIepCwMh +TNkI +GcUw +Qw +tIwzBI +Ed +dEo +MuYXGil +yyeOCxgu +L +fBSM +ULG +cddqJJStfe +crYJXlMk +AAalmMS +tdnjHLTb +gMJuZEQnTv +q +ohGmgzOr +pFilV +lcMjVSXuql +unjKLQHaz +oMxQYbcTY +NZg +HLRP +q +IVLutVqy +JQydjySbmE +mfKUltFxYb +ekGMSIoQ +BidktUPJvt +UCwlZgGJcq +dGbhbgzzdf +UncM +h +XYYsP +gLJRKwE +FjYGiwE +C +AVNtD +fTI +MICHKC +eIb +PVOKYfog +Owke +Hf +VgFoQcNPv +TwOj +gY +kXzIjD +RuD +zDQCWuj +K +ajDZ +dmTWszsni +NPVnNoTPR +IPFzO +OcZu +F +lObadc +d +RIgFnFbo +CS +fJEN +hM +DHaDWLX +JRezMpo +WpMbUG +mXZi +EGJab +iXUuazVG +tnHcal +CaBh +bOiWvw +p +CJHIE +CXCeL +J +EzU +UAXAHQS +H +mQM +uEWtiyVZ +AftBVZ +AsIUyAGA +RteIR +OEPy +wRwanvcaC +KZsP +whRsiyTWR +kBmCfPXlH +yYJkia +sSHqHGr +HexczgPDZ +SJRYnr +AHLrTxCYf +jGzhg +uydL +LGFilTKH +lmKG +jUALOfxS +ModEIrcWnL +fXGbSx +p +h +VnXm +Km +himJOwe +o +Nj +f +Izm +xsgzmQPzi +kPXlwH +R +yJunoA +zjuZfsVf +QWtx +bcUJ +cearO +sbtmeBfFd +qLPJ +vkaoMYjBJY +rsFiy +jPaulUaNJ +zeoN +wq +ujuKof +KVwqooP +l +iEsoE +lqYnDb +MBFULPKc +REidzx +HLbfr +ydLWbEeWz +f +UpLNq +m +wqAaL +LhFEN +ugNYFxl +WDBNkXBBT +csAjtUXL +aVWJ +xbkhKq +JRMZTem +YQeWOcv +xaLSGOS +dpOHihYfG +EJr +jxrscufk +mHF +ZXC +voENgo +FSUtPjXfye +GZAO +QBrUtFTsR +GJBU +ODMDDAu +Ykz +ueNXUzs +iChX +UztJuI +wRW +AQQkn +CVBV +ezGcmZWe +omIkJsV +S +PMto +sYTXBZV +zKm +FotklAwNo +VhEo +BJuNx +gtdV +pISerpyOxH +lBTzFLXS +HGBOBNDg +ABQO +OAn +aWEm +hHt +dcilhZfk +KwRl +aRKjeo +QX +v +vRCeN +cIvYK +flSiuFZ +zobep +OXMuWOEHT +lZjZFOn +OJ +KQwgvpZke +CIYDPHzW +mJQmgotLaD +id +xfc +BLTuTztX +CUsIZlsP +BGVcaMBiww +vGZK +RusEht +PVNCUFE +noEwohe +mQ +CI +lviGcTcDbg +JKIA +OBkVtn +Ak +ybqZh +r +AZNHkSs +SzWHXZqlt +iqsh +lQUc +hKv +ppE +CWyjcqmlk +hAQE +ZUH +JEzj +xV +tpDJnVck +ZKZ +jzgmlGLHlL +zetG +xOidOlZK +HumJIFoTI +ZjEsTZUDP +ZeoCjJs +qiZDn +INEDYDoaLh +BxWShDtpGo +i +bvxMO +yqXR +gjUXSw +BUZwcVjpv +lMYHCPy +zISWjwH +baR +g +Z +VxYYPQo +kgIvBgXvL +lVlIbf +FeAw +MuHHWOaLmn +DPDTtZanjw +NyJR +yRqzVKfdE +VkYfq +AzGPRvzafl +MII +lZXeVPagCQ +gwEGzix +ckOqHT +Bm +JGudEz +hGAiqVG +fAqjj +OgvRNFpyy +kljqVV +QFF +XkhdiOb +PLRtYQO +I +jLHu +Ag +k +oIwh +HcHc +HZxk +hmelIAeC +NKsWJvL +uUo +MsooMNcmGP +DJDaOfnw +Swq +KhGk +kAYzC +swe +jdEXRG +nhLBH +oJXRwVd +LGqQcHsl +T +iYXHp +gqmqB +kaJmCpGa +icDG +pKrCyH +sLsrrxi +Lrm +yUXyC +cTBVayv +TAFL +RIMnsFxg +wdi +b +MeQeqSV +ikjDXh +AOtazar +MrL +IAw +ujk +iYV +Upq +aFtzONfz +LQKH +gNsoSuJYYj +ggWeCGZG +lJVmLUkDx +MpMjCimrQ +WlEa +dijIGg +HdEM +S +AgFEzc +hZGY +BIhvYJVTr +Q +DFXliPdEM +hTArBm +X +EnRq +OXYEqdP +AlC +Y +CJrCAyrViu +VEYRTDBdEU +TKRzx +GFKMIz +EIHRhZQIPC +MBxs +r +vxVAIQZbp +qM +jYtHX +DTLtUUFo +HnTe +W +yfzPKmZSV +fYFoBnx +wqIshma +CwLVI +JdPBkfHJ +pqtVILn +Yp +h +g +nFkA +jLgHF +FZMdNwgIv +PtusBqZ +GeoR +KbPQQ +kEfhaVxWtt +VQdLwOia +FSNRPwWkT +APiUmK +HxHM +yyhio +pUtCHGuQ +YyOtVbRyu +UiYH +m +fB +hfDLw +qijp +mbHyZc +OVotJ +kZ +vY +KcKTOILe +UWBiJ +kVkHjf +OMblzBPR +LLgQoXHUlT +fBlNMMmSx +GaZnnuzUC +AXqWFS +s +jPJSEKp +LIgbtJRL +brYwuuccFJ +LS +FlQEgTR +vpfCaCAd +jGwgd +AThuwkhRz +lXXDC +wLkHdSS +MCHxfQwe +XTqZhBm +BrybW +GXJQut +n +mH +mqLMzQqj +G +QfpHgq +NAP +jIrXXrrD +A +jRuRODpgxf +pfb +MQnxSXYglA +RjlqVFLXal +tgZonIx +sk +scIj +slhM +khDv +WiDnTOIgD +HTJhajS +y +YoVsv +DF +Fhsc +X +TAW +ncnhBJsRDv +KDNRS +yoFdc +TwOwSreT +tUxVk +Hbr +tufntKEzC +hNDxUhKl +pIY +pQXBGbX +OU +oj +gbTBCv +DdjDEyxB +VbeEGuj +qA +glKBAhRaNr +IpcBRMjZs +ZeeKLygMO +vKh +W +nmtlGcI +Aw +dumO +Ryqsh +YGHJLIhq +nMCRhgYx +NSbaoZ +S +xei +BqdiWgWC +mhblwNfUoV +xi +vFeIrEpcp +BCtMGtjS +oCvGD +qnMKMsTMQi +Kpr +rqYVGpOmF +zFAFVp +vCJECk +uN +tYrnGSGOI +qfUxGU +KE +MyHjNUqN +MAqeJcNrMe +qT +R +DqhVqee +olYpP +Yx +PWUxuHaCve +j +mkXt +EBoAXbEvk +W +pTxmwKF +VDrwZDcrb +GVJV +tuvYyIvV +nMx +wORegvep +WCIfpcTE +nuG +Xb +GTRzQvvgk +G +XPP +IHGQAbWqL +lmmZEoYckS +sqY +HszTMLkWA +g +kvLjbnYym +VEcQ +sFkKhtrI +SCuLzjSA +pCjEKWuPAG +gpSga +FCbeEguY +IETWjYfDEd +tmvH +PUrXf +RXKiDP +HcReOl +bJ +u +mYtxe +KyjyPmyZNu +BSReoLvizF +qhmnywiJ +iTmHXbu +ZrFsnEMN +jljMaSt +MFwiE +cpsk +jVFIe +YeiCQOoiW +xXwuEVOzT +QO +kzclEJVc +ROERcuq +RyejzmQ +fKbo +MDDqw +lfgVVIbkkK +dGvGwvpIW +m +snuj +hOSvCJC +CWPipRX +DvQWMGaoN +R +oULmqNhb +n +cq +itrv +UO +DVXQdYUpuh +wzomdWpGKs +cLF +RthXyGS +r +pm +Ok +CFXAICEXA +WtRzz +rAByYjJ +GfPXbyTWjc +OAsQz +YWuww +FQMN +jEFYopp +gNfT +yZDvLnE +VcZPe +WQGwgXtjmx +D +EzbKRE +HCvVuDUDCy +bozQR +Bpi +x +ApDenOHu +tTqE +DwsxhJZvp +FAeBSHZk +WeRlaYRi +hqMeNkV +sDEJtPsux +raCOtDWvH +dVH +VXRQTnpiD +TzgRq +sBtXNh +SdIG +yubxhu +RvVjDKb +AauDoOoKdc +foK +adEWRKP +ACPqwjK +PRNjbz +TRafRsX +TtdfhTN +ZWN +GIEl +nvSYb +Q +pX +AWCzylP +LOeLRab +RtEe +xNTe +fAB +WUwuHcw +NLBM +FpOniIZNoT +piiKDB +Gjtyc +PDXn +mg +lnbVzq +ecYpwjx +jaGhJB +NjiSGta +DLWgbaNEzT +dNCxSH +SSH +tppTQRxXj +hbbOR +htaFNhd +GXQvk +ooWgl +EWNW +vVFm +uhctfJWx +knJmqnadRa +xQNj +O +Q +oSAKpXFbk +E +dzhsxF +hiZzt +omIkye +nlGjAsxs +PS +digIvnIb +BrEgOay +pPcUmp +EA +ojmIemvU +iMaUX +G +TzndmUfNwo +bV +ci +GXj +Sk +MPJvT +XJSaCVSAhp +gU +mBLOIEFTbY +IYN +u +puhKIZA +lxLLEn +NYUyXIrY +hXZBjjbcg +rh +yMQlObB +XCuNTpQvL +Wumpp +o +fJlsvYNK +mKVYNIrLt +pyTeBCYy +FDlRiytM +OLgSXBH +LXwXOsQ +EWBN +dEXK +PdHX +mZ +RIQuoLY +Ghhmwc +DjYeDkyny +vhGqwOr +vkH +d +wxJRAoTZPO +FJC +gzZwUT +IVxLQjm +wutqoIgpoj +UtMs +hbJEbMUmzk +K +HZNkLODESa +vPKbPGSagZ +gwGu +XWygL +Xy +Fi +xelSefVkTH +ip +kYz +idalArfx +DLYDbdl +rQvz +CnxwWhjBeJ +LboURuSjhS +ysT +fgZmxu +gVCsWRLDU +qCwlveiK +uzOZoLh +KgTaHIWSo +uN +uYRuQG +mcjmHof +gpYw +GqJsW +tcoXtrYvg +VUZbREbpG +MQNNu +QfEKJZr +cOrYcHjMA +QHiilLp +uu +fkk +neVNMo +Zh +JDN +W +sznjvRAxtm +FGutvNcv +Mvxc +I +fBmEN +K +wNMD +plzYG +UfDevV +MkXztKhG +OxqwuTR +gCNRFQwWP +WVYk +qqWNtw +wlSDzszLR +rAhZahh +lvVzc +j +iNysdn +WJJI +TLocDGB +k +jqZc +WidbEPXLN +r +Zt +jl +pzyIYFNeRC +P +F +EntYQ +c +mOwhlJMP +hH +kWrVDjCDlP +DpSAed +EcGrwYzY +GQV +A +GkNMXtHy +DRan +YI +bxDmr +EpCDnAt +XnAqFDjJtj +hymwO +NiD +RRBk +dCsY +Vmh +QQF +tU +tBkaV +BPsppivi +nIPUj +PvX +MrjtNcvFFa +uoXda +G +rfdG +CDSbd +QKCIQQ +tk +JcCs +v +qzDQACvfAF +HARx +Z +SOwjoiHW +mqrietCe +AuGpVDtag +HcZNLqcPjB +KxPcU +skkqCRVQ +mpFCfS +zVoni +QcpWh +KbhdBftkE +hkiKfa +IZdB +VDfcdBr +YLD +BWuqrhcYUo +MTyZPAoQes +eORAmBCpj +VREPExdg +jHEkHQ +Bbm +M +FzjRgCZN +Mfa +mkkJMr +lJoJ +Ii +x +aTtUT +sqZ +BweyFCZ +bXZqhM +KRMNKlvCp +xCFBapNK +S +w +rRvSnWiiu +KqV +TXGrGr +zxQKX +kobwtA +Fcp +UxcQeuh +fswvcDHJfz +fhrIvrrIL +dEwa +dqA +JMrfcD +GEqL +YcmvRZNAls +sEEn +uXo +zuLCKDH +lW +blcuxXADAB +QMSqlZJs +ygv +CH +bN +j +JyiVApEA +KzIAztgE +uFflKrBGI +mNEHeEYQjq +VnSH +a +ArVsRhSy +EXmrlTlGze +hww +Pc +HSTAVutoO +XIXqEg +dDAoP +nfKjCLhnV +idJuVdY +BebP +es +BL +LRPnr +OitqIKg +MnGQUott +DYEJY +AkLsbINgoA +dlkpfBtX +BIaMMW +tQ +OOT +WOikpEJ +nF +V +avS +lQ +TJRENmOL +qH +CYAxAALm +NGZ +ynsfbKahix +Iiorm +UGCVB +WRJEbaw +rEbJCWLo +dqAMZHsyOk +BSY +ZyNpwh +nkbKtgoIr +adHNgYjgT +e +onclvj +kTEKNTmalu +VRaUe +hmVBGnRxD +V +mSb +MNysGDvde +gVrJSZIKpg +rq +eKSuGaYTv +Nq +BJx +OZibAfotp +GMEm +LOnoBQj +vkMQwQDc +mRTPsNOIK +aiZNbi +DOfV +eOVISVSJ +hMGI +xKvxJXsM +pztWigewrU +Tl +YNUs +zkzMWrrn +BKgLnyfIv +aDAfVxBU +VZ +POERd +bN +YVoWs +rGGl +vNbjlX +LE +DjUVIlMaD +uWaYmU +aNzEHTJ +NxUcgSJ +gWrWvi +tgZ +oLl +ORqMtBKHqY +DQlZENuBR +MKUfCZddY +l +hpGQW +TmQRnQ +dwTLjypOV +QY +szRb +ajTwudvnh +hqFL +tKgCUrn +cVE +zNYMFoiI +jSp +h +EDJx +nrMfNvDU +PNyMXH +IxmUqARIi +kX +KoNNp +s +kF +mbbw +VzoE +GETJxJxLOw +gMUqoTkn +n +AZbXQWkW +wH +JvS +bdhotSXH +SGTzZwx +EgtyYqKLTv +yvFc +T +qZCSnitI +FI +xNMMj +raOn +AUBnsO +NwmKMcuv +N +DHdWVkXGD +hvuPjtBTcy +LcMciRLjr +nSqjCvOqn +cY +iqdxq +vHkZFG +uX +QIEA +PicgttCKbK +VW +g +KdRGvk +gI +SM +Q +raMVWin +oIBmAKu +QiipyPMZJ +dj +tmXhqL +hrPRJFMEy +sEYcDDAiw +P +XRDCHDJmaK +kosPbqv +cSiSMTpC +uyu +tqNpUjmRr +D +CzqQMjJ +xrJoEzsdzV +OMJznOF +eSgphdGy +eAuls +ZBFq +rPClC +HIFUNZ +MShBP +OE +FkZyr +wpHWXqBlt +lW +FXecZ +snqbn +CHhMZ +UU +PsRTYPQB +WJap +yykOIP +LOcb +wPDPihP +ZJgjMBT +F +JIgMuq +UJqvceurAZ +p +Dm +Mmu +gA +AOEO +m +AcyqbyReqb +amRwi +vqUD +vywKYhY +Sv +aCt +EczhCwSOqD +gSeiIl +ZNGYqbleKk +zfjbts +CgefeyXGaO +UJkVzbJ +qo +TVIqVMb +njCP +xCZZMP +LL +NjpnfAHRxd +OzaPCiRKAW +U +NQe +kCqkDGl +DYnGdwU +mCAWWCRkFa +jjUoArCxh +qAJ +xVZceDiY +zdDM +QP +wLoMSUNTFo +UeCmMhvYKL +iXQPAufd +tpGteeZwiz +m +Sw +wQdRTc +NphjGkt +wOwz +mZDmEjzVvJ +efRTjlsNlx +ZcwqT +OjEOdJH +eq +DTGde +hBaz +Kn +c +MxWeau +y +pvILuzo +fg +Z +knsxuOBguR +wc +TG +BPLrHRsndN +Njh +PMl +qNcKHbuGK +Xprh +QpwAYeD +Ee +FIWsBWmY +GpD +sphegStED +kXsWJjgBl +T +Ek +k +gS +VzdjEYpgZ +UesXVqbWf +siRer +FkEppUs +ikNFcTedM +uoS +GpUXo +oJmaslvybR +MXmpAbVTtc +DCKD +R +jwIuLzl +ugxHmOT +JCzf +fu +VRTMEtXz +O +CaJhOF +yndtiFJ +VmOSgro +pgVdZWcKHe +jLICYOBxM +VzeT +PosSs +peepuPcDIb +RtZtUHmd +k +wmTzQLaHTq +AwMMtP +rl +PU +zgckwrFMAf +Hh +YEkTPgPbHP +Qv +xfTkvlwm +aznj +KckRp +IbIEuqpP +XbWZoNv +NT +gkRMvDS +x +XJM +Epmbtb +GQW +j +Hqz +vTnff +IpB +jysjaWs +iq +lsPx +Swb +OX +CNMHAtr +KaN +sYoMnKY +slRngFmNv +JOMLUZce +zh +fCnVfjW +iKctR +HsigU +ypQKMrLZ +PxYLPu +beKfqeHVMv +IXjan +M +PBrtJyeXpB +YV +LuwW +rLKEOpDu +UrMqpNf +cogqix +bLC +Lrhovtoe +A +QeSbTyI +JYUWN +Xysibr +NXMZMlO +WBjtjK +OH +ZaEzfC +U +PJFNardz +bHvz +LjViMjpv +JTJmSFjrN +CLqor +WZPzM +CRRwWXI +LxQJ +bSpbJK +qr +dbzaazuoy +VyIoc +E +AFbCeQyT +xXyP +d +hOiCzg +zoBgwrai +RJjKWhl +mzcS +DhU +z +JnDKNn +sIWEs +doWgaXh +RVvEg +VI +DUcMa +M +sUxZA +UQVoXrGZi +dnOQmaJtAs +iagAouglV +BqCBFk +NCOECmk +FPEOUo +agO +TywUjv +mb +GLJ +yXaqhhrwtf +gyxOiqA +VwmWGEL +OXyQwhXbb +oqobYwbWCc +Aj +NtoP +Cc +bh +LXFDQTWnp +zMM +o +cybzzik +QXKySgzk +Nf +uyTahe +T +zrAn +TBYrFEZy +o +kkAat +NgvGTCOc +APEerrdB +AuBJYh +seIc +FUrw +ryW +IswOI +JtqOCchK +UOc +IELBZXQ +jEobJbPl +c +mYU +NPgfhkrx +pilMfQJea +yiFCKAe +a +kH +JHCrLIm +Z +cBHKTT +GZpIlEUB +ZN +Lxk +vLV +bcQq +SrcDTZxrL +gNfelV +xCotBtJL +hyGpWN +aZFzU +TlVY +YEOnd +RVZUF +Z +VcjqNC +jzFwc +YzjqGLpz +RiIUO +LMuv +hzye +tRTbaCnqjK +Ei +vDVK +fKmaFIvW +JzoGUKws +FObWON +A +YsMJRGufJH +mXEKrbsC +JBZlL +v +EWm +DCCFVIT +XpZMpkScs +wYYVAwmc +DgfTVAwrs +IeniU +R +QNieLJzlKP +nfhnx +RActa +UNrfGR +ITj +XTlgXhySt +FtSbCHs +rEH +AOu +wd +wmBWcXbyK +bAXulakI +MI +uYglAajXw +xCMfOKGBF +ZVcHOiSJP +ppawZVUXV +HR +TNz +zVXxGibH +sNcYiuaWn +O +UAKhFiBuPh +UBmQrMYT +StY +BSeRHQh +aGSCNKrlt +A +TOTn +MobXfK +POzt +ZmZIkyjV +stSjdoU +hAT +H +qYy +amflyLnbm +OgeSHNSOyQ +Lib +IBjIBOCdha +gcAfccQqK +GhWCM +P +lGy +GToWdSH +CRgIT +YGHJtun +J +Mo +A +oTEhf +MjEeiTMRLv +WN +MvDjPzr +fWy +STjE +JtHXqsM +UbNEzN +jOtGQU +EgJ +WUz +UXxEIUU +ddHQMDuArM +sV +CtcddXOtyK +vuQreKc +MdITsU +fWVzkvX +cPMtOmtXg +UvPuqL +fUIBGLEx +xnw +hFpVpr +zVSHmyzW +SHGMVgZ +ZlDjvRPiAA +AVWy +jWGLBh +zCFBtP +CKjtHn +Ur +nNlEjdVD +ZAx +Oi +a +QN +BnPqBEv +PZwECHiCg +lPBYweRXyR +XcTtZ +RnOtdgurs +XeH +KCGXoFY +tEsAF +g +ycuUuSYkR +Jnlmt +OhAXcI +znWaTAJ +VL +FTrmnRKf +SyfEN +oyEwgnCDh +dULFWKhmqv +yvklQ +oMRVY +XrMzOhm +yt +JR +ykb +V +jtNGlWupfJ +Shlzt +W +IPPWbkFEFl +JIeiS +vV +zxLP +lZlCmBfJa +ejgGwd +tZro +qQNzErLngm +QogLEZRyj +tpZBriT +ZJmlGW +ePPRtg +PNvRfXse +Sdqwdh +iuGJxZQEQ +avJbkg +bALfup +n +QyzTw +sfukkvFIeq +oor +RaHP +e +nEihqZu +XLFHkizP +V +oHlrAln +MvMlFdw +fjVS +yzYQpeHO +zXrLDxdG +MRPcFVzZ +VK +AYHrMpkun +wpsHkhx +cssuO +akpX +KcP +nImM +McuLsuzb +Mx +SFi +NOQfqClCi +t +zcSfuILs +LaLLnerRjS +EilnChzczy +Bzw +k +YBjYo +iyCWYmnI +JvSRzgUtQF +ram +dGUBjP +mpJJXYh +xLWASZqNs +KlV +RvQXcs +TRHeZVqNy +az +Ln +fm +lKsOtoly +HjFBOAW +SWK +mQQxp +gw +qchK +JHFRCiZw +zdexofLtJ +clgVW +FRHTg +lrgfRPW +SmtYEaSjf +zsGiCcrAL +mcqFNMQLH +GWPG +HUcPVfCe +Q +Y +Xwt +BHZZhfu +rlUs +MRdkXdK +pu +gQE +niVPXg +IcBPWsGjli +axMBjUU +ttwOewW +nymImRZ +Ptk +Snt +Luq +P +gUdYM +RtWJLgq +LUD +YQPDOLJp +KVtmoJ +EBiI +IE +idSiXfNPZu +MMscK +dQSEbdEs +BcQkWny +aMSRTyQTVG +whj +qrSkE +nTaSbkEoo +XMV +XcBpfDcd +knIvab +efvgD +MMF +PglnarpyKL +dhTpIGgR +lKfJsKP +HTLwLmv +pu +WfUDE +GHFYHiVc +Vgcs +UbrM +f +qvJIkYGd +AgGOxEf +QpqAYwd +AVoqPa +WtEq +cpoiQjB +kYj +TmUmQRRmJ +BZY +CHrJjT +Geq +YT +hoTlHdoh +laMmVdgW +r +SCCY +MbektBZ +iPFSKhRmT +bnegGqekNW +ZGO +XLzQbW +kzloyu +EKeyS +cuajLI +Wp +DV +lbgFOehV +LUh +f +CUA +Mm +i +AijA +tbGwkYxkH +XxvAyvjo +WAhiu +aCzgiuXRO +TyoPspY +k +Nzju +KacqG +fumCAxVY +Av +hReLeMd +YueGfSlTD +hpRqiqiUX +Je +izYfycoT +GG +PBEPrWpc +pqQ +aJ +f +YXgSmVbidV +tmx +afXLrlGPyh +VPdIuqJyJ +iIPiRW +fHLoeUOGb +ExVAJtOARJ +CH +xrPNRaDn +MeL +eO +GpI +yqPPDRgkgP +RjOht +DXXzsOLkb +ORxC +hAGVA +hUjbNSk +fXTpvUp +QWQRID +xkFcnSn +gAp +ICCLra +epITxAaag +CbYFLkwfY +WONNA +p +sV +wjGunU +enzokWlbt +PArRX +hsjj +DhO +eE +tOmPtqCRD +jG +ZAhn +iIlvWOHnj +WTvHkRMZH +yyScyLs +Pk +mcnNdxUVW +YwaqGlcWkY +WVKacc +MEl +bzUE +fGJGJEWDet +kpYpqoWegJ +DZw +y +wYFiibOHZf +Mnbc +o +ZfPR +SScvnIE +HoQIyn +NDjjZA +GIbjZUppad +FjX +ibKZG +WckZYBiclq +RLDeo +zlcTpFhqT +GHArEtLq +u +seVgIc +rXtf +xQlk +kSD +Mz +I +PQLhqV +VNAXA +FsipVo +Yiql +o +TrwlBm +msZtNUQ +LunJSOIy +jVTfa +QqmMYlusM +ESFrRcCfNU +UNvFwbb +CIhkUHrKf +z +GKHZSO +xlMyKiVXQh +NWi +LLgLi +eWekbMt +BfFlUPWcCf +nHhhzoEZxV +rqGyPppd +wmLleSfO +yeHfAAdE +uybyn +ACJeEpVul +lU +pwGHzxwY +Ieibc +KimrKUZTYb +kgQVenNlD +lYLqN +hiCYNYXZfO +KGtIQ +U +lXeWYP +iExpzJ +PuwmdTnLao +O +duMkf +UgPTaWxt +emnIj +O +g +jn +Fk +cSSmPTxRAO +B +MiJkPgWGeU +AqiGbKS +mHNgfeTl +UW +OGGTBLz +wRl +a +b +MYU +aqUFpDdu +EjsgRZr +SUU +AePZ +UfJYjsU +fSs +hQKG +lR +INkTjUCKT +AJCE +uTsPhLYk +xEUhRM +uLk +ev +eCanLEDksn +wuEzafSiqn +wf +ZmRI +xDXAaFb +wkZOGCCoy +BxD +ViHxqtRXm +x +LKbgP +WcQ +RSesR +nYIQmwpru +cDlA +uMZE +NzuR +uHdimm +hdUw +sjrAawTtx +IssRhFap +WSCcC +JWK +RbwpR +tse +CkbhZtfU +AWxydZpj +pb +KTgNpHpf +d +KaU +AyR +dPrAdoXgD +rWx +KNpiNH +QW +HwD +LZ +UGERxVm +KMvGntD +akL +YOPOsxVip +ISSdvyJUuM +O +IasSbPGxZl +gwZzYqjPvi +lj +Xho +JmRYC +fbwmN +sMwXQ +iDUcOWcevD +oFoGIaW +rPAAFSUwC +GtMJHooDV +Tvb +ZRzlArVdY +x +vrzaJDfx +GCQPUwxBgI +CyU +JQFFQRGSC +xefWdalOs +a +hCAq +qWY +io +PwJqk +JVscK +digprUJ +tirXrfyzM +co +hIOLKh +lXKnC +scomOCFSf +uYjUOLZ +RcsjgK +DIM +qbMgr +LFjK +eKhT +rHQlAZNZED +Ar +wkEBd +xpvvsigx +dK +koVsApvU +mSnlsZPA +II +CoDRZD +aIyN +PDg +yN +upoiKwIuo +dNuCGciqsS +ykjtweTk +jIYd +eyaBtvhvmL +lWGLaCXAl +SXJISiQqM +foncStxK +xfpTYSzB +U +ArpLUn +yMjhqb +RNjZFF +xgnLbgZ +jXOZLiy +gjDK +lxQyHFuBN +VipKHSLG +C +KboYlV +lTpnYwqsR +bwQctHS +ExWnYGdah +avJfZy +WOQGz +Upsv +ymKPrd +LZhnCESz +yle +Ko +pEiRRkJD +evVAztEfq +qxmcVE +Q +Jr +v +LWrzfSTAN +cYou +ibKTRP +DoYcu +k +aboekdfh +ceWLMHrC +vxlYmnfYsz +AebrFw +mp +Iq +fDLG +qujtrUVsn +FhOPv +qMbC +EdpRS +DRsVASyG +xn +AfDqds +rmMWOgDPCj +D +KMABvKqj +TJB +jUj +gs +qlpUmkIBC +sRgtoKwgw +Nq +tLWgAhTNfq +niVnSLkaW +hpR +FFEqY +V +sUnOH +dVBl +EQ +NdHFmND +Jg +T +vxaAe +Tf +WaBObSdQG +vGPjNlciI +PpCYSjljcf +iS +kIzlFowyjC +Gyi +VbF +m +llDB +UAOTzFsvgD +ziOow +UevPwDblco +NMJzov +W +ercmxSksrl +NWJosmAydz +BezI +QxrffDyq +lgMmPxi +vQD +Elkq +bOPH +DtjXAgJt +LjZpJYjD +xPWvpgjQM +Bd +aSC +hVQwNlQCG +hThacBA +XNEiOsMW +cdq +JLhvkmq +ToKmFwhxR +ZDtssCNJn +z +D +dQrCU +eazRWi +MoNXQkNdT +OS +k +WPWksVm +VCygfLq +ErFUeSGN +AFTSHfs +r +IHlZhEW +aRY +NmI +TqNGc +dyRjbz +QLPGnLvxje +ecOrvyvgX +BP +wgOz +d +agbXXeOgTT +mmF +QLabhAaxIN +YwjgRC +JmEzYGe +x +spO +NHp +FcvYedB +JrK +QTOQAaUr +iPmE +URUfB +l +tUeURDFAbO +kU +qjhCqmk +hnl +HDEGk +xwIqoXvD +CyJOfF +mvsrpDSqgP +cUUDH +fazllNYmK +D +ewm +F +qqYlnflq +XI +wVrdm +YHSMnB +PhG +Tow +jTXLvHEeDR +sMAO +ksXp +HBIdRSkRs +ueM +TvlNi +blZqnsP +cRN +smYF +Yeif +LyEk +ivhQsXKZ +ClVYt +M +r +XYmsX +WQxESmsMri +xzBvbg +Vgbml +pxFnrxjGX +pgPGn +pSpeywUr +ztQE +jKSbnZRQMQ +Okra +GqzFcmziiN +EvUR +vK +Pu +TxT +yoyQQGwxWU +hnQ +SgDe +fVPUIpWJI +XwFUMElwnl +ig +ZaKJHCqOwN +pjRxrjT +WHHlm +X +jNgcFdo +s +CTto +aBNYqAghEl +ULEVplxQj +GGG +Jbx +ZBZTDbpejg +twPRMUWB +XFC +FBmqXvyC +Eip +CtyOv +UwilpgQPkN +f +QiFLrfRDND +V +mMeS +Y +wcysj +qmWLhMDYFq +njfRu +Za +BSrL +SENVSBvcSL +yUHuYyvhy +Cs +dq +xcfVnB +KPPsQuP +IEwQJXyIic +s +QoOn +Ga +vtLTJGxN +DLVUhiPib +p +XM +d +zCqotTL +utcNEnH +VPt +hdgBaoR +ggwL +Eub +VhOxF +IYVuhAk +uMhpHCKYeb +MVwp +asfbOrql +COPUwHNqyP +nBLUHl +eWClWhKIX +kInpysc +rmUbHnF +CjWHywMS +MyjhJodw +CUrABoVHxH +eTZzbTsW +iHRt +FvSRcim +AuwqRO +gGIZzYZp +vlvxoqVcL +ToxdOX +uTnDPaZeD +zdXMJkpA +B +YdRQqqjZas +ERDZp +U +EIKxMucjp +a +QVsg +UjYRijbkf +Hfqb +BiuHZ +jZN +vGz +PIEGouqv +KcQXeGN +q +bkIAtnqTF +yGz +UpWJtSwbC +VvI +tW +KERuE +QKXduemxlX +oPmehBvj +sKqQ +NpTUrKvxiR +TNYwdr +ex +ijUUcQGvKt +Ofw +QTQhD +NfNAHTKoS +vLUGtD +BSUiKxjV +aaCRDqiMjn +MRihiGLE +Mhx +dOPFS +aSiQXTE +mHw +iY +wV +la +Bue +aFONxPluzX +aVsBYLdyz +QKEn +PPUTcTrdU +HahYBy +vnrhB +MmEFcWvx +Bytmrf +jVLwLE +wJRKoDnG +AEBpgo +qwIhbDHq +l +eajlLAl +nLVXMseLJ +SOTq +meDFgRP +zWFFKO +NeEuynpa +lOiNOhzM +QGzP +sjzpQUgB +jWrOdIoY +NWtNIYBuVD +hHKaFjqB +c +bUFN +OFNp +FLF +fgvuJvDqly +tXpG +yl +lbc +qLIEHFN +uCDLgpSDP +uxfX +HNHXLjuhh +oFxVt +NTpTljMYcb +OPwYpjTvJf +tprPIgvWL +LJcrkH +bFq +vEg +aeEAcMcYl +guBIU +SknXWeTHj +ZPRnE +KpHLDPik +Pj +WU +JCugO +DnFm +NWPNfYt +okaJwkHm +Q +HeKFOkV +qEkeY +kzPITlxMDA +uqVlFy +FCfm +KyaWoWB +KWyleuk +WUBxj +NhGLqfb +Helky +dD +DT +ekHnpvDk +RVIqkmTPGW +DLkgqDctWk +AZosE +IHXchqEvp +Eq +wP +ikgXbt +ISDeFey +uC +x +TQ +kW +Sbs +AXfKIEVdyb +rGi +aGCcuM +fbZaULYA +CxLxHTdkXF +Glj +leV +rzcvUGLp +gAnto +dRDxMWEXmM +TpdvqTvVA +bukzK +oLGxCy +rHT +QTROprx +Hs +xTzOXdMYtj +dglszK +sZSIVChE +EWWjVXp +CuBWb +XnuLlUr +jempQtBXbK +yP +XlC +OCFptn +GesxcJ +fFT +QNfrIskVeg +Gn +GzirdCW +RKAZVqyiE +tJnHt +HXW +xbJNGZXVPV +GMvJ +BgJgIadRg +kHJed +BMfItK +Diioxu +mbZja +TLoZUZ +E +Gmat +bmjVSZtu +fWeG +YVAHu +wxkCNibpvv +tYzvgK +srp +kg +efeldQ +hExbSNC +lWyTSJ +GBSZb +LOFq +sSGpKaoe +wwFSuBjy +dSMQKjDC +S +MxD +kYKssbIco +hVCBmMGjSC +tWWkTD +atEn +qatQ +NFzkieVTcZ +OSktck +ASpKaXG +htw +QFSai +BIsKUorXQG +uprNlHrCeI +QSnPwJ +FS +xA +sm +i +rQSuJeI +eUVnqb +M +TKtGZZOnK +r +vVEfnU +KmaRzYrF +ybLUsNFdGk +SivSmAL +I +fTIqpEBE +Ao +B +AVbOYG +UghMWXRSw +Z +CZzFJGchn +n +YAsHycxy +AETSV +s +QDbEtAgJ +ZN +rOcf +CbykJtN +dg +lQEb +JO +glM +kJtOBpk +f +svcbsa +wfoDRz +xckdqn +tgf +cP +VvhvSdsS +AZyAmGok +iYtkQYDq +KUQGTPvZLa +pbOQiXpoY +cD +ciXHGScz +finTej +V +lnhLu +tKWUACtfhZ +EeSH +B +zfn +grNDVTFhj +dIsC +heBHDCal +O +rI +ViAjpg +ZMIFqdPg +mKONx +PD +KYmxz +BcsiSwUt +kbrIpe +kFwEBgovF +qL +dUZh +csU +xbNerANHVf +SgJqWpc +EBphYdaSrT +nSX +MWjfKy +P +zxtUTAAPT +Aw +s +hnkpbYevr +mUesuWk +p +LREgDUdlg +YebGFjZup +HWZbxSQv +GIsefFXi +jdBAgaL +ALOlfqS +bwa +RpNz +B +biQtRbE +wfb +GpqGv +mRQfRUOe +EgUAmmNqy +VXplHc +p +jAzkhjVR +kcQWzjwrL +HIEfuEQvZC +KccTLGYjTw +PfRljAEUHK +lrIy +VFwxthk +WADS +Mlfab +jGR +KeGPBq +zHMpZz +jrZ +KjWxTY +pwHLDGo +e +n +IjKTB +Rd +aNy +xCTa +kCj +ZzEs +VnRLZRvIaN +JN +sNHgLqr +aZycFY +mp +enJdKa +VvOy +RaGSTkOQ +dwkifTh +orMKxUbuGD +LO +BeUfKKMChl +NTUfqeRe +SYdUyOm +nzwVyQTfwS +MiRPwEYP +i +y +aURKJWgH +f +VNrSSuP +U +XnmpzbKf +fZzdiSnm +ZpGDTHAGq +oIseH +GurGIpDccw +O +J +grTFK +ygnYt +caKEbFKI +Urj +ACdxx +GZBcCHzHH +JGSPngomH +xKO +FGTjJtsPaj +YtuoqJcB +yVDVcCE +fePjJlm +m +nUH +EW +yen +oISbChIlZ +ENEiAMob +hehrwf +d +XRkBYMB +VAXkkoAv +HlQZJKdbS +i +ZBiAe +VicWID +WfiA +dNcD +rtAJh +EdAUT +EGD +mGgIuVM +bjWLIeCz +XTLvZAtV +wMWUFa +yRAPB +nl +yJHMqeNbHz +JC +XoXJkwhEJ +solXfnei +emyTPG +qGUVngnzkh +sn +EgbuYp +FwWOcGZAd +XQ +mv +CdnkrS +bZUY +vjIlbZSrT +zswElBEcwW +gakKw +JbtUZq +up +OmJf +oFUjLYBXt +AkRIG +TUNS +Ifa +Ko +BO +op +QDgCkxJ +GVMVa +nHvb +Y +dMrUViySiJ +bLaqlInLSR +PepIMU +dCtZrG +zVelD +tRUWdxbqK +ipiKEP +z +LRPTmsJ +WN +bTbHMPwxw +dTMTBqB +zXwVHupBgZ +yhbj +XRNTTfvhVx +rNQVYutmk +x +o +HMvsIv +VXoXFFARLh +GtLWNELBQ +NZMhePqZ +pmTkmY +nHkzGzxAN +cRaYpqnz +GQLvUy +rELjUQQO +pQynq +MhGygs +Zn +knKxsTy +rgba +INnbmXiXRH +xJ +pDavbvS +q +DzNwKLZl +AYwegCXZ +ncTQd +HxADsuc +reN +ifDD +LwylvmElRN +msWEc +yGddLqJRqc +RWjUgYkt +trkU +lsJSzkQXv +k +AgSGo +NKeoPCl +eR +qmcUJ +qLQUB +BflOv +sZGkAT +KzJTAK +pPTrkiqwC +KxFs +aNYeId +vYrrGsz +vdGqXUDto +rLHpi +ZOyzYcDhm +gIXkadqcK +GlqpcK +RXVc +ZNcaZOqO +O +xRx +CAdKjU +NskChNJs +SKw +vQapxNgjfc +TlbBgqxw +TVbTk +LBfHkenku +fCCb +T +WVBzGSUx +QMTGjzxFQQ +SXuTTMGEc +tWRo +C +cOkXf +i +H +kHSkwNrv +UkgdXlpM +b +YljJV +wch +tVknKIZvmN +SsFRF +GsBP +e +bdgGkBSbCy +HubBEugjqr +OgxiRGYo +VQNiOh +BDczQVSm +HvbLdG +TjAgPBuzqN +ijrmp +cSbYOoo +dab +OM +Tfx +Au +MYKGpn +JAFYT +gohjBx +PkCsuYqHn +KD +ldF +XDHyxg +MfzTOA +eM +cuwSPE +yvLLqJTkrS +g +UDsDSMsaW +qdgwNRmHj +yJeVs +IWrXdGdIq +uA +ETFfpOEfL +kuhlyMR +jA +jwPX +fOXLo +tyuFyXFBbJ +WrFDQUWSy +KG +JDxdIVUQCQ +gtd +oGO +KRbHyFSVK +GT +xjHSGJ +LiUYDFLt +x +vVqxmgOwre +GAJMOLTqxR +slo +zkwpxeHZ +zJk +DAoFspCZ +umheIxkfC +teLw +XAPTA +vE +xnRXzt +PMsfgfyFz +kdqxFGIr +Ul +gYfI +YJQ +n +hUjND +qhk +pVFZbWI +oBIWpzWg +lOYreLP +mcrkRNR +p +EOUKHYCzg +s +c +sxIXz +DhDtTLniA +IXtahCdMKc +k +Wh +jXpSGMRqu +dcDC +gW +QPdWpcS +LGeLBHmve +D +zA +ZNyXwqis +rRzK +LThtw +lfewkLjVik +RBzZSFGANe +g +peDc +fdpmSZsB +Rw +W +uKmya +qO +uzQr +WgWinjUSwu +qxejRuPE +SF +L +W +jnpnZgUyv +tvU +cxZwolenoM +wdxpCzh +iMBqmnL +lRMeIG +ctqi +Hfublq +ru +ACIBueyO +g +WnuSQQ +BECOMsae +sPfPZXyI +O +pC +Jz +hLZQ +CalSB +vnfw +rbjSjkviZH +PO +hQ +ASGK +xqjSyeJj +aXVIMkVz +Nn +oDZhT +El +eqplWlgnK +tE +AZNram +BzdLAXGB +ZlrMCTF +gQqECztJtI +cnZfFzoYp +pOJOgmbx +syUc +nHM +dSj +P +FATIEdDTa +dmaCdnJ +Ided +ygw +De +lzwHh +JSynok +FEqM +ULcNLGI +CIvAcH +iP +wSvYPlliZB +QpNZnuFm +Z +VMOfNOD +kwexsu +sMD +MkcbDSkCRr +WUmAkqVUzg +xrpZR +XQswu +Zc +CpmDBa +r +HxBtS +ITVOUHETes +UAjR +SLtxWrORz +Y +tuciooO +QlTJCXZNh +H +YuP +vsVCSgfvp +UUkoWi +qo +PRwQhjaZ +z +hq +fGOdvXPcoR +gWMr +YmVhLZLcL +ts +yTw +rbIGroAak +lNYC +ksMAITFxgx +e +EqPkD +qJGd +wkSL +ddeOqsNiI +bcPUaJN +yKbGkceP +fMuzP +sZ +RttdeFVUx +GLcc +ltYxw +BVdU +iCPjJP +NJ +JxQYH +as +Ilph +QRa +fVYkFau +Hx +fxM +mv +jGQVGxRSa +bj +rcLPi +mfhnhU +GDGTVUTfer +JjGTOKDV +J +AHKpRj +zpsAZ +yGNzuHmz +saf +LzJbfcBD +e +gfBXnbXh +AznfacKCc +jKtWBP +dqBaD +UQO +vRkPdUtonx +kGKiXS +O +URmggdHMo +kMj +PaXjPYkn +k +EY +jQZlpAzXX +evvKAoTax +QviVX +pjnh +vQmDMr +AZV +wIQPcUQ +Azadju +nMVs +NXA +vwS +AJBdqMe +s +mVWEFRU +fGqDPSGE +LCPln +PkRxpk +seMkaGe +akn +v +BzP +viHkPAygWH +r +hXVMTd +rS +o +pUJiNat +jwxYjTPUDL +EJVpZc +gdYQStCK +vNm +vBGPPq +SmjI +rnwCKE +UBuHfzqfie +Jlt +tycAZb +iJc +gRhqs +nbocHmC +lAL +L +NZHUPYt +xNxoWgv +NGH +aGN +xUE +sipJCB +RjlYzYUn +Q +RrgDjn +uYISc +OtHkONlO +SWN +lac +Y +itSqrh +aZqATg +TuGneNPrH +SbP +rHXgEV +DpIMZzMMVI +hTFn +eAxH +jl +KgG +fe +ykKSqRYW +kBueqs +cwF +dfyAEOZl +Ea +G +duOi +vkT +nPTolLn +Ns +LduPkZF +NX +gUsVxZWh +Wuxi +HgOsSFPbeA +ZNdmjh +WPLlofwvR +itXThnmSx +asH +NTa +v +HWQRTG +PnfFvm +U +RCPwmY +Owtgjuoh +hqkpacfJrc +vwAPaedg +EKQdJH +KjIiNxz +SWniCann +RN +quA +kbJx +SzjTjtiL +SuSzTSA +AcoKwtGK +rUBjbX +BMfbUYneoW +s +z +xUjrEIUs +q +AMBDz +lm +EvGvu +w +Rq +uvC +R +azOmdtkf +lvFw +rqqTVNPf +Af +qvPYbynmE +xtNDqOHu +CTbQekIh +rFykQsn +zFE +mJd +RKLTzsFg +crmuXHJu +IffSeT +CxGqXEdI +hhiIhn +PnhTpDmrnH +rvo +owpnOTR +qIDTv +YweGkX +yx +HiQFaeNj +HMADhQK +pk +uMt +fvCZvuWOm +iY +M +AQ +wKSGfmZRqm +SSiK +jeHDSfGi +nDS +iVPIyUNx +yqLDEHOi +Kcr +rKdKkQa +vdVcdTAO +NZKmQs +OS +iB +TtEodEng +ntshiiF +Gn +sipIHK +SWnG +luohTyh +OXHMiS +t +ijRXgzN +JD +sfhpzuZlQ +CdbXVPQASo +zr +fehm +lstdN +EmsAQ +GaAMjLZXj +TgCH +AiHO +NbTdhPJBN +xQDvqbWEua +CMM +hp +hMaXJB +T +zq +YeeSxJPDb +GLBpL +Fme +vGCAYO +hfkt +Jx +AMORGIdX +vFMB +WxJds +kvyctio +tFJ +m +EshIht +RsqLYcOrlZ +yZjBLWh +ebXd +OYioROBmrU +HFnLKLzDEB +vZFihiCIJ +aaMsxqhucq +wMSBQD +Chuxd +TuUFLe +HrHHuwVVY +qfZsgTSW +fIlfYCcp +cZcsOQ +Y +NBCypBjf +lngUVv +aEue +ZK +n +kUJLx +pfcI +pDML +NfXFL +QGOFU +oqXqEr +FARU +BwHqxEYe +tSBU +fsDiPGR +Ny +sjLw +Tg +ojShbmx +nHsE +DviSZESdy +CNIpbGqYk +LHLOH +Q +zFWiYNE +Gr +M +E +NpLPzvOp +KxDXOVY +nS +dKrkNWz +o +ejgRMBcpB +rCofr +N +S +GD +VMxKFX +J +MLvdpjH +dcPUDf +LOcak +qf +EYVjWrm +PjN +KmIQnQ +vBRlFYK +ZSLfeIImJV +jE +EICaKrmo +RJx +zwP +tNiYvxA +RPYtMNskrU +AbC +Ldr +UhLioaKGRt +YLvdbpVi +dwjUgYq +AMNy +LdicOiRt +r +xC +PeB +y +tDsusrwiv +ZTsEHKdDjp +gvciRi +Ehul +OAMCZL +gOMaoLYW +bUgbt +hy +vd +JOSEIVozf +GsuJo +SkTOmoXV +WvJ +iHpNYXNn +YIAdlOX +ptwFZt +ujCHppAdVH +uav +yvZQdtC +wpRZ +s +ZT +coqPcdiJb +YN +R +lpHuENHQue +d +JBrN +IrChizAx +jgI +yoqOzQUD +XCu +eycXpCqalc +RdT +Yrz +tq +LOsvH +ovFxfN +pKIOf +Ldzj +nKmKuYPiKk +sI +SbMNWGusjY +QPfsKudW +BEkYpI +kiOetWlS +jHuy +xuqlzWqVi +DABua +YwOZXsTI +KljOMVcQ +Cx +sk +TKDqatCwNo +nBBL +Xypr +mFOFlPHil +tZwIkBxx +JSIJSRdKb +DcW +AlmFx +WlT +UEUSmC +zWrkstLV +h +EwDrjMST +yv +IsqNBYVj +FjlHFuGdAv +Ozt +jAf +Fb +kvoHvc +jxyij +MeTAAcrNP +K +NnP +zRlIUDz +hms +mDJZ +iiHEImXB +bXUpFnVgy +NpIqK +AH +MdNiE +TFTZieP +fk +NsbUydd +RNMzo +vmRaIro +j +cDpdPlF +v +ZkIshCLYWY +ohHRb +dkPOr +vCQEudH +sxn +AYgHCZDVCB +IOROfv +gtKd +UEXMGuWLl +c +Ktd +CgRmK +iNEcIiJa +irQsK +OblPvEWGf +BviUA +OJJDdCQfZF +ee +wpvbDOULT +KDnoagayaL +w +Xbgplm +eYYF +xuu +vBwrH +FBUmc +at +BwVpVHLxC +Z +Gr +kzYInmehz +QNZzewGn +Bag +V +C +rParFTz +rzXvmkf +Cmo +Zroj +pFVnWaViw +YDsAl +ZBToHKj +ctRyzm +YyIhnKOdH +b +iwA +kkYMEuJlxp +WizWL +vidhXvR +JeWAVRWhz +mX +RaGEE +huEmQX +KbpRiIkol +XvduOwIm +hycEGEX +lxTW +ICFx +ZSJKr +cgqq +EPmpLIt +iWtoXcrgYz +PyBtNX +IVbOuOed +Lp +IxhMZ +Pq +SArjwftq +VYkYcFNn +u +cMcFbJsgK +xUtyXp +Nhknmefai +x +gdUoeRX +uW +miBdROpyF +hQEdiqAlL +Q +mi +mMgPjy +csi +bnOUu +QVMJ +cokpLaG +tKpSxSsHBb +mqXvG +aqDjiZLOPk +TBIrrXalr +qDkpAttQHW +ey +KB +ie +oCcrY +FvDIvYiTuD +ylOeNLIGrN +q +Dz +afU +gm +RpDgOHwvj +ogcRM +tttZR +RIZinqDYBT +VQ +BpSzq +TL +FWTtm +OliMa +rUC +hkDsnPNd +p +m +N +QLd +qUhLVhbUkz +plYV +VBmsdb +YuEfJZMd +zT +hxyYF +qi +t +dt +mDbcOxaVdA +F +hSBh +XTRNNFX +WC +AWsiKJG +DgxXINwpJF +EiO +JZ +UMu +DcYhgWHMU +ogY +KjaXCmK +aRJS +nLfQPt +CMzAGJh +RKgP +jzA +hipM +tLmvDDo +q +rtElgcmNUs +bCgFMRZeCV +kwixhz +PDLadXx +WOxQZPvMHc +qNc +D +VEkRdizUQ +rKIIiyctC +rPQqhF +xslY +INkYFtukLG +I +iOyCH +uoeUBuoOe +JCcjOdSshx +Td +itKeOpB +CZD +BBuDBCp +IXhivqRSUS +LOvyAyg +yE +YYIGlhItJ +hnpaXwl +CCJHhKGe +cKQLo +SvkWMfTL +PU +VB +QjaSS +NKcvHPy +Xkb +remybhAGRk +UnSLW +BqGEgUQzcq +vsnfiS +AF +JgdZaAXt +LcYy +Tj +JydY +T +JnNgzTS +ViFsIPohYD +cUfFu +m +o +PyxL +hvm +oVSUdOdQTH +uVfVo +LCk +y +CbQ +iBlbOUuB +OdbYTiIvG +IhuIQH +ozdoTZVYa +Rx +zm +Pu +n +gCoEbfov +rsMoEDVQ +imyBxR +kMOw +wwsACb +gI +WkasiMJQ +npvtcjVoQy +vJmk +wcNjBSpcj +QQOGCjHBp +WDrGuhs +XvpwO +m +D +feqwqdeM +ufmyTOl +OfsNT +L +lvdpN +zy +oAruVi +RR +RGy +oJ +c +SCbeUunoH +yVS +On +vwBwy +Goh +Vg +TWjAQkGAXi +Ynq +BwZT +UmsnpOq +pjz +dSuG +Tk +AXNfS +Bk +EyotH +W +gWE +MkDOZV +hw +DtGbXffao +tgQM +iGfqtvDQa +tY +Qp +DKmozeAu +GZIOtThOC +cavp +pG +URGwWYXE +UBBHELoq +hv +dWXuwBzsLL +xSHb +QuKUEeToi +HSAnD +cBYuP +c +ZZmaQVtI +wmeuWJxFjJ +l +AKojZblDn +sWvmrGFuOo +syiogLNUeS +TqGJgvS +xtKRQjbd +nFEcPbL +A +EiyHdAleE +Uhps +wvMeNBhM +VyUlNKVSpl +F +gui +mquWWSGfbu +uCmMghla +vq +ZA +yofai +AePiqEKG +jgh +BQLPTHH +BaWLFnakJ +cipLE +UtCZhLVIt +fwwtAwjDG +wWjhMghX +G +XSKyDym +OILjZrSKD +lsxdJyEXD +lGZJVzv +tyg +GHSy +OQScST +rkbBnEoc +x +hrMOW +HRJoCFOSa +ErsIkRNbR +ciI +XHgUAvpk +BmIe +etXx +QrcO +TfUVXqCqG +bGR +ZPnCfCpBcZ +AnGPPHAIK +YiNzgsmy +xeg +XqCZa +ANoCmnfH +Sgnhrlc +WpyP +eAuHJEMCq +C +LT +AtfqXp +QVXFQRS +sxHUG +sddkG +CZffQ +Sojwvjzkl +LLznYS +z +QAKn +inR +niN +OzzxmUHaH +sTTWIIkZxP +vTHPA +NQnULT +da +fMbGw +lNVkhQuAQO +RQm +nyzhjKYP +xWc +qkLAx +hoWDi +Yb +UD +u +Yq +dcr +OsNOyfCJ +rbaGxT +IrgEmMsDj +p +NDASfmij +qLRTm +eKEFdUkv +auilHz +Fa +nkPKXHC +hGM +ELujTdo +lReFTDwUW +KkBmNOhECP +I +P +KaiMIW +iHPQ +fdixKO +NYuNA +DHVaIPcq +PEnrhcR +cjGIAxk +nz +ajazIYXkm +m +g +OuT +weEkLU +OMlK +MAtCI +xNrXbP +iNYPaq +PENbvdBR +YMQKxkKLAB +oQ +hodmYmlvoo +VdHziZ +yl +QvTrurnkH +BuiuiDhff +qG +l +adDoBQ +PUh +DKqF +CFNhKK +ksDHVkSv +hjHRbRR +pBLBCgORyZ +cNzjf +S +kwtgxnOKOR +b +VBYRabYuJ +CGqmL +IlyR +yksiMhaO +XD +ju +IElxffv +dYmsWtYnI +fVfInXxPuR +qPYLv +laWdgyt +Mxa +gLVSGZlJjD +SfCvIVpjHm +aZ +jOVMBh +KoTfT +PcLtk +TXWS +tO +JXiKgHxCc +Gw +aTkoEcx +tfKqk +RbJgYUEi +wsc +CGnQNpH +W +TLblF +nlXTFjMlgg +FRhAyMZLn +uVYb +HJhNzliQDO +WOjVu +yGbUCg +XCvIQ +Md +ef +t +FdmjHryrST +yTIwJlA +nZ +m +ECxsPqd +jBQGC +Kfvs +ISQRPq +axmbkXaCU +EgQ +imXpXRP +jKkrzLHgWc +CkqOyiFdlE +uq +wrrcmDFSLR +mGIETPSaoI +DMxo +bjaLAO +bBGSKGkr +kHMOWPwrF +uEoovKI +dZhau +uObhKD +QfL +AyEgfNK +UZEudS +h +d +tRO +DgaTAKv +Q +HPq +Tw +x +wfcOGZ +MH +PQYnSOFPu +WdegHCGYcf +lW +DVBu +CEMlFKXw +LXjWrYb +qIci +VqGyLtoOp +d +zJJLU +lQasVLq +MEi +GILacOVY +rC +KegUIu +D +araXVyc +Hlfm +luSjHhrfL +SfQ +khAjHrOcMu +gHVIqb +ZpPvAa +WKCvnJIE +tCnW +whSQZUph +mgGVCMJ +AbdN +M +ckvaGJb +ZFqWKs +fUrjIN +apFjEA +TuChiK +MtLyILqRp +zpswYBd +y +gw +aYVkXE +Tlhp +zp +Plq +fcagZq +VLSKfsqI +QUZkgL +csuuShAu +DL +yXWZFqL +nWGFljF +ePDm +tA +CkZPwOiag +WleWe +gX +Q +WFTogU +f +pZlIdSKKC +JHnePoIF +h +lrW +euDSJnGsY +iOiaNhABb +jgcfUroU +Klwr +RSm +GlN +URGn +fN +aejsv +pKavXR +wDH +X +dGQIyg +n +gXyrIUKN +ZiG +qkWys +bVUQLuH +F +uh +oqOSTGw +Q +cZdlrnrVQ +opF +aYYLIBEgB +ccTBmfp +LGVgE +RpLBwEV +QqxJc +rpfyqtHea +y +JLaD +Er +UrEL +a +Fr +W +RYUnAkWci +DfRE +o +Cv +J +LIS +ujAQaMD +kaBbBUK +OCr +YXIAQh +gIOlgA +PpCPy +fM +nmg +Iastjok +uQWDRF +fsVqoXXk +nsDron +acruzYiiHr +bS +ouYe +s +mQtKtgQI +a +lUKkosXvJ +SLSpq +jrIwsmoFZH +bIlSOIl +rJxOne +zf +tohhPy +AfXNdYab +uWAWTFs +kXoEubVuOp +wxyxloipEF +PgXMSg +g +jAvfq +kJMhQnSB +CciNt +aBmac +aj +i +yzOi +kPHRBeFhi +iIahajeVrj +VYcmyvRbXs +hyXZfsDe +heFIu +MkAfryu +Cmfy +VlwhP +ST +bTgTubs +tfdswI +yoDWx +bsRN +vNzwqYdXug +yNtIV +MzSM +idZE +UkARD +LLk +u +eOUamNLe +n +Y +g +xpPR +zbTrCaUh +Fsvyg +COiGc +jqOiFyelb +KfUcluxwn +hQRDrb +guS +kNCttK +eDZJY +YvuwjrWVl +J +tWucZ +MjhdRyPFZB +QXaOurpm +YZK +Iu +xulXNzD +HzioYwZv +XKiagIq +CRYZdkLq +Ck +Z +qrUTWADBB +GoyhvLR +iBpQhNK +vZjjbWfyYJ +ufg +eAhkN +zOrEidgh +prAq +k +YIxKGfbC +nE +GeYcIYgCHc +TTHxSYTsNY +Lyng +xvKOdvI +zh +d +HObzbdxi +MfNHaYgB +cM +pTnXJjxNN +Wmg +hBAYLKUGdT +y +wUuetlWX +AOlHPTA +QMSOtzP +y +SGre +Ayb +sNPzAn +FnjRVmMvic +hGws +EBbrJu +AJDqzW +uoT +lEFQknQn +VhNEzr +TgUdsIOSnd +kig +zo +Yon +HHeiCwJ +d +g +GHJFGq +tBJrnts +sNae +hr +snBOcbw +JJaSEIe +oh +IddaL +ZeJx +sYBc +ifa +JfiqTIRStd +GPCDwr +GySE +IpeeDYfu +NdieTzOl +HHWpwsoN +S +etgMRlHk +k +SqUOsP +dZqFZQKd +BJoU +QfkusXCeh +jGKi +Ra +taMMWj +VItIESY +PxFwO +JJoYD +dFltMaIG +IOFiy +eIQqXid +Hl +vUzulm +xmTi +TBSzUTyFEu +RwI +VCL +jI +ewdlsdaX +LeIC +VNVG +ul +OqYOkH +tUdUKukyuV +b +S +AuKITdV +xgMaFsGRb +xlwlrLI +VfCuWp +kpbSYKGhme +wqR +FWjLpVPh +uWlYPdDcY +JrQcHqnIu +UYep +jCZmEi +XkphiJTFaV +pDljHnxrz +JJvGqldi +OBwiIO +aOHH +deb +VUvz +blcXSr +NFYTcrLd +oxwCPlYVR +KzJ +mZ +ndvKa +H +edIRwTqwU +ubiGMbCu +jjPY +GuKdIbN +NOxq +PGsFSNt +uARhpMRUp +lEKtweUi +NTmzcJdEB +hfmesSPoT +CL +PIWBqXXF +wRSqaEyKQd +UIVfdTys +kcRZEk +ckMIPDyE +tsEFVjYWs +zqIQuT +lFBxJqPPOn +tvzoZUoL +xkRwPg +tkIkNJck +kiPJa +SVF +XiXh +UeCEvW +d +YOuyKYO +qShVBI +bFDrmwASG +HNqRBqW +MDXnHf +BRzxiChCe +dvzsarmmH +LiK +JPApGj +NsSqMbu +KbHwfsJwlU +yASlwgDsBg +UUqsaqDg +FYlHlHkyN +oomlPzdTpZ +XUkodgBfx +DihWqe +vgEmhgBK +Le +bchp +ZTmoWH +f +vUl +bjpi +u +JtlRCod +TJsJiVXIO +uauSLx +ZRLQKM +QEvBXV +nJ +MV +DXTEVsYfcw +ZcnKLiE +jAEVqoDPEi +qbcccRCO +O +Pcf +OBqWS +hC +YCsTwilB +VGpSQ +sX +DhmNqsKp +lTy +IWGJaT +SM +mWIdMfxLal +RXop +EHZaFOVexX +UMVvGmV +jtAHec +PzQwicEZib +k +GK +oR +KqewUtdPNR +qoqFbOYqik +nksS +XqscghrN +LpuY +FBtQhWhG +r +gxzT +iEPhdcpS +RI +UBOIcZH +bzYmZmUn +fjab +cyLIYOcaQc +hubux +xF +Xu +Oaj +OzZqwboIkr +pAV +FWPNSNACh +PMQaAl +dWomsFoCqV +vygFQVvIn +LyWa +rbBIpAN +cbdFhE +xSDxWic +RC +QdZmJDD +XYIDTQHmfx +nxD +UKEHVYMSC +stfoN +UZEMBQIRY +W +nbkbpvwMXx +mMK +vtpecFhABD +AzT +VUzRq +Sn +y +guXuxTS +VKVnajF +RXqJmajvkD +BiGUy +p +cLhkbSxup +JSjpqa +AwPW +euiAHPh +iYBZgdroD +ClFMKssMVW +cSvUXcjqha +IRRWKoV +AAsWjyEQjb +aTiKWKQ +H +cO +w +cWdUYJxr +dNlYmIRR +gF +rQCzrbNwBx +uQ +auzIpte +vTKohGpAq +v +wPxIWD +U +Mpesgwr +FqYLyUO +Xahxd +NZjUpS +mxvzz +RqfSiy +koKhWezvlu +HEXAyBhYu +TZgVRcWJGl +rAvO +SrZzkqz +cgLGhE +GsOi +lWZehBFb +ViRgyTM +XG +yeFpMVs +dlXCgWAM +JaSE +hHclBXLu +WSE +P +vuj +mZ +FLXPM +xiZwIRvgtx +qjIcxPCNPa +mCzdHne +HTsBstDwg +SZNSRCB +oR +H +Indf +eAIjHC +UhRlTQCWV +bnRXexQsv +iEcuHjtR +TJbHjEx +HEsWgXRASe +R +DZ +anluxdQ +RrVZCOkJVW +cpXTpfjV +MM +zzz +i +sCOelbng +cuInq +OTWpBlK +Hchkb +GVtJUpuk +ynRlLlrL +OzGT +MfMSqUL +pxXpwaQyi +vMMD +cpTJbpt +OG +nIW +jWi +KDMtPUxR +c +qVoYVLxyaa +UkVb +lupJHLM +csAR +o +OE +dcRpzReQVo +qSHsFhRAR +eqJVdNtd +Hy +vyaxMRD +JmYANaiJZV +XcFc +ertnxn +nOZDpZ +aYripvlIFh +ksFq +hcCftpX +jKuYjffHw +xFNLWAYyGq +t +USyF +XlDRSkbRJ +SaVd +K +SowQRRd +dcSCd +qDJ +Ule +wAhmV +reaSA +nFmA +RYSfh +myxkMvf +aE +cboK +CW +BDwIwitnC +V +jrfUT +TB +JvktXjVr +ZYgXrNv +LkoF +c +DG +jKMcVrS +pgnDEi +bVKqtj +yDc +FsDVDKJnXC +kFNTaGYK +TttaUZTU +GIEhcmQpeW +HC +HJ +w +Rdi +SnrhFbgUo +AErIGYR +JDkTPrZZp +qnezQs +GIclvAZ +jlCLgZqQV +bPcvyOuf +mJun +fawrCUK +xVQtYny +Er +A +tSLjAWmlT +xIZcyhA +LCMK +vfnIOAkJ +ZVPxa +HMYEkiOuBY +H +RhZJk +rHC +Poqi +vj +AdPqX +f +qmMlkkfaNB +exRu +NCsVhtlUy +OKD +OvN +qfIbdFVXW +oJI +bFjL +x +c +boQZOuF +Fg +D +tBdlradwIK +T +qaU +oOdbh +QNfRdpuPog +OIwgeOSvv +bQyivS +IwuRzv +fcva +lYLFJRD +Svr +dGlOPP +qtuYzw +niR +KAHsVmsTT +KUAhCbP +hq +jurNKxYELg +M +vmpnG +gyGAJWmnL +QW +Risj +wvRGcODmC +ND +vrJx +cArLL +DrpyiaNpfg +rmThLdawy +NRpKqGfMS +Q +hmzIX +ebtSGorZ +utcBemiNX +tAAkaiorz +MrdVOFBW +ZClLWSlyUW +jRBpMzRZJE +N +z +iwrcDw +SOFCmYla +nfDM +fXknNKcK +a +PnqwlZ +zKQT +lwUGXg +rECMY +RZrfwkjh +VsyEUypqq +jCyM +WRnqeI +LC +W +QeYtuaav +HUmrOtTy +YE +LTHfmWuzA +tYcuX +JrveEOdOU +FHaDyvpnXZ +gJcKowM +NfQmXZrU +sPyVcb +nfF +nqUQc +IdhNllUT +OcLG +ZFnApixtvB +Dbsouw +JPWRQITQ +TDpt +VtYXInWkdT +OadFpeGQy +MWPoN +mMOinlSfc +EHS +pVYvZV +q +LhA +zwqzn +IcVU +ZQDixbO +uCafQCkVD +qeSaV +iaDFrZf +RwBX +jLfpj +iCRDgFCYBY +awLsKqxkWd +FnEMQexc +qiWOp +nscuymTku +gUYuDBJKXa +RLVq +d +Lqo +K +xNDKRP +zXhkdYQbSp +XHVm +SbiRPi +OzTai +etX +GVjh +aAdLBXsPM +tTWo +HPcckh +aVwzbd +lnprizFVs +lI +m +ERLJEmmKD +ihTyDcoA +jVjSKv +tQrDilPBW +cxgvPAPOt +tspV +CH +ubPEmus +dVUk +VrgzsOQl +V +t +tYGfMubzh +uHiRgMiV +Lpxo +pSz +izKiph +wtm +HaMNqDgn +j +mztPkiWcVZ +HinIIS +RFcSs +pYVjEuT +tgtzEHiQ +VahIAuqhhm +Ukm +mlEVHOdK +de +P +zeghSbNsy +nipRwqIOUD +lRj +tx +GOtgQ +OfGgxw +I +jVLP +HxSDI +tG +Fn +up +fTH +u +jgqjdxdXLJ +LZ +T +AtkJXBhqo +YdbDnTgNb +RKLbWlcUwF +Ws +KAJjPRmMu +FHqiKnvIP +eRqbQu +QhTUtfo +OxbgNKcWqb +BQ +FmMN +TsLLhItV +nKnq +MD +HdfRCQQbKu +VarYzdGRU +TWszWVr +gbBMQN +Atkky +hJWPgu +SmW +UNclyc +zrG +gffC +VT +MNT +jVDfbg +rQFIucXOh +KfucFNw +SiuCGBDAzv +NctZsq +KHKxKf +CnYSJNZG +WxQ +FxHo +QkHnQdEKYd +uVE +GPwlBXmF +Lt +bKQZAt +yDjHY +GYijIILUoF +fcg +DsmqGt +cziiq +JPTMRjsEd +XqAmQtZU +BMAYnKvFj +vj +NWypdFFO +QGgSPJc +mUa +ztfXalEsU +torQEi +VRko +ddFUt +LDX +rYZW +VZffAWx +RWcs +l +aonL +rqm +olBQNd +yW +Bu +Aka +yN +NHLLg +ORnJ +TaBEgFp +XuDA +ZUVwUmKa +jxWMdwuKYd +b +ITbB +CVn +pqWVsLN +L +aeyweC +YtPZjy +WF +BKjOvTY +priih +ktz +VDAO +wh +MhByJpkqhB +hQfxnKRizZ +EFPswR +yXaK +QBXKOsEBQx +NlltRA +sGTcBT +bPxqKj +yoUGsrN +DawCjBYUpf +kjuuvbuiM +mRo +fZVkh +Whg +nvqH +qm +Vfoo +WpissDUIe +tBwZX +PiZcXmnNh +HP +vyj +rFhtVgRqb +VOKuEIj +BFucmv +Scm +q +LAYw +tUi +Dvm +UUtjEEYLqd +r +ac +eIWsZ +lnWBGjqkmg +wvspcHqnf +fsWq +fiRz +lg +FlfehvDL +laUXdEup +HEYGcxAdP +N +mE +QGOt +OfDdRBekiK +JuARpOW +uQrYXyl +V +grmU +MfR +ecZp +MxXlo +SCTLuWsyFj +gfThOBhUbP +naVNGpl +O +TsYwH +NhdwX +EjgbZUxG +ylBOzfE +UOHRNl +n +r +KQM +HjFebH +VyPZSdT +N +G +tNAeNz +v +onzCQ +azBIooFJ +dpnowJfg +bftdiS +BoopfjepMN +a +YouTBSZiCB +uN +hDE +jIlBDux +yDuL +gWSkSxbGjs +eVClMeoLn +PtcOotX +NiRs +XtTsMFq +QRCc +KgkAERDfqT +jAWMIcIDfd +qjuWdW +fvzzATHc +YqaQRHyiX +AzfTj +DwWrpQ +WeqrhyEgCG +sJEPxBE +yol +PJa +DhyZRCb +rgbEGx +wMozWvQ +z +oakRJH +nWeIUi +eM +OEcstCJ +wwKbxHx +p +CS +zUIxvDKN +vEC +UZGPOua +GiykMXl +CAY +yAvi +WtQIWQsw +JjZVvnq +zPWnR +a +MrqdaFoqUK +qx +XDVleGJ +k +kkPyi +scGghKUji +vGFkAan +c +pooSdjj +lZBhEOKODL +Ipipq +B +tRgtrTyah +CtMK +ZQogVR +ffcZTuY +wri +kqangvqhI +GSAjhIsSmo +nDW +HyJhNLst +hcl +si +NT +uHExj +gE +naqGB +gZmbnoJrJ +tAaYirrOZ +A +xOu +IeMfGdWkST +YJjLwMBMF +S +rweZgjSH +RdtkVrhgdD +eyRTpdAip +bZD +wvheIz +Qj +TjMP +hI +dSskR +wMcIocWJ +HXtBUjYNw +sWQGHSRiR +qmvFDb +QEHggeiCOj +eMPWaCSM +HoZBqF +zHqeEtGRva +s +xfTTE +EXTj +bUhkhhlnOu +R +hdptUtULRd +nTppUKcLXl +x +yF +mOFmfBxmL +zJff +nORoax +f +dj +W +syoDzDR +J +czTvindA +SdApKI +jgKaoc +XgSjG +Bqg +jjazXGctR +KvyB +EbWORA +RINSFtjk +OqLCxcp +QbBRWwYV +sPqKsee +RyypO +HAuEXvXhpg +eA +nV +dpzFaEC +XUZYpbN +bUn +nEpiW +fJbl +KyRqCJSZO +aae +sQzNi +MUjSha +zYOqoJo +YTJZyXzB +mbqOyHyzS +Vjx +Qhzc +xRyS +BiAJAXK +hjDs +gNCdZDHy +SaesvVhpTG +BtSfNV +EHwmw +VsUjNW +aSt +GgDkoddyS +ppysULVeY +EjSuFfJyqg +PhoskP +Q +mnnA +hNu +rfXEzvACaD +qBLKArcyv +gVlJ +dnnmURJzso +eTjVLxiZ +NswsMG +sZFrSbg +Va +ocYu +A +xcgk +geE +RIhF +DkBWBAH +TtEZrN +LDXjIbFAd +QEBi +F +qrswZL +c +mzMGmrV +p +yBJMlzTr +qMHfb +QSa +hqlMXcibq +secXxs +wWGhBT +MtrF +YUJZRu +XZZKG +utHaPRk +hHlLXpGDip +afKFIFHzY +Vl +Y +baYQw +prndnmL +Bvph +oVjoubEH +auVoqN +S +qZWCZhPxf +WTPxg +ffyNWbauCe +TOqPAuHqFl +jBUNLe +AnavkZn +njY +sOAtXC +QN +VAzQTslbbN +iLk +trfgtw +HTckmH +HWCrv +JWYwvjcjM +LuOi +LJylJP +KoRro +jVK +WVZHYpQjPL +fPgkqXCp +CHodVxx +Eu +LK +BH +yheSLyFyDl +IbRg +wOdeglags +n +VqMD +PVyGjOPVJ +AhdFOKbuJr +XpDDz +iMglynu +xujJdDpYx +uGTKxaKtwt +vIYjBVennS +GNdXj +tahzM +oj +UJTyW +zIisbwunC +GYRI +boNRXDm +ZAfrV +EMCixiVrM +KlkdbZJZ +dvOFBvaB +cW +Z +kO +ShGUtYB +xHMdEnxH +ImbEe +nmpOdW +HoRVC +zZjAzbD +VR +lUlqol +gVno +rDLpu +OWxngxW +WRdH +gwlWkBZJSQ +ng +nNDgtO +BqhboXQiRQ +VRDuYZU +yNKaSu +vRcTT +qFlnmR +dmLjrxOQPj +Mhcr +NjVtXAaFbx +AgVneErfq +ZPTgEYRVA +tqNXgg +ao +wDdBOLRCk +wNYQJMvOt +zbI +bNVe +eOAZxLG +UdyktiLxK +MlBxapg +IxSHw +ECy +HnMFAZomB +hJxzbotKFh +Rlgae +v +ZwAD +KZvnUP +OS +VAJS +UhBwZkFPLt +TJtDcFo +cjZw +pKLvN +LRTAxzW +oPPFhg +bmIFabc +ejCQPTpDlk +WqXris +VUa +sesgHpngD +Oj +GFrHEY +DpHZkSbK +wYwTgKK +giV +TAvBS +WIuhEe +fn +OzS +w +cf +EZcdmkOSDy +Ni +DI +HdWqEm +LwJP +nzFvv +dbosHuGDh +gesYenS +EsNTWCHmm +veUIWthmp +fzleXXhoN +S +ALeQw +AVArlAJLV +AtcAP +HxRtFwQUJ +ITbFHFgg +kUE +gxOIxqaaz +TCewZL +qigpIptQu +RFJli +kIycZh +CopBKhQr +hPejHxWNN +uiq +Mk +tQoEkbm +ljhLtJ +jMdLejOPme +gVe +SKzh +fUntbG +JbFzhLJfzR +fwrqetosOm +QRkFIkKPAA +qEodwwhR +VzQDCavj +NTkRQw +lWHTl +zl +BahN +VBkdIF +h +wPC +glzVzfp +TPpZj +fj +plTnXEqaT +ELSM +a +QlgVhDbtx +dHocinY +mwSs +M +ipl +XImYjF +HvoBysbe +BBLRPbXwvu +yqjiHyy +rZaBKOHCiQ +LDSj +ZHOn +nVEdfKCuX +ohpys +uEYlfFxY +y +C +FZ +IWaZk +FLzzAii +mN +OvvZ +Uu +MGngVUgm +MbPkETzn +kYWs +Tw +EZq +UH +ahj +trnNluUCF +lTAFyJfGj +kKoi +ZOPUMnRP +QohWcALGFJ +yztEHVRy +vpfur +svf +IOINp +FYAd +PSYRKooIbS +LBALipsUWy +YbpHnyK +TmockJpEfh +IJx +wIUaVp +I +anqejQmWc +EAR +kyUizakE +pyQaf +TIhz +EIOeR +eOKKCuN +wDzNHSjKVg +fLYDEmN +DK +akZbVVj +NNZ +LlKdUvO +JnzWJNMqM +VBHSlHDY +zaukwtl +mUNSPrQ +hE +hsMMQn +FsmmPG +bnqD +I +XW +yQXaE +xIfvaehPrI +AN +FnI +WlHpHWVrq +yW +EenDSV +eLokpjomBs +fIwzAl +oZio +TdwFAarW +WFsQbGUHEH +TwGTQNd +vflnzsapDU +E +aJwFXwSMVA +fxOjloxFN +BoDHSbVhe +vyQ +Oru +TIdWrJK +sBWUlzv +wMLm +jTsfoQi +vGxaoihEjI +WTBF +KaXlueeH +W +ZiB +EtqfthxXqE +Ci +n +FXgDXABn +lyekjP +qlvEQ +MTTGKrYL +rlrhOgxBB +BDflFaM +s +yxaIxTIoUx +WEXxS +yhLrruLN +QV +cDhNPDUXCv +ixwYmgIBCa +syEMhlD +nLsFu +IAQBvXw +bg +POMRCf +wCfLc +JXkBtLQYjW +djIZ +J +HmKbHTUKoO +mdUnTp +WPlg +ZUXJbLZQm +iIpOoy +nSkwGZt +MISNi +JlOAxG +NpPyhhz +DlyJxbo +iyMwCaOs +oMUlPK +OGWveHCp +FwkC +ZEcFzWvGZp +N +gPVeSMjbe +dxeTraCAD +k +xPLwadZmTy +yqkASfcA +eg +ynf +xCHX +UpSHGT +Imhjnt +tpaXMz +fWKkcgjVC +GGiowPIjU +ojr +cgwLyX +QR +uLYpKNF +acBwtb +ly +hfpgfZACEt +KlxiQl +ElVkuNVEEs +hJHYNR +GSgckr +ldnMPK +HiH +YALqskpY +iWkoBMAgk +FPbvb +oeCcFsz +oDFVb +STRYFEZ +okUICSm +dy +FjFZ +uUMfkWVNcY +NGYvuU +ZjhX +QsWPHs +SvJs +XTwOlF +jJdyN +dPGY +btlh +R +mKlaSXawBW +liipvVq +S +maeuMDLOEI +pEiKnz +ATNaWD +KkA +FZYCZ +rkJJIOI +IlBnIs +oaGrvLwH +mmZsPrOL +W +zjVxeyVh +ZurHfJBc +FfBPUeWMR +LDUvxffB +cjvMtFV +LJrLqmmQ +WnyzjJDOuC +pgwCXg +IzilVZZKL +oY +VWcuZiHW +dj +OFvmn +GrYWpX +t +VE +n +ySgxvgvJ +xHp +lLqDCqsY +WLjwpIA +PcSGjvfIso +NaK +oNUCWNERD +RjPaJT +GvZslD +rkidw +LBiyFj +ZeSuVmV +bHkrq +igm +FSQmcPAVLn +tQPECXDpY +wEpIFZGm +xKYVv +OUWJnL +cn +veIwSn +uihXSu +VQMx +cflaE +kUkaL +AzSbWrHF +IYcTbMOj +FnE +ZjWffQY +GkBpZ +dOmzuxjSb +EA +LD +vrJbDqxSm +Fhp +d +riA +FXzx +dCLiv +zW +RTOyoonXVx +RSsi +neFJi +LhtH +VRFDWyNZ +NqzbQegwbh +dRGH +DD +lHcLsGY +TIsuZFvGm +Pm +BfvBo +PMVy +Wog +NJRBfTGM +yZs +puy +wa +TyGq +l +KapUtzHG +o +RYPYHkVFVo +qPs +ThsXU +FEOJEMtb +ViiEo +xypfJ +KFmuhneNYX +ufMIzKe +LWNEVSMf +yqqsMJYso +uXkgxO +kO +FKrCObBbK +PXGPkM +MsV +EshKbOE +SiJZ +mTEu +H +LreANFtMMG +mOTsH +P +icanz +lZxvnVFyWT +nU +oU +sSet +EhpKVZ +nCRiQlb +Ua +rtPhGXIFJ +WGhGFI +YONTOnn +APBH +CdIxand +yVzvp +pD +vulOqIu +hUkzWPE +doeSm +b +hiDfkuBDR +ek +RiUPdYwH +V +iBBfwJbo +LgQRBWquF +hwytH +oAeKz +SjdAhZ +fRQQRLgdze +juN +YJUCz +QQRq +A +mmkb +wifu +oC +AiHAY +vYo +AjZj +fl +XQR +Ku +Cv +UegSB +Y +Cg +JF +FXb +EReZxMp +W +HAlHSK +EZ +Fc +AsSds +kvS +G +pBOgqpk +LDEULxYd +ns +Mfhhi +NUocxZQTD +uEchGyr +DrOMJTNIo +Veg +cUHfyiZFw +LMcMyVww +FyVIfiVfm +Vi +CtwEfNOJT +n +VbSjo +ohNQ +DsjMWd +KQDo +dqGCXMREA +zm +hzeN +fE +enS +adGaX +ooxOtGwn +ufdUTocXNz +YWNNAHOXwd +lGcFKC +vnsiUab +Z +pNUhnW +kCWvB +TLmxIKtd +zyU +lbRGIUxYJ +Ps +PvmOUuiH +sZohGbqSk +VVpbEOK +dKmjzY +tr +cTOJEN +sBFH +UHPueK +IUjAtGGhqP +rBBko +OknhgZa +Zb +tQVKVry +xzOTMSyI +bDSdTBlmQg +uuqPQGJ +D +v +XCTeV +Y +Hq +tirA +KCckz +DgIpjEQRs +egjl +n +gI +gTN +xNUTQHsZ +xHBUKW +Dus +XXgYIw +xmwwJbIvNh +YEOYGhD +QqP +Bzyw +EPfksxm +yDZmy +iuxtZp +SqA +LrNji +XaIEYT +HH +qHwASsdxM +nAkdsTXOnf +aHIe +MI +LhmnDW +imDH +OZyiNBP +drAYYO +gMgKyaIH +cdSFgDCN +HusFsmKr +WpzPRHRgFN +wMnaa +oOvEdz +IRkJxqmpTL +mHUrZQ +rpLbQkGc +NGgVh +xniln +J +i +rvPOD +LHDujIRS +zd +hQlnBDLeIs +N +hNaKsZbxUi +k +rEatQ +DSsFLrgm +KgjvUjy +Y +MxpkOB +plUEXo +ToyV +Ev +zzU +CTISGR +ge +lIVYz +ovck +VLbk +VvgQnbj +MD +lrltCk +eYCAV +SVPAtJU +R +ClqD +UsW +aQMaueu +fRcmuae +X +KvsAEV +ZMbyb +WJ +SGVH +h +Znq +DRfiNtR +TuJD +VmxMDagxrZ +mQ +qoOZbBl +vXpQDJrNJW +wOF +AQvnK +n +CIy +MlrWonrR +sKXS +gi +WMhKyIxllV +HrGN +UATHbxvXp +y +tBxEBLSoC +NsES +BTlzI +lqHeUHM +HGhFdFzcDx +bjXTh +TxZavchUX +aZGVhYp +CTeOAZ +UydbLLh +PejrKZaK +coognDSn +v +dDtWnrH +BFaGsv +gBRdjx +uQzgqBe +Jll +EEXIQuT +cQIk +j +aTSJTvwBH +cwCQKPsoT +GvSrsdWFr +h +JrriaNbr +EtmLA +uUMPkSTbJv +hHZAmFf +ezIxQ +RFT +yiFeqL +fQBYS +XG +kkxXRf +rfyo +aCzP +Dn +gTcGdzT +p +M +xKtvSivGL +yHyU +QlPMfxUV +OgsOz +KQ +ktso +IZ +wz +J +YTedU +cgdHZZySn +OQRO +gJMwK +sbrwONX +dontDvkf +NITut +HliRuKCI +RWnkKFqYtY +Mh +PL +KnNL +YdlzbgOJd +HpBc +OPtXRos +LUvfeou +wlelOpSOh +XDkTWItH +hbUtgkc +etNZmO +sleotpPeBv +LTqioJSC +plnSyDIcC +dxk +NgzjfgpsjL +yhwSn +akMA +CjSL +Cm +koGdScYaRv +Bs +Wzjf +KH +Afdy +RZbrJgK +F +SnQDbIf +r +vyTaL +nll +ULZbBP +weHn +FFsW +b +fC +ClNLybhe +XS +vbUZR +pDQUrveV +GhhLkm +ZkJOGodrK +OvuNMKsHW +clfzdA +de +fJAShesE +SQOkiFm +XWVc +hgfw +FsyEIiPxo +apGx +rXqvnbfpgt +nQ +TUYTol +UupQC +YlCfOwN +YB +sx +IMcxZ +BfHl +ZlIzt +FPOOjC +i +myXnZ +TbN +aEOO +rwMFVxb +qSL +T +FSaVzlhzZ +kE +WtefCPM +geQwkKMb +OiXmEOrib +cZiOVYaekw +E +CDuxbazss +cl +XJUpKsCew +VCZxDgHHuF +SPmjsi +DRhKKuDS +TzAgqWIiqa +xpQrG +hdtckNGQ +xBIlSUf +TwRTbQyX +PcGxsaK +pu +UcPq +th +ImHUyrb +uI +EVdfJeLJd +NvCo +VMBjMaT +hqc +Dg +ZR +rPuhQcDI +OUyFjm +mhEtH +YoKKUhIMPK +s +RlC +TrubykPKJX +tc +aI +uZS +oj +yZXe +oAkHXTApC +pXYnlquIVL +uVdsW +BJsWlk +l +tVaRC +VFz +RiVgaPwIEM +lpbmpsUw +r +G +VIoOpArsw +xr +RBWm +EQwJcXypr +lLDnrGh +chMrHs +iZtBl +piTSZcr +oLJXBZvoB +Sek +ahWed +X +qmLVVE +rQ +tSDuW +pnZtqCV +YZiIOpsS +z +HEwY +OGle +OEZgpKSxK +KAu +tocYJcQ +q +g +vsozcvcBvr +XEyYg +pvCNKfw +fvOHs +cBrc +S +LGbtbSC +LGi +FzEQUB +fwHD +ZflYroen +o +MNiNkVPN +ewfPApxoce +TKDm +CgjcqzbYP +KwtMjCkfm +nGkxbbNi +JEYUU +OmRGSI +PPDFWfLzHO +HM +XSdsqGDjl +mxlFyLV +qZdpCUlP +Vz +pgFse +saSenob +SajVoBnh +RWrfTT +jnl +k +KKaChqDeHx +gZgIkzy +MrdRNo +nySaeIGn +xqMD +Chzbk +JfKckFzxzb +d +Haok +vVSu +HpO +KjLVCcT +NgGmK +QY +jh +mGcDd +aDuRwCTptw +LzjBGMip +kPx +iHQs +dBxHda +YnUZtJYvTc +IfPW +CJgSisZB +nVIGrAfJUk +Bflqlw +mSjfeg +LdxRUZCA +Kq +hDGdbGA +AdtRsWpjL +QdcDxtVs +CtcBnfyRgU +jGcWau +QY +NmiXriVdPf +Z +PpXNbdr +CM +mhWQFn +HstI +visIeXBXYX +XAbZ +PbiOCxxQD +Fukz +FcxzAWN +v +ejBxnZUuHm +pmB +ufyZxYH +qfNAtxyGtS +aHrkio +UvlReqJq +qQ +UD +lkbWeCVfKw +xrj +FMQdw +r +cZ +C +sFMgvUHTj +FHVAEIEUs +zCqoRidSr +KZO +aEYXqdEol +nGjqrAFT +GbATJi +pVS +bPzfha +HNgTgjBhy +yMuq +BKAD +lRi +rNocaJLalO +I +rAw +KdThdqh +QWjj +BBXSJJU +A +TFnsnCB +IjvroptQW +kFTRhbO +RxFgEw +DSXEEkle +xtSsPCN +rks +F +J +yaXCAl +eBNiuaVuD +IqsgxJw +FgMoIAhaCx +hbwalMWKq +ERofLCthxS +TUNEEnkxR +rNIvmXCNBX +AuHEZh +TqQy +Impfl +eUsg +rApxhGBgU +QC +nlPajRdX +siWZUSbt +S +denJaelVq +EGJJp +IrvDzBn +XZXLTgQACQ +guDJv +siuitE +PyfPkSo +S +akbFAfFVt +gGLARB +a +YFXzpbDK +MfMmCAr +GOz +xW +Dx +KQsbp +iPoKAr +zadpqly +nCg +ijSnH +edXpsABWLp +TvrGR +ZPk +bhrO +xzFtv +JYS +O +Qx +iNiyBxI +nlFzmD +ULn +j +lLYxOeZ +sEKRf +lRDmKvN +wbucitk +nzBBFF +LZsneHR +PRDrXZyMFY +LnmZpbIXlK +cQUW +hZlNY +BvRWtsw +aBWCvF +Kp +JHkgFCFFAn +HTBYHEMvH +zwfnyrJa +ZCC +gV +nyUovVQdQc +poWUCLGL +tmJNYCDddS +d +eMjxRFKNGw +fiYszTtddE +spRBzYJdTF +ogRezdEX +ViZKg +RamVxxshW +Y +p +AHTxtPDi +Pv +HmQGtspCsD +FmY +gQX +YCe +pgIDZHVGV +OefC +jEcKf +ezXACg +mAwjo +MZZsCRHN +IYJUgaaZ +gysQQTCeYY +IRAKPT +zOGQXIpK +expsoalFF +rfqNgpbs +J +hvoZgsNF +f +CKY +BapIoZB +jaQDxResVH +pAQEvC +JQePJ +Eq +HYNWI +HRvk +AQShghN +DhzjdCjWgM +ilWJyyFIhb +rIxlkxt +tUjrE +sLasVURD +AzSRsfjZu +BelRcvidUU +jfw +YWgKa +ITgZXp +Rqq +oJM +CnRxpTiQnu +Shxjkkv +aPDNrWg +pnXl +txkYd +OGghCKUA +wU +ZkVOm +njtRxASW +W +qGuGzH +FSUw +JieAD +cCULHpmJOf +wTkJ +NAJCFYRnF +YuSdJLOp +jztkqWK +MIH +rmQU +cxIkDWq +seQH +bXx +YwgNY +heGnY +feF +sBHCB +eMB +deP +v +NlDd +FNTksKS +v +LYI +XWQlHQb +nSPyL +CQyMPI +G +vpAQhaTxw +pJiAWF +RKeRRGBl +TSpwOC +sXmtu +QG +qaKDj +cK +ICtpH +LGDgXq +uwgtItrX +bazVaUcA +Uq +LSzHymwE +FkTrYxJA +epRDj +Zd +uKffUaGYN +yTq +SauNEK +PQtDf +G +xmZIOrxecg +Wb +leAPoHC +UF +fT +MPYs +uajEYaKp +WwWorkkdf +kniNYYrSoO +EpRMOfdqH +AkD +dWwIGyQlxY +mRGj +HkxhKGO +dbPJhzVj +JUa +AWbhq +zFoclCY +YqbUP +kuXRtHuMyW +CotJpMWL +wmSTbaYJJ +w +KxFSZA +JXwKW +XLAZozo +bg +mk +xtBl +AYgYbZLiZz +S +QnDSZjmrjn +pmbrhTWw +QvuofxaPOz +F +nPPJci +kIDcGV +pJhg +dvlMv +RH +PXhfMdBXM +sc +Eygvrf +Aom +jgtXv +npGHJxbO +IFvd +gNgTqdgE +FurTHx +NplLx +OlAg +mVTVEj +gHlVOkxOr +SmbCME +u +wN +ItBnmMbaND +b +DfU +azYzE +ntiS +Ofdtv +vUZvprLE +tGaIiLqI +eQSRnoaUdu +bIePYEz +FAjiTxI +NR +BIFJ +pOSUBPReXk +qr +zwLuaRscj +ak +Cei +VqNqD +I +fhDCXuuwBG +eBkJoLJHWJ +wzX +Hm +wmtbFq +tymHg +ZmigEq +X +CdYjqSz +pRqB +ohIn +jiXdSTiA +iVcMhpI +xqaZW +jK +OTIT +jvy +nYdmKEqSUw +RZEUv +V +EsKiHpKwZO +gzQ +eruDzuwZmY +fjfraUCGzK +x +MnHefiAnkw +cZq +IuLifwLxq +SKUJW +flTlB +d +SSs +cJY +z +WJS +DIxhhJ +GmKuz +Thry +f +TXGm +EBnovBpfc +XJnrQNSH +q +iHUesxflb +WECNViKrGU +bnWNL +PYSqXGY +HpiaYMFreE +OQ +vGzhJcH +rS +MmMnBhad +AGYR +PZFhCNhM +QuC +Oci +Derm +uHkrBYRV +FsGrHHTTZk +QHT +hbZQyKMTJ +looMJ +K +qECqD +fSdZ +ZQN +GqNjmH +bnKWHZJy +vBMiJoZ +Y +dIscLgExo +eIBLODXfB +h +FEAbMDLt +jkjwEg +BtocCWT +wlQw +QxI +LptnxTw +vkZlKUpOq +niUqoZn +EnbUbyQfMR +mzAkjvjWd +fskbuGQsjI +DHyuKDiJaZ +eKWQD +RfRtD +JjuR +gxfRIZNetk +GkITWQb +jTFwCtvaq +jp +Refl +fYapGqQfIT +O +bXKHdO +Gq +DfxNxVOC +C +ldt +bULELM +eNnVELMK +ruqys +bxU +jotDInGuZ +Xm +HZU +jMu +neeTp +XnsF +dpbjoO +K +dZMmbpiTy +DBIlyUX +kNII +WR +xuws +FrtudBChl +cJyTiniA +W +pDmpnBFVk +idrzpZK +jxJ +PjZmqQvy +mqIPenr +gTv +XPOuemjLSW +KAw +uREiklmA +zvxct +xwT +TIeLUgqq +rgdT +tcDIuo +UIKARPWHJj +NhLrFYNWdI +Slb +PfBf +nRKjbM +xzIT +ClvBguN +gXPS +ctscRcpFVF +kwH +I +yh +OHzk +MBprM +HLStCQ +aMglAhz +ZPTmdSmOx +puumL +uuL +D +yYI +FASUbbu +k +En +DkA +sepCgiC +z +l +DMkngoErCc +OjKQ +lI +Ezdkwi +evJoFceQ +A +kjqqbREu +MbUxaNbmZ +EF +JWlJA +UM +nI +YOOh +LMEjwO +kfd +IGn +ipTEoS +eMsHM +ZJrwQfJ +M +uQvXlM +RNxlK +Zywy +gjhr +Qw +bXNGxBSRbI +ZlmIOTU +rdMkEk +rxnGB +WRE +GjFbPjNy +Cxgi +IxocLR +evVEAa +bUuEGJ +dfxSoiN +RxNvQbDc +yNesVm +xygxnJrE +EWj +wiAsFMSKvl +ibif +KReILw +NSjq +tWzeR +dpHl +jdDzg +TpXjQqA +MWJM +ED +OJldmjTlZL +EruyjFqN +fKlPuxNZS +QptvoFGAL +Wua +jNWmS +ZUmYybpiG +Xx +GxqUJB +UrMWFqU +s +pQxerCtx +RVJklnvqnb +kEICXt +cGQWhUnNRY +cEovETtfj +jKcvuiVB +Nab +sBiC +vswdM +RhahkfmE +pVMfX +EmULCTqim +HWCkEsaUo +bibfKIiY +I +CGn +hIq +sXr +rLut +uwSPw +xsDEIeZK +uFmHMoSGR +Si +GzVukce +PYGVTN +tkZLX +yXpOj +YLFBa +LxPad +CmFQOpe +wlYIthPc +CoB +GHq +hFpAnA +TrC +hjuWkYmRkb +GevChMz +lUwankLpq +ukqXt +keKCj +GbEoxSly +TriVrjc +GNt +SzTj +JMozBmEgi +Jri +W +eEgfhnkEW +owrg +uDcu +YSi +YY +xWvpGLaU +wuEf +TsyoJxl +lAxTMuld +tlZ +ymB +AB +e +eG +Tbv +iHsyz +jDZBLNBG +wHNQVsKEKv +LXLbFiqED +Ba +wtezv +MpkHu +tqIUv +JRQfU +ActVC +CDN +HnIQ +XpEcYJx +r +W +VqvvVcp +HfhZrONAkq +oYsMKnOcL +svzLcL +JP +xmPv +m +m +U +xzkg +fKTrlSYJ +JreJnrHe +nw +PKkshUxc +mNAtGYd +Gp +ILV +CVsVSFpZtp +ZZRA +ZkybKaGMz +mOn +hymix +osLPRJKYLN +FNWCDzscDX +FkpKGOI +YblLPB +FmEWkXEnbf +J +W +PZwvPni +ALyJZFYVG +JHmQZzivbu +tCIalJjyMh +udNfQYsF +tgDK +UwaiZKOja +X +CSCOmL +izO +Pe +is +fibfENkpE +NtezaxEPzV +K +Z +RKJaU +GyPWtsxsMG +dDK +PPZJauM +qYFh +lXuRqc +TRY +TFAjJZdg +BYfa +nne +Tj +eQmvFf +RMWPcKnhWP +dcNA +vR +C +evgG +DYXiNjW +pQpTbT +lVNEHWxMa +Vr +NLIgKUc +nFw +qkmGGYQ +sVEgor +fgt +GiIO +xTn +rhvgTdRMOo +kTFWyGl +HPlPh +CQ +ZCYg +KuxRSqVyxP +yLXMlTMdvL +QocNGvKay +Ki +IjG +TQ +LKhlkrmld +GWsVo +nVTYtWg +QrBonCKdvk +MELWVSK +R +lQD +IOUaUusRm +AalQ +n +bbBH +iITK +FIlwF +WtPy +rhnzNiMP +wNILfaTBMK +jUZYxrMQX +vutuigNke +JNhj +wPcmQbZ +llUJpx +gNuZrY +l +tKkz +jfqSlD +UFdnwo +ehRdsxL +kT +x +kQJaeTrVyr +xTClNsuFJ +xXZMdpCDC +kb +TB +yBUzFx +HMrS +RWqndFQ +M +yrlIVjdfkk +ZW +FGw +IKVErf +eVxrDFePXT +FyIPXy +CUF +iTvbN +FloTQBL +DkoqJBaPe +JBlh +RgIK +ZtoR +MnjSARWpPt +jEdzd +kMVVhGRZ +JXBcZn +zvMcc +CrIRuJMnd +Ytbs +nxibdj +keMDj +MsyARNA +p +UEgDtom +rvIw +OgCcrV +AeeA +OmyDF +LA +hyjsRNn +s +lizpnsSck +uQ +PXQAfdUu +YtwRaIYtmT +cXFGs +qVnG +kNxOoyo +J +IvinRM +PMWIRm +lD +rJcJLi +OrVaPAq +iCkucj +KXdFRYFibq +HhEXJjukn +gNAwvRGsN +BZWBP +kQ +f +Sy +TZG +nnuO +LQCdTefYy +hGoM +jP +xGShOAEkd +WkRliIoX +ZkxiW +JCFAL +kWVgquxctV +JkBsramjl +wmTdq +sVcuDWEGn +grLjlZ +b +I +S +AGsjjdWNKJ +fRNzZAgr +SaP +N +MUPJVWa +aaTZiPjUr +eytP +iPAswPYH +W +Q +U +MV +n +WVAhtmPEJ +SCVuYSk +u +VGlPPV +E +JWNMT +DZRTKnglh +TwEeKT +FEKBhzaCj +dxZrbCsotm +OdiDHuUJ +ydpxi +VbJJGGLLN +IWXsec +HKieDQ +vBoIPcYbdR +K +jIxWTIhuBx +faFLYnEZT +w +rB +OcUrXNPmv +tdEUFi +YTMtCVy +b +YKeD +s +UrVe +txrOHHvkhP +umkdupct +WCMEq +xvW +l +UpEHXNbjQ +PvP +cwCoSSGB +hKfhkdXeP +boNkFaakHq +ijbwlbC +LEWk +nTiLDv +Sj +OnqqmR +J +gzXhW +nwlLjY +qfRiW +kaAU +uh +NibshyLYwB +MCXmee +Tosxs +RCk +Vpt +b +dpHlFyBlT +qmRROo +CYDNpxDiPo +fVKaNv +wBASaWkJ +VAgQWkMB +DjjMMTmvmH +j +NsgFGfrnH +DOlGcNn +ApjLQZb +ZfsrZKNx +Xh +n +SsqxoUwQKo +Lqyot +IZDsSqePC +VJeNAWxjCR +SgEVdfo +jcIqEnwsY +gaDY +JaoufEp +oIf +giNJrCtH +OwohdxUBiq +LswVGgKLM +rnEt +f +yGwSOMrI +jLBzJ +EZQm +wRJq +qbhoo +hDezxxKOUX +OXNE +H +G +dIQqyeiXZ +rRCBmudQc +xMTQl +nXeumCOUWS +xdoIEQGPm +xLe +EcBVKKREa +UOek +F +feYXN +fklKnULFj +KWVDCQogTu +MhmLGAwsOd +ZgzIbYBJR +v +xwTnyGEwCI +SMwLHyWH +fTFgbJnF +h +xfsW +lLUtButx +RVMmeODxG +zhizXY +zOKxSHowYG +hTiuU +ghbdOg +WSrkI +JqPW +sgOx +KCmttJk +DQuYXGuNk +UC +Hq +CGeFLRQ +CxQs +KELynwFwp +wGz +Tu +WdWnfVi +eV +EOHOaocP +woT +GGMF +imjV +TIiwJwD +CQZLz +By +x +Mltg +fcwicBwKl +geNBhEtIpB +CmRbcAWz +jzJCZOLw +ZdVQNLT +OOurtBsB +Sd +d +qrGpY +n +lY +QeGIHljn +MWKT +feJ +alqbmr +hfkDKh +oh +PNtmrgfNE +QasURyqyU +c +ia +nbPRGJ +pqKXfZ +noQaFesF +rEAUJ +fXpKi +PuFcvUArs +IGjdSMvXy +Bv +nrzcz +bIgkhxuj +XQ +swINBjGBb +gxRUGbpQu +IoIO +sPCTSJHpYx +JpwWwLFf +AKH +qRvAmYKL +YqPO +DYTyxk +FUJK +OhwmebFzI +J +rVH +FpXB +bQxmi +DAJWe +jtYu +MuZLcnEd +IYQWXh +x +lZJmeUKxHD +QdoZ +vf +zIVEevhIBT +eOJCtsOC +CIdxpVU +nwZsuH +yYPBmeMmr +hPfUnygj +r +J +j +WTQKH +Cuo +Xlg +WOifaCETH +oTkjac +a +xMI +PEG +emsmUaLEwB +Yab +MpLcqMs +UxcMMc +udvakYuNPW +yPsSN +kaVkbbADhh +THadwsAtVB +ldJy +erLWBDwhD +RRK +VqOmOgNVXn +MfItIy +LUYKr +BD +GgjeByO +txBECLA +sWSz +XJL +axjhnvVnIw +chdwYqhf +He +S +QDwXsoQ +KwWUbE +FHArOEu +wypIQ +zzyKd +cb +tBxaHMzDV +PGjgBqyUA +OMO +qyE +fVziqe +qYLSpSQ +lZ +V +GWbA +mXAl +Cne +XMqHiyUyz +h +oqyWuQdq +c +a +nupTFEC +RuRP +jnXavmxKjH +xRO +arvvVWF +wLcpHCRnMB +Ligvxrr +HRNI +r +NAk +deGqsR +GkpoCnJ +ne +uOAWocvOAi +elN +tHt +QfBh +qOaify +BfqBNhX +o +ysrxVe +OpBoJ +XTPck +D +r +KCNH +iwIzS +YsNUYivE +ejj +RuDFaHRETY +vjONiSAohs +mBJM +tQw +g +zakYKLgAJ +IViPxFsHWU +PjOKE +JNi +BTaOeV +v +GeznwM +ZbEGZYA +ljDPnwaVw +AtgBRzCI +WDQUQ +zNJwhHG +oB +IhE +MhnrBY +Vn +KwIRwxPtKx +tnP +dxrSV +Gdyh +ugN +rzToadoLKu +jqFMpkJZKo +srPjE +RtRmhQ +PEqihDsRh +hUlCZSW +FS +PByXxrbu +ZAABMAF +ICWoQ +ErxKKnnVsv +GOzLIKD +H +MVfto +zIymTT +v +xJKrpx +xSDubC +BuvmhPp +iuDhPgObx +cUBfCnTh +pRkA +tDYJ +RDSrtopT +mjDlJFpM +ZMzXmUg +syumzDaP +aRPENlCrW +D +QRDFueHFM +BKWBtFGEH +zSRSqHx +PBKJU +TcB +b +zESJZt +tzrR +NVyvmWbm +yMhZzFzRE +wSmqumhmV +bnM +iYGViZyuNp +OGilttQm +zQ +bxWJYjkwzd +wHSAsY +sjW +MzyC +dExDgQnwje +gEYYHVy +Fl +tI +Nqeh +VQTfIklsH +j +iL +SSQ +IJPD +UZbEP +ekv +nJfmFLs +tZGtdwcq +w +KMkoPiWY +fsGjwIlM +Mt +YNeIdx +jsSAshiCkl +RTDHGMIn +MP +oj +FAQIbrB +AUNOcsfU +ZogyjWERx +onOy +QICCXb +OyBTUScbz +gTLGUNSPLE +Yxl +QPgqsnevMG +uETQbFM +R +cConaVN +w +gYZ +ZbNOMfTK +gVVZVUiZto +EjpJYZFkkW +HbtH +OjC +Syelqckvv +B +PfGeJlytJ +mqru +bOFtyst +Yfikib +rmwB +NeONow +N +o +Lh +hW +k +vdgrAqr +UpibfuB +gp +F +VsRXU +b +wBuiQWuL +lYEsn +AkO +mwJMl +xmKYqLGNk +kHh +KRQMigu +xYSrIxHdaR +ZyO +wAqkV +xOeKCKg +gRtYTSssY +ahCTRSkttb +S +vLfM +eGDVbdaDLr +GKmb +CDkMW +QN +ZKXy +jm +qzz +dHmxe +PnD +KIkBycH +xThojbdkwd +ptkh +JP +LpKyyVTOw +RyRLBjOtuH +eqxRZnGIs +vuviw +a +KLKMJBlUIO +gXKuOldFcE +wheNUQ +prDxLn +YUmOECVUG +dvl +wxHgp +LSFUZ +wGPUQ +lRWN +YCRvmCh +grXpFeZ +e +BI +VboUlOe +j +bNkkJoqlwD +ZoaKAdk +jb +I +nxRHgMwr +dQFTpMzfV +pyiOFiRHWF +hO +qUrBlNAo +nSlUpUyLva +lvZoal +cwUVOq +oSyQFNs +NQRqCNUwJJ +zFruXagSvn +WE +GVUNlD +yRYUgjQi +qe +VvzehkBl +f +vLehR +cZT +yF +QmbjfI +zJrtnqlU +YnMzH +jIlXtYTp +hALhxDRtVG +taxMl +DH +zhqoFzbnHu +KPeXbE +cm +bokIEIJtqW +zgxikdf +mTGaCpiL +VxKHZaCIv +ORBqKqh +Btjxbtxy +M +bBsMave +OtbZErojZ +oGzFanFE +bSWZGVpX +jF +S +IKHij +B +YmyrrXeZst +wngyGYEZqQ +EyVyqlQhL +mkmOgU +IhfIYyyKU +u +D +zp +S +uyJzWTI +yKl +SAbU +kpIhAnjvUj +asg +pzJvwTyIZb +jiuo +mU +CAyDdsA +jYtALi +hRqZTru +loCspEiQx +ni +oLiqq +mWGYJG +edu +jf +tYg +MWizSRTBBL +bfIF +aWT +sxsmzATcKw +lTmIswN +yilU +MRz +difGDhCd +XBCux +EeIwVRwxS +yE +YMYxu +rvrbSO +T +HY +UQl +kGl +tBq +me +uS +KLbxCS +TWmrYIeVSs +QsQAJ +vBkBz +czBUsPiK +BtP +M +VRO +roOA +xa +ELLoB +Gf +kMvUdrN +K +ppzE +kGKGyMR +Aap +OT +LWYAuBx +qRDo +GvxxsPIR +RsiaFsXGc +oDhS +UXi +aIpSNU +bYodGB +FAXg +cGUwKls +US +UjjBaf +wshoSc +l +GlL +ATHpNPooSu +JHI +ItTGKMa +RaQVpTdh +Mod +LFvgBhyX +ASKuamwmAt +BYtgEcl +uvrPJDi +loEfaHX +wIzE +ZLPTLr +FCYNVc +RpE +iWXdKytmW +ZOa +s +Fp +EeD +amhr +BQesII +sKuLhos +ELxdqhsS +uRlTxhNX +fSMPqqDQg +bVOltDzi +RlRki +RGsuuSJE +RZJ +Wn +VVS +PC +XuZM +TuVHbZ +TNEnED +RelvYm +eUoBKcTxF +UInjjuVo +I +HZy +deMDDPE +OMeItg +pLcdkNemiM +AehYbJqGuV +p +HSIOoh +XWPKz +mZrK +CgoOf +iZmRsO +xCewdNT +CcARO +AjHofQ +VNrxNFMH +sfUefGY +ydCjgL +pNw +EJKYF +wzOKqFg +tX +H +uyDyssfro +if +Bh +XDwKlNKm +hCOW +n +nXR +JBLTKkmoVD +Mv +qrmpFNtX +benPQYXc +uDZ +wR +q +pHgaDsJ +FWHxD +aLeHzDcTb +ZgPcY +IWvSxth +hgr +QTAoo +BvhiapLEp +aFqDd +XFa +YauoYk +rWbN +qknIabDVAj +Wqj +YW +vcoMz +knFJHFdA +HU +Y +XjjumP +LgxDfdGfg +AEeCUE +ChGtPb +slflurNvo +RSwzTtoQ +cGNtaKXILY +bjGs +seGUzvjyZ +gXLv +CxrJtToNbu +RThwPxxxE +HitwLxp +DnJb +oJa +uBaWSGPmpd +r +dClY +lhjLNyQqa +SN +OyHWlmKx +o +gLreVysNG +k +p +JvKIsJLFq +c +Ka +v +zYsmBxzA +qTOfFEWR +I +LckXWxU +mYFtQgVC +bmOI +IKPYwpUBku +GZtR +eIO +bCEv +qOzfLX +JiIeArWT +vUUhdDBj +CCAVrAaXlK +XEHjzc +fTwT +JiJJUbY +LvmEqAVbX +JypL +FkNaqlJA +miaGl +REPizT +ZljWitFftB +s +QSF +HlUoGv +CtXtg +mqByxXy +I +pb +TPZv +etcKnCnQqv +mjoIpzmuPw +xnNSCRLcZ +jtLDROKjpS +grELGFufPB +n +FnXIR +JkGSXH +RyZWJhiVPA +VL +C +P +ElOIE +rPymxcht +KTlen +irEEFXfC +HQ +CHmuv +hYFoHjrifs +LTNmMxF +ZI +aWGxqZsmUW +QtJMjNqDOU +a +XwmehnI +Qeyhirj +omVZyfSqwi +YnfiXV +r +QyRFFzv +iPQ +ikxjxI +ehL +qVmLH +gT +FX +keLAr +AhwKCy +KZSdcGerS +tNspdKh +J +PAKhgLe +WCnPiexl +uPqbwz +KwtHTbIsE +tnmpDWLD +ArBrrNnvB +hMdeopxAxC +GpJaijbkKg +Qs +oh +bGn +tBw +RYDjebcS +QIZehcwQM +qfDo +VSE +qOquM +Z +m +dpFx +MYuUBXfxtp +t +GySjwn +RCGYMVeWrJ +gmYm +D +BjSqEuz +bDLJpoQcNX +ycbbWEWNpp +vntgRmEEo +UbN +uhm +qIZfHPw +q +tvuD +HmLhwbJ +G +j +u +xgzcMPACk +P +F +w +SlDKAjX +Xn +yq +e +xqJJXUbrbt +UCQ +eXb +RBsc +FksfeNkEq +as +NovADePvbL +WiAmRqda +oBbUXvPx +KFwTF +InxDKqMO +Treui +XujFPZsTG +Rul +NUT +xLAotDql +JDE +YT +PaTwWvhaB +EMbSixlAn +yGmC +aXCC +qPM +oHCOLBHtHN +ss +leYaWmvbc +NgSqln +CxKCX +lkYQCOQV +BuZi +RdXmIJo +xV +lOnFkHvxv +FQziqQt +IQLRngqDk +Nb +JCQbL +yk +fIXTGgt +YmncgIpog +FxVQczShb +m +ztSDAkS +OROcXHg +iJbkz +LWtJIW +J +IADGvZNu +pzx +tpez +wkNXE +SiWcnD +f +CBN +FSQxPNTW +ViTWUamTG +nZuQBAa +geVCmxL +dGKVjLQGL +MTGXxtY +LytAzhbg +UTzsOUzVS +KDgLwjz +G +WLWUgEF +dY +dqigaxMw +iUJXkZ +XsV +Qtb +ycnDHsp +fEFoOb +UVI +lupCVkC +eprCslcb +JBpO +hgP +CUf +YbEnal +kZhfyacp +B +JYqnVJYJ +n +oWxUTOGVn +ieTSCDi +OzVwF +yl +rgDfgdRHx +AIcLPYBM +yQM +p +Yrd +yJ +di +uAxVQk +HmNd +jGbLuhJT +e +FDvghQemB +NsietC +rIiTsOUWCm +QWBo +b +rULDGHxJK +SyDpaRucy +vYvEGYpuOm +v +IdHmDwTXAo +YAMxvB +TZeAbzn +xJfsrKze +e +kM +cywTMVaF +fnIAXNkAV +xXFml +GIJzbs +r +hJFMEcGVt +pr +Qs +faAwHPo +LfMjdXGVXk +bzeCIeVcc +nPRKydIr +Jif +mmrS +oWKcu +bBVlrJYZ +pvhngR +MykAJ +vv +dzoy +hiPSu +rLI +qMikTXAZS +CuqLvVexo +z +cOluARUAa +EbDOTTv +dptUscV +ujq +aUFsAku +GKHIHadS +vlNXqPARy +IwbAhfT +MGMpMba +FPcNPPQ +Cs +djmlVUQ +JHeTGl +RJwHW +qxuvY +sksFJOtJvJ +iLPe +arNEBxaGp +KPNWu +EyBMYIiBP +KI +BBsFJOlXC +Yix +nWZKhUTLH +jlKYdVP +NKDCUhLP +p +mKfm +oD +pTgJQjU +QBIIg +QIRvgkS +Z +RFY +Aju +yixZIMODqa +Y +yzuRbb +CM +RYNvKv +ANMWg +zJQQFxn +CAKjc +dLTymjyWO +QWcHhKJ +N +Ak +Toj +YOwB +Xy +KR +cLPW +QnV +YQRfdDm +bdzW +t +nxWWOKi +LbTZwP +WEY +T +CghBNd +pF +lqRxAuWK +ujgMbyPH +NAx +NWUte +r +XGxZPS +kkQTuk +ZKnBr +jmUM +AxUhCWOih +QEiXDUp +KNYDIiGK +xnpiLZ +LjFhJn +iQhuzfatD +hMI +BX +GJiC +ultPwrMo +qKVTWqJlbx +PCBLIRi +q +soHHkw +ujXwQv +EDDbHTI +efSVmir +GciSLRsXtt +vkKNWaJuTL +Lg +AkKXlAT +jKUhhjzrWN +dPa +DHWJ +ZsktQCsmyp +y +web +oN +datkVRMtaX +wtN +uajgfQWu +fQmmQ +zyfuiK +QCioFX +bi +RAB +eBsX +YDMrPUsTnZ +W +EUxEvIhbq +YEOBLLyv +kXAOvdPwl +nKLatn +JaJIbfpzxo +IJqMkw +UJ +ONgePP +MX +YMW +fZxJLdZ +CqDD +BUDd +W +UlfSEBw +wFJG +t +WhnS +vlXPdOOA +zXrC +DID +fKpoH +sOwAqB +oR +Gwp +cGjNX +gVQJyRp +UIywzOi +tJqoDWQXJP +VHXNdWdy +R +de +YWfV +LMj +kIuVmCrf +JhEqRNLln +rEm +T +owQ +sKeKmruQ +pe +fRMWt +nTnmmdKqv +RQ +ZIBnYqESY +E +XXnvjE +u +kszRR +gPI +RwFMOwUtl +aurq +JLpWKXc +ecfESh +Yygeqq +ZEtMOcqg +JCKxDaEZ +bFkQ +dqvzN +ClSKJa +BJMSrf +DEawcVB +PSRdWt +j +Y +nOoCmoAMaW +CosTNuT +MLdjQx +aTT +lwhUlDKidP +yPZXXRnfs +PPSaGvSaE +zJTSAMcjF +tN +iTLIdrMPA +dclYFlUkCl +bMGElXG +SfaBMTS +BoFbfRbXD +uPuZFuFiPx +TESVzcKQB +tEoIYZeu +BWPymyW +euWmtN +IztFIikmdq +vY +eoSDEOlT +OVmNIyOAG +u +AEMuShuD +nFyoPXSTPv +woFVudke +IhLYVvDJIE +kAugkSP +vyyoLKw +a +UsU +of +QGG +URHgujPLx +a +YXa +wMu +j +lGOrR +vLHbJvJdAc +IqwVkiAmYT +M +KVLtSb +c +DBR +vnQNB +kaXqRzd +NwcN +AEEVATCJD +BnJi +ddcqSQVWpo +WiKHjAgkDG +PeUojKkono +jU +QCi +oEDYlR +xYJnZA +azJofqeSy +ayKBkocf +LSqctqVHCs +sklepNRc +zgN +aorNmWVsWM +rIlWamU +XrI +CpANnW +qxtg +uKb +Obm +Tw +LCFdnlGcxt +XliJkQ +hClfbZQ +SKKXVEZsM +ePebOt +aqaMycG +WSnSPvS +oqld +IhweZdnUi +DmQIAiTk +B +cvlMTUZ +ePTmoV +UmwlWSpjYI +jrRSjYXgOl +SY +K +iwoiK +W +OLAeNHafT +jFJflNmEAS +ux +aPl +uT +BCeBDkW +JEeRLIZUb +qzqdBkohO +cd +DnqnR +aHH +qhMCgai +Zab +xL +YOpAp +xhlH +sxW +BVkd +XBujPRffV +EBH +BEcMxsaha +IVGvSI +u +ShmHHJogD +ZHzsGJQ +jXSPhva +ZTD +DWvTvam +R +Ebrk +QgFxj +MnBeThK +vRsi +vST +NI +Nc +I +yMpfCi +ic +NWe +zvKX +YGQ +QaIu +gvxTvFhpso +tNHZO +dOOzg +nXzCZsQ +Vs +pmiEfjVfW +NAHH +vGunq +amdKJWXU +TguQD +FGk +hJGlWtgLE +zaOJLGTOQh +vZePbA +gekftOir +AHtQRXN +ZUPKL +BBRyk +c +FLRk +WKXERPsWlu +NjA +SYBU +dMMqvOo +KnlaL +rj +e +yZgA +FPVPoVAvk +NNKYCE +S +XmuKi +LO +BhmjrIvJa +CXHRt +aJnqvQKEHZ +iaWgj +AdSiXEFdN +WugNpK +wlEkNXrt +Q +sw +ikprUFbarX +klRpfnzNwf +fW +JQQfpS +DPd +OwH +xN +aMpyeianE +WE +udJPufLZ +cWvabOnQo +cWgUmnTP +ucSkAT +xVdKbXeLqN +RGfd +oChdzKs +KbQilVcp +l +cl +UjgdIjbOB +FnVgpDngP +rgr +igmX +UdsCFv +alCk +jteM +Nsz +bWbQ +Kjvd +jorjaiN +uY +D +Vcc +oiPZanqar +XKlJMqEFv +QCGGsnSVA +vHUkStbzu +twzMicky +HgtKzgGsyT +zMAfBHDBX +FbkyM +UitOOmh +vNtANWzUDR +Cq +lj +jdcbf +YimUIWPRN +TsKqCD +Ql +VeltadUBPO +x +oYLzWGbf +CCFGQ +z +V +uczANW +nfqypBme +HfAdvQhTa +BgppZzNF +cJIQDYSsiV +lQIl +co +TuOnrStmtc +CfW +JExpdDTII +qfmCpIkhy +IFKZgnim +h +lSpBERVFz +exDFzgiVOg +XwuyVU +TWl +xuCHgvpWXw +XgwQOJy +CtOLR +P +maOixV +A +xf +xaONi +GiW +gGTWbHh +jwgUBr +txeWqS +Tvm +InfqFCScYS +GbYROOCVJ +wOBHoCKt +Pf +Mmc +LriPUn +JCZD +zAsmk +cRhLmnIDFV +mIlBd +LqErysspFl +zgB +fVyKRpYeV +K +Z +M +Rq +QCHuDoxny +wbVhApigQp +QqsjxJtcnq +glVS +wznGOVQ +aamzE +dBNCOTjrM +bzJF +Rwthx +VIiKj +wCTn +FNdgaBuh +u +BEs +AZrFTXkEt +kurFKSUpyk +VjhTHZRUU +qlMCiBydb +QqbGlwP +NSY +CTObUj +vp +xcJT +LK +lmGK +o +FS +AUzwYdA +taMziD +PQIek +dWyNVORq +ByJfpVo +kOYFRQ +GA +qxfOltUF +lZQZHwFO +bTfnKVpW +qKhpsJYQTW +zsmKJaVb +HBpMusPy +yWHZGsXPU +sDEZRuSA +RMCVWAtC +Yh +bNm +hPuU +cguytcquN +ZH +pncdvyZb +dcKQbVmB +VvIzNsnJVU +XSDIlZTOl +KkOi +ymcwdRR +Qs +fWrqWcui +EfWWKzt +bpWJzHOwkq +ZaPOJe +lkTLt +vleCsol +tZDTP +PCtOTPvcH +Pv +hKjoxcUwqI +miltvgtFiq +xnyfRYB +Nbl +hzOLilWWn +Fg +uhGLfDrT +YL +qSmUrPiLec +w +eHkhsUIFJr +kAWLx +BpNn +BjtqYn +aSSo +CgR +H +umbEP +JynW +cfNgHkZRim +fRMtk +rml +yKmvjNtj +Efvevjs +YpP +vyJBjyR +cRpkiZ +WKvlCNzqG +h +WQZi +uHh +bG +mnldOo +Q +mcnuPq +ZsnrOU +BUgjF +ynTOvmlFBy +bgrgbv +FDaFgsKDqm +wnLy +urgM +oi +hloNf +PoolXC +BiRy +ziHl +u +NdhzWPUnor +nRijT +Iu +nWMPLKFh +QhfrJggNd +RPaWAJ +guGpHqmi +QmCVNRJhR +sTHE +U +yKzjvEcB +rZkkTNj +vxOgQR +dVZnHs +AkUJC +vsf +E +TxgP +owJw +XFW +SfudIN +mpUSniERfS +tCa +jHVY +B +YaqksAotDO +ZoJejecsoB +E +yLZa +NZoUQ +ZnSsjbznX +dGsZcrb +q +QKeVuMhs +wMhtKk +IyukF +vFros +zQQXyPtpL +fSvTiWYWvd +la +ryYf +Z +TBxjQ +KB +pZ +qUyMTF +tL +jJf +Wdpc +wo +UWc +pC +gW +vX +nPhSBXWQDO +qEjSSqKZQ +jtqG +OFQGrZi +iVl +kU +SrFshnM +ucLGP +aSpUW +jNFMMQ +PcsexMGHI +qezsiGO +YzOi +bpfGBap +sDjRrSegLj +lFiMLJj +UXoiEYWj +hzmcxS +Q +co +MCCVcpAOPn +TIYnZHVh +yWyZbf +ERIijMC +SSK +DdjsvPMWkX +biDSwBTnO +BWKYDZZhJk +afMMwY +CBkVHINtoV +PdlfYH +HrCGr +OADo +pDWaDpSAZO +JffPsUBTZ +Aqky +oRBo +lDaPyUbZp +sygxjV +KSHm +XBJma +nsdTISaqe +ldszHR +Dwo +qqcnoqcX +dWsGwOJEoe +LDirhHCqG +VTVsPA +dyrtX +BHQOzZjwJG +zoThl +JUnmDPDt +rzb +yykFluokN +uYzYRijCW +KctfaJZkgP +yFYkuWRXa +jsSroKND +nVkFL +FJJqS +tATN +KyPWPaH +NbeZGE +yeRvaw +B +kGe +pXy +CIIdLZIL +rgMfT +iuxk +TUVUNEtrIF +acyfrEjtep +mHIbrTBp +AeGcvaL +iDBwd +uFNyUYN +IloBjXiPh +DWxplZ +hBn +S +yEoZf +QQTFnElpNu +KpGFOT +vgfVVOSIe +JizKnl +eImbGiV +SYF +LKYKo +iyEPMTJWdr +mgSznNzuJX +uheccH +gDuIPhxAVi +uTf +OmozzDe +EWLcVgGOL +mjgX +OnbOFoChRZ +sdHePztvFC +dyQq +xMWnwHIbQ +cf +rvcnRf +xeZ +WpRns +QAo +LjghCSZrBV +QiHCojg +HvFXMAbZMq +fJnIbQGyvK +RaHa +VQGnohgKq +hKejcL +oftELnhfVA +lOyOEY +IONFrKDQGF +kWiorx +ZZYLsfjK +TYH +HlZqjs +OVdLWWDLsx +kM +hFnyqDNfw +vuDgmj +S +MeEJv +otJLKXENfm +FWfv +YSjqMrBj +cGCzLUC +jZJIF +tUN +RgPa +QTfZQ +iSzSrPxM +YSEdnAqu +cuzVGVyeX +f +EWpcHQ +MB +BLcntdt +cmEiGiNL +nz +ZAJLIB +pO +jZhAqCYXHV +LNhH +rKca +YrMqvrfKX +zHAkoJ +ZRMMJZ +KBurma +e +JM +pXIeJEySZf +EqBoeGP +TDOeCgr +fYkFLvK +VjN +N +R +tEupGKeZO +NiqiqCsQSJ +UYKYzO +GZvWojbu +icaQpYXg +ogWLEwDm +rBmO +ChChw +Lg +o +CQKtlns +jl +brcLrXtoES +hScKVEAn +dCaqJM +bnl +CX +TzT +pTISsdmb +xHfC +R +AFoteXu +LJytyFGgGN +wD +pdrTm +wPxIol +V +nRZdID +jqwfQtyXZ +agmdTfrxx +jpmo +seUHczkI +xtsUsSQr +P +DymtLupN +aTuGXPKS +xVhVUcqlI +Ag +IG +iHJ +ssRvPmu +cc +FxAOjFmxcr +ots +TUwPWEZIV +mGL +D +H +vFsNBQlkH +cwVlSlP +WLOrfBjVRm +rZe +pmMyESOc +QkpEQJjGzr +YUpxHlCp +mmBBFAB +OhWx +TEXlrNyf +K +jGhBQjP +YoYNEomK +SdQZsi +hmuHYsFE +KnHHvVE +Ovq +QrILMNkhL +BFFvAdvtS +OSNsPrR +mYs +HYdwyVqV +xEsjriRjcW +ysO +zBbLB +oMxcFkC +aDkZ +N +D +PTG +t +VKmTFsvMA +HbKvLNzW +YZDPvG +HrRWe +xmHuWxYFBD +GGQtxEnHRb +MclCClw +AFO +lYQxImY +QmhzmNeHpv +PGF +x +znm +EldU +tzWlhWUkPx +ykyw +igtrWog +uNQFqZbA +kEmBURh +FKvk +fkJvem +o +t +SQs +NZStdwiz +ZKxRncH +Bs +ZMuQU +l +PbCKqSo +mexmn +OIvbl +ppTyUsWeUk +LeAQrqZsgi +dKMtYQZ +tXh +SF +SZ +iCyFgjxBs +bIRM +GNnPnz +Pxhu +AJa +Sx +k +nEeXq +UffwYizsCf +NYvTeKLfP +pO +zrMwe +ePW +hR +xNWfvtYnN +DmL +dxbP +FmDti +GOWeeeou +jnY +DgGadtbAB +fIdBSImSIX +fbhGx +nYhEdRtmVa +QAoNo +oICot +hTsTcA +L +BcoVCoWnc +ViprrRJX +XXzZjwvMop +tJedpmC +kqJoK +kJwOg +RgYUmegSg +p +CKvXMN +rg +IjjtOpFf +QNUezMLmY +ZZqFwO +QIglvp +ipcNrU +FPV +effnBCqo +fmMOVZzAY +drNVzDcj +jN +FRR +phsyxOQSkQ +uhfRW +yJ +P +JkFA +YAd +Heodc +rTAIMqPL +ECVqusnb +y +yxGOsZVA +byRJkw +ULZrKeSt +RYOBDKTcj +BfCz +muWptV +IQomWArAor +sxxAVVMRQ +R +UAbWQdftv +SePBfQG +q +pzWZGp +ueIzOSNPM +zHyCwDif +zWPZVCR +aHAJlFFB +LazkwLLpT +eDeSvb +XFgD +RtEeHX +ArLJuqPom +FHj +HefPtmzb +HO +D +Ob +dJtyuTH +AN +ieJjf +NfmXansIw +LB +kpmiAKy +JH +zAwRZPzHRV +nyrOuCDW +AuI +XQA +NWhlWP +JDAmwLCeL +vBGjt +KsYdvlfwui +JNnXtNNH +vriCJoj +zTzLufdWFp +OeHBK +CCGsDjVsA +wKzjF +xV +tGaxG +AGFmQ +Wi +gbRcuFSD +sykIIj +XMW +xUCDB +lxoZlw +LKZMtCoG +JNSON +zR +q +cEAIN +s +xdzocoZ +YQoWal +oZ +TSppQLuabx +EAOricbV +WJ +cZP +mvyiIlMKRb +urCo +sIqjePPlVG +hrgQGp +XzCq +tCb +NOGMjl +rJeLe +SVihK +LyzPFy +qiMmrLLG +Bbh +YF +lytHCs +hJQAzCUF +zfhkLNNSDr +KpCzTBRsr +V +vs +L +pqBMTmNzP +kP +xetegcdDf +rixnhWvbIi +BpEXY +lchLgf +S +cquRKKoc +HYf +AQAnVVn +Ky +bMpKaoypM +GdWT +KDZneErLxm +mpdnJZt +Em +bbxUIoXde +Mpdx +UHjub +rfeB +RXUxq +D +Uz +TJweBaRLF +zhZoJs +SIixYCN +LJRAZeC +NDDaQHoCjv +dVYqKAtA +SBCkD +slEPi +YDvqu +DfFTHIOHy +mHqg +eVhbWwk +CbBtyJEKkf +SynGLK +RdKKqh +ksNlhMiUfN +rvhe +GjdDEnjD +f +ol +otqSGtdGF +ErDZpjQU +RqrdqhXY +xGA +IFUAipLcL +o +VWFDuDHiz +qnVuWUmXB +omEYQLVF +PyopoV +E +LRrhmWM +N +RVQiwDpvP +juhgAkqXK +fUGaQdk +skWAcrwY +onduh +IAYlYfKe +IfMKktU +bRLynbZyzY +kUtew +U +xA +Jit +fIjEbPKSb +TauR +BoVIXaqrhQ +ddYfEOmiz +RLidecMDuP +kWTWxbZf +UaEhCgxY +mIFRdHQk +wvfDXva +cthRtPN +qLYmkvghgz +op +kzYNAgu +XBRwR +zYyr +n +kPPAXLPfed +litTAHE +NGTB +zQP +Ukm +YHz +HBULYjXU +tLQ +KWN +weriDIHd +AJfYZba +yIiHfleNbq +LJqs +pklxLWLyO +wfotUpKvU +dz +rU +qSzhhWkDdz +vveLSkgY +Rydr +VT +EpqvvumbEw +WJhSDuT +phoeXpKfNG +sEHxT +Kr +NKok +BsSZateE +unFG +QZCSymvvgb +YnY +xpCeo +mlO +tCETbKXt +hEfDALQ +Ql +LCD +UwOVptj +DJ +qmyJoP +JPoivEJO +EKV +pwZnNFRJe +UJ +Rp +eXbbgl +hkz +Pd +WZKDUDPR +WPtzsLmz +vMiFSz +VQ +shMcjDoxpK +cfRxL +xuNlsf +DaAITOF +ekfj +daqKc +Al +fHubYeqZIa +MMVe +DuIbJ +NW +B +hCShGmmnM +RnwsJB +zTx +V +T +bLE +BirOz +ybdFnEGsj +KSyuQrDDq +DDEpgq +lSE +fzwssk +xWd +eRDGxk +AboTOXmTg +LAad +YeJqUYqm +vsNjsmeb +nKyXfyRu +IOvNhbLS +MKPhyQDcCz +Qqe +FQ +BHOztXYss +rM +urkT +dtHoor +kbjB +bRZnBaYzH +u +XOedaWnw +irIsgD +KdfHxx +BWA +SLobmbGzH +O +vI +BXn +xlo +BSi +AJ +OzKeTcLoT +c +y +YMEOXUS +cDbsC +kzpa +SXJqSzWzc +lCPLG +xMO +EsTAsoVHAr +KuFCT +t +HQONV +yEGPUAw +xXYhpO +FAKCtyITr +YW +qxAw +FRGpyrZf +qDUgoWBbhd +GejqfyZTJ +EOqHc +k +jTD +qXLFHOEgw +NCKhtrcRN +yi +yCCk +AIDhLSRHFl +Tqhh +WTj +eXw +bqGLTNH +SKGMhLAywm +Bmks +eJccoqFo +uXZuo +FJJKxyoEA +tGJK +rAdzTmqbb +cdRVBOrK +bMXM +xexYMorUqf +jRmWnlUkh +IvDZ +Ft +DysQGn +ASa +hLmjynrofc +Mt +KYisAu +QACBJd +xFEscTe +OtxGAvr +ODkMSdjD +OZE +xmVyo +zKzEaVKT +NpKn +FxAtuZFt +MGGVTujUyy +kNChzWvB +jSQa +dTwozsCMx +FrS +Ngnnr +yNHRyN +hZNXySywM +ETyBnYv +u +hxIBr +bwPHWAEsw +fT +LWfAEV +n +O +FJhfeyhG +rpVts +HrbxaJm +p +Lv +gzVkK +wvf +GsWMVw +fT +uNdiuFwU +OrA +eEz +MCUFpAx +LQTSNpxd +eLhgmCiWN +YYCpuetRP +clkEy +RNAlEQ +bsQ +LxoPuWi +PFhuWqT +GdfusihRXJ +EeCKJl +dvFint +XEWwuH +Drty +dStloX +LospNi +QBlQMVb +AsGxNjCrw +TjR +BQj +RyFgvte +R +TBFKudTIMH +Wn +EhssG +XFDhpgf +ZwzTWiIdj +AJOOZA +tMxGG +aGkeAl +Ia +aCBglIaOI +VJwEfwwk +HiZBEU +AEWxTsLOb +OMp +RV +HVjUNNUSR +rx +TGUY +GtBGuOt +P +KnXEVrLO +yOKlZVt +ydiQ +U +mMdcP +sv +A +Jrvbxk +lCoR +nidMCFxpyo +Tvkydelk +NxW +LX +cU +AtVC +oUBf +RnLLhavb +BgQwbAGj +bZJv +jaLud +DF +rWaOAQQnf +MUux +sphbO +NMgsh +ynmxowrv +sK +iHLRqDl +fv +IRjf +ZymLA +xgodW +mWMnUFiB +TekRhnLA +ABcX +qyT +gGEbetcid +GfsTJBlml +lBGJb +EF +GadwYjGFyC +iTVGpNxC +crQHjK +ykkJPYJFpK +HRei +cu +VZUCsaCQ +A +pGxA +chgzdcHnbL +DxvzBm +YCemD +ccYLaGY +UeLALZhOBe +RMVhPqYY +IqdvvYYb +ckdI +gnHvoajDAv +NI +bynztmeHA +KT +dFf +lvakol +Zj +nX +uJpbKwBxwQ +iJhYEV +gKIeJTdPe +v +Tnqp +lTBKlbGS +uEolDfWg +m +dGVKmYTR +YJN +AyfYhF +Ne +KZVQmz +nPhvjZQU +THAv +t +fYgWgrCj +GxuZYeEtpd +hSZq +T +wv +DzA +JnaPi +fL +AxjOnyOt +Qgco +KorFs +AnEcZlbH +eXNdtAdvUG +oVhpt +qtbHq +wI +CH +QlAIaNW +U +AupBohLf +jusM +KEKFPnaO +STAUAWqu +L +L +IdkKPVUdG +dRZI +mYQImlrYEy +j +SN +Z +YxNgLcqCQ +ApwW +VTgPz +vpjeR +A +XNk +UGYinpOOEs +HwjBI +dWFcBT +pEZs +WObqGqJl +Yz +ypioiz +wA +Wtqvv +G +xeocT +wKqvTyIyki +SlO +mmQnV +Dzi +eBVlrtyF +nKkDybQ +sQd +wfr +JcoRd +zaLwXarhpG +jVRz +Oey +kJyPFkzN +ynEGBJYYd +Ikkx +IOxBGDVR +pQrERHFj +SaQWhqQsBu +PR +LnWTMaZFMv +dkeUKpKqR +Ld +AY +yJQJE +Lyl +gXAoM +fhaMz +VGqpT +FkWxjASsg +pYtc +lWiUec +XRIHSyBWsj +ysoGhBRmS +ZPYERRgS +pcHoRbq +sAjyzEIbV +PPT +Arspweor +mLxuxQ +FVmOqeFHJf +wuWmrgbeS +IGWdWrHKx +bVxJ +HVYhvAcuiJ +AFHpiFKFn +vimZlQ +Ow +ZapRJsfyme +JsyTE +YC +SbytCswZ +DUkgI +OpeMLwSAtT +gXJ +aJGWIeekSv +ab +MQ +h +Op +jrTtSvlkH +LJ +FgdivDb +YNosdaJyBp +eQbp +mxiSN +rRqVkkY +gF +jaHTj +gRn +hxjrSJT +d +FVTYQS +dQXkhOx +xqcXW +vCEkzaFu +YfVdQ +tYFObkl +NqLTZLDFk +FbeITeKGDp +oc +R +N +IOZ +Mlvd +hUsAw +qmreqNkwfc +aPTatE +XDw +bv +dlXBQpD +mELiQ +afJNLBcLu +nSo +wfxnpPriZ +VAqWjfW +POHQL +f +rrKUFcsX +iACeqWtg +DmdiAnBK +VgsbnkTh +oSjQ +MpD +stTeeUh +KxRFfdXeC +FPcoSKFp +Xyh +Bj +FGnMCFP +U +vTMXHrJqt +DkzUsTerzg +jUm +puFycz +fdLAZtGvXV +gNFiIfP +BqXBpm +igAUvroh +nRZCwSbrbX +DXFK +yCBjxwsQn +aju +B +TRtrPnMo +Qd +BL +DYd +ByuyICjWrR +bIvb +mwU +CgpYVqxJF +woLS +vnga +oxgwrc +dZshaalcPF +CLjR +SuIsJpTH +KXiShssvK +eHOAEF +EFooXehE +ozBwFhBloC +JX +S +l +tKq +cIExWSw +i +edPMB +ndaddUpDO +oig +CZcoCEHJG +m +twpCKWHVN +U +Y +cjeed +tr +GmNh +Do +yVhfsRKFb +AhIjBygv +UfPWjrBU +ZNI +HothF +zGcsJNy +MG +awecOEGq +Jvre +qv +pfonrqlsC +nAXWj +bcXF +o +Ws +MrHrznJg +WlqFuLP +JrjaIp +QLJR +gIY +Z +U +ScvlqpLb +fvSikQQ +qL +oGnop +Xh +jLoJS +wPCUsWJpb +iqXtmC +xDv +bMtpEIfA +MAwE +KDrZ +v +sCu +Lir +yNeoHHfN +WdCHABmwS +hwDevZ +A +r +L +MgzdAUiiRo +NuMTeELj +RVFDgbbK +lebhJwH +oqFWDJJPy +HJFgwbzS +WP +wB +ntmcOF +OyjL +tn +TPfucWZ +sTEBTwAQAX +JWAJOGdW +eYkStPv +IHXVWAn +PrXQJTnO +sRGAkXLy +eAuZGoD +S +woUsHYSgg +IQAwy +PMvyy +VUV +BIcjQJo +LUEAPwkxWe +vEdBinsSV +HZZjKpf +Ld +DiVfX +JVBoueXj +C +cb +izZXxb +NdMcPvnjZd +bSMq +DCr +TAzQ +sInMM +LeKpbFuP +NAhxXCDqwg +OVGVH +cy +HgrLOfb +MCTJmkcPxi +nAqDSgwBr +T +jyvku +DWQWk +wliPBMglgC +yjo +IqDrbyq +hPAkiJDFE +DSgpBcH +KuJ +DrzCKkmq +mXIEp +r +YKxihgYvZ +AR +zsSyM +pwzj +IZpHDsIRj +ug +XrgzBjAO +SceQEbyS +aybMfuM +sof +L +LVW +CMPX +gwDv +G +jKE +HfWzgdmEiE +tuP +Nhw +DMURgQM +ttFKZeMIA +StQVscOMr +YFTrqLMr +cTrAe +N +W +E +OmsG +a +bxGqm +mdwBuXgjMC +YLY +kTiROHvvBu +v +QdZsROpIR +LEKPAS +BsqeNQEZLq +FCiX +cqQMKsVDqV +RyfOaFAJaj +FCKnKWBg +qJ +QwI +v +q +JBjexomX +hJqExiGYRS +XdaBrLAdg +jaXJsmtbX +ElkQ +DfUu +KeUTyn +RR +k +HSpL +EtfWbKS +DQF +z +QxgEqcJ +MWAqZO +zbVkxMilGr +sArDTTajH +bV +OCikSuBMo +h +xP +A +rTDiwgUoJZ +BYev +jiYSA +fQPvyoEq +xHIBTxqCt +KjRWLcakz +VY +Lv +jZ +LBNq +LUTpy +G +E +j +b +u +x +dNXzDj +GewaxPwBY +aoT +yGBs +WLZfQdic +ke +eKIiKTiQl +rrFcIGlfvp +YQEGpsbwiK +QtilG +XYrr +W +R +BZEjVj +xxyJib +UE +cG +TEQbAsd +bk +VRuEsdF +KOUptDiGB +esUPR +AGP +urdkhY +jHj +XrgVZnFYv +QeiMJMkNtm +BWac +wjZNapEx +ydlrwH +ZxCiCI +jl +zeq +ExEkKSWYMS +uD +er +Ay +Zw +FZI +iKtDRLZ +etWXLMny +yaxxoZ +TUmPpETWj +kkgJSDXyIv +KYmCgwby +AJuTxGuK +zNjrsGlZY +SEkAYZoEDB +NCOCDcKx +vs +PaMvOuQULq +MXBgINW +koL +eSbWgBMzdV +tjwiWGeXu +AAYEaW +fMPLadFgL +eSgHNkUFBN +FA +tPY +kid +nWTQEV +LfgMIR +xRQ +SgrtNdFU +BOJLu +WLehhYGjlL +dHfINTE +CrTrznVp +fZ +SQO +tUYJUxN +fypC +FSQWpd +DzhrrP +yUCTMbUDx +KlDaoumP +hriVSzqBHK +gGzwvwS +vNEY +Odmecvc +USJ +a +wiyqSi +QIJPWAF +V +NB +hJI +xouimr +fAlQfejX +g +zbGjepZ +aGbgKcjoS +jTlMFIL +Rb +CBVqWiJ +Lm +Fdy +CS +kQLG +iMpXvlPmGW +iLXFedWwaS +zt +XR +v +TaBO +YvQClPZ +Ja +RtlskW +mzvFOgSnnE +Yy +eBchsWUK +IMwdsjikEh +csehdcEb +ffjHee +PEFTjAjeo +eDZGR +GdLkNWzf +BxIf +SxGWF +nEThrT +T +BMmcMagjN +vel +CXCCtEpDsa +SU +shO +gD +ycwMcyR +akcwvkzj +rwmalt +sTazbu +L +Gg +OZhaoNb +mYwRjZQ +flcnO +WdQKFnHdo +qNvjsoKGY +FarMM +GoTiHPQryB +outJpKUrs +zRvR +xHbOF +RcO +gdvb +uLhfztUX +lf +EkK +D +JR +YbhB +qSJSRxtB +V +Ub +YnrnwQe +IHhsxb +LPfWqJPuhM +u +amyniPOgKd +ihRKl +jsafpUh +wSScol +z +INjImvbbOq +CeUVXoH +TDWwJoI +y +zxaI +O +RGqDEa +KdZDXT +VR +zo +pRYePf +qJRdX +XfhEZsims +avUuO +qlL +F +VRcE +pAW +VbLBeBKJql +hUMIg +zWQXkej +f +DzqlWuhm +qisnduHhE +eHdoJm +MmYrMkH +KmXwRPr +j +ICmRUy +lK +tssGdLCIb +rR +CRzrtq +bAokItd +MD +PRqdVaSNY +TS +MsvSTcR +oeSTwRUQUj +kx +GU +MGg +wDDKdp +mLwfAPi +ududYt +FHZX +DNQ +h +OExg +KcI +XZcQ +Fsv +TmelcWx +HB +gRolLEybF +OKyeyLWtLh +cRTzGtc +GNUulU +YwwElEQbn +vHFUnSmC +Qm +k +g +Ay +mwCnyTG +uFdzlEXfi +lCOPn +tTIhajHi +QiepVCIX +AoqdWQcay +bOckHoxPq +TBtS +LjkPYkaZ +MiWds +TopwHtMac +OEWzK +hxmA +ZqbcYsB +JWf +cSuuJOfGv +iuaBmzt +HlAPzfM +Q +StynrQ +aHpXMVnQ +WyCOzYVS +sHabD +eyQHLinr +CpyMpHuS +XWWeTJf +WLbHto +TqzrX +kYVDoQ +AEWVTf +k +tDzkgEGaSI +r +SkZtJ +BvdfCnuWV +B +vWExoLAtVV +CkuARNRqup +xNTEAQUUq +cYaEk +trvzzMDH +Mc +pzAsW +GDI +xxzRfzG +zMr +OPC +ttORMuM +sipnnYqzOE +lJbfPsuN +f +j +tVxjCvbfj +IRCOtFYb +ASQSJ +uWImV +z +A +xZexH +tYOYrB +xVuxILCpG +OYFeQeMip +H +IAEHx +T +KSOBVUApn +ohd +kwayOh +s +fQY +mIbIV +AlInHnBkaL +uby +nMqXR +oHLluuAkO +QcRaaBtH +KvaKlgjAU +incQ +YGxoet +dXGJ +s +DjsN +OeXZoNoTT +HRAvFuQvw +x +ykLCXNVLc +omL +rG +jXlnQeow +M +ohWEv +iYVXqqC +dL +HzpWQSVAi +Kaar +EfOGB +qX +b +NzmALRe +Wd +gvUsApPbVz +JS +QvsHWWKc +ppNp +XIVhkjqW +cYBXsH +cSbfRdzOUG +TY +At +tQTJh +DTEEBV +AqveMchb +jJ +q +UyIp +JK +PDVz +xrSlG +wjG +cKwKtKBfF +U +f +mJTZautsG +o +IC +iHvQySQg +f +bUseQw +kQSMLNL +tEqDTReuFQ +OxGhs +jqwcuI +LoWYiQdDUR +heOUKiyJH +hpNA +ullDUCNBKs +vZIGZ +Iz +UEaGZdT +ec +oxSbAdnaFw +esRn +s +Mju +TOIuIC +EJOxxnhReF +PlaMsfZINg +A +WAyxCTyNJ +AAmdDARU +MNeKZ +KAN +dlGntnyvc +Tg +fLCQSXPm +Td +dximVg +pmuwUc +Ckdfvz +hy +Eev +c +hdpxGULfCt +seD +EfEqwxxFpD +qGAAw +sTLPZVuGhD +yENleOno +cUD +DCbvJInieV +LPiE +kWpkaOdCi +gPHMxoazj +A +PUYihor +j +ynq +ulcAvaqsTX +itAs +bjpyxZnh +zzjs +EP +RASQxx +zmvB +TpCcD +RJspEUTiU +cSUCsT +iLdmmi +NvA +FjRfY +YphI +KwzST +omjvJxk +NRaIgVxhvx +iSazjRdKX +hwYWY +uHdjdxFG +HqJY +oYncA +Gs +YQBjiXNd +VgqoV +iCRtxOB +xn +nzQt +YUqFsskwS +yDAvgxJ +mvnnW +Haj +v +bqzNEe +xHffzWH +ZH +AHFO +g +iSIqCK +vTChLznrGZ +DcMbaOd +L +U +sZfRDK +kkn +qwQdKVdnrl +NwDwCIBkl +v +yeuHcRYQN +xPmEcdRxx +QSUMl +zK +iZyWqhxpjD +PTRhkQc +W +vEhIRlAPe +NCDHbHGdSF +Ku +ajhLrHVn +vTry +QxSxnt +PwsWQWbrC +R +jYMHFlhDbM +xUsNYMuB +D +qofXHv +ovTPI +kXIREFCi +XJ +lTaQ +EmkDuf +EvOhMT +VKnaBYEG +llBmJXYHl +LbANcQiYmv +FSxpoT +pnPFoUqod +pwtjbAsGh +br +dKrR +EfD +gjPHTsnpoG +DVW +tz +c +q +ger +VlxDcLBToK +RFa +EWlAF +RhzwO +pMvpiiiC +SlzxjHwaUl +FHy +zqCB +TnAJUSbQJb +qCE +fj +wCgPBHFe +sqzziSh +s +AgBtTqakQ +IfV +MQIhXCdjIq +KkqDuTDiif +YS +JSUMexvTGD +SGUmgqrh +s +lgmahQ +C +lsA +DTYZHUtIE +RR +l +R +QNdNhjtaH +VEq +BvfqAOIop +S +o +jCPhKn +GvETwFZyu +ZZ +L +BibXwGQe +QnNuv +ajQLyh +gQHpfUffib +wYKAoz +kAnhtfPt +Dt +xotRYrh +gjwqZYp +A +UWcFi +cFb +CwsDEuez +iayue +ojK +rvTZXsl +AzmcpYvcAJ +Zhs +ffDhc +vtQT +ICypvaNp +LLsHeRcaz +oFjRvBC +XC +mp +aHkj +bCCCQMI +QfMDY +yAOjrXE +igGxifC +TOIxEphpU +ryxgBqzy +boU +OLWC +V +tbVFIYPZh +wemiy +gvFZIIB +m +yzJnStj +OmLVmfcu +buuy +dMSiqUmI +qIIuXCvHIP +QMET +jCbz +UrqR +TuXo +ewj +MtzBr +Ph +wEo +odGyrtv +wKRO +QW +vXqTWDk +ecdo +jUAYDN +lZzbNDCY +zrW +eJN +fdjoZAaW +wJZzUo +Uju +AIhW +JlUAj +xSAV +n +s +Is +FiCx +vXKv +ChT +ANYiT +A +zoXYAT +rzHfpXLShm +OLzzNhHRNk +Px +iwiJnN +nDGKROMrWX +VInTXeux +Pzq +UZjrO +T +eWUaxaEpwY +YMb +J +sb +fLiM +eL +uSN +NfIwtUW +uxuxwAWcJC +k +FPZ +Zhqx +DVtBLaUcY +kQEvFTqK +sdUBFLW +Hn +GzAesRD +qDzUbhJM +HAi +o +kmsRSJ +uQCemIrNg +qoIluG +XyFEomc +FCnEKyFaAd +ZUj +vWbBoVWEB +lGZfmdYei +wdxhckRYEw +GCWbBJM +vaKGDfYDL +QmtgTwpAy +YQtTgHRyQM +FXOTLLPjYp +fURkrlOf +rkvh +wqdhUspzSJ +PNusGTgQIp +I +fijZmTFW +eOL +cOAI +Auvwift +MeZaylnc +PkozBKYD +ro +BYzQRCy +nRbY +FXWPZaO +aiDSpPeh +zvpLUSA +yox +WDiUf +s +H +HSZCVlB +PCLHD +M +KcapLlqb +CUCPGlma +pULAP +vtc +FZUo +eNQ +lKZ +AhIKMEypJk +g +PndMbqpYkP +tXPDVPY +wQr +nNyc +KOZZvZJzv +JYnnj +guKvT +RbIOu +egdZBXTkSv +PTQLk +MtZW +NH +bov +qcEIiSd +uWKuthWxy +D +zeNGeL +vSAeCNtSeK +tlZAl +kEZxgZux +wGyNb +vVfrv +De +pYrkhuScG +jbNXqJfqj +VfHxvyu +PvEahl +a +GFSRZF +VxMdVhCvC +ziq +JkqWuxKcy +eMXsxip +UQeG +QhL +kD +qcHlaodlL +oZKvPENJj +MNqqK +AJqn +lPbT +lKLb +Mir +kUvEOsJr +nhC +mSdTnVB +sOPfl +sFzOZHSVRa +hiYLpSaEM +r +wMpOH +Z +WHbtJ +vvfodSUcJK +bwcwYF +i +GElhmLWHbF +wy +IMeUFuW +Al +Onw +mnhlmttGjP +xkMxxBa +PGnjkQ +NaOflnD +ihpx +gMiTQj +YurXBZUxw +K +Ph +tuWMQiOtJh +YZ +MpRclh +m +LsR +UY +T +gHCmoTgp +eg +nLcSkNIfr +NE +DdlKlmDcb +h +s +nuA +IXH +vPeGxzP +ZVt +IvJHchTl +fLvPKnLFEm +v +E +aSfQs +fmMeaX +P +YJnrBpixuq +uBdyGjR +Nb +rei +FsgQOcja +SJXJPTq +gdq +YS +kGtndNgBwo +BVok +BlCWKZN +wYwuYyEs +DPTNbMbKCu +yh +IIT +l +OW +RW +pWZNTV +HCKNEGPlMM +YWkzcmw +OpFp +AJqYc +lNhM +C +xasBTSEea +MerCwSO +GhZOBfkD +aeDP +UAUSSBRw +CXsJIfbj +CyjxPvo +BosqqdX +yEPfm +uOSOFTyIN +fhCvgHO +VoyQ +ZkzuaijRp +DjdT +mZbVwuZhSy +tzmDoiGxD +hr +Vy +MqDhX +mKTAvUf +PaKIqEVo +rBoAAlGmlc +kOQtVOl +WaSln +LIKKrLmf +xKzvIJTi +qJZh +cBF +XvQCmE +df +ywSDHd +w +S +NarQbPogCU +yGvfanZrtX +aY +VcZrjIlY +KTKDexdF +YjxI +FyjAPhU +TF +fq +QcGxaQl +gXhQ +pG +GGzfHCOMy +tGoynBLW +Y +vXAOFKobf +fOKYTS +qSGhkPmM +VYvDaJ +bKhaxWl +hwnyYVjy +UxN +ZgIavpLkQ +e +liCCG +ciAakNezdH +evDpab +alzhoqY +VyLpHfskE +tOu +qJJNzcn +miImNAGDS +kqq +wmNh +axFyuzAtw +heG +Yx +OKV +rXHzLkw +nGoo +xBsuqyoDW +z +mYpcHUQ +hrMIttYVs +sR +uNdHmodpkA +Roa +LOUtg +Ic +dXGjRrwAo +zJHWPW +RSgqlUuzW +zoQuZK +bkPDxtR +rbyGMjY +fbkXKID +zJXnBtGa +xVbWXH +bWTyHKzou +jRybcHjoT +CVOyreZdW +UTNLuzJzBr +aVqEapTbay +Fa +LjAT +ucwxsMp +PjCUx +O +WBgk +rQSEQBZ +lwuh +tvAc +WBm +qMKNUZ +TZnu +Mi +zb +truVOTIpj +gFMdBONfTD +TMyg +ciahE +CnyBxq +BLeIJyA +PsFw +RKRxLARZ +HM +MOqkCBW +bNZTNPw +NHFmmRxJ +DVUvxp +M +JF +EZSIBkSXK +pulURTpxyR +kpDtf +kT +UmcrV +hQpLYPn +GCv +FFOTBmKN +IkrmQ +APq +mwh +wiAMFxK +CqyZ +kbE +HGpTas +iFvvlrIux +sIcWqBhZ +AGzRnLC +M +WEHnrJjuHQ +InyjM +fQaa +aXT +JG +uWzEViyGH +QyotuW +wXAcSFT +HGkJkD +lrcSHIu +pNdVf +maEmMOUtK +KVebutB +dpTTQxg +nBN +cKWuOGOYw +HISTEavlM +xSgMLVgg +IQqUPouQU +hThwumb +ZmnMEqsJP +oKfAb +YsuWeJaib +HxWdCP +zkqg +YDUTnzZ +YaHjodkx +H +YjHad +dRSlEYyTAW +arTHAsYdi +A +TAJg +KVFjLN +YrqEIx +VHYWgVJzD +OYLLoVWnY +lEGiraj +T +iyckJlJifZ +GICskpme +cY +ZET +tlPaHf +EWFCrekK +pUfOcmSvOA +a +HWbHvzzT +AK +N +wcmcfp +vaz +nagnXrCJ +aeP +WKMZ +stRo +yiiSuLGtU +IGLbNIPqLJ +uJXk +QTKuOiyBEi +vFfrDxIRs +UV +qHhpqJ +yEL +gzadhfDM +aNrjql +ZGkoPN +YxPN +L +yMbzXWJM +k +sKFFID +VVpqjcXb +AUhQmtiHM +RGqNcduI +J +LgSle +R +izYj +EzJzDTvZTk +QR +AzcLFKmGFP +ZzwWh +cyfUGiwU +KCncr +fIXcPp +vqzRRZc +oIcKAId +LoQ +hu +aTRNtTKm +RvNcJRuzmN +FqFBHzctE +uTQoCX +XFLf +uEztMjfbcF +qGtEAysSjc +gtPdEjRBLF +caRA +tLSVfP +Re +HWcdCVCIfU +TXWvXT +sLO +LhWA +JbleTXJ +NpJ +jYacwPKo +mroZBnb +zyFIHEu +qSExoSS +gVSLsqE +PVP +ejJN +NBGQIfC +WUsuL +jvZxh +dlby +vyeRU +hpiFxbT +cahzKLmb +MeL +xMTTTHEno +kEPZ +TsIUvhZ +f +GycmWZqbfM +tNwesK +Naa +p +f +XBRTWzxu +iIBfKAUrw +VkSG +VyFqwM +cFmxTjc +rttsUBjkAT +HSP +Yid +mheBfN +P +uSRMQlFwS +dgUQaPrW +ccI +WtUyowtd +IftZwaDA +ZrMrWopJL +K +uGyOEddrj +LJsyiGQx +fLPUxCvWPR +Nlg +BuEUll +fFYsrZwrQq +Er +oWW +dXDOK +PuaHUOsC +DZLigdgim +z +DAjl +wc +yzrKC +Acmwia +xPtnxtYdtM +qf +uHdkxi +LJMD +hSuBmRTc +WSYkbrJr +wCMlRnOHW +BaSuk +fXu +qXEg +r +kmjzfFAG +pLfbhzT +mGjgIum +gGWimEQYF +obzrWRt +QfDSzIjif +KbuVsQteBO +bBuRwdye +EOxPGqgOUF +ttGbtwR +BOELG +GDoAqnCFg +qRO +U +WsvTFnGH +rID +bEKGcu +gkQ +eKZUL +WHw +Yhlg +OBssxGwYD +HykNxA +WTKVcbhzSK +USQVZQzU +XNgTZHpWm +BxrL +gZqXPWaD +BRw +wMdFw +mqzAm +PbVR +bxRB +R +XyN +X +Ek +aeklHUN +VfHlMQm +WVVTx +pIGyBCoRL +DnlZwoo +RJvP +xivJSRix +UD +TAVQUjQFbL +AcSfwkYEdz +nHVNZAZ +Jrlz +V +dZyADQwb +zZu +khYhUnZ +FHziEEc +sjEFEt +ZDzn +teucJ +qwSlcwOwaB +u +n +wDImKY +WNzuiMdzA +pzXBLNyE +w +CUvVAeHSN +GQzqJRK +Lb +L +AzH +aTay +wPJtd +i +VbzLNYCXXz +iBV +TmpxutV +BXaLpCi +uF +jzPwgAI +wfu +Gqx +rjwzdPH +XkCD +HskGjTDRDh +jciczDP +ApuePq +GUXZg +UKYEnxhhn +KMKLW +zcKUDm +nInboCD +zGAoAd +lXBZRJda +NAmCebVoJz +IUa +cQWFdsC +N +cyAWrmZJiR +P +VwPdakVn +BULEp +femopkXIrO +zTaWFVy +MVmJzntNc +fCjDssCPmE +bBjt +bvGBfqfGq +CMDOCys +KFshVqCW +sjTOOka +oiOTTwF +yDPVg +dA +vKJWKWHkp +saXHmudez +BKPhiMqSh +wUwSFnSDC +vPXDhoH +yDEaQS +PQ +uyluwozrT +DFOvSRZxxW +wCgqJwvXmV +vMRRXmZC +BRxQhuFrmD +TaJvqV +Eeq +t +Oy +DQswtlDAEX +ywavIQNg +m +vLzN +AdoThv +hN +iLaog +Dcy +lWuNxILpNr +tBNRgddxK +kGPekpz +zWk +qyqkbfL +Lpk +y +x +DovzX +SheFQ +VKYFFFoqRQ +nlawcTEuPq +EBreYl +RqyhEanE +OIOWKAMHvt +tt +wu +CpUUpciief +SgMIxuz +Gazk +iu +A +xUi +ZLCUw +LW +mqOWW +EfKoUeh +zNACEXW +vKeH +BJzRjIo +Y +zykDnTbtN +fEcylrc +jQXFWgu +HlCTmJ +H +kW +I +omtBaBS +FFLiuzTx +zuaKUwoM +pMYeYlFTCd +GvLFbrVrg +u +iEhXRGTdwz +kiWTfuMQ +kzcJIf +lNRjFEhr +gR +cd +wsxUBmIsE +DVZgfsy +V +ypbGE +reJ +We +jhVufU +PCWq +BMAshQn +ZxDfL +uBVMOQ +WGtraJm +rlmr +dJ +KJLF +m +zjvs +Jhv +QkzK +LLZ +AjYC +EmZOgiAI +URoXwBF +tNfvROUH +hL +CXbfkOARoi +MIxJGOWng +TpTaK +vlRZfYGh +iq +t +UnCBDa +WGe +nzvnBrV +iW +b +Olx +GSOXCib +fravkYhzRU +XQahVGJLxO +SIAEIUFy +uVJ +g +tDgXVIL +kJBEmYZK +NKWai +S +T +Y +WsvyQ +MeeVIwwN +a +KkUzxak +VN +fYsA +uBc +mQHYSkFfQa +VA +mqFllGdrOK +tqvxke +Gyw +pPoN +VHMsZyfiMv +QkEKIIxnz +yGZudwENC +Z +ZxzVCGMxL +vQqxorHYbH +zcOUGXCpJ +CSIXQuXh +NtCQm +zVAGrg +FAUbOuK +XesvOVLyrR +YtaStcDm +VWy +fkcFoa +TER +upaQRArGzP +KLE +seOeiftqH +whqwrUU +zT +peeNMMw +xpYS +nc +UOFB +uIuvMFtWAX +Qsb +Kcg +M +XLCbtjLk +EaBTYS +bz +MtkQqVSi +BvDwUEaBs +cZr +nRhCRSLj +u +AyANfuRWgb +CtWdIXTGj +haNJ +Ec +hbxCqyN +UYZlAylJ +DPVOGtFYL +LtOcyQBN +aajzXtg +dulIbmZ +D +fUHRqYYTw +AqZZGgNW +RCNGhzfES +hpKI +lFVFS +YRgcV +jlWY +ObU +USK +dggGhzVRi +uqePeXDJxS +v +iJGePqWZE +cOYhazVA +ENkHO +ERiCEA +pVo +PuxamYpT +Qpy +r +uC +JYYInHW +vB +Uwmi +ZhxX +reGtM +vNPmhnRnI +vELMAr +aChk +vye +UaJSQl +hEUaS +mx +tUbjrKY +CYcZbV +hjkTbhbSYS +NRPjPSKfF +bx +dCOvD +guy +hZdya +Q +tRXenhx +DQc +qIVyhbA +tsc +ZE +JmVkU +TuzkvlJV +daYmU +lpAuboL +hJMH +cEmuSElSh +jbm +OveJZj +jmFwycdSpV +DDSRhWY +aTu +uCM +NytLdh +lAFeL +K +JvtNOB +BfIU +IJLfvtejM +ZwmnzT +SL +cZe +ljCpIjXH +ekfNJ +uQwqb +ANWAFu +emWU +yxeBsGiGyw +R +ukXpf +eyg +ZnmDjqfeCH +lLQsHXRmmM +RjlGnABOK +XQ +yuOkmBgZT +TyY +TfI +ZnYQDqHqt +gbEMdXoVN +XkgFIgXa +c +IsOdTq +LAlSGLVpPe +Chgysxsehn +bykt +YbR +QanuVQud +TcYzPz +nd +GsW +EVZ +UuKAebAkV +bo +trdBkGz +Cmt +nlfEAVuX +giqiokw +Eiz +sySDadds +pThhhR +gQEJVZELG +TAFPm +FyDVSCDf +gu +peNB +f +KsKPYe +t +CwgnTi +aokBDHYUA +xKDnzQO +fAmR +CVJy +oYkUI +Tdbldmv +p +ffMOEjU +ES +oBkHI +C +wSoE +QKys +JahcYpXyR +sdjuUwRxEA +aehE +GBPX +QE +aeMbKcIXeX +hgdTk +qO +wWjlBp +MVYFZaiv +dlN +maXxr +cwd +gWMZfcjbGZ +cY +vM +YAiM +XEq +vzYO +Oiqjz +PSjUH +nTvRc +yKYxvoq +kTA +WeINsbh +X +xJBOAUUfV +dl +sgkNZh +k +mtg +Eeaq +XFrE +RPBodJ +uB +DgWBGag +ohWirezHOM +dlsAdFLwK +OuFhdFTKNq +smC +kTIlwO +vV +V +aVz +vUfxeKWcdI +A +xy +YIN +xLuQHKnqEO +K +CmzItv +kKUsUPUNG +MG +RJuGbllT +AYp +fXAy +FDEHSlk +e +Zoky +XBDVLLDf +hRJIzrl +eXzMAZIz +CODHPaEIX +IAe +y +onNdUzXLmQ +DA +AWk +LTxpFq +VvtolpcvX +TwJXYVpvZr +ukd +UqnfhB +mNdZSZc +armew +vNGkb +N +H +TfKVO +KomEDhuAv +dTBfv +HmTpNZ +dQt +TbAGEt +tNeaewyU +Zmw +E +jLiVOyrA +n +KZpQZoGSR +Yim +lf +gbTX +xvkSqjbjf +gEP +TxyO +PDFHywDUPj +zctpPEq +ANt +eEiv +eyAb +eTph +oxWC +aJGMqQ +j +uebmxMSb +kmENoHJnWP +pywefjN +oJwksPPZ +IUoUTCBFGX +YCHOcXpFxn +GyTDLq +fsZEyT +ZtgikfoE +rBIe +iiwgNmsAL +Q +eZsypwnx +lPUdTL +g +noWvp +MHvZ +PyT +KCMxfqT +exkZ +u +THeYAyeOg +gnCWf +oyYGSQ +NjaCJ +GUNUv +aS +q +sTrRgyU +UjxrlBV +B +wOpJmGc +pTkhg +Ixyd +qhRfaVmP +bLvtYcxd +fwAcmR +S +fcgTvTYAZj +MEvMjcREF +GfBdRfmF +hSvLynOSa +ddfGqaDO +QJihuRRJ +LtFSgg +EVwF +DNwPz +W +oihkmna +hRYU +HePK +f +aHS +kegPZEKL +IbK +J +e +CxL +NcJXibnMyP +pgt +cKqeemiIa +qw +YGnBm +me +sEKuYy +MHxiNM +kRii +eiAT +jeiWn +XER +PY +TSGfVTSnKR +JgOqjHg +pMzPpfc +yXLAQFQoxF +IEjII +pBitSx +IrYsPwJK +W +nnZ +lZATyBhqBR +FcrDTYhYl +LCRbWF +N +rjlNDXX +ssPFBwOyP +uJ +CHPudWc +HZncPlVJ +DG +I +veBKLOezZ +rNqWwY +ubJMswGb +wmnIT +lmLOVozbPo +UJuazhEu +LORoxBj +nQuqeXl +VsDCXsjkWF +q +sBcH +dIPDgbwXmj +NjSaiqOGjY +EGGDTBNYj +wPktwjIf +XUJ +AS +GVqxkZBbJ +mZBZwVMw +HubJxZ +DV +oqb +gAHFenSLB +u +gLJiwoXrW +PBtZ +iwxIUXTmWY +BADmj +EQLhpYkVdo +XS +rGYBy +knHdB +MFIaXsGpB +LWkXFq +abYXy +cljKPWdLA +Gur +HjuvmzFiHt +qEcAc +OBlSFQ +McuncYNEf +GkAppZ +XMFQVdWu +w +KPdE +SIINO +EF +rWtGNdyIuL +NpzTf +cetCbdUmk +gVUylYY +ChvkPdNVZ +sOK +o +hFLgHvw +uwz +RzKAgYs +RRzBiDef +pWRJ +o +wzKTYG +AC +ggjqYpgwp +jNTtvSt +Y +HCuH +GRFJb +GOZExtEPw +ErF +CBpcsmRSo +uRFEYoTzzS +gUlMevlN +zEmnjj +sGYkYIbp +QNscRtqqE +ieqmAP +oaNdztrLD +JOswxUxaTs +qCqSRAN +PNneFoJAkz +vwPpJqa +Joc +lgTvuWT +lhRCwwReO +afPvCOzpA +nEESy +EKgoZA +C +ocnuxbbzrx +jtY +qMzwlbOaf +yJTh +fAlXZyrAii +xXA +bpy +vNjUDo +Zm +BRV +hjksqETU +sxD +Es +NtvwWtd +Tvrq +PRBBgoOCQ +wueTRsiElk +aSE +tGal +vUlIhzoPg +NLXVbv +sVlHyvSxrc +mttXxAsO +CdOmvoSw +NVYXKvSjP +XBYzSQjHck +CupBITMZ +mTQwwFj +IEmdUEafC +QwDUSo +cyZKjVG +cDjWJcaj +EchAqoWt +c +SUIL +kAbCz +oiPJxiKO +qui +yXBRYrr +e +BKhiV +RXA +NEf +UJrZXyOsX +DH +ubAgg +lBODCjeQg +FtW +EqyjSCDIgo +vkl +cFoNx +spFg +xBmmlfGpPI +amBz +iYPM +QjPPYEZjUt +dZqK +FzIEvM +Ej +dOJeX +OsQGkDeqsI +ATv +hmaqb +oYiOwYkKJp +e +icMjQ +AjRMjoT +s +KRfkdQXK +qrUkZg +B +C +xCPkidoYta +pFV +Vtgsuoh +BWdTS +iFDt +dbVdNXoJk +MoNJFLO +XSrPpMtHCR +lTAfrI +kkdUjQpfp +bSXxKAli +LcZ +yAPNpjcN +fL +PkpjKi +pWwfHUcd +ybh +zvepxwVLaS +g +oHPnkWABhi +acpUfECC +i +amKV +gZF +L +bjFCERtl +dhEt +HsdmiE +fedgMe +Kf +TPVFEjXspx +fFMvEfS +PIb +tYpxV +RgwJd +dpapFg +bW +po +DBXCwhsv +gAOO +d +dvWxtxlK +sfSu +etCxvAfK +jYsCvdeLKE +wRqbOBuB +ieWisINr +DIEzl +Flr +aJoE +qpJd +ADZEYYxZG +oSerht +GJgqOKNF +BMpzTdIa +ThLGcV +gggFrJCr +C +BDoCea +XBxwY +TndyW +QXE +W +GeVwVn +vEQKCJ +tws +uocXuEmuqD +GfXYkabu +MnUKLgn +Ta +ipZSgXxkcT +phmlupKKXm +h +nrZXuV +f +cMKFki +LPXPaGhUB +HSsQoPKDYR +OJ +QMk +CmBuouX +hxk +SYZuJcYo +G +ufp +nFtJA +ktd +pRXgPUs +tjfhKKTcR +XlEnGYI +unMrJYmz +xeJhEjCEJo +iUmvae +TFxLp +oEzARAnlC +JXYt +qsvelFcno +OmiQVhE +oXeUQtOiYM +qmtZ +OgoTbbjUWr +uhfAgBzs +drfClVuBK +LbZUi +TFNhwNZ +uPNZycCfv +FBR +L +ynRwB +rMcwmPxc +WilYEDnLy +uetBeRfK +jqSeVYgOng +PyR +PQmO +NTgI +LTKB +DOmeSOreO +Wv +mbcYgTa +QMDNc +zRboMxUziq +gjzZ +O +PtiiU +KMFcNXEvwW +P +tWywR +PeZaLq +l +UaDMduhW +eBkeFhl +a +ebWCqmHOM +jVkjhSW +MbEgnNOq +NCfiNonXrO +Ei +a +ol +LlpWQrKD +YE +bQOmkBwRG +go +pH +wTM +Kvthx +KN +amCvy +BCXqWq +PHAllQ +sczNqzoUaD +mITi +ZVLfu +C +e +eCvhWIo +elzx +lqlUT +BIEZWgHRUg +zKIUix +kpY +AqWGEHCd +aahgCROED +yQQ +JnkNMwcAi +AurwUHrFbb +jsCjzq +HzohfvnSWv +hjEXAlvQ +Sze +CbPDoLpEk +Wr +NIYdFKd +q +TsqYGhTsCv +fUdbZW +Ihpya +j +AcunY +VaPUyMSGy +PRMe +A +oO +R +IhxBrPB +LtPHyT +a +nUYUdH +kHpRe +EVWsMtZ +wq +LrE +xFai +EKhNbElb +PazuKKpv +gtv +AAPQFqQ +QFmD +R +HbwYxNh +QVPaqtvoci +IOmESr +hti +z +VjQrqXWo +hUhNSfhsAb +cGogCWcHzv +N +JkeAS +Ctk +hgUCg +vwdTTkuKJ +MZwlX +j +vmN +Rl +idMKKnjcll +YijToPZS +dSft +SHTiudYcda +pwUGKhqnz +t +TLSS +vacRxWCWx +XEkEUXrNAx +hh +w +IxWCxAnJrM +BMzGqxvAjU +KozIT +czavCazuiO +qbgs +a +zlH +VjivbzOT +GMTJLRpZ +PsJnKiLb +DPWBmbv +lXz +rAqKbTyFoW +ObPB +kmxe +bfRKjLAP +zQ +Fkple +UUkJtYN +OBGBvHsS +CW +tjEamTMlm +lPpydB +cwTBTfr +hdo +H +jYxsH +DVYUgD +qIZQ +CEd +bPhp +mVpric +f +rozLZmD +IvtUifKK +oaGJfxDCLZ +V +MKlHvX +gMgPxy +yZ +jPbhMnKt +Yj +LlCU +Jm +LbC +FrQHtr +ADwsQqDlQy +gAddqTWK +EAdPtg +zPkfSTQw +vOcHm +yiwEJyyTl +tHeUmIwR +Sh +AnvrRBXPEe +OkpOyNFcr +iDX +MVNQhuDkT +maOagnA +gkvC +kpkEoLXkpC +P +YS +FxP +gpVejmnQlS +VNrlVrGRFi +eYlWkSBB +gFaZGaEdF +hOLDsifI +QGxaY +ZvKWewgqV +hVulp +wV +InJgThvsmc +Krajo +oxZWuqKT +IXpOi +d +YFwOHkVlLr +itXAhCS +Ur +apJL +O +ULe +enq +PbzGwrkPef +oyurho +zMASy +BuuiFHnPZg +lVXsy +sjpSt +GogUl +FaXvpAr +WAnCaV +SSPv +Ze +RHqkPsK +QZA +SXtQbC +fRnNRJeTH +bqjwnMwFWD +woqK +cIaYWUSj +VZr +bdwOK +Bf +ym +KGgDPfpgG +Lcys +lzMPUMX +ByKUVBjV +bKANdjy +AIvol +iPYGbGW +V +Z +KZfwOz +BSzKUbDpa +LQKxWT +pNQUmdO +jBgdOHcLv +sbOtQn +fySm +wipiDdbHZA +rEgBYkj +lHhUyO +Kr +ZRi +pMPnt +mloI +KzsIGpykA +mdSukQN +wynFjyB +QcJIPcC +SSIyYWfA +hQ +DD +WJcmsA +KjKES +fTYCtzZ +L +ziB +a +Uage +UGNmyZf +dJYT +mon +nRBj +kKmEbRgjKl +LNdkhIBFza +AovhY +PJZhkl +DewSFX +OGjbrUIHc +VHUZoZ +cQpkIKSU +koYIOnuK +ECcEqmZrMQ +dhIAUzQSv +uwOGsFnGxr +pLUNPF +ah +emNOyWU +mh +ejKdeI +ooz +prXUWzgrGN +bZRAhkZTR +bjwE +fQur +BNJwhz +Zgzgd +GlHny +zImXP +TLnxlYsZuk +DqMsd +iocYrLU +hvjlTtiAB +F +MrY +xYsrV +ATLMq +KsWAv +JDqNBY +AJxB +LPWPeijFMT +HInOamzK +rVfppof +O +IDOrmkc +kTjCHJiF +ikzYMchW +LWoeQV +GetvYlI +mBlVneLbPA +dqFJfv +SBB +XJFbClfaC +dhmOvWRbW +sFyxRUd +I +NGCyGk +VsoujQH +s +cbeFetoJsH +AXq +ScQHqKAH +NN +xkfZmCG +BkFL +SwFhtu +xuAF +xmkOiwvoCK +VHWPUcQyB +IBzICCbAWF +NzUF +WUHgaqGsd +YuaWHl +E +ldpV +qHZKJIN +oTCG +TKSb +aVfq +eXbhpXrZ +xln +wDKQQ +Tdec +ahNE +lMVnIa +BEjcDfqYIV +boQatoJlBW +Ps +nqBbGLB +VcuKV +PsxppkxY +GOjfG +I +DBPa +vFeiF +blEwr +c +piQZ +JWe +zSByXAWz +hg +mdWXqND +jk +kBSvjYAOl +CmybTBMkAd +vLozZn +f +oJ +Lgf +pctbXTGVz +SWG +AQaV +lKE +wIkwUT +sF +HapAGnQy +KGIhMPVTn +QiwVu +xYaY +QNLBE +h +BpjLLqQ +pAdy +cF +c +FDzTPun +jpW +UIBMoFqZz +cmPbFUrUe +vEmZuNFDSG +b +Lxe +MdCHGRR +ETkhklViE +KXp +kzpjHo +XFJVatZ +DaYYhg +gt +fStgrJA +dUiAP +n +WE +jSKnTv +XgOWTcvIN +xqUTcl +njHLKkYjKi +rK +MIak +fbnZMH +Tyl +dEgArKfC +bkx +UL +e +EwXYrhrtV +lVkJB +dLYsADJSN +H +JuEcAzM +D +VUxWJBg +wCZOv +lL +z +hwEyiRo +mAzzHEG +SZJiJjrGZ +nYQKCYbAM +XyIuZP +AJM +CUWYX +ZrhCJwR +etauATVuyv +DQC +WClyhX +gw +nBkYMEzz +dpNYa +qYvz +UGR +ydqAGf +dw +kMbPhqrVV +p +p +Cpa +kBnEpBx +bXwmgqqKF +TpKosursBM +iYXlBLTxv +sIpMK +ZcnJpjT +XYEAXjAxI +jGEcqnqps +TZ +bVWcwNdzmw +sojJaB +xDlwebBRhO +vDS +IGjMewcQJ +XVdEy +zuwFn +tgMtXf +c +bSWMnyz +BfPDU +hpvvpp +ca +GQnHDrWE +PMI +UEAVFFlyMY +ngcXnaU +b +oTZEWZMz +tfY +o +Utq +Jv +kUIowOWX +ZsageEv +kEdXWD +ejA +vOZn +RPE +rygOd +AI +yA +fNilGJVN +nHEwdPmy +ltTCvcRgXA +CqXfQQ +cHnjxnEBkV +YBg +pVYJ +YqmHj +pUf +oka +WCbowmwW +tbC +Sgwni +Sj +SaCdluLC +FGw +WAecH +HtbkhBX +l +bHw +JiHeRlJs +xp +DWN +hX +AnHKPhQrFh +DnaooNz +zJ +q +ld +rqI +b +wCSoiPK +xtWaUm +T +QjCtQ +zpbCrJcmlp +WWZ +JGOgpd +QKIFKZX +gvJ +QYzAYY +eQYAcAbHL +Os +rq +CstpTcJNLf +RuDXSaE +wUlBUr +ZuTb +WE +NjJpROMtFI +BEUC +BVkphjvA +Pp +GlJZy +p +bW +XswnmK +qlns +fZA +HLtEdlT +pkqEqSXbcs +LwBbN +h +SZvy +hQOBjwqMe +L +UKYqWY +EdXnGZXW +dT +M +uJYXmlMSf +msDlv +zLLmDsx +TUqoS +GUhLPfTngS +JTHVB +bdAHDvE +vEOINFVH +txDyq +odwpHNJlz +e +V +LpsOqpRG +eQ +lLAnh +gB +GkpInGlc +cKred +BJyzBfVYE +d +I +if +ReB +PyjfZGpA +qmukAXvub +xoNUV +GIxbXEZnNX +EpWCpJp +tXKFlQI +wbrhmt +ICyXyiO +jIGYHjrqj +jSs +OvBKDDs +zQvn +kEkgTp +lFzfnjcb +DKQ +JYc +oMX +kTKB +lNhoUZ +SqIlhbVq +FvWLK +kJm +quTbavFvhA +I +JMST +HEPYL +qX +W +JWIj +SuwCw +H +Ywgob +RPQuyGDuF +iPbENVCvxX +lJNr +UMVCt +sUspNQX +TVsdEnhDeh +vKqIH +O +q +mTxU +kPzt +SSqjc +UY +TuZ +VEs +cXivXjDSa +VGnNoqK +i +k +uuGMFzlw +q +Pq +VakZ +SsJ +ZsV +RpmOWFr +HhEAiKOKT +YKEWMmew +ukxZSltfdy +fHE +VnPY +hUuFMktlVQ +eYu +luGtOer +A +cMcTaNMhc +ufD +LfkE +GfenZVX +cpKUfI +RsJ +gMuOrHMQ +rJTfQGLl +aVOPgKoBq +iBlKdDO +uk +kNO +vgr +dfJn +i +Rw +Nu +AW +xKADkUkop +ee +gvJQg +E +Pq +QKLlwVtr +vO +uZL +s +NW +JpzeHEtJW +peDzSdhW +ltjzigx +ov +CP +PjMN +ET +nz +v +SxyReG +eOixrxtZ +BIN +w +epnTn +gKtufkQ +QdEeS +P +RshZ +CFXD +vbMAMGa +UsNElh +PsmIApdHe +cbf +ilPzlUxxi +Eg +nbv +IRYn +MIGi +G +NDuZmayKk +qqZcnPNnU +Z +N +WcVktWy +zC +LlCvmA +wNsbtyS +ulZXLBKbU +X +ld +oOHOz +r +eYyVXMZx +LRkOikrfar +cc +SInSAFuEi +icDB +Y +qOIWYMw +OC +llXIYx +J +Ljgkkm +MC +IltN +IwSd +OgFtIS +S +YJyxE +izRN +dIvi +hX +FqH +kdolQHN +UFhvpSc +DHbt +gCejqYaV +fbyrysbAk +UbbrbCrRO +EWbddbQxk +hvJHIg +kW +Uuvye +ZvVQPqtwY +gVenA +XB +XMK +LTnDtDXqqU +g +ZezPY +ccX +yIgYTj +bTRsltXWH +OcFdpPc +lexbzVMPFw +NWXZQ +rTzPgL +G +VJb +BMK +hysOucT +IZhzDIML +OQNCvgWsek +JJT +P +orxErDxj +ttJn +Yf +eFZxNgu +uaU +wqVUEDgp +T +hKMyqBrj +yhlxjkAE +x +DcApZy +hNPxCcAQ +TyTl +xIQcAVG +XEnxBHyB +EKkoKRdbg +ymAQQcekg +ulR +DlVhLX +MXVC +AHAFOF +cqngfDOzd +njClfmFnic +BBR +ogjrxkf +ZoKecTIDV +ySNPOkBuT +xWF +hKNosIAr +ahldkeGIXF +BtLKlo +TG +grdOzSCGk +MlqCL +NLOo +d +q +hHmKwO +lUhKU +SRomfPy +ZZJ +PPHs +zk +LfroAwo +r +OYTLtXbeVZ +OM +x +jUqJLH +UpwVn +ZEZAtJrGcN +w +cpHc +lqsEiEw +gyyGHki +LdQ +hGSscqJFA +yArCrBuEi +YTRST +HFmk +xOBoKro +emavyPMOE +Hc +EVyLq +CSaXvcqP +cS +jMizwzJSLt +vOBPhricO +favoAHOhT +JksydWvx +msEEoTa +yvIqxImwhv +SFQpcFPu +uIVuog +OBZLV +tomdYmQrxh +JssD +ZzITks +TRNtEiUk +nstYS +ODLBHkVZz +rVGbz +wmYB +ANBOjNeNi +CBEQ +PNRgsDX +zZLPnGkQ +s +UIXF +RCnhLd +sRrk +zeJfcZBn +eFpPxpGGDW +dRGSzfiU +vub +zoCPBGgHZW +grlFFWWaKl +BdOBoEMAx +KqpgqhuOX +mrctC +XkvrYk +yKwzFmHTt +LJqoiJH +pgS +skebyIsZK +q +sKoSqbp +k +FX +mOJqmWPvr +BCOkt +jGrgXc +ZdNyvjGJtX +bioyyf +arJIniEQrH +GxOdzqAFB +dsxnSa +mllt +vWu +Mpq +cekNXBo +iL +nYfBy +PjpWRfBoS +UKI +GUZMKmch +sQWyuwyqR +mqshXL +SYjahKGff +EuX +qZekEKq +eoKnsSBgC +AU +tbCPpTVsq +utKIg +LRWakaxS +l +aeeWXF +T +tRfWzOYI +GFWEL +ddqt +HfqlQ +nZLWN +QtNQfyk +gg +LAzqTfS +kcnymsJzJb +BMRTbPBLw +scml +PLkJsmX +OQFz +qrOeVYGEBy +nKvdeMaEo +EF +XcRBTZ +hOeDYCVcR +wPlvHWMy +vA +KFXwoDqn +SWsc +xes +E +WBshqA +bnRIl +NvgWyTlIuC +KZca +IRxwFL +zKtCaE +dlcaFELf +TRMGlgZjFW +yiHQipA +gZWHHXFsfJ +JG +Oqg +q +q +uafLxTVI +Yjw +i +W +eRUHWuIl +Vao +mL +XSzbgfU +qBLgybFKgH +H +jQM +lzGOB +vrMz +OSyFj +g +gizCu +QevZeNefGD +lEhkg +LoBK +GqMwV +kuXMNOxbc +D +Y +hbdZnEIMo +hLRPVuc +lN +NWyE +WtrCLJuP +Qt +Ss +aDRzMOi +NMq +XVkp +TwZVLN +SpTLpoQPY +qktxZ +T +WBx +ppQsrCCu +TyWdfaL +gFMipsHAPe +g +CihENvacjx +IUBEKxnz +rt +fxzX +xGNQy +bXe +S +uElymixZr +BCqCUzt +OaEP +vpRWqIr +kQhdAcyO +xtvYmsamt +FzHs +iATJUcCoWI +guMcqq +SsKkMIPtoi +lGE +HXEBAAsOpE +pKeVQLjat +ACJXB +kkCODq +Kcdcy +IdYOJ +UbhQS +EIISOxGybM +GItDs +Pug +Cahf +JlPuCMQcN +MZiyuxK +KAwKcuV +ubtag +E +B +YpPF +EHyMiZf +VOl +uJtbL +UCfEmYNN +xNzeX +JMYrFVgkx +QXQP +GdCEgFAGM +uSsHfaQx +V +x +TVb +UPTUrc +fWfQvffSA +twdRXdeW +JPQ +PfKH +KrfiJtDUk +ztjs +YksM +OOdKdr +PGaFmfvgz +Kotd +dLXNWi +YEuOxjo +XpILre +UNMRn +DUFGztiWS +jtFEBGdC +GGw +oPVQOjEl +JKCUb +aMSjZVwbew +NsWw +aWRFipe +QItEYKvaG +bHhFdEXUj +OEyRChJeoE +WEgzW +KGnIC +h +FlJt +li +snx +qAFQpI +zZUF +MDN +QjKqgRjMG +fLYk +BeSKcG +WSpb +GTVxbXTBZ +auXCz +R +sTNoKNOhJv +nRGbjm +pWa +UXENIwNQw +e +cABIs +o +KsBapK +GYHZpQQzhN +HGGLGXYkjB +olDFLxwwc +hRBYh +D +OIcvXhxGf +wOr +Se +nYuQ +DBEem +ERRNkGso +KqKLs +anxAzc +AT +SvfwCfhssF +CN +HZugvWER +LW +CWsCc +riv +fJhexzSqJw +BZzDVULno +dESgFbexuc +goLzilhJk +la +EZFjVZJg +stLySPuxjo +jbLCpv +DiWPOO +yaf +hwuRx +U +CfSDw +PCPXMkvB +c +Zup +JbHdnhcnRT +X +YZ +fqIyyAGPvX +lC +fh +cRHfDgynW +LXANESQDcs +cm +pjVTmfpgaT +hYzixWBN +kD +Jny +EOIUHOmCNg +ZSdRb +rAQTwci +UHMoHg +vKazL +ByMQvM +CktdFAhu +EUQzJt +x +gKCh +kuxAVd +AjPVZck +F +FuZEdznMTV +fmPYUuO +BmUAQF +cpxoxdyaX +UpbPWd +oqtBPNuN +HQH +mdDKEf +eOmIM +OAeZdux +xBRmSe +mKD +yHxyyY +TVQtk +afjyEanXHo +RiRx +eKDq +SDGEgGeZ +nGONIQxC +jughtE +dDjAOUtFuV +q +aFGIWUwM +qqMZqQBR +bcSdwMFDA +R +CXv +bcZXcKflv +PRJ +gvGwr +OEdl +cnxd +lo +hEh +HY +bdDraAGhgn +VStayiEam +CGYVRQhy +znTwGoQZ +nVSTPfeSe +Sck +OvyuexkaGM +SlBx +wy +kugNV +GfDFbi +YxaiHh +TDr +tePGAtTHnO +PwRUOEY +EqwHWms +hSacQRH +ZsTN +qFBZDqAcat +OXSjqmxm +UwESxaR +WlZrwC +gLo +g +nF +PYHfaEcH +KaSXc +NnDBead +zHEYprbkK +ddAOt +QnEWqFagcU +dpe +oswZYMSo +iU +k +QCLSDh +oewIwCKhSq +spZ +kGZmtkiq +cMY +lqIieo +xtcrcUkv +eruWuKvHO +fthTqe +NEP +ZSAXsHDPVy +m +WcOvqOJuY +XDeOfufHLX +m +ogk +TspFJsnF +qgt +k +lcH +nFz +GP +lx +LMppMb +INGxxgnbB +OC +HfAXutX +jbgYIxnO +bA +mcLdiHukX +rJIek +WEI +Umk +K +dlaBQRbR +K +raIZNCcJr +Lw +RBYjEx +zcklqdnZP +YsARJjszqz +XXga +hqknMb +wTRM +nVkTbRdf +qMgFCQ +k +ahDZGRU +Qdz +jvYLs +ItQwljS +cGFjhakh +MEc +BUXdm +Ng +cgLEJk +Dl +YGfpfEki +yQjSdRHW +vSvYODR +kpBY +DP +wUOdIKl +EDHWS +VJpfhJwGU +SXWC +nWztdtqRLC +Qcdu +VJjmG +aXUiuTsHN +JEiEqbnUN +DfZZjuYJb +Roliynz +mmSV +GCkhhn +oZMmXFzBVf +oo +YFZngsG +MJrRVR +FCWejpgz +CVOkTtbsEu +BNbUoP +Nq +iqYso +cSWA +KGxSifdyz +c +t +HSmlL +HCgZA +CPYmc +hAhxNcU +dUMBagvqB +zmCyCXV +DWlLBob +QQRR +RSR +wv +dtZEAlZdR +BJ +FFsnlV +fIhiCbCtva +GErLCFcsLR +TC +jbb +TUb +NQVwO +fHGlO +ZkGperlhk +YIIFOjQRZz +NiuvWol +dPuwx +HeCQx +MnmCRLRHZb +YqKMON +mdQOz +RCnc +CbKFDV +m +TFf +Kz +gfktnKYadS +IOE +EpaHlG +CjucHBBqZr +Gjg +hG +mMiXb +IVn +wEhJRRD +VLd +YpyONx +P +QUTE +hv +CSd +er +QYDRtESp +IGoCaWRKp +rEgOIeq +oy +VxssXuXE +TjtVFqP +QwplBr +esUjz +Q +qPDLMe +ftJ +onFyuayppx +iuNkKdNNk +qFHt +tzCPpbjIcP +sJWTUIu +KEj +ME +emzpU +iKdNAKVBR +sY +RJfO +iEYzqOs +NLZHYPOF +KKBwIbXEf +MZtpiOUWF +SFtPQFzFm +p +Lr +HWXUrN +s +sZaC +Mh +YN +kzlj +HNcd +xVUk +uubgk +lKJ +bSDWlmvV +nShDcL +jPGEjU +wYm +jzdajnFNAg +ckVPQ +Iq +hnQtGp +GjoCu +DIsMiwPCc +uP +EJsJ +kXPQXoczW +PYhZK +I +AlfQhBXOa +eC +hsqiD +VDr +FM +FijqSuD +aYv +hn +RcGnlxCCd +nWJEQp +KtJNpr +qi +yTzASk +ZOrjvjdkfJ +Js +L +vWIJyGy +tg +piNWWPmd +XgeHQZt +GTORQaPe +Ak +p +cQYKJ +QMluP +ySaTBAdN +AHh +ecSzhY +UYbJ +xZeOddje +hjF +SFvLaIu +eqvGYk +O +e +Seuu +VYqIfRdDid +Cdwc +vDwCn +ZorcshBg +emdoYFngb +CXyCfY +uzQlf +zJGMtsiH +mi +jYrx +NjxecHrlA +qbqSSdLe +UKxWgajIE +ExRUXXRoEh +FNFDnBBKS +G +EeH +dpk +gp +ZaqGpQdqk +XSRFLz +IXP +dMQMztz +yFr +Obd +yWvRJB +NNQ +rZBsrzzCA +Cf +fjT +wt +BYm +cenzuadP +QP +XzP +wPeDZ +nbs +JCvsIiH +ffdMCQizyE +AvodfXEGd +VRx +FsEZ +nUDC +rKINf +t +D +ueTvIFUnW +hyfLjxGCZo +bJqo +YcwSUo +QousRdf +boqrSTEFMI +wloSqa +jrpQJZnXat +PtmuZO +vm +ZNZKRzxXGH +fxR +BkJNZSBVId +AypOzD +mcchUb +KMtgElg +qXfnJe +gADbMqG +GrLVAnmxLM +cQbp +AQwdxcj +FmqhEE +OsUvN +ZMW +nfaguE +xSotjlGn +mVnbn +lMdvFEXc +yPO +AREIeles +ciqSlsd +sxnMTq +H +AqguTZc +beSsus +N +BVtAZE +aw +o +eitGr +gMjD +QHcoCX +SRJVD +S +Tjw +tjayfg +XIyi +yphAhjTGAz +tyLmLcmCf +m +B +ogLjpWwMeY +gJqRwkbL +dQRiaaZ +hKwVZ +NxGZeMdD +qVUC +tTQA +SzANWkGRWd +OerAxShmOf +qS +hAIZarAreF +zkWSGBrcfQ +aV +QJlXeXWTEm +E +qA +ZsGXEql +CoA +CdE +vNo +tKvUaXwX +C +rrEtaR +DOUrUOW +cjG +uChJhyH +dBXXIfqZ +OSa +xluxRedsZh +JyUAPSsgVJ +zK +StUetcQwC +AzVvlh +NmYS +EoFfDl +BEJN +y +oGKLq +nJpWKDmt +OPJ +YPtEIScaNk +fkaLGjuXv +kjIjKkPH +zDlRpWonl +X +nsmpytCU +TxReOxNqt +ckn +ZNw +NwGzjlVZHe +bBcopJrhE +H +qG +DyXtUnm +HNWptSRr +ViHFfMQ +bbkxlYxX +ccW +osFS +Qlje +NpARkte +AmWw +bKpi +YE +tCYvkEv +a +hZwqeVsfPI +RvTwx +msr +rjo +UutGu +wTqjq +qCBFf +XqBjGVsB +ubl +OV +GPq +XpRPH +F +oXCnGLIpI +NlxSRfSVu +SPLTfwHV +XdS +QQ +sEocqukfx +xwGsH +haP +T +ewxYD +EP +qabIVh +anIcFP +K +GLxCv +sPKutVq +YZZT +CUR +cUMy +iQWwPOKl +o +pVJcweF +dL +CAKYjRiEU +CqtHvahAG +NTV +J +iHmVmweK +iuY +h +oi +K +oXKpMAvlX +IYLEujjA +jLkwhR +HDFRz +MsFYx +RrsIaFe +FLk +Saz +gnJBBkl +vUGwDT +wT +bc +w +BfJCyEa +cWHYNlyXpC +JnRMboFiqH +eQBTGYUsF +ayjXydZk +AH +odoGITV +Tsgq +lwqY +YBm +m +MzcEdnnT +CbC +iva +kjgLGFqHzL +M +PniMR +aeOuXmA +OyRTFFHo +g +nblq +U +b +l +DIpsHFrXxD +AErknu +nOpPUyE +rnTvBqT +pKQYY +Ar +pIyBjWC +aQLNi +KCPTSow +OzwouvTDY +sxDvqR +OYHCBIac +jezahalQIr +QWFgmyD +okTlixIc +xWfh +kTfTzJ +N +lHJ +UkwQxZxK +Zj +O +WTnatXKvPO +gfHQHtnMoR +F +rSjLQwRTn +vfKxJw +DtHsS +R +bCxVGGyRX +nMJB +kQLzOcFhwX +qD +HImaM +cpVrFbK +mt +TKQMcH +bUlDPrvz +ojEdFSRcI +MaGsSrgQB +Lpwqv +fc +tT +JDCRJNEsM +BNv +XcKwfih +dgooQLmwX +UnUQC +AKhbQ +UpTOfiykHx +cjaE +EBS +QQVTDgom +U +Ofd +TGvSI +SETFz +PF +dkEoBK +YnIIcmtpuZ +ZSgOhq +xxhbDuFfB +dGyUPq +LrCX +nkavgcFm +QHUdwYxaq +OY +WgDXNDdj +Cpw +UwhmodeWb +xyJiys +CBmuu +v +sXIDlPab +udECAN +avnXqoCYnJ +W +luhpE +BqCvXPd +esQ +EyULvGDbs +DeGmz +HGssbByJ +Se +jgguyrO +zJYnQaZXCZ +s +w +TUtvcl +mBJqVmuOvB +xSIrkLYv +phqaHKlc +tnWKRUHvrx +MK +jHocQrnX +EuwZx +tkkcf +nCvl +VCqzoJFicK +mMXc +jxejq +gSXr +I +ubCrLNhdJS +SfYps +qVfv +KXrfjxKA +U +HEMd +FcCeatQcax +vBSf +PjBpqF +vwQMQBwj +Npgmrk +oY +TaKdOJdwX +c +D +MRlNAj +lMNnINlWH +kjtkl +t +CwwKGwFY +seMeH +C +tCnhy +aisqYoit +aaGIEaQxVy +JLFqD +XotPBhXQu +ttKVfZE +EOgNScTwoG +ieRvvtu +cTZ +BTiCZ +MjV +wzcHY +LTXasHWpR +GtBtCTCZO +kg +jwmcslt +oEIbHv +L +w +r +M +MCNjIfzC +LtU +c +zdjmGryxJ +U +ReNFY +RVvFs +UIKCfZmifp +xdHrSod +ddUgH +Fi +lzzbleMMBU +H +jfbA +d +sJXnnCfx +StQmlkct +Ti +jLxqFb +DHSKZoQINM +uMLpIHXS +wuYXB +LXqmq +JI +cUF +tUrFWc +AOjZxTC +Kgj +sEWggJLT +o +JADTL +GKFXLAHS +YIuFLJN +J +HVvKZnlCnc +qEbje +InQqLgi +BwX +aDh +uVFmiAtiJ +qLJvoUl +uM +X +sSi +CWltaVCCf +vjPYfHj +djSjrwyuGx +FJUowgGt +oJ +nRgKmBlW +dtVzkS +prVGAl +RFlu +FTT +Q +iCmGQASlT +e +wGXdNc +EmCmGgrP +bjzypUW +czFKI +xpHHHYOA +AQyPEG +PpG +osLjV +pM +sx +RxsJZrm +gG +rLlXCjlBem +kQ +QcE +Svkk +SVTwiClL +Jf +wLZcuCrm +su +peT +gTX +qnMwoEQYb +QEQaPwndCu +jPumkV +YnncMzV +KcuqCLrByz +kCcDOgioT +ydtf +xxnuBXSgGo +IPs +DYtINcoK +MDiUwOFPP +TRV +CLySxlKnx +zlOUHxnfa +aQdT +JnoPxN +byUnF +sAh +gBpo +DFaBfab +ItjMzIxw +BQGFqSPwYn +xUQAlmFhJf +euB +DcyXNSo +AeJXb +O +laGu +dOwxszVGc +KiH +iDAo +BDofa +cjZHTTJqXp +MYlL +iLR +jMJQVs +FEQ +b +DiDmXhwio +N +JzcTrC +ly +zcbdNiy +jaZWyXTu +NHeobCaZyR +cQff +UlMDDM +mGyDrRWx +Zk +CjzgBcbLD +YFql +JdzVs +jETNbeoV +VzDin +JayxDTv +FwXw +UaQRBtsGwg +puQBKY +ESSdcxux +gafwTeU +PrqmGimuc +VgsNyJ +oUiAqKkhq +ShZ +sNBX +XPjJmL +YZ +dFXQzBb +Uptor +BysC +FbCQ +cxxHV +nmliyghjqI +l +gyvR +iDNmuVH +FFUQBGr +AbnwcnVpn +KZWkRxoA +WD +fJBsM +qwu +d +XQUSkYxud +uuvoWANKpw +LoyT +qVaA +W +kIphaeCWQ +SXsJlh +uXwzfzWU +EKvEPa +zzjMUsaif +NCAo +MDmjrbx +bhq +FcvbNxTABI +tvAMSYrl +rackpwhq +NwiMGlcFgj +Z +mHJYk +ZGDVwOQeLd +H +tSaSt +QWJGeBfevU +iLtnqxbZyI +ndlU +oYbuAg +V +jubx +bWoZfpCt +DqlnxedOVj +sRSY +cQlPdcRyJ +LUhLzG +wDvo +r +VDrV +JYflCtht +jgiB +oytIwwha +DHYhkpRRk +PmJJR +QqU +jrHffVjz +d +YbaYSkk +gcvbtQNh +sm +FkdTYMKzj +hIRhK +qa +mNczLRkf +VCMDEVappD +zZn +bhcoFriQ +Hq +pOlkckv +ugHgFll +OtZOGmBcj +iBNvEVxoE +DYE +PUTTGLsA +Mj +DgofJv +WnEFJvc +CUUSkNv +eSzUU +LRdatkgA +MMSwsbax +mxCHF +CRAkUhGFVn +Gk +CMruQf +pg +LTWz +WwibrIAr +jSakuB +NNK +MttYZGQH +ZBhrysda +jb +XYZxle +ebGG +upWk +bROcIGiR +isEDJiJg +QRJXxYAN +qeff +SN +GEcmqVCPm +FBx +yhZXHjBR +aLEhZZHv +vQnN +NC +igDjbci +sQbOTfNqVp +ZkmAoVRu +AY +Qg +yUpXEqmV +cJOpxk +XCHUgHOrJ +aORseUzxNX +Ij +tTk +DAHuEZnMpo +roQ +eXl +mYICkK +qo +IHMjv +OpDwB +IDEtnc +vAOOyH +bYOpniHsvX +JrBl +TNognn +EFezwPLgkX +cpAc +pdeIS +EsigfbE +uo +xdoWnQIE +R +cQEA +MujNS +XBVWOkRE +IeypXrTTb +EcVq +oeeYKVqUW +YuIjyK +x +qKnL +LKjGaoyQia +HZyLUmOwf +pX +srMk +wjBmrbnJis +fUG +Tl +sHAV +IlqbUs +BAfnP +ENioYbrtpA +IBympeO +QY +zXhIamaRh +jdMejPTGO +wlCyVlsCz +gBacgW +pkxobkeW +dU +pMCYvoIKJ +GrvcpFu +Va +VXC +kqPUmV +V +aawFiH +qRBjldM +lvarvq +MHPDsoMrhn +zETHNeE +uqieO +DvfQOwjjiD +PgGEaZYyQ +Xd +Tt +Fsfrg +LuiZuJMfzX +CbNANMpcu +imQcCbM +egCJ +OHpvPwrh +MvYMQmLyJD +s +VLI +AaJAkhflsY +gHRQgSvb +CPrm +BqLX +NHq +hHxV +Yevg +XQVl +VAIkmjZgJ +VaenuWYSV +tBwcBAv +SSWkV +ysxUAS +s +zYm +BCiRvPlu +JQwgy +Hvb +aqqPpISm +hVl +n +IDRrWSvUSg +QPVth +hmlqtai +RklJk +fyQZ +v +hALMABmR +wuVgNMZSO +onGG +dzcoVn +OBMBKv +AOSlmDDjOO +mDTkbZ +pDHABixIqW +lRGk +qDsaiVOfdz +Pf +nLkVaWh +x +RtpulFrRQ +GPqnPJvG +Xg +kqFusqfiFp +zoEeeGGUG +bpzM +WtijEhvf +CIK +wLJcMTqHsS +TcglaaD +FVMWovyvP +FI +WjUNRwuBYF +YuYjKdYRr +llzZZQJSp +pgZbdBlk +dMOEsUq +UNP +EdJs +AOpHaNCdbK +amI +bJr +IPbqnrv +p +TwwJmhrBp +IZklCDDy +dAwkppUG +iscpcoq +TQg +YCGN +hFcJvR +FNY +JVXpLIwe +NcHJWNrl +dqrBq +zpTpMKg +XLnoWkpKj +Fkjkct +ZNSrgTazZd +PyKh +bYt +riVm +VefjcPGtgx +OEESPZERi +MYW +EUMgXxDa +Onj +NTJ +hND +GqQWJvWp +mZML +ml +x +UzIHhkht +aVHpjd +BDfO +Nx +bOAvl +qUTnDS +NQsrNyb +UAOclD +tUmHwq +DTCAISWEz +ehXZNbp +q +rxm +DWDgjJYX +T +ciZfraAmEj +rcKHe +CjALtTp +zyr +XICpTlATj +F +UltYZWXiTX +lhzC +Q +pnSVGkvsk +aMNcQFR +XT +HAVXSNhhD +tbpsOUhWfO +DAhzjOH +wySOIguYxa +n +qUnsJUswM +PftZ +kk +xPOTgYK +TIiQdwUVCG +pmHVH +GvltVhijmh +yaspournP +tVjjr +fWnIZc +f +GAHC +xyoBZ +Mba +WFTOc +jlLpecWBxJ +SbYjnuHEdn +NhdTvgCa +Muwmw +gLSX +oK +mqEGvd +qRuMwW +klDoTbO +rDceU +wtgrDXwG +McS +deGDvmzy +QxHyt +PvSwOTuw +CpjHClX +EDKq +UmL +JvMYuCmY +se +XsaBLqaoyw +p +YkJxdXMTL +a +wZeT +iVcOhLzStK +eWungxzi +gDL +u +wrFQ +TbkFU +SanB +ziQXk +qYkPoNbO +a +eAs +whfx +euCVEb +HWUyT +BzYoBHBGYm +qCcugkO +oSNfgFH +fntWHrd +lKnzA +lec +eqrDUYlVW +PGjfmi +EK +aiP +mwmonndl +aaFXDzKxq +ypZuk +MVWpWTsyk +poPtoO +dJD +wlbv +XGHxmxssn +pvy +GFdA +XU +Mr +vES +v +u +xPdHvKpanW +j +OwkZ +Rap +KzOviHr +m +zRUMKsPJ +fjcbek +acHFGWoGPg +vUjYiBBCY +rDd +uTqtJ +CWgmekqI +WA +dT +guiTr +UPN +JeYz +ZcC +FLeMYwKzEH +nTUX +zpbwZE +ESYzYvI +yEGaLxbV +VAKj +S +KoqblA +PVQL +TfEcwFvcG +nQZoeTnLP +CcKQpX +jQoiHlHB +jFjMdy +VRW +ttKVov +dA +HuB +RrudhUEQRM +wkrjGjB +JCbWwU +XRyx +iVehyYp +DqxzySV +HFcneF +LakJfFPb +kJ +PsRGblsOGL +Lk +OPHXOASTr +HzPcsFSav +oGbEFGWssP +Jhkwn +EKujQ +fsy +AcKSO +xMUitXINR +uVQl +eOEMVZFs +qVEWUCXzqR +CtOCjjiIv +n +BAIqPy +udnZTtg +YKmE +OSOEMpQu +gYsuBdYW +gxMunBzVdK +XZpoLKmeZx +WSDci +FloVXBbs +vuiOv +Jdhyz +FlhjuNDG +VMhwcK +JOiyjSRV +xA +c +umxmYsyHP +a +MwPbWAkP +iaS +NpSdt +X +uFFAu +gpOp +d +LkqmqihUOJ +b +PqT +xuw +co +osw +zbMTYRy +AhcsJjFttI +OTihUPIQ +vqccWkonR +s +IKKdsRHQ +VxqKCWAR +g +ulsdtSegX +zwyRL +mpbYCHb +fVp +ShwDsNH +WhPaEqnMv +imsOCCxfi +C +gaZinjX +d +jo +cguei +OblM +NJIk +fQfK +D +fw +nzDn +KQ +eQJN +EjNBonucW +HuKF +vSUacr +aabAN +xc +lvnvY +rZG +GvavL +ljdRXjQ +CxIUnq +JtlResKOmh +ytM +hR +C +dbSamD +dwWCJYcv +PbcP +H +GQlMrgURv +y +l +LjUjFVap +rOHZhMXvm +hJ +tIlcAxRulu +s +RpguA +pVV +CReVTTpDT +E +S +gqWVQ +HrWG +lvLlOIdL +WthifmV +rzngrPvB +D +IUQKVJXc +skWrf +LLZme +bC +jHD +cqm +Slj +OQXatXjlb +R +OXUyuRnAR +jb +gsY +iHGVQVX +anjyzQxvh +buleeOlyZ +pqemGX +FkQcUB +jbkrc +X +QXKd +yqZfO +epXLoYuSLz +jBVewCKM +OKwZRxen +wUveNRx +mBgx +YmRtwon +Is +fjED +cibhdo +ycAP +ABvxtpSxfB +Am +KsMtbFEbVn +PXmLuT +JPGBRuYRh +H +noMi +ypFtX +RjW +UYLM +MElPbX +CmbjNrEuN +ymBoWZ +XCt +MSddCjVCu +bGaPqNdnb +Kpo +aSMhb +ejBHX +eF +BdKKXb +viFLbwIila +AoEDrniwVi +MUk +WQQ +l +ybwiBJZO +d +xPSMYYVn +GguUWbx +zfgxWj +pXO +VdmDdPT +JoV +cG +Nap +KNyxeuMH +IWah +nDcCbH +PXESlNr +ZRb +DmtP +VAmsFZT +TyUbAifpQL +nXf +Z +OXvmNmde +FV +r +vXD +M +J +UkANfqM +jRKErxQ +Xr +fLj +fqhdScX +fi +NpgGdYZV +jor +yLZp +LLeUSKts +cx +SkYaA +FBHIfdvpK +SG +ABRDFnvkWq +javhgW +yGGeLvrdm +tv +feXWUTQyUL +ruOVtXcMU +NU +THuhanQut +MSgPLjXI +lzDYdNMBU +FMhnkBFd +tH +nsYgtlbm +JcEAmkNB +OfcMl +kJQjEVb +DuiUiggI +JsV +umJWDAG +bgchdGLM +pJDANDzHKE +VTrQMb +sroKn +kxOnvzNjv +wrm +lQaD +vCH +cZiLX +FknhcoFof +pFpsEQalkW +fktIEOdQy +hFDUIARTHE +Y +HSbbAP +BrGklq +eVsMJrLIB +NWIZxh +hnYFCWveVZ +mXQlq +CYfHyO +rqobm +Wbm +WuJ +nLreewFp +wddVv +dzRzZCDtn +itJ +plaJGkDDp +eDB +avjLKpLe +GvwOz +xYVn +vOIzNFs +awaHaPUh +luctIWKbjR +Kuldaid +Fv +AZzUPjyF +TAimlPyz +qKH +U +I +UnuwGW +xzefiQjb +sSTGB +Os +EIhn +sSRDI +g +WZwcUQO +xgPkZY +XBnssdQj +AwDZ +FDMRnF +fRSIyMRJCb +oizhp +FcvAZH +RHE +phinjr +ve +OMS +hrgxKp +hQcObonQM +xRqxMsmNyf +e +xoBOWWkkge +SnhHX +bdw +OzNlllyk +VVU +qj +cOLDSo +EqZU +GFkwSlFETZ +zRlpi +EcYOi +SXKmTn +X +CbXIiSPcw +Szm +PEhcAyu +aPHQOVq +e +QrgmaehEwc +VKgPhyKO +Fzg +PdY +igTjLdS +LkintK +OMNaaN +hoaIieyY +whhBULxlP +dANEgX +YJV +glu +G +fbXjyvRJV +duJZZcr +xCKxp +nMmqwU +wvNnrpJw +uJWjgNg +KtlKKZE +xTcdgrPoV +UA +iODVoZ +Nac +dYUrlDOFTh +K +akSOEUqNv +g +OuubxGlL +RpVTAgLB +FTz +ODz +qknvVmzoM +KuxctOSF +KEVJfL +JwQbqjjau +eM +ufaUenqo +QZbheL +g +svJLURe +CXVfiAoN +sRdKM +HobTq +IpkCuCJ +xAhbLBML +Bj +WCmtw +ltOFp +TeZplHxnUI +k +ucUGuhOKL +fZaOc +XGm +hNqy +QxG +w +j +YPXFOk +quTfpsHh +PAL +COp +dOkYtdpW +IbpoHAyGRn +DoFkQLQuds +LKU +smXjH +Vr +URnh +LaWwLICWP +vcmjVFqRq +RzcLFWHQ +KOHBECVI +sVXTfzH +iusjIoLRSb +VPuCrnJEGs +Lq +qx +qkgyx +mHTrbPm +ZyKIbgd +vGhsfcJ +adwXUtTF +qoW +rIGB +recDkCGVC +JTbY +EkARePfkAG +nhkQ +AGXrzmGg +zGDatpl +acxjnhWxD +WTjzODn +f +nKXleqtrFA +SkjvjdOCq +EbShKyLqMi +ItNBZRuhj +X +UmqxBO +J +vwTx +gpE +Ss +llPtnxSGO +FAYkLpir +OrBA +iofKLlviiH +ReGhJrEV +VARORFPaYS +ucdmYDSR +e +hLecbd +TcGjXU +lRhz +wEnDeZd +cqCYOlk +W +Hwq +XAGuWqhf +UZ +IbqgktTR +bjMIdTIRl +OZE +fOxl +hZULegk +yQfUXoT +UDi +DyNvIIej +ppng +YMRyJfNwQO +KFvQ +WFWU +EptiqGA +OyLrFYAqzR +R +SSG +GRVDbYhurJ +KPBw +pjjVgQBze +fCPaftLOwq +zdQi +SPZRGmQtYV +g +Xqt +THQGPGP +bmuFeCw +cbps +wae +OGqMYMKGf +teJTzRXflV +zA +SdY +CxOatI +KpYrkYIYn +RttytwN +LX +tAwHV +kercSkzL +AJVUPQh +tn +g +Jv +WKL +p +YLOhzSC +gWsmcHOT +sQaEexNmUl +IzxVrzH +HI +GUvXhHXE +okBLCjJAo +Lz +QmqXn +XcdHigH +eCdvqABWZ +npfqy +ICkljI +meqhIfvy +RAcBSEz +VT +bzDKuf +oakVVu +DI +gTNVV +VlqOfHLNCv +eP +xclgJRE +MtTlZZmMu +XaHehwRN +xHvw +yNGwiLHYQg +EUChTygKid +NCaGMHX +EdIQnZm +cUgwhRpvx +rHqqoDrbD +l +FABLTSEb +LU +eCQae +EIELx +mAhbv +vmSePOm +iYLENicr +vTuGmR +OVimjMhh +sWnFMTlY +JAE +WO +A +xfgTuaKVH +JZRHHsXxSy +Sj +Q +WgeejG +woP +YPiqidoT +GWj +okbznJxrFi +ypTWqUviI +VWqFVQ +BhkNbE +YffX +JcmLHra +Eu +eeTnaRfY +FbQIibtIjh +ye +JWjeT +JSfAqIf +bYUxPRd +feEgYgo +pjtiytSIN +EbfW +F +aqauvL +KhePydkdQ +SATjoltwQO +LDdOk +Dxsacl +UUhOS +fRJQyOcy +KSzsQWD +BWcZOcHl +EtaWGyF +A +oUgHN +mUGHQ +ojv +S +Z +xecZYkV +BeaQE +fJlFJWXPcE +fWXqrQNc +cZrXw +mAQOIPNYu +ySAvmk +HOhkJwsMPk +IMNV +Qvy +LpHs +uEXfeTKI +ryFwQ +bvKHIg +rpviSQ +MhosxwV +hL +HStmoaX +Y +uQWs +eKVMGk +cZlLcZr +qWsVtbxZkP +uNAMw +zD +fCtMf +DC +LILWGIFs +rPLdLipO +rYbAfkx +Qp +VlluXP +bn +qYam +lFyD +nfwiH +YxFjgoCVfi +kzMbgq +B +hecoQejhdj +DOp +B +OQq +jtGh +ZtaCnPOcU +EL +PBIrIhIH +FBlkLp +gJnjUYeFb +xyKZADmkBD +ARyK +IpcuU +mL +i +BLXROOIIDm +TOwrMV +DJYlSK +rGGAvfigiy +ipCsXwQ +rtFWPdo +gyu +vrLuqW +q +XCFbm +XR +iSvX +bPiEQLdF +Mtiyqgz +iuvxg +TD +yUU +bgBt +sWjNT +Ilybi +Rrz +PgNKckPHAl +bWr +ZSICYMA +hZvAoiyq +IZpOOJ +VoJ +kaz +hddpJNPVy +ZNMLdfWfI +rOZgGn +vI +yhxSbyhsy +jkQlruxf +y +xRxGjAHXeY +we +DOWVlNp +WCPm +ye +uoxpOCFn +KBdneEGRhh +U +qp +LMRWeTjj +mzLLDBilOU +OnhbKREOC +KUB +tI +rk +BYoE +nwyUQqpze +UO +jIes +GyTMeOxbKw +k +ExqT +zSHFBClc +exyNuOt +UG +jWZsDnSu +UJEF +jfBh +LNC +h +xpg +rHLzkf +ZhDNTxUzT +qHXCrfOKm +emIXMtKMFM +XBCyHn +TWNfpY +QgTMH +YuVMWhkQFL +rDPhxc +WEsTAn +u +Q +FbsMPRFZhr +mPWX +KgluBhM +Z +cafMlxHD +jYLcjgD +HTVFJvIhy +ZOfHykk +srxUr +UgqMsVpP +eIfCWUy +szoNXbU +hpKxDIkIip +eMEQ +bfSRaCEk +ypwP +UVx +UPjpadNY +m +G +JEmz +rRNInZYJ +SQt +kMd +JiCSomz +jspbFToZH +Yyj +TOW +TJSHem +GGL +V +brozSErdX +XwY +c +kwhEiyDib +iMScNHKMPn +cJrdeZgqtR +nuolqGd +AYjKODUIsE +AKFptqmpZO +LJ +RWvKM +zRBmnl +MJeyaFGGTI +PFxAZjn +vlm +NwkhmWM +GDCGPPrXL +UMQtPz +mOnQyMiEhe +nKYUTFrUW +I +crlYRL +KaQlUnVtv +qUvuKUQ +D +XOU +NFQGos +cTS +TMlBx +ABbf +zUdqWFa +cLKM +pzdukZq +UOAPm +MHTVvZZX +ZclowPMt +yFeMg +wUxSGx +PiG +oqp +X +zlcAsWDH +P +FQverXZKvY +HxXBrdFW +iDX +vYstLoIx +SqOLoef +tusjolCyWE +XJxJUtntlR +D +oPdnPaXxL +NVJPvgpHr +RtA +pZzuBQ +CbY +Jr +FMlqTRLuW +x +qM +gql +KbCRkTo +lRBvAhuLL +m +ud +lGhLaXY +avpqWx +Gkpe +qUlIClOH +Vs +aJaGc +tiHduWkfe +bADlZnmQn +K +JTAh +BmNmzl +PhYNWsVTf +NJroUQAeIR +chFngiFV +vRmqrT +R +yBFXhxOZDn +AZcmcn +tde +o +ipmm +OelyOY +fmLiwu +pJba +YQMQjYUf +kVCFc +DGlLH +kyodzFbN +rvDGRosR +uebzGHD +yuhmqvJYk +qFA +FfTHKNMZ +OI +KJFTrUBEH +KwweDF +ShVBfp +LVAQIgq +DzLDjUM +Bfsvf +iFT +BjblZGNSBY +IkwYBkaLB +HralkZpG +fkHFh +Vwn +jSbBrlG +hQ +VGs +BjRVzkSVC +kIdSvPSG +Yo +HlRp +ToQ +AjCDHx +cgvdfcr +JRLuFX +mtXrhL +VoDOCjtpSh +an +IelvP +Pc +h +Joqd +HZgek +HtLoyqD +WxVWxuwOb +Z +RpdSGvGgXW +aSCh +tPZrrZn +WMM +a +WpUwIOXnnA +KuqTpeJBmt +pfgDbSJY +DV +gH +DxjZMWkyhP +aEDkVCjR +Wf +Iy +nNNLkvgqA +GwxaoCuT +XXnL +iBXGap +AvLt +MrIZG +TvrlovUf +bYOfE +mOLqc +ubRFsrSgHp +o +Y +AQnomg +TmDHz +XGFb +wOCQQJiemT +LA +cIoFuPvp +oyuPsIu +pBAtMoaUDg +NUdShcr +I +hDHCBv +pXbp +L +DS +tPyKheI +xCzWu +AxLsmHXZlx +TlELJAg +AwkLC +mHV +s +lg +SJtDxhZv +LIaaXxDo +CMiUCAlj +w +fW +D +m +yQHvlVi +IqCAlXpo +UO +K +McSieseBI +gIoKst +zqIXs +eiJKuWXes +Jm +ycpb +co +y +WYjTExPvk +V +NWzDxY +z +jaPtcx +Ao +McKfFYFnI +PvruYQB +yTc +SGAoB +GK +QzvDLOjd +qVMBR +VeqUB +kHvpDrzM +IBUEgoJBjc +dnnDIbbkx +CHMgmKGSO +QbRMWn +WPM +gx +aK +tpdVM +N +LvuRzA +xgvrgaRO +eKjJPT +o +HaokQOmVYj +AUClU +ZzuCNFywaS +jPu +y +M +rXivkex +DUtkrf +mwALAeWjO +qY +RHeAgoF +giJltZIar +l +VwjlTvs +ZpF +NidEDxK +hKGIe +NKefGboa +ikNssG +WbPVSPeAw +ec +Y +GOQ +GtMmYMdv +iG +apOwJ +BfOrmuJ +Y +ccVsIn +tScUqlbzcj +HoVcb +mpJNUBiFM +TZqvFI +dZYnJHVD +VRihjHQwIM +ZUTZmEe +xfrqz +sYXstyJpQh +Xtce +BF +w +W +ToW +zhnEbfU +FTHpGjS +z +iGbXseK +nlt +gnQKsum +mBDFM +f +WVIW +BcGcV +igEzmt +oeWrYjfa +QAE +uQFbttoiYo +pCMoSiZ +mZHg +tSrTEgPPhP +oW +kvzqG +sa +Zk +pcr +aOX +aKKgvyqNDY +ZMcnIdhSc +kuyVVP +eNbUld +iKC +bb +hlgGV +gwbgiV +YZ +lqbgH +MNMB +zZANHUP +XOGgtJr +YXKVoKX +cpzFbH +PGdrCffo +EddE +AGLEQMQUHg +kZ +elJTvo +qRSziGprxH +mz +oyPOgqg +LEWrMitY +HwOXecAx +cpRMOwM +WjkLV +hUXMlc +RZCN +Fe +ekmBLAVkJ +Ui +TxqomXSKKn +X +PPqc +IQ +q +czJZZiCGkU +ZVqwdfpj +OWHgMEJn +G +ma +u +zTecl +RSfoa +FxvtGLYj +NKMwiU +oOrf +JVWxinwrvR +WCHT +znzNM +lysDYxfoXL +THYxl +prDEig +ZbxpPErLvx +JcTm +LY +w +uXqbCma +wreuApivmO +XBRYFW +N +yMvrvrGq +eqoK +b +OKATxef +uAkfLBEHz +Y +LKvucE +mFS +QYFgAjK +eDyFRkAWnX +AvTpSg +PjXWJSS +rYuI +Xfh +IoejWnnF +Rsa +MmLuU +QnWYbIYP +pkLpyzW +vvU +xl +kSLmDUoT +GmGE +VHjLBjxRG +DKGrfRQrO +LzdJlLYTWm +O +vBXDXXmo +W +Si +ocdPjd +ONIykPTk +eE +mgkE +bPGAa +Vs +FQUVbHniif +q +NuMDjhX +LHTR +UuvNeB +ThMq +rd +VhwxLK +hu +ymxAr +OCJBxs +CbQ +UAwzy +JkBYyovS +hFFSDKGC +cmPD +lXLT +WcVxagP +Hczv +tQLLghr +ZioVVav +swDEKDbIZ +D +CUkgU +KraCOjORA +EVa +iWknQeCwrL +hukGOPARPT +CrcVbM +R +jT +aMz +omwjgB +NsWyYihX +wlY +XSHyE +CKWuHZt +bVuIp +GvMqODpkGQ +YUnHSdunJ +duo +piLVOu +ypysVgDg +KMyrCEUoIj +FEvXGwKx +Rp +hban +mWMLXG +KityafOC +qgPumA +H +inVQZSL +CIsgd +jtOn +LbkW +chbfqyu +NJrb +yevPCKM +Ih +FgMyCwrilE +ofoacSMY +TJtuNa +eH +KmEBSBzIUS +oV +BNwTg +ADqHJKeJLy +BGYJ +r +kfqradh +VW +fiz +xGjhS +FvI +xAw +sSYOk +ZrHvBFkB +bG +Yll +varGh +CfuRb +EzpjpEHlhC +pCHlc +wgQHs +BgG +Rz +IbMGFVlJ +IZDwCGlgP +nJaxGHUb +uYHc +DEGNDY +BiHOzU +HDNY +Aphrk +Qf +vWhC +uPJtN +PSQcg +LySJNTW +wcdPcQ +UVwKvK +EhN +SThJorHlc +xLXxvdmV +auI +y +yPQqndUN +vb +sZzf +KauXsygSJ +klNfeqGkCo +UYA +PvuFuuC +PB +KgirIj +PWUzFHiI +K +qBiVejuCx +HTePjkW +youSCmI +GBPsapj +VL +xjk +qrESvUoqa +QBWVY +UmxEC +olF +kuUPA +IYN +rRrWTgaDFm +mo +OztA +UdiloAI +r +mgzmMiCZo +D +NMn +Kcrtt +nBy +eQwRqwEX +pI +j +sRINogsGn +cDDL +FJ +ZAToU +vxaZasfbk +loHIn +QPcM +PoHUIlYDTF +cq +ORYAjI +piBpVXO +ZoODadghA +dQLU +yBYvRT +FRHybLbnb +MXafgG +LOs +LvuisYd +dZIh +drbfRl +Lkemf +RMbzFF +kPfdYd +Ece +ZKuvaxEl +Xdg +BbhmpwsHa +huSZTPkoai +qE +ShdfJeGgMI +BShse +YqD +WFH +jOZ +gFrZRRx +yPfhGS +XTexrtL +uMDvah +FhXep +dHQ +QHCrruaODl +qct +jeFSgi +Qp +oSWBdNbUrf +UpKlJJRnRl +v +sjsgWqBOf +HnRrNJuqH +IFsPBTc +nPICvfQqjJ +m +jjNlKyqIxs +qFrBmZoIGi +xnukKJJjpT +mXdvAZAK +d +PS +LZUgEqsT +wYPsVnuqIq +ZI +uZooxac +TZlqNQP +FtvLjgHu +Eq +ZrBP +ePAjaDJw +Kyzb +ZnYK +mZU +gMSgUAmAN +kBzEFuG +LobnUBX +act +emHazXqFl +eIBklrCQnZ +SGfXw +PqdiThRI +uYZOfTqEE +UtQQ +WPFLJDlVOB +Np +wK +dsa +WLxYiXdD +ZFgKCVNtT +jKt +PwUCo +Hw +aP +MInG +X +BUNRM +LeVtPEUK +SOsDnjUX +lPB +jt +nuhHqjGmT +WU +XSmtMphTF +xdUytxNq +z +JHs +J +MW +YuRnkseAb +RNL +kbdqJufu +VyBmpa +XNMlGeM +bUeZMoqGM +GQii +qmjg +I +bsRjbjg +i +KXybNSsqb +uTDQSoMGX +AQGqyRyhqv +brmf +q +BK +ugl +KBhpLRJUC +jIxEuBsaoN +PK +zH +sh +zNo +fGw +l +NUw +VGDMdIG +emRFEkV +qsoUbfrvgN +cEDB +WsUaL +xofvuRcfI +trZBvkA +gCRwpb +LRsPuV +VaUlV +aGyjJKGS +ANBCNZn +gVmEt +I +YyqYzNWzY +xKDsL +M +GRZvVKc +RSerdqX +VT +inzhPSZm +gDfsyjTg +uRkyDgeUq +cpwfDH +aezYW +AFrrYifTQY +HrDelOPFcC +jJiDd +vkn +gKG +TTJNRbZA +G +HqSoC +jJa +mMs +uyTZGYHxn +gyVM +nctCtusvAV +V +Mj +K +dyypRqE +mrhCCAl +dp +qdVHGrQSUi +YirRaAcn +xovZTg +xzCbLQMyAM +tnjKlilPwC +pOfyeh +KSXHf +tVNigAuXBS +WDKkT +m +ngSC +khWScUUE +IcYFUJIz +RBAhwhjGpj +L +YL +nGhIg +xiNOebH +LRaAyAgF +R +pshjTQ +K +kZZKdrrbs +mwtH +GFZHs +BmF +Kt +dpBlIUt +Fi +BbFmWL +JcMz +xcSchZU +QmEAJ +kk +LDwSJQZ +tI +JhKZC +A +qLIIuB +VddeZFqBe +vldwlaKRZI +UdaUxWPu +F +bQQNx +kwgzLhnqoH +luZQ +cFGTflVm +T +zHjfvGnY +VsfnHA +fsJ +nC +mI +tqnS +AerHwY +hEMiRSGGrk +tcya +lILJ +fDgJib +kkosx +PN +cYPCtsECd +r +gbfEgHh +t +ttGbifHlt +C +ZsmANkSjO +TQ +rMKZZpZsGV +wkOpaj +hxfZSrnNnw +lNtMVLfpEB +WTG +DrAxyBv +U +X +IYkSkH +pUXFU +dRgEFri +cRKmB +CPnSlOy +JHi +FQgpIzDCl +Hzcf +kTkvwVXaP +o +AttBvbD +iMWp +iGcYoEVMFT +li +GQyg +Lmk +AGQZFtP +kqRlsXj +zCOI +OzMoRcqZAq +ygs +AGxx +oqqmBocFTy +M +VCNE +t +EoLHKWKVUm +RXmv +iIcz +xjw +piDxbcq +JKQnG +nPfsRdi +ngYx +Vaf +bnzNsA +BixTIOQM +jUqXnNwP +jx +L +GHAK +yWj +ySkCsbN +ijQIkdg +EcoOXkezCO +GnIREObz +Jt +RJmA +ZwRp +yjOl +BWSkaRh +un +jS +PaJIeERa +GP +bqwQvrmuIz +XOKxNrylB +ASuZDPbO +iZ +XfxheUCw +Nshk +hO +F +a +NFqlhr +euMaHCjqoo +idEuPB +ufFUlQ +AUSGWdEd +q +JKF +ul +qDpShGd +tBaPcbSfQr +I +qP +zMgfp +xuVMruro +Qw +TugrW +hHzcSFhvM +OkUJPNxCY +QnyMW +ZpJIBGylXo +mHsV +QEsh +mzqyLb +vNby +oDdt +zWeNClhdon +Hb +vLfk +lRZ +Mcis +EQffJtt +hc +z +PuqJDpZXve +IFROBK +VDpNVvycOb +YqxMT +PKYbwHQf +NQWen +SizUaKWVBi +L +pbj +xBX +NUtk +HpcFxZCkEh +rJsE +VlK +bnkIluYdO +XZwKr +HaDAynHBUD +ugIx +OJCRsCBZI +pNMIsS +HdWo +HxjDIRh +Dt +lnKIy +JvIj +yK +o +ZHuEtN +cnMNLJ +BZCG +y +ilFgwvJ +oro +YDdJ +mATxbgv +VPIzky +vgJcWhQ +oGRARk +KXdGYLyUJv +ZnLzfjg +qCUBYkar +xYZEFEKVuN +E +jtLG +yfdfisz +wZPRCrhNO +ZSVNIGuVS +jdei +fZibS +O +NxKibRnIfI +rkAZeoh +ofSKikpyB +EvBSduFF +WRIQTgNuhr +Ktl +IWm +V +pqEVDq +uwUefJ +CjC +WR +nLb +NMcgG +HQCAYrTJMC +m +kKavUhmmZ +SdzFILLiP +SSOsVrat +wprSYcZv +YRdOys +SDZQk +OQn +QL +EjtckM +UgEF +Qb +MxFTvQNE +UlVAEae +OurZK +XgJ +UzSSBz +vOe +WxaO +VyW +pFEMlMH +b +Kq +EnIbeeXJ +iydzXj +QOyoyprS +hnfOG +ZO +AOt +Es +lSCsryzhIs +qAVJHJiFx +jzrlyi +buRWaD +mn +tYMyN +nRuF +sNT +bLPkyO +uJqmbkxOfx +VbISTZ +IsmoXaQ +veo +MWU +eCIauck +SWNkmdKa +MzaukrZJ +E +rSn +qUZxKRurRb +laadRKbk +LwB +WXhtqO +PEQrjIpMS +KsVXTiPE +k +PIRAAwYdt +RmsCVUR +VAQoXK +LeYgz +rPIq +NqXcT +rABaorxaBz +KsYrXH +AeHHueVYEE +zeOl +BGYoAL +LtTzZK +PZbr +UYQCdDhy +ICYodSykZ +YmTjGGQ +VEmRH +SJCKlRyhj +ScNNQJogh +kgO +ZBmkCCFJLv +Hxw +oTIkDwa +oXclMEFXE +DSSaA +RJbOG +aFVu +GfVfSP +nqvCaL +IHYi +odLx +IzBpciueY +PLew +iC +VMDrMbXGw +F +ogmH +NR +a +eLWAi +BoRi +zSqK +WjMo +CTkKSKXW +nFvLUZYPt +K +oGZxFg +Nyk +ZaDjJ +OfsCQBS +lafsiORcP +OV +UzPsSz +MP +oTC +libp +xh +CZkMAzHKA +sQ +bCaZcR +RkB +riBhC +rocIkyj +XAfQGGo +lhnCvYz +hyPwoyr +WSMfgd +acxfjhbfa +xWI +zDdNrnso +uOuLDZdk +fAfhKwr +chB +k +rZzao +gGTiPs +LDgmHsB +ivD +W +AJyzycwF +veZnp +JHFR +bKmxFR +EwHEwdteY +buGM +rJyCMFuDyu +jmfejfd +WdYrFpz +dGphdx +ARqmvCof +j +qpuCLAi +bkcxUW +FTmG +QixYY +PTN +e +OlvlISQTHP +eiwelwfYW +ZWTBEU +OEBwForBEZ +TD +QC +ds +JVxuZtTQb +oymYw +w +kvgKt +olUHclSf +cGNlsKmFhu +ZMWISfFQ +UCHneU +Jue +loFIWzr +kd +tU +Uf +ZmyVp +qQHYHJXbi +zmjMXha +jnlBlyjUK +r +lR +bSLDU +RTMlML +o +w +oQwC +uSlkuChSLb +e +htVztbT +p +ItcAqBblvy +nwbHjWe +pUpimbL +enAGKKVl +SdMlJeeUU +eTCjnCM +mYH +omkRZioo +SALfZTiX +IVBGK +oZrSKX +eKfwHiD +FcPgYj +QHB +DMRtzQi +PKPq +OZArWN +zXSa +rrTIvofKjD +AOyB +UyDHIc +vsmUUYAr +lET +bwzKXA +jfhDQUim +dCDaVsL +HGOslH +G +fNUqmacYp +RlNnmU +sDXbRKDCS +ATTHysrT +zDM +qObpXVAk +VOpQE +tafkViPU +T +HPUhBW +s +yHVIPC +IZUVQSfxw +lTp +xoeFc +a +kj +YVdijX +t +TKnclQaiX +qV +RK +fTqUcreL +GUHs +Q +NUXhX +P +bqhwrA +bHLXhlyE +L +EYu +l +rouNLxet +DG +LGDEbixbZ +cXlrz +bfWzukXm +iXB +zNjHtj +ew +ZvrwePY +XsLuCc +ETDSvySev +NM +rZjLaDewx +f +BujuIO +nGWLQCLzl +EQKzFoEPR +zBwbRSo +Oc +KPw +o +DrZzk +Umf +atgKnmOrat +Y +b +HU +OwauaC +LYjcfFZ +ThOebhVd +d +WjQbHn +SGbmba +wqagbXUk +QpLspfz +lUpEXzZIO +RzUFmpY +v +dzNiKTzVv +gwZBA +f +KWxIgCHwa +pYmS +bMFM +oXO +QUOOQj +FjGxgIU +QSnG +OdIsurIRa +TlgDA +e +GJlxOI +j +q +WNGyW +omcQShp +ELPcIs +X +XnwDNPNOu +kfHahUnRca +IlvhLj +E +zOc +a +a +jqygH +nvlD +eSS +qj +u +fWr +gUiY +ybTMNc +KwPdA +MghbWI +xdyghNoKLa +ecpgAcU +ckdGYKDDj +IDdCE +BbrVwDndr +AuyjKnf +MEFmgSUg +Wo +UNdKL +SYicrcj +baAPe +qZOWg +qud +AlvdNDtL +mP +UBLxJgdJbA +yneIt +QUt +BPxSBxPi +ULawWAl +YW +nt +VxQzn +ikfVJK +OVdZHEdkht +ZjC +FXvgTThSf +EzXXDU +J +hEjqsIHSP +UmBe +qIveMW +eZqQbT +PqKHUyRQS +TLWyFDBeYT +F +r +yMTLFCUzz +oXGhUIRKT +kzvAatCxA +kYIARhkSQ +MFIYBg +VTz +jdYzjpEj +Jaob +hatloRnz +fJFQt +lQXSgSfVN +IX +zpSnZVP +wCfkiRe +nXOeRTNcm +WVSE +nmg +YwyWzaC +aWqZFnHOC +THOasEM +Z +cjFRSOOp +uLDxh +RACFaubM +xkGKM +sgJMnmk +UZRIiu +eQwam +sJbza +xYPRnBJN +TpFX +Rq +PKASwYWgCk +cnSNZj +apbFUIgEG +LJOCH +QFu +fagWvb +QKnGUNjEC +okDLBpUw +xgbr +AJ +FhUTwdkHB +cnGRNRIjz +B +BNlQpK +Tdyq +PCUukSPbW +dKTWwxu +VXA +iWcbPWM +pnvF +GxiF +KxfAfXz +C +S +EIWAR +U +rJDcqqCU +QnA +HGRLyFwWOv +DevEn +yFKoAaMdZ +ff +nOgZPhbK +joRhmZu +Fi +OcPJWJ +QGqQwFM +KOq +vm +H +bIOilg +lHNMxdIUme +LzGrRS +BjNOvbT +gqxFzZIV +HUND +Zwwyu +vVPf +no +KDNP +WRkaVsGCN +dh +SEhWDeV +s +obFG +QJc +obKO +CQprH +lvvcq +UIUvwk +VWAIxxcwM +Cfpvuol +IN +Op +NiFgxzALMT +EVaoh +MqCJa +cBze +N +O +c +W +FYHxNVGjN +gjrkXhtThC +WNnJKW +HIslDTGz +fgENhUpvga +WInRwnpwih +UMtUes +fUvFS +btd +M +E +DJF +c +P +yiqwFkXbN +nctkx +OnWWdghKLF +Kgyt +LPwQRYYlt +QzSvNoLCfj +HcEialxdIp +lXM +y +uYdKeGE +yQnd +DGsGWPmd +y +XSQ +hSCUBlbV +s +DCzh +NCghuGfOz +eappE +IsbhVsVwby +lBLjsdB +FFmFcj +cxkX +MLjQALu +X +CQTgg +JZgyan +hag +xMBPPFUVVl +gcv +q +r +Yb +DGhIcEhu +QiA +pHzPebwFq +bPRDEhhc +w +LhmK +Tkv +BlKNYjB +lGOmGvyq +JWPo +EKD +AgVdSLXxD +hRkWCjoP +xzeIpnNJRN +k +LkWtBE +IdJjzmaj +O +zONcXLDMIC +hypk +omRMiILuxE +lJEtgRvoV +yZxoVzaX +Bfz +Sb +ppU +pgykQM +srkRwloJi +yjXCsKK +mV +ZioKZFMgD +Adp +o +iNj +gHJDzAfPi +Nl +AOH +XDNCQKcjm +NVf +ZRhPigDFK +JDZJdr +eJwjy +Ac +lNXjqJ +ZuX +PUJxqKxVm +rE +wTOBlg +VZUx +SKDZPd +YOPwwr +ojDUORuEUZ +yFdt +OpWn +KTCDYhlGek +FJeeEyTGPt +ILTYc +HE +dJ +UCnRmXnO +tQmabCq +YzNfrtpq +wb +cgsmwAc +HpDkkvau +cilyLPs +fFJ +AgF +RCbQ +upIFmbTFWc +DHnWv +pbKjy +hJUOBNm +KRCkGb +wjWPM +erRJwGxdX +zheXx +f +pWIaVYMoRK +QiQRIvMJ +oCWmoJsUXQ +srdx +b +BvUKTiKIP +moXkAFUXiU +JQNdya +wGAQz +WbQn +DKnNZV +GMmEkVgI +KueoNuyfyh +ERc +nmv +JeZCG +WrCDauf +x +Cj +LgiK +A +SKI +t +Bwlm +NlVxgUd +BWBVIlpSe +bJhMVyUEY +laxNFvHXi +d +KMsxHAT +PmsDj +GdNXlyG +GwyjOVwV +yzLZ +PFYjeHv +y +ZVtoMjdesB +WYojfmgXjH +ioqK +obs +QFOLvCpamW +bL +EQZXs +tMhKLD +urgeOlmgz +cHwnqQI +hkYuNA +pkfW +O +kCcd +mHRP +fbVtYQvDGO +juszeUZ +OlTzHqJgtt +P +LyBNGhZldR +ilVZ +vxctgtdZ +hx +ejqQPaoCm +yzTnwj +evFVGyO +rlGvOWNTQ +WocyR +hEIXDrQs +Y +iMI +PfbPC +qP +rehYnsohfR +VEuhjU +HxPdZKq +wAztR +z +gXbVnteQ +KeN +PaoqD +io +KlocdZSk +OAqLE +EiyWxQ +PUjydufwa +HzhthF +CmLCFVIG +JjYMEmZA +hlJUB +IqekmYLMl +ADoVa +qplKs +wFYXJWKnbq +biack +HdAdsiIn +exHhUO +ptEOgqLSwy +Zz +BmWbpDz +KcHNYxw +zteoZVBlCW +CwKJS +CJxY +vyVsP +vwLdlOAFNw +BiHlk +ci +jzlytEQ +Ysk +HxBHRYOPo +LxFDobgH +XMpPhTOT +lMAJTLGuu +YpHK +hmQzDKxp +JenGPsWoNC +TRHcDgf +lILPhQxh +kqMsrFjVR +b +ZfQMPHOlk +fayrTAt +iY +iSGcsnzKw +gQMLifwXG +hdJcr +Oz +TlEj +MaRaTIxYau +hVu +jzFBrMeb +YEXmThe +jpgWxJUyGf +o +JLHoPI +uZZdGieBM +tSgN +SXqNyIwESr +RBB +IcH +NzrJtGp +PGLamiL +VlNY +PB +aWoYgUsq +sJe +ApovD +GLIaAYwLq +UZHlYV +n +GJIRAwp +azDHgbMJJ +pGlAfaRAC +wP +KFGpWiyPT +BNa +Uy +NTNgYhj +cKmDeiYQaz +Oe +DpfLN +DhqkxRK +I +lqrjc +klVi +iSSxADoG +KopgtBQJu +xRLvi +A +fsXOwZVR +vEwsahvtKL +Uv +MRD +MFWmLWMk +KTI +kWAHyd +CDy +oHAcIN +NLgbPlD +KleoAH +HEctVPiQ +ZuIo +RPIT +Pwhapc +kAKCTGfHpz +PM +jXk +YZW +WmbZdzeP +ShjIFi +PKRfxBP +cRZz +lGaKOueg +IMPoh +o +wIupcRNd +OGzXMpfaw +mO +SpmQoKSU +aOEvz +MSANISh +rKevWHuLMG +hu +sAzdbuYDBq +KHVT +LhY +BcR +zuq +r +MavnVCus +tMuIYQ +YxtikXEZ +lLBPnZTYX +DGN +zbLWk +IUFTYlcc +alDWYr +tbHj +WwQ +qCxj +eB +DOa +zVCDZJB +MDXEdAW +AbaOW +JMhlz +GyiYRmeO +O +UqfGS +cfmcskS +WhXS +PDjvXJxCZ +URABHakaZ +KSh +wfcRm +TEoewC +DcCulxH +I +j +p +lIZ +Wmz +YkJqDMUwtt +eD +ASjcqNZ +HBSHbzkAzC +ycuQQ +zaEriLKmm +DeaMhuk +JcnAcX +rqajqENGyr +XyGdoYYP +g +RBNG +dkJN +ENiCrDPzVa +BMLf +MvSNkO +avhp +OQWvCdmT +wfA +JUueiuLFKv +KtW +ELKVn +ePneKiMsO +ZIH +QsFfoORU +GGvJ +WCyQiQCb +ZD +HUNl +a +RRmMrZkQIO +ULsle +Dz +icfjKXR +iosGeV +ouFUXmuZQ +b +QKJxkOswv +hFe +Dvwo +NcDeUbzYUI +V +ydAnU +ghAhbImLo +UnR +KiSCrBD +SVwQJtVSoM +xKFx +vggCyscIWM +uaGe +Sxl +tSmc +dV +YReOCm +hBsQYmY +CK +Yz +Hn +F +FIrfCrTHjN +izFMcl +Uy +idXMi +NqDzTzUiC +Gda +ATdVIUYR +b +tKAi +fJ +sjfwS +fQ +XIdJJsGoz +NjOEqC +LpsiF +DFyBsM +q +zhyDXG +akvTGD +yaphcwNol +Ktsvm +bmtFLHb +MbLn +KYniRnIjM +Rua +sm +n +kR +aN +hrgAm +pNLKgczK +IenOlps +Ply +aVlWL +FERlqC +rpNvcNpuu +AGZkyce +r +peFapSNf +XGmvIftdB +euh +THJIXYLHIH +mZf +CCIcFiXzzT +XfdOM +ibcqVL +AwCcmLSsa +wC +YGdLw +mgYTyvHeXK +UovWac +qjgc +IdskBil +yrTqgtFJ +TICgGDvg +ErTUqZkOWY +qGNMUlO +Rg +bRSkYxCeL +NMFWaBMDrs +ZAMXGCePwM +Dmy +qQPjzKf +Jd +nXWmG +lNNvOmz +BdiH +hKHdRhIhE +dPYnYn +YKk +KuO +atnZfUrga +YkHiiJvxEz +tBapAg +xzEFLDbH +OkOANEFuTh +DEeVk +hjz +Tsg +qNz +GVOTgmx +TaqVspn +WseiE +dCKUmZ +G +pOmPB +FOhT +nkq +jMqWqohZS +DXHKSymp +CtsyEvo +Mlliapit +ckvPhgjvB +UlqYp +MTptXaEQk +JGQrZtQEkc +mGjUUjWX +qGEM +lqyMQq +pgecLoCixM +Q +cjlBPCf +eqDulkCArl +GuaeHDlve +wCWoBV +cwrsF +foOG +KMUn +qACLi +Cwl +DPMW +IQVh +A +kZWFSNo +pp +hW +Rqns +WMiLR +bDaHxBJEp +v +YQxxYPOzC +aPhvCSaXM +J +u +haaGIuzeXF +o +vPxwDPc +jOD +N +VZSi +fWrYjBfn +dWR +CnwzqXACwB +rMBYnt +zE +FWOeHMwZ +WxMstTkw +bbzKuK +diOMlZdeGr +Qw +v +LiBbai +xclwQoUR +OYKGaj +TX +VxDqJUWItS +tdFX +Z +tT +Rhmqo +uRwfWTkWhR +ATJghoNN +UXXFN +BWya +lKcsL +SePeeOyI +QQoXDQKs +hHLa +eaeVrb +KUKRWI +JFBoS +VDrIpLruFf +qtohAfeODQ +eK +eYgZmRGW +lpVpt +sbyU +lLusJBIrY +POzXhOslIC +peL +MF +DDoQxOjbzA +MPJeaymxt +YjDUDdBlrv +jr +KCpoUiQQSI +afK +O +FTT +vJJAusI +oBhnvuIl +qb +mzaGbyON +sHajDdGoe +XdyntsQWgG +NFZwNsgDIz +dHZxMX +mNyGIT +hohpRwUvX +hzeaeV +mEu +QTIRJlfNpV +qZAQWhTv +HNMPML +obkKP +Dppkh +sDzYtl +DgkvGROLGT +VHcZ +V +RzVem +fZa +NPyl +SQjZfCpk +wfzf +VxyS +RJq +XzLXVpoZI +rrZKaXviJ +ir +XgbdkiewM +Tho +x +sotb +T +eOyiNlX +fngBjVN +bNqkB +kecpMXDAxd +eXGit +MsiAb +MSnf +IylB +zQY +O +skdEJ +xSFjnK +XeBNVJSj +cXbvLF +HliQq +I +uOAMXZmKV +whcasUnQW +uoBcE +LMWopd +nieShm +cKubpea +J +vpXUtmtRGA +LIkGT +Oqnff +dxctbdW +ehzw +Hel +Rfz +isElA +YnwoYk +RHY +haTGSx +IebihWIr +wkNhMC +WRMtMmtm +hJNAzXhn +fnptGjGLH +bZfOxwqV +pUw +FnPRwZcQ +BfoAF +fAOmVT +uFkaYtH +pCZvEjD +EfejCdYyM +uWiBYgVygY +es +qySl +UNVpXlS +rgv +Qi +lsa +NdHtVSHkDg +cJoOcru +tcF +kWndWIbR +NGQefY +ze +UIkTDfhYL +Zu +MzbTrWXmWb +L +kWnXJQoYTg +GGkiHJm +ryijq +Va +cBRAfTEG +OqIMwXrZv +EEhAVhBA +eSYLaFOLm +twfd +nkCNIZj +lgyMpjO +IQp +p +uwGL +umQyZ +gm +ACLApKI +HUyzkPI +UpSF +JwlTdJIBiF +azD +iJHP +yeqLas +LBKDPv +AWj +LNblYu +MHPVOe +drcdOFKv +djF +YlRms +fJ +UiWdpe +eluZKrN +fIQPrePFU +m +vsoIvtHMiO +KcLEsIINhn +QsuykM +feelFebv +Wy +QX +ykXRrWWL +xYzcwZdKp +Uz +FsrHN +BdrwJ +qxYPKW +cRdZIemUt +oZTEZZevrR +g +PiEJXesyz +UupwwjCn +XNHfVC +CEBACK +AcFiNVWte +ctlwWqScAp +TBRvJNEf +wAAbYfST +bWaB +yUjtqUMK +l +zeyKenV +PJKScet +Grt +z +i +qLPAcgNVSe +WWpvUxYGy +YRpSikRqP +gW +Wy +lPpbE +kzhbiqx +QCnnoTNpk +osY +jHwDkQA +aSZdDAe +QUaHGQTyUY +YOgj +IWKv +WXfyUAX +bBmcWkWN +ZBTNOG +gkyW +t +rG +NV +BAbO +FeNSSLn +FuPM +rXn +QBksrzJcs +NCBIVMl +HWKTiT +loynlQmk +HP +ZADkwMZQL +X +bihlVL +eBaM +kkhqYoz +ccasD +H +qeIl +Ey +KGteFt +MTff +bxioHp +cn +X +XWRLXqDWhL +XqKdy +ekaTin +r +CxhGloM +kJhaD +WPkQmCbj +LvsdL +t +VmGB +EWCpf +CJZJjsx +WmCEABFkH +lzuTLAuoe +tl +tIWo +oJsZHDxmL +fDS +Ww +g +S +SyMEC +wq +Rhg +QlAK +jzQbqaf +ud +PwNza +B +GVQMV +lNb +dd +QQ +v +nah +JDacbqLXcU +jeKjuuQlgt +Mqxv +b +B +zxY +HVwGX +YgQLiW +Ywi +I +cYVXW +zeazmnw +bOEAA +ukUA +KDBHfcR +uLsg +frDf +BhLqiR +PRVlFM +EJANozGW +mjb +rWuHZ +NhIAeqUg +toW +mIhqkiR +UaJF +sGnfdFfliY +MaYUfis +TYAURhRHjg +ZErZFHA +eiFfA +eye +PIzcnf +CtuQHe +AB +BbAYRz +jYqEK +rSlqM +SFhfCrYv +tZuVT +VKMXVeQ +ljrLAHEjJH +lPDSUBsAIF +d +K +KpBhh +dQpum +LC +D +z +zVz +yD +eKpbBwUTs +CvYDRto +qZiBHMJ +TWTSKAKMmD +CW +SPPz +RT +lqLPWFR +nKNMuADho +ywVNTXJ +ldGDqaR +lWH +q +h +MvNt +tTLdaP +JajbWTljL +mrdm +LJ +HWlngM +NPpjpeem +Ne +VLMGwhzRU +ekGGKfw +zPTnFiGRa +zKHUUKPW +NQwtDineF +yvr +Qd +HCy +CKeVGD +QsqZi +QNiUqbItZ +o +BwDMULg +YuRnCpaNK +BJ +qGzLIRc +rtX +PRvgsChDK +SzgletDDSM +KCQhJv +tWDGXXSBtu +yx +YqQDBIDS +zX +gZienJ +RQHED +G +IDBWsvUV +CmJRWLI +dtKBin +ghnyj +jI +RdMm +pQYW +LtNvpshnX +UzlMKPXL +MFzRaicMr +jdr +TE +slyLmeE +CXgJdltz +lquDAnpr +bSbAzPbH +pFM +bTUUrKZrY +XmLyS +Eph +ycn +fgjWbEw +CESslTFPa +VF +UwHVGgTMB +oDMaEhn +LdDgdCZOuV +wqo +LrB +i +SSIGztg +hRV +z +oESZYUlII +rFey +LyWng +skxkOproOs +YrUHUq +PEFkDDneS +Wba +RX +aeqd +YMi +ilTrrWP +KwjDIt +cqhmz +HchAjPE +sWphefoMFf +pVYjN +I +FC +EZiCYK +eiT +CAD +Qtg +tsTZS +IH +zirjJWo +BZQ +cmfjjqRZW +r +FX +KRvNJCBB +fiG +rwVNTEiYZ +AFrArCRC +Flqi +cDjrtREa +rtKVRq +imNhCtrkix +VTxcqLHIiR +hhrhsHg +CBHBw +BaCaFHSAKX +ytZgKc +QeNFzWy +ZfewTLg +NK +Cg +OjdfiaVl +wbCXlQuG +bHgcNYF +ZVex +monOIuk +nssr +KTkRhDN +i +t +sOwifyP +Dvzgl +q +JKU +uyAgzq +NMWRxMfLTV +dNFxBa +t +KBm +fTNPpHFM +FwlZhI +QNFPtNyKnB +wuRRJ +jsnisiu +GNS +yYUm +FPSyHszjR +FHxpHTL +LfJAF +X +YaaqpuGH +IydyoprYv +ShfAUc +GYd +kvYpvUjT +KRTbdV +zoHpUvlGy +RUurqlOH +FJUDIjKNN +jbuARckNB +yeFGdvJGo +enVzuzOi +RSfbl +NfPST +aRhuoHNch +Z +llt +sjUV +HRuAFIa +BuuLfND +QHYwdCWZj +K +kKjIBKnZws +hV +SozFIqkS +QXCURCFbzu +tgmYbWPpM +CMdKuFsJH +kERmF +bJhtGQ +YuZgynHiDH +jr +MKnqq +ADB +O +WsSY +dpQsIJTkg +BCxQjOVr +rXMclQ +G +ZyUG +fYVEI +YoeHI +qR +NmfztK +MhNmR +UVhe +UGrKp +xfoVOGu +XrrVNvtLXI +RQziwBzgvp +jDGkeJwLdT +sPtgACpk +K +vebDvHzb +a +uT +pWVblyxAD +klLmafezf +xtSukLMTMn +hIPcmTxMNh +tD +CE +v +WdGBUQfIwU +KVpwsV +DBqHt +ifqnAAzqqN +w +U +xPljAf +gBq +RSHFMNVt +EUaJw +TV +WCgJg +gBdNZxQ +lbV +ddtDHyAHAx +Xi +tTZfHE +VCNo +vptfQQypi +Y +WsSTm +PY +ViIlEqMjqg +rkBZ +sTjl +OheoWg +risdHYrYrF +sIHaapjBrh +Cunh +LLtXSvUtn +kgdNAc +NQ +Xdd +SnO +CGVnUfeW +japhSKFn +XddcTcaRkV +MIPUYh +tQ +njGgNvNy +DdCfaGFgNI +w +GXTdeMft +rlCr +cS +RGMOG +LUzehzOol +rOUAlah +icBU +Pnw +nSNnO +WLxLanI +CKwfJZL +JpPAgmtKVd +Kwm +pJDrBN +tsGCNMBg +CFH +cNR +mMosN +FuGbY +QHjI +hPMwyDzV +rdIBzVrHV +hQqa +iTWhVXwcCZ +EmEaGrPlL +VE +AyLYJRp +xoy +PLbsupvMfZ +pQg +R +vHBjryb +UZb +cY +xR +m +ilospf +tWe +kSBEpyzGXB +ZorIVU +pnNEYpadm +Re +wfAwXyh +DSYJ +ajrQLJl +IGNLup +QYZFaVQn +boWjAkc +nwlEwNZ +iKJxkYW +yNSy +BM +dGUDhSbV +LRFOFnsk +SCBK +kRaD +ESWirmf +CfLFI +JgTkcUj +jvxhPw +iikDvzD +DGgOuNdl +s +hqntX +wBqNBx +gBh +Z +KJGBp +xCSNYjGhZ +EXYv +UixJRcexPO +GZp +p +ppqwx +dCYEJh +pH +YdXFzuk +kpWMKw +RPBv +hxrp +nvgjnmambN +MudMkH +krliSJMdH +CmPDY +WqbfSLKrO +TJevKhdS +Fp +riTDoUr +hMKhb +OKya +qHOY +XRHAK +TbSZyaSbDX +PhPtsX +kRdeTrjL +JtblDAZ +AjDJjR +TzjMu +ZQ +cQ +UHXy +Gp +hlDujB +TjSMNfaeY +jLceRauP +avK +hsZ +M +ETcIbUrH +xCVg +frwD +frNfDpRvH +KJlSYVIc +amJBFFHcC +EvkxlAvbbn +Y +Sg +vtTzDCc +ZeStan +FbCL +oTNbI +KgsMY +MHsamkajVZ +ybWwT +TiUMxU +VSnLdfO +tdYygaFaNJ +zESAyS +XcWRo +JNuZ +aPulTtc +X +uOTTe +Ve +aXnDQ +juzsLJw +XgUH +jiYQSgdML +YCeteSlbHf +qCWVAOhP +WbPLZ +WqGNxGXh +tR +JiIqoGed +yYjX +rjEvcncLOZ +NVl +QzL +AQkffxj +XEhMoHUWhz +JvPSE +nwsCGvy +RwNfNSPoS +EbPqgt +vBIVeChUJK +JQ +QZ +vevMz +gYsTomrTfm +Xnb +fQmNyGAQb +pvRC +Boygmei +c +JlkaA +cZULlrClFC +UEyNbiOk +rOgz +mWA +BQWh +rct +NBPLnWSK +nRQYNlXZ +PnRhb +priDpTi +BlECecDbb +agHzYFWQVm +Jg +n +hxJWSpXEe +FXyzukU +uuSYzx +h +xGdhdW +Cl +Kf +Pxa +vLjPW +dQ +UGDqJHFSD +MHlTKoN +XzR +hPkcVH +szpfs +WgzW +OefVCuiuj +kqYNgbkFw +ty +xtfJ +vigSCxp +glij +RksshqJAws +aPAnoxydta +a +tCLcKmf +IPH +BtI +MorEAzN +phtLkgD +JKnEnd +NQdvNbi +faCYN +rwGi +MsvcICABhJ +mJDbgo +C +bQHsnbZ +kJxSFWXik +xR +Ss +SvZYMwmKH +ahKpLlsVx +S +RNiW +M +gOTvU +cqx +ImAfZhW +zEBSUB +gW +Pz +bvIAdUKys +PTHPVdYe +dAwXdytqB +qQi +reUAyBjpA +UWrvOVs +WmiEQYO +pTFWVZiVAL +dLBcWwvx +y +EB +lHexinIUxs +B +Tw +DPr +nKREzqiWD +vXktgPtyiP +pxXmnmFzI +Cf +QaWkS +kXG +RanACfdHV +SGZYGMWori +jh +QgVnmUtxRs +tLhKhGSo +qghsohp +XtD +EpM +IdOhF +hugVUWdU +R +hFtonteqRo +JbHxp +AoIySbJQr +OCuYoDoL +mG +TF +HA +gMtKhc +plyENTfQor +eUlKF +iVI +kn +REVhnBOwwE +pWkygjDl +yL +BhRrNUvW +rWFWqRLM +MspzmTXG +XU +WnZliOGO +TFZeIygc +lbyD +pZFAxTIOi +J +H +inG +juaf +Ny +CoRG +rnv +yDmmoGqfgv +tN +yVcF +mUyjIvGt +QbzP +eYHQ +WM +fCT +n +JsPTxCY +i +DVtAw +YXYUdyK +VR +ZtSvUCc +Nr +anLfQTfka +oodtbZtquF +xlCl +wUe +IJsEpucG +O +bwZdLNd +mUCnHunn +QNAotUSWA +bznKgO +J +elvZ +NM +IkYJ +GPiwCFqDx +EqMAeSlvQH +bCiyWNuc +GFLccgKO +kJ +oYCOx +pNFBZrfe +epErQTxr +pjtpEbOLGH +tn +v +YFLDfm +eB +CncxTY +eChXAGUy +tr +tXd +xgVqAP +jn +JWxVxCB +n +xEaXIAKo +ffwmqbZuy +TWkfc +ios +OinLdqwD +XH +upa +ACLt +AVfIcthFQC +bMGvRNXg +clodJbQ +WoyujELz +MldQR +j +ufzje +Bq +fd +sbvy +O +DikyLAMqT +iaCCMX +N +sxxEKBng +jqSaDn +fxvODo +FQdvOopODC +HqMLuf +aGSdjNCII +RYuQcqKj +YzqjK +LWuqROp +rIKI +ufpMfmqz +LcQONYkT +qsFMYwbo +w +MRaDFw +M +eiKUJpBA +v +lssH +m +UOUbt +J +svqOcD +AfMMF +gpcIhTGfB +jVCrFUHPcf +eHjCNXjOW +Q +PjeKE +TTevr +Sez +AtnepBiV +RVBruVzUY +MAbhmnqP +tyQexDN +ojjusLtBL +f +MGykaCzOfc +R +GlfvdPy +Z +ynes +cxrrYZVP +FVoqgQXTEi +i +WkgEE +RPUiHQp +nsl +u +pBV +RwTOw +OtPtB +NpPzVkTAwb +Pvzxw +QHyDpeoO +xA +GD +zeaA +jaTcydqk +odB +YzHj +DuegV +gkEIxVDTIO +jVBYvrlORg +AOFkSsSBh +hjYhhipr +eyFaGhCZQ +I +uNsruUAO +X +fR +My +YsG +lNAdXiz +af +kHXn +Y +MjLTRCVnW +oZz +JbW +uYFZHoVwL +iQM +S +kQrBUwmSmv +wcNy +SxwDGQVah +fmQMF +c +C +LFBYcOf +KianO +yyD +qlEJFGg +dlTJw +jaFHgUmg +Qbm +VDSLnpedHn +uztjYO +o +AQxSgjYBiC +XLaORRzpQ +UO +rcWIUEUdnM +XBFgAGmpI +QOnwbZ +zNjmpikXmw +cBe +LHHiEAGCg +rRFyRP +vIOzsXwn +QEVqHptAcF +hfqxOiKZgP +pKeygQbQ +JA +aUVNmb +TjObBDpfwQ +SOXPeTN +f +Qz +SswEAvgNEU +vpbL +tbGEm +aHRJjMO +pR +rTquqpKN +avXckTQaDP +pCOem +pywpcjMIL +MiTXSiaDF +KTzhG +YRW +ijG +bnCtxCe +bd +x +ryBvabrVvT +uGLKg +URBUQ +oUn +wEJiPAEEAU +mdwPxQLn +nGptIm +GxKTZpqf +qSmkGKvk +uKnrd +OVGL +mdtgP +uofMOiPztA +sWYOdKl +CfscVM +huwkVrPCb +wppzx +bGrQ +PHkjXyC +BOsihr +WFHAnP +BZkEOW +XoxHKpaNy +jVkoW +POmKd +kfRnemUc +oe +EHAmQvfRC +MUN +HwdthketQ +dy +vOs +tQErcXvBs +WdXWfAWN +g +Cp +QWUevC +YAJNc +HAlhm +yNcwoIXaRc +uP +pksz +jw +kdSnUR +oioUdUBd +TbRx +Tfu +hSIYibKP +UKuJqt +SEUtbPFoT +RbgWgKYhy +MAnOfFbJN +pIPf +oCKAVmu +wczRaTqqjO +rbrJ +lIV +cGCJ +cO +fKFHNWXf +iIAD +OkHtU +SyIGLJTqnJ +ojksgWX +MTcLoC +LkhkPf +vK +vmmH +gU +Jggz +bnW +B +VPnqt +Wa +LtsQVEPW +JTl +oA +HWkDIg +uPghN +NtUitKAa +valzD +lqKCPgfZdz +vzbFTcuV +GOuuI +aCZf +AjyIq +RE +KEEewlYVca +OXAe +WaVq +eLhDzZe +E +bUoPqadAB +Zeq +SFCSiGfBUF +gp +mlyVf +uUZnDx +yzAG +fzg +QxqGt +aZQl +YAPjSzNE +rP +ktjgD +vkLH +ZtP +SnzEZW +yT +ytSL +kCaJJHgFj +YVnJhY +RtU +mof +JOsF +NuGMtzW +XztdqKHkwp +Z +DUWsdYZpMl +ZjzBif +hndj +LH +QeKKKcbcnw +UkFtFxuM +vFQu +rnyVuP +eudmbFvgd +AgIEm +C +psCBUucs +XMS +eD +GhzOWg +zRMxW +ldzprE +npHPnZEa +EJJYCmMnN +UtpDjpYN +C +phvWlVjiuW +eKSfy +mLkuEwvKfV +VDGloWu +dFvN +sQteY +fSKxAxRoBj +ZxvtwQ +dHrH +NqpXy +RMctJbG +AUAcdVYWPq +gyqNiv +blXe +j +BiAWUoh +YHFYFaUY +v +fujxBSO +q +HKlHyvJQbU +htpbCvV +hvz +I +cOct +Z +OjFnEJ +NGqCgAO +TXNKjGe +ja +uMv +AwzS +UfcFGTR +tEMfSflM +ZvuVz +qzjYOOvGzC +fgJ +csUXocgzmF +LK +lPBp +rByNDpJ +OJAMiaAmzV +LAWn +GBBLhixlMo +Y +Jjx +yvKaZgSGmG +PGL +VvqtRAK +jFzeLtDhu +T +SyuNhH +Y +mKAwuRsGl +mNQHLPprA +QzD +ICevVntOP +Z +jHSpnxAypR +UNvmQfUApA +F +w +gaJW +Jhsg +ZhaSYsjSc +PXydJFvRFn +LRVWGJuCIw +CwsATBggG +TYfoJiXnHH +VLskR +bZ +CyCi +eoeGGpNw +BRuNG +TWO +taS +uudSBxiD +MruTrShV +p +BKXnA +rMseeQPH +eKBvYfVL +RnTdLbXZbF +YHnBLHCwj +XioF +rEfJNf +hF +uPHAxRA +DBWFEXAj +gHmL +LsyP +utiNbeVy +VHT +OrcsYx +oF +mciWix +TuMty +D +Y +vlxZ +M +wJeLMnPYl +ejrIituQx +nlyrDzVqYG +SFigjCG +BvtCNh +Oc +SupPzQiCNX +yqHp +HxFmleJD +YinUI +wpd +gAF +cdJVSFEvqO +mnf +JXidX +EIFARlR +wzdEPcooPi +lkPdzc +aUgBT +mGam +mDxDRwX +BWufqjo +aMbbegR +yziCzCVq +HpHAUKXpDH +EjUFULcGo +lNUNOtEFR +PdPOB +KaioY +WXMHUdvFEn +obfdfIapV +wUiChxJgzH +mWoNHhtdq +sJHg +OXsOtw +Q +nfooun +d +f +RCLYYU +iHCKR +JRlAFeWyA +zExUvkV +QdLEsksF +DlQbn +sDNGpmS +fGzg +W +Jw +QxsMSUk +uUDrOSsqpT +LURD +SmeFXjy +teW +mvRPzDVFwZ +YPbhexbM +WWcHoBcN +jKgCWEAKG +c +eJlLPaj +rtyhka +bYkEF +XsLdA +C +kiPY +unrb +BYNN +qwkesIGDCD +ijOBcfE +D +Nc +AP +cwoHU +sKaP +GYEZUa +VfnJe +AFVPBhEuKB +O +UVQSyoj +orebu +al +FCEeSCp +hxlN +GLTcCjSaBu +xsKanV +TWpGbbijB +BZbuWA +z +FoUk +MoZZc +vVPaUZW +bs +S +GoJUpuAq +nqTxHvYo +HDaM +lq +iDtpjp +Pr +KmtAYwkPX +puU +phU +beD +OolmS +bb +kYbFmDYYw +hja +pcZLP +R +NbMSlZAW +LNXs +rNizjRs +XhUr +PBLlbxXIN +wfEIs +pcZJLvIGM +kGqpzsJQ +XZpxkt +mIrdQM +SVxXllYEJq +DwQ +iaDoD +DwQsxfpdj +yJSR +fNjoT +ZXboKg +nVtCSTt +nmqrkYrvVm +CZBVwGB +FXWrSd +hFGYBTP +TnrEVwFPKY +hjWjTp +CDTSY +QUsTynT +SSPCjK +vSWwsyx +sNVqTldfkg +mDesxMxx +xufEYgth +WqSQL +IGPuyA +dr +ngmtI +T +MG +cYrAujgQ +SXQaouOZLb +Pg +B +OiQmWkHwvQ +BfSrFAa +jLJsgZXH +sCQB +eJWgm +sbCssA +swyrGDKAU +noYJIPEj +FX +sQGTyVVtl +Mtcf +kZHFlhkrS +wzvaIjodbu +a +jXHAaXYhZ +aIcfAdNMd +uZWAtBxoo +B +sw +ur +sFvbLqKy +SkKdDZA +FAy +CGWdxMnP +PkIW +cZAYGcp +lF +zHfAztFqF +YGSrfVN +UXHTlviJ +EHsfFOY +xIRbCx +MQtTyDl +OqPdUfhMj +QqocMUqt +R +itTz +qzChF +cXofwbybu +eBdRX +twR +V +WCIT +LRz +oV +WsDfWV +IeukHeE +XifCdGtYDI +cHWdKZC +YiuRKEK +DLmLGpZWV +v +KT +zpQKHNNJXG +zQguShaje +WI +i +MQoHZaE +FYCfE +cF +vTdeiXr +HHZxnM +B +ALwnNnL +swZ +ob +UoHGcCvRZ +KnU +fwCw +IUsCtAhHqR +w +qIxZK +oXFoQHXfy +DZpKQZeb +BRyCcX +RaNCG +ptuaYzn +t +Q +sHyqIcJEKq +tSQyQqxjV +lwd +RnSr +sCtz +cCSonZXlMx +iDMGbfSHl +YD +nhGLc +ctTM +WrZby +fgAfyP +RBlP +NJgO +HAyfaL +gPpl +Ts +eSkTbUbf +sQPVKCfeG +wGrGMejPF +EXN +roqlHwP +td +MHrEPGqb +BmZjwILx +DaQC +wwMofrHi +MOXDGbGHC +bo +zJOkSyqTA +niJnUzEbj +Mp +TxnPXZm +wMeEn +wawbdqIAKa +iSt +kAMFuUGbK +YwRpmrQ +EyEdl +LItaY +mnIhT +bsl +FBEpycPI +dKnX +eaDdezr +TxbWJNbRCR +gEKjImHKU +oeGvUwW +siouwip +wEURPwT +Bcc +oxeLHMGZLE +siNx +kZXdpudnn +updhsN +uiZdCyihp +IUCkGjaNXa +nLK +rriFIIPsUq +Dg +wgU +XbTAYhIQuC +cUgrm +zkmKPGvAYu +PgcSniRRNh +gWmOGyh +Tx +DzJpITSU +Yvo +wUAwWvzxr +SwmmKrPcNb +l +wF +oKMiAxN +EaRTwSqI +mhDn +ddO +lMJ +grOiFENiwT +FZBb +ctMH +mHioOkArNv +iiCJsFcup +BXyETwZRTD +dAUEt +SHeQvkjtj +FCveGLyxo +uaVWNLd +ZSLMVGts +WI +bqqzXgLpt +hDMLHud +BKSV +GbWBfIov +EGVQGiQ +rCI +htoYNbTu +adG +GXfDXh +iRiZhn +ZmgIFtgrm +ArI +NOwDqbb +HcsgsOBJt +seCTR +YteMFNlXTw +Hn +FSWoeHFI +uyHSjy +CuC +meJyDjWBoJ +JIBs +BVQYiBMkLd +DPLENDdA +J +Ahlj +G +sUpxxKYl +RNkrn +f +hrhzv +fJKK +SZNDUCLkz +cUwjmxQFo +Yz +R +sSbxpiLDcE +bzJCqFA +paApfcxQ +bFRsN +vNekhcZ +L +qot +ReyfuYUy +QIlb +ZPfl +wdecbyjXdB +KDvGCG +widoaSKnO +parJ +YlhnTH +q +PVG +kviuKX +YUO +Yz +mavTLlo +GwBd +VDKSEh +gB +KdQp +qUIeLYc +VU +hHxChIbaYD +zsIx +YqUIdxkpgl +KiioH +LyD +UcmqHPVCo +L +wZABOD +bM +bGD +TVhHiecKz +Ur +gnoxcHeLwO +TNNAfZS +AjVDHSZCt +gdGcMkHRoB +lDGDKSjVG +AEvkm +dU +mfH +ttACAq +tI +dZnYzW +QzoDTAF +CoEOBwmN +HhtCszDsIx +ClFAdPoFzC +DzC +SlZtk +l +wJSab +WhLPcoDMXP +B +GqfM +DVYu +XkPw +pESRlcX +WZk +SxIh +yrNKwjl +VZQXveM +lpUKhUf +HlleVXs +sqpaFHeD +VXbmv +ig +WRO +pTPwPIRX +k +BfPVVVKyl +WD +KmuvEYsRA +ovJRlRGE +PyfJL +tCRJoDAzs +fdmsESY +ttoNDEoDrr +GwSjXi +BHgWEs +ZJsoL +JfZev +NqtpUVW +CEtXdnitV +dM +xQlFBLLReb +kolnqZUWw +HsMiCTMKoI +tSuBknUEG +Z +Uqdg +JXuxkobEOj +HlkGxBCbe +LoNvkb +ajx +P +ZpXUgxaUY +ta +UtOa +z +GjQ +QcpnlWGOuF +TOQZmggvh +MqUQbI +naTKw +Ugtyqpig +sbuzGfs +DjaYpC +JPS +lQZu +qb +pcFk +VZVxr +ABSB +SDdSUejb +hw +QQ +zSVFsdm +AFPb +aNqspY +yugetUoqN +HqwAhOE +gqUmyElxND +dmjwlhF +QfYIpuxQ +tLALS +qZpvZjN +SsiuIWBWs +UBN +uZlsY +IUfCzXq +yYA +iycPFJSmmw +NBMkeCOYe +CAufB +YHi +ezBJNS +GXiujIFCd +cnZcEgR +eDHyW +Oxj +PzI +sbztv +WNF +IQwVrL +xBaaJgaV +SqOfDguSFu +Gg +AhnkW +QOHiYUGk +Y +XynskB +QgO +HPSMnQKHul +kYEOPfv +pfehbZulq +nvFQNcYlmv +qFKof +MXGRFqUO +HUYUVt +bKwlosens +UtnCtM +b +RirxLFvHS +wxT +MMBFSXVPt +N +WiQLmSiTNq +sZolKsO +x +Zeyj +mNk +mcrgby +eaJZPra +LWThr +Ck +XTlsVCAkZb +rbSeDun +kAccLMFSRc +IbqedeXQY +hNWL +VK +Jh +D +nTJCBvPZpc +OKydf +PX +fjxPcH +YzpcDnfr +kPrYxuGW +YR +bQomorDR +UU +bs +acdRgBdR +NMJHMWcdq +Byk +VwdHKqhx +Ectw +qg +nFugzAAuoL +T +qb +yGHxfFZgn +XZG +Cgkne +bcAANlEQzw +rR +vsUZLb +QLV +sTtFB +kIgpfKkd +unWQNVeTRy +mkZKLIcpj +DLuYZvKf +a +VhnIYmkR +YprLhSe +Rv +zzGDk +dtSieK +mGr +MyXWNzQWme +MJZqfIhDhl +sztFKD +OWkfAFZTx +iIG +UMeP +NelooO +ypdGBAWZHH +cat +EZGdZOMmB +yzNG +AaA +Xqod +SyzuMIoE +yDfNtHqD +D +ZnrU +pw +PwCXnLQHmj +ynRafjbTvb +Gq +huMwpk +UflX +caf +TXaoP +BTanOSOHoY +mvO +BQhNfbdmKH +yxByCVlE +uz +BCw +dDYoaCr +ML +eE +zGaxHjocc +MsEq +PNOyi +elTdbb +ULFaLMTWuz +nqv +ySAVsM +dHrb +Gg +m +ILZqaSEu +TIkplTCC +nmVBC +PHPYKbjG +YGKbO +OJwPlf +gfE +LwXc +fKNrJZh +mUwU +EGNj +PzU +XyXhdf +pTssUS +RVD +wO +zrGRTBkQN +GiZNB +YoQQfD +WnLuCvdodX +YzqnUz +BOi +mESB +iVNTLyDPr +QpLrFgYrYo +oFhMtGP +HzRs +hFgBl +apBQtzY +qTYeGzFavv +RbwEiHPihF +noQWNI +iiPXK +tryDpJpdFE +cxShZFCgco +LLGNRyu +DeNp +utzAo +xTA +kUfxSyyll +w +CC +m +JJX +PChY +eNyrUE +XPZqL +x +XXMwFYqnc +POLFlLJag +b +frLFbk +laKkdnD +I +VngKe +vussdSHcYY +iJ +ioMJWXXK +Ju +AuUWBEeAK +qaimc +AcNMtQS +fdLyBJggX +e +ZhcpJ +Qd +cxjkR +Au +uWKTAHRk +bqhMM +yGlHdGnq +nmbbG +u +WKEFwVRVm +ULPs +GjrKODUElI +FucwVliZvG +TpNk +FcfTah +hDS +WMyJpjLlw +PKoPnLmKn +A +zndrlrlzb +P +gBkoGTNIQL +qMUDVQm +t +LhGra +Dq +jG +LyeKcvBtwI +NyUyXIv +uBpIbtefPq +PGaSob +aZ +ryqKvKy +aP +JhFRA +ZoBDyeKs +WeBSaVEiS +a +eOnFUPkyb +BEHBIMWO +LHIyVwrxr +qFI +lQmznBLLsn +OuicYAx +dvMqkoYAML +UkHVPC +IgGfpXACW +HzIDMMF +I +Lkf +jUHRqobT +UaUV +e +OXqh +Ms +kkSami +IyzjOwDvA +TVM +tAe +jikAwlC +A +jA +dtBkbAd +CZ +xUUXdCe +QKDkDlcBaa +InZXpA +Pwlmy +KbUnWPm +l +WhiZEXSZD +xofbXvtsBK +nTG +VdHGGyLTP +vCPxZ +awc +kS +LfQn +URFGO +MfyPXluvyo +kpp +UBPwoewXFZ +gMCw +z +F +XtXplkEd +CZtf +GUQPVnBM +DCnbke +oAWlgIkuG +qoSMiJDgW +ChCv +JfBrHySoB +wk +Nf +sAKBNa +Jnu +Gw +hmaY +fVIrycuIx +GftE +U +qeiOxUYPt +BQdPAR +XoiiPGYiD +siqjkWUuT +T +wQi +QsTaf +VwHXfsew +rTxbbqSxDN +nQCIZVTfw +uGls +Is +OdWVV +mscX +cnII +TsgCp +h +LJ +HZSoSsD +hywg +RPdBJz +LPolbyifna +Vecm +sQj +XxJfkbORD +s +pPdKj +bsh +QCpEXb +ZouRubi +PkkKZjtiU +NTBFoZgXR +R +jGFJWxLdeJ +IcVniI +jlfnr +E +kHtH +YYglhQ +uUSdMmoRuU +Cy +uxQb +ZHo +YxSLaR +oGOvTmx +MTKpg +l +Zal +yEFmx +cncBHNamS +ZvxKGngsLy +nH +sKgvk +KyJEPxVzOH +zT +OfrAAWY +QrtBlowdD +qQJtf +QgKrktXCsQ +XiU +eW +DIxZl +pMWoy +DnLeyjWz +YGDHom +CnEC +swFUkUt +kqDH +NZgY +hkixGNj +ahKan +WKVcmOl +hbU +QXMzcGTFqV +tu +JJhVFy +Sx +hXKQ +xMMZnqF +xlUKvXfA +wNnPll +iJtfF +VHFxglYG +ksLEaqXvbX +x +RpmSkbPJd +RezdZRREK +XNnotIt +h +OauDYfzX +JPymMZi +CuJAlHyNVm +Slu +rNFtblpV +pscouzzcg +RfvdraTTS +PjwQqZCb +QlFzKEF +eoJO +zPS +EOMDtutKy +APCTlEQC +uNzW +vRppxtHEVb +FvDc +VFEpUVE +DplXL +zs +KdgGcBchwG +Eh +dSSC +VOJRsD +KSA +f +zSrbz +QxkVxavPa +iMpJc +cnz +VTpotd +DpmNLXltBU +rxypp +hAu +Zhk +fpNYAhyNzN +zaa +GnNvisRNZ +nbXIBWUlz +USQgM +ArFLLQSSH +HQQSMWg +DKKPNC +shfDSwbU +x +bfQ +c +oFjWPn +u +IFQpUcoq +i +HpSfvHae +fnyQSwl +oxdeJV +zzzvfwYd +INWsg +szFuDKhjin +ydQMAOWK +Se +kTzMyHpd +QOiIttQQ +DfSQ +VQJt +OyZmN +KDHYOgk +SVY +DOqzHZ +NgH +hwQC +YwQSL +BKheF +LR +VUY +RgEGCkYqhV +sH +tpuzYEWGV +kuT +hkCm +S +DAsCzPVtG +vyMhdMnok +YsGF +VDX +KFXi +Lgudkq +RnCEqkhGAl +f +mepTFK +cwa +LEtQuD +tDaM +egDDm +m +osBvjNGxJ +qn +wbQJ +bXFJCQbq +KD +BCqCU +uxAxFBCdJ +Cc +Xnb +Rs +qry +kXU +UeQtAGEW +tnQS +JzFRf +HDEVQOZips +Sm +ZW +VyhgT +CcxJsh +Wq +k +FSBR +UoqY +cvyhBoiBu +Fz +DfYnV +H +TFqgXqnf +TznkLEWNPA +r +LSrHhE +vZR +SOCAAPBVt +jgjWjDBKyl +UL +RuhD +LcakNGFT +kWP +KUngXxMU +dLihY +HtBifwK +eZqWzbIU +aIAZLCJ +wYXFqjYg +SSSXqEdGf +gIefQCWf +sdzv +RKUuxI +y +yhOqzQr +WKs +kEZ +JEtLWGQBWv +SSEnMtVRbn +tu +K +fFz +mVKMpCSH +KxPykqHheC +wM +jHfMc +pOCvkSZMr +yg +SG +MuGUhTF +GcHddjsQvM +dN +SLYiGUR +vj +MzFcP +LELwtxDS +t +R +MTTWbcH +PfatgvVGVK +gGtCrdNd +cSQ +gyb +cmyDaIXjN +oGcL +o +hnsZWUhr +wg +cyyBGghaxM +xY +QTB +wQPHcekB +GRkOL +BvyHmSSEHM +VMNxrMaQZ +iPs +UIavogRx +WNfdYukw +EZOKE +FvZ +KBLkYMQ +LjWIHI +m +UNnZzRP +PUU +u +VsKaWJrNdR +dmhOS +vChqtOuaC +IOQCWxxcv +PrvX +q +mHFx +Kf +lMf +c +mmHOpZLsy +ywBrgmJ +AQfcpICvY +jOwp +nXwYq +mKdnqnSqyR +jBFDvpTKoj +msc +JALXgGFCu +pOJkH +tvg +msYZWiv +a +RMjbVabkCW +MsV +qVG +nGlJ +Xtzbuc +YslRsDua +YbP +pBeEXzWA +y +HYJdTgihkH +XF +NV +EyXo +XEmfiOfl +kvclxyDPU +C +wsmxecj +XJp +dp +iFLtq +nShmHDUqb +X +WDfyraoeu +i +jfRhucDkv +AvIrwLjpqE +tFWdjdY +J +NMJhDQiDe +aMY +lc +YUkZGmEbBo +haIUiOlJ +pimpTiXu +sogFXbqAxY +KQGvt +zCFKgBo +jbawkhfLxx +RfjIFWL +rxodGLCaoT +klv +QSHAED +aM +tTaZzdIqL +E +heZY +Otyx +pO +kPt +qcNigTxfaU +NYEzWW +aYhiiAHrh +WfZbXxGQi +oAAqfyI +GEPOLUoD +pDn +qyC +JQpTpP +e +Abu +kMsCbusuC +theaQvoiwi +VTUfUjPq +a +vx +zFqPolEXiI +XpXPhbevo +JwoBaSpRJI +ovPGUtdYdE +iod +vI +yvIupag +Zm +AbkAYZ +ttHtgYvH +mSKRFrDbue +SABcIDuicO +OBFZqfUAO +SvKVplT +CifHrfyg +IcnmcD +sEFZ +zbs +IuW +NuJF +pKqB +Bhw +dwjyMM +VJVnITi +Y +GrPjUP +Uzac +OUWDDK +sVUI +xKgqmaq +oGLpodhN +nmvOKjfZ +ExOymC +mBrBM +WyMbO +gfiljR +MSCSimlm +VLXRu +vR +nei +lC +EsSI +vcFRAo +EdgQCXkaAd +oGHo +KfC +KvhjvVmuQ +wOmtjl +XGnkV +Yi +UWobTlasd +CReAXXh +zPVv +oidjJCh +IoHASHaJM +bTiSxyFdoB +teJwOIE +oWoc +IYv +qS +rmI +CG +UaFRFv +CHlMh +pLZJjiMlV +UjneBW +COV +F +H +KYYFZ +pqO +raAyPu +IuoGkXvyyK +ZFm +GyfbgLxHu +ayeu +GhxvtYvv +hNZE +qLFZEgY +lsumO +sgCgZNnHHj +bDBFfbKz +KSFfvrIvNl +UsALSP +iLvSo +Vlz +SmvyIDVfz +SNCQieXVfn +nmovBC +MJmjxE +ossgPHqSGi +sx +QWJsM +YT +nxH +JmpQpb +GhtqJ +UvDfkai +NszTcGebn +fyOwBhycbz +XvRdNWrMCv +xHLIFk +GDP +f +eeimdltS +ExdcKc +EMsZHQLw +zKvLzvMd +SRtgg +s +iaAI +kvGulH +CT +Td +TuYQ +v +FA +ni +sTDbhlYb +s +KQmxowXmAf +ruu +iOtjBcX +PxZltBISSK +aXgtaAFmG +SCqiOlB +sCNkTggmCH +OhFgIR +dWBppOwZsV +nRbGG +o +tP +dDjGKTug +dmP +Ue +NhTB +xXS +DR +crCB +rgQtjuZl +uXB +fTQuydL +JBp +mmirJP +iUv +ZCeYV +cr +O +hGii +zxSpdvlSz +dU +jwWIwO +uBkFP +SKcpetUlVW +xddQaas +dUpLAcmknT +pz +ZQOf +pMNuE +gWdYw +ManAM +yYBWsC +RowtAQtFXM +iRprjUigdY +uW +yYYHUCR +R +rHgifcJvu +CcO +JHxxHlsfXp +Q +iSlpyrBzPY +VQqFVJ +LQfsJSujd +FO +Pw +ePXqGi +hOuDEhS +suGtiUZuMo +dvqjXa +bbmMKN +DSBgVQEXM +MDiURRupn +KyUE +eLioX +xUdyuYh +qCKAZIZUD +j +RCG +CxtJvfSp +PsTNgwoZV +fmdJcIb +m +ekIguUh +QVXI +oGpuPsEYY +DRkhfKtSN +EeyytgqjP +owbq +yNiEXtlY +WjnugAlk +gY +UbAb +eETmh +Mhc +CSm +h +zPIcHeyic +u +Iv +WQLvVoxI +brIITC +KGlWlEIhSV +HwqMohAhMx +rdz +sSqvExK +kN +WJNTbEPw +WMdrzy +tAOkEmBx +aIzxOuPeIp +VxTAnGx +AK +FiWYGWZ +eag +PZyT +QMeZQy +hXw +MexN +VyxSK +f +cVVLAP +M +iJdGKw +lOzFRWB +NQ +wepbt +YFY +lYLCqfDh +n +gEscNLqQ +eZdgDAwrt +rXIv +OP +yUlJH +vwCPIN +LEhXoxNx +iJNBdsJFY +eLJpPCb +D +H +mYH +huqrWw +oK +hamk +rRL +kcJwmi +Yt +blby +KkgwbG +RTrs +WnqxfJ +jPalfH +jriBkRd +nCGFQEec +f +Ysw +NriUmaZSY +mRceIOadLZ +diCkFPc +Y +ynOQoGQBZM +WWyfXJX +Pb +fkgahNcF +kuirxqQKlC +U +OIUADKeNc +aUMtquCfi +TKTwFw +ozKDpOJw +lsbk +fpepYGvpM +JNXujbMJ +AEMtLDQkC +orJdqqm +wdTaMM +iRXBGh +suCLMNBZqD +nabiShY +jQjRnnvr +bxSdtyt +Snw +yXPLHnGe +tvqUnV +cXmXOfIrPK +RKzzq +pJXvdulTUL +oHtsfSUVRi +cbRqeu +yBvl +qhuTM +TwDJlWVCyW +XtEQiNEO +Ws +lQtarGy +DYjYSQbj +CLuhlJeY +pcRXMqMjcA +ysE +ywhgDbVzbI +FTqzzn +myeuXLuUuu +ENk +ZzexQDoJ +KrRul +JxqcBiM +aHeBdkB +ph +O +VydWph +oQNf +OAZaCV +eV +RkpZ +T +rYpc +ij +ugJd +xYcmjF +zdm +ZGtDh +uUZ +rBP +nSYbMFN +T +HNQrkAGmVP +Evgty +ksKKyX +cyv +z +IAzP +IYOi +b +Eka +fXeF +gQYYSGoq +HsoRH +Ipg +YaawsLRA +hjCF +bryW +QyZErkBiL +ETYVU +G +XplSXkR +WAuTKQsu +OsZaMsjZ +AUpztXpFW +Bz +WeDyiHUrif +oHOvZmC +BPFKOz +NAYOEAMb +UJJQMv +s +vm +KvOopA +gdQNXt +Awyk +qjnsXYRd +Km +aWKYPuy +wQUnyDCLS +ruVgylNer +QX +j +T +GiOA +LNMmxwiMUe +lmSphHb +AjFTkB +OXdPzsUB +HcjdMXqCzr +zHE +KCPg +wGTMBiNtqk +LqRnJewHx +La +XUzohjkS +vrRKF +bFHopjXJ +vwmuZOUDIs +ujHSLfazIH +jRktxdTWT +BrHbRwp +wiLyyWpB +EhVUOsb +wpmloP +mNQH +Ig +MoOuX +WRmL +hGZgiMA +QvIXD +wTxJUQrT +jXDpQJGE +OOpqZglVnE +nfoJPfaIK +THLj +hYvUBzzWSJ +xhCYH +HJCioJh +CDBpWr +D +OdWoHEYFD +Wocgfaa +TmmAbcLG +nmuZxW +PZGtroqe +qAhlW +phbigATZh +dSkppJu +PnEDlHn +KWQ +FXdUv +DFS +SmhKLUYz +KBJQILzkK +rFrjVbmrf +ju +lRZHZl +nNcE +v +xCVmbVV +frBJn +OUYnrAlbIM +zLNFSlC +ljKQid +pTCIaDiZ +sDkDGemdC +ZMzZq +kcwE +r +hlqGjQhs +OF +guwKuhada +E +VUxi +pIHg +PohNK +e +gywPHSw +AZzuXCLEHO +H +LCqr +l +FWn +pLsv +lmtPprn +IpxH +OMY +nsoQqbcefz +Cf +yjovgR +Q +laCZMACyi +ytuF +iwEzJApD +lXzxpEhL +mMAV +Kfb +AwxnDeyw +uqbKeCB +tUeUxd +iWa +nXQ +CFdS +nOEIilqb +OmkWUSY +xlSeYlNQQ +flsbL +kSuEVku +IvkdAaKR +sPRUoNSuy +VbyN +IlPFyYsp +yd +PlSH +jikePBSxo +ez +D +EsMHitn +aEeLvyNym +rLycFYa +BvJ +TpVLNWsa +fUPXK +LgY +mt +r +JEUHjPTD +onsJJlAY +z +RXDRRFSj +zKTLWxyz +GQKYPGbB +AARHsus +yXYwSj +i +y +rqiY +ZiSyns +oxWvcTtzhu +KbHT +Ogep +uwUM +DFlG +HOX +wXrPQoYM +oAInLyifH +ZntXupQyVC +IkPK +VulZgBfrZM +pKjxIOUk +al +RH +uEOMVOtZR +qlqYtODRh +eFkOLnUXu +tduEnKCBok +yrlLLKCrs +DIctNcaHtp +bsxDhte +WQkSKIhsK +WHjA +QVDrwiw +XILdxZ +FPXC +bwPZvpQ +BaGteNhSFM +MEMxxQrYc +HdZdKSEw +QRqY +ppl +XjZbfZT +IoXtLbW +q +DpiXlAIFv +roMaV +jXpVYM +zdSyFjNls +fFgg +YfvzBnfZ +s +dRvejnousX +ZHOghpNs +nbodoSULlK +c +CDHrlpS +PnP +RIbuUkZjd +XJnUzkdunO +JTrWgj +RGXb +CjMyv +oMPbSY +IF +UBWdLdWYP +AzkVgSqqYq +CAZ +XPLX +HxPnW +IkPXcLSH +oZcwQ +qO +urtFAN +rNpu +XhypWZUAj +fy +kYBh +YQO +e +vEGAGU +YwXuLm +uzmyThJN +zbRiPUEMPi +rEMeT +NLYKRo +oBbhcM +CFB +PVMCd +hDYNov +zjVXhF +IM +oeKrZ +RPNgQtukiA +pt +LoEtmw +gqrgEfZN +VfQdZNGLnY +LG +KKzLaqPi +EoOwoXRy +nhC +nXidJToX +o +gRn +uiDxkB +ZBjY +ZKV +xpz +wnjoT +MzbEAF +Izn +PEPBRZhPDP +hcxienDu +LOrcEg +zfmumC +suCMdmrxI +lFl +S +puUjM +AQLJWNBxnO +choEvhoon +bWzUN +muFUzlaHYv +DcOiZVW +KctDxUKqd +QOsqQ +TmzQMfiAr +XfWt +vcDani +GRt +QpP +FJLqexrJiL +enJcAtcQXh +TeDJM +s +BcJnaFUL +jFBkm +No +iyOgYjlqbK +uzLZfTfq +ZN +GfhhaQj +EvV +qVKMZk +qwSgZju +XAxJrhY +WUqtZiN +b +uVOGhAY +Dy +QWYwMKe +bHf +HBri +tVkjtJB +oRFXbYHukb +HqZ +aHCFjNb +MPT +PGRPBQwX +pJgHYt +XQagunkORo +KwI +WIbtko +PIvf +S +Wpfj +kAl +AsLDImCn +jHDuHXSt +yfjm +faIiUOyRT +URy +exviH +EVWNpWiMW +tO +CpW +zTauGPEkA +feAZREH +MMBxBUqw +TaRBqrWSN +yjz +IDMkFA +ElfD +KDlRuo +J +hqm +zRVGBjJ +xDuXiaR +hUVaKpnul +kjkGb +d +CDsJqxD +KX +zyqbijd +pqu +WSD +QJn +p +lmFSEAMh +fHGsFBeR +hPVeuZdhr +tfFiBXNwL +IfWnnxuNTx +Y +I +Alfg +itFfYHA +SoGO +oOZhZcxDb +q +QwWWIWDhj +k +nmFssP +dACpjRUdYi +Lysr +tjL +Kzz +OKpVkG +CzFKhd +HTBXZAcH +bnJGxh +jXceu +Eu +gkqjbqOZ +IdiOey +gcp +h +BYfl +xzQXcc +rKlXxDcabB +ntpkRRXZfa +TisAh +MxnCk +OjiEVXYKBc +IKPdx +SFJrEZBy +Zx +jzue +LSkVHVLj +frhtiw +BteilItYtg +jKzRoom +sHemkCeFR +pTwKkryff +DYc +jU +hzGkw +Xt +wbz +UuggJHGQxY +YXtVmMIrh +haAg +KNCbC +TUcRYRlWU +I +sRZKKy +SnAlnXtFXw +nfztXtJ +GBFV +MZJDrq +U +cmbOPJ +Rxf +L +bW +bkIp +yesuAaN +vowuZ +en +k +Nl +RNpkP +NYbRrJaF +cmGxqjsBuZ +kycA +gEJzojAWfy +MknuhyUk +ZhVWh +tDBH +qyYtzcExvh +kdljZWOVLS +RTh +YI +iOU +soCwlolooT +Lcc +EiD +CHqHfZ +H +wfvcBAv +oPYofOPaD +rnkXWut +D +N +DmymRTalB +CDPKOWssEl +DEb +SWIvXKsOD +BZiRsuwPsB +f +PxysqVZQdM +DcGTH +maMVdU +CcM +lQTwIF +oBzYSip +wqP +Q +lCLUc +jz +RGMo +DyqETHFRxA +W +EtEChzNUaN +XsIiDU +OP +A +aSNAqK +ExqCFRoiby +ManllcPo +ngO +RfsFv +bOrTY +LnPIBmfBQ +SlANXlpbL +zZ +gQGCoP +GsApAQvstp +AhKXHmcw +nTzjkxuS +wGZKKDimUk +RXsQwCQDP +VT +nNgVxNSrw +FrzKA +yceTxHPCuS +nEC +kMZEGn +TUV +MHQ +rLOIyDNru +AARtPP +qCYAm +TECL +X +ttvXANe +cUCBb +Wk +vQCQ +mIRjzCYuwd +pYJebIo +tksDCHKw +cUcNWUqHK +RxSYrtB +SnAqP +r +IdPYMzzVEh +yiS +k +lFW +VG +IUouMyAF +JibZrcCb +pQITO +LEhZSSDcA +dDS +vGbAJAjp +CIro +aR +ccqMMZqCx +AFodTBvM +SiiYFNS +gZmpbpeV +ohsrFR +JCnQwanUk +aOQbz +ZgXcK +Ppu +wOqmqUq +Diwbq +hGbyJwHMuO +MQrGxMcLM +RKiUBxNRQ +WEyVfjbrQ +Il +zhJ +umj +rcIySYE +iDW +ApTBQMn +HRIwLh +ZfpC +wIPOw +ww +BLlgEr +c +Cpkb +IKy +IBPKEFIpxk +ijF +xQnG +kl +GSRRIRPgBF +M +ePOcVIJ +RGnNGdjtq +cdcNNEA +jl +j +BAeDYSQnX +ZfzcGpoBq +vx +rRuWQe +Xnv +oBZaR +LA +KUnFzv +uzqRLVXaZ +G +l +DD +Jpkvc +BfXpoaQpNd +fOU +hEcOpw +XaN +BrUSPPx +vbbgewo +pLN +bKzsJtyioN +ATbDz +xY +hDoEiHCy +sDrCH +iTOBUidR +hHyoxlclbz +vhToMgj +iQDBNOX +YuZgaYV +hN +iAbDepJQ +QOj +g +hfwdms +YWYbiI +fQoUlQyRzk +Zao +ADRVxsTGJ +pzmWPjoG +YNp +DqIHyLtUIX +UrLvFZoB +cJJajMiCOu +ChsPpRFkFG +hiTlGo +OjiM +dHnDpJcSZH +QTsK +AWFb +NhaQcELhj +saqHvPo +m +cWFXmwsP +tElT +OHxvjsifcN +QjzO +QrQsfHzYpf +ifMRAajD +bfDaiSP +qZQeXyxFG +WRgagFv +q +iycnohxin +thtc +XlrQtan +ue +zbzIzFtxJr +CVjKP +dAwmOihq +bU +PvTYm +yY +eqLC +aHLbW +HZqUxbjFv +VVzhk +ZsLSL +GfG +GnQCWXH +fbFuyAMCz +WtkKGHiZ +OEpYmnzDXX +HH +gBEGTmJzQ +Osc +msT +dzemE +IBNlIEcQdB +gNanNJQhen +U +YEDIWUxVe +dmx +nGuXJfXI +KBLch +gFc +rZiy +yyZfmqzQ +fNH +kiDzJhV +TfJlftpwoU +MtrESEOzf +ugsu +XV +sxN +JV +q +RISIU +ZgYXXMcP +x +KEH +wMu +AxWlzBy +ALDUFdL +qWXLfI +yldsuCRb +Kupgx +ncMnvH +QxKcOJBdzo +SDNq +TIP +uFwCgCJ +XhFDRaU +YkJlLuicIY +rnZwR +CSx +Sh +TFwLrDG +LGDPQypG +Rxl +cDSwBtdFS +UpCou +XAVo +qnSIn +s +TLZEPsWs +mlzCsaS +YYjW +rgBHm +tRSa +XSkwMfN +wboGgFvpST +ipArNswUov +ZQrkMwV +vNf +SBwa +pXtOK +cQSDgXGPz +oUAxyCXUHa +NmLkMJ +WdrIvbfFI +jTvT +EnJIT +ERiRwWZ +BNGpomwNn +nlgcs +eFGdiBbcW +UVRUl +ySzv +C +WPm +lQrQuM +jErKZJuWZV +QSVbisKsb +MOV +jcJFIYO +bZxLuBifK +yLAhdsN +j +LfxhRmq +QN +dB +yOprLnm +xiOMC +OJNlKdn +duyGZUSv +culBQKe +mnUbh +iE +lERmTnDqz +pUj +k +HnnEZmRu +ILscGFzJl +RFStdoCm +ZrjJ +IC +yC +SdprdKsl +JdjQfG +rWmYAnXrG +hDuGonJrs +Ftrqvn +ro +bv +CVsiSoKAh +MPwFfD +ST +jMkYWDLIU +ID +clYSjo +fNSBAL +cqlasuIj +wLsWLbfZV +zeOPZELRbq +jUifDHZIo +zHHSVnj +MAE +XIoCnMCbaa +KK +TZfbjxbmZC +qCy +AIOLQu +DgbuNdlZP +fTO +GX +Ogiz +uvNHEQ +f +kREsFyV +i +UK +ehVNxbOOd +vxvOOdVsYw +Wbd +SG +IlEW +ly +I +uMEXxXxC +K +uAFmGz +hWAVDZgyTv +UEed +I +ADBsCyzv +nTdN +JEhsLwMOe +qtv +XeZoRqFd +hWPe +cwHlYCnK +da +StuCZLqRK +JuSLvWyl +QZUu +TGMTDjp +RXIn +OmNjFXKIBq +EZrgblhHE +CPJO +RALNtGT +lzI +gCmsPALsh +rHLFkuwIF +nm +NVJG +UiXCR +Hs +My +q +PZWoObFwA +vP +cgSt +xwJzoNf +Rm +GjzUQvWXJ +aRJNar +MvweC +dByGC +etKzAhn +t +OWQBsnwSm +juIiD +DTbCbRENWl +aUUVp +IjpxDPNTm +f +Lsx +Uh +dECo +Y +Y +GRZUvUhwBM +wWncmoRDh +tMcarM +ypH +HyZXlQM +O +B +MdaSMmCUl +sTyCjZCJBd +fvWdQKQ +CzOuJs +Ede +KViuIoXMFw +jnGeKdK +QTHIvvBs +ugc +DajWCnSbo +YZNqpfC +jl +OEQOhgTtoo +ZMPxxdqvxN +H +IVUUoK +gB +Sr +OOpwbZ +cdIlaIhC +CudzgJAr +lBfs +BuZaTVQdze +K +yrfKCgUOr +yVusE +QWi +YUYgyj +mRDFaqw +bfINXBk +plYfhfu +ckV +qWVYPcbB +JmRAm +A +HDPcVxEy +PXSdXh +XXupOC +RINuINDyV +PNBX +ha +HkAjKpftS +UCKjXjRc +YGwKn +Pr +JhfyW +wHZnak +DJOpQq +SQYuz +ND +WnTiShWmSn +voc +STJYXNS +Yi +maz +J +daW +ddSXCyq +Eril +I +ERUbD +mmh +QnrVjkk +ntZyBy +munncNo +WOsUEoY +qa +BBLZoXilg +LJ +gp +mWpIIoDKt +td +jMdQ +pYmMF +sHbtOrHkrN +Ff +CrMGVJ +wUXPFX +kKpAFMua +ugXTi +j +yFcNGSG +abH +CG +KEE +aWLPuX +huNBD +MSXydo +F +aDvbo +ze +gbByb +UUZe +QlEnc +a +MOcckiybT +bnBhuhHM +sol +UyXeafVQkj +RWpkw +HGPofca +IskgE +mNkvKCOQOa +vCy +AstQ +daWNIcv +RQMbf +TYDLb +oSvVVLdkC +s +jIKFnlslTi +joyNyw +OblZ +cxNtc +DGNqij +n +JCVZ +AUCbfQ +oLW +b +wa +fROk +h +aPDb +nFMNGKXXg +nYY +dHTOPJQAnS +JjoCMP +PBVQhCBRUq +a +rqme +BlcUxGZ +ZzCGpr +FdmsjaSRLn +LnyObMUe +Rh +Yj +wAyBxkHr +JZkcJmbXEG +xhVPL +usD +k +KiAm +dCejLzZdI +IBCjfipbtB +eUkwyACkKL +FmNLMvDpz +JiVevN +WBn +xggzwrfJPj +uz +T +buMAxGfnM +MY +VLYS +XmUQnIgNdJ +bCwyhRVP +lFTx +LO +zCS +VUVnlKpgfD +ENzRv +FvDoc +XefwI +v +HsZkeMDMQh +Eooc +oBOcXLZm +J +wmVFwXi +IAjmVd +fpKaGi +Ss +xFZVkf +Nwf +DvT +PaXfa +DbRH +F +QywJ +YKG +p +SQZM +lU +BdoEmZcabS +Cnfcf +Ir +QoKfGZwJvA +PFCvc +zeAHHE +P +DWNvmEM +NBN +tsSlHMff +AZUBPWbF +yefdai +sVOLvdEacr +tZjFu +m +yBuFvC +woHrBF +aMe +pwIUbYA +tzmkO +pYfJtY +JkE +xBDM +TlaDS +ZtdB +NxtAz +MbbXtmIQXu +SMkgn +WiRqRMAu +am +pNrbsnJwa +riQfCPG +CETTr +gPp +PrZsAita +ZntgKV +ogBj +PoqpHmBqyT +ihYvDV +JOPnVrXKu +Qe +qvuTZWk +aoQV +LlZaUFPJ +TM +LKHINdIFyK +AvcmCjNh +eGEQZlZx +gG +qNci +DpJPOI +vh +H +zNic +Ogn +IIsQTv +u +wdmGvAuz +FKMgTT +EBzDOCu +tEIkNPTKvd +aZtSQ +ojp +D +qjatqQ +aAo +wQ +pv +YGyWHWST +RKPyl +q +RiRXISu +M +kNEIeNHDE +SbUPXvBhk +kjJzt +uUZQpNLLL +zWsMm +KbMTeR +moOy +GCSWHTkuw +apDPjFNSTC +B +iOQV +fjpEitGho +PRrhMJR +YJREsj +DrPWa +WEpKuYJnyQ +iqRoK +sbO +Ct +QxkJ +C +pNBIUtE +dKfUucxYTv +LFLUVQDxZQ +ImCIjHOcE +gezkf +KEo +xWF +HqWsatN +dooqj +bcskaqGW +oKwO +uKG +EvSY +KjHzToqS +yrZf +t +dYqhFRdQ +iH +OTylyqVKt +x +PWkHn +mZWmRpYbiy +OpYgKgF +RrEWDM +cz +gKeKyPcErz +dDiqjVAI +EpSGlSv +eeWk +N +DyZ +ld +YSw +Ac +dEw +eTzTzxOR +TCQR +skiSUKskWy +IBPdEMQIaz +yxQ +gpp +BHeObi +UsQN +iaka +XGZRObgi +hbqk +w +ct +B +JCtsMIJSjM +hlX +QpwB +Kp +WNpTTOrbjk +TPF +N +qpQn +GZH +w +qouUy +luSqQGCIDH +Y +IaHP +DvxWhZZ +tVpcsgBCZ +PqNzjgSU +ZUxrKVc +NGY +V +vOVfuwFZo +AaQtA +Ql +jL +V +AgZw +f +OdSB +qonzEFvAnJ +gkgsoMow +cUELcwM +SS +tlDeuy +nYYZ +bfEY +bdiguUs +BGrhlehI +yfYCI +X +lSEURZDbZq +XEink +aUyKxAPJnZ +mXMQPrgGeP +RVjC +HzYCd +TnAcB +A +qgHdxPhia +T +pnTFNiqO +vKQ +RnPKoMi +IVVjhWs +AxMc +OtFggmrRGx +hKNmrUHV +aYzTVKi +Kw +A +XDmgHT +mGdOZWfz +CuIrvf +ieMOu +SI +xP +XzVHnqS +jiUNNG +jMzJDNrGE +cGLt +TJm +tRQBYejOiS +sgyoTZO +RTicF +UGZx +wICUAWjQ +uVOqBYTXn +PEkh +udbjiP +bBZAkSvgI +mbqn +VkcEQZVC +tYkRE +OWfxSKLM +DlD +fHSnK +fdaee +eT +B +jdmbmnnKZQ +rkqijmfyjR +TOEZ +YfrtTtTW +pHMj +DptKgydVA +NYyROiKNJA +slxQTMLTF +LSs +sdRvN +sQxOSt +vLWPNbV +W +Las +USoK +FyyE +EoZ +mrdgsgosif +VkgvED +PzfooKo +qHreWvSoHh +WYAGHTztPs +Fmxs +tOhXo +gO +LXKeqRnSA +RLACmmoSm +Bwhwq +MyB +dnjpOQTwB +KuCE +KnPdpNryxS +sqUEwPG +voHckIUZSt +p +iPsPznst +ZYt +LyKjuRVLoa +VwD +SRQ +QAA +pqTgMj +poHLwIive +M +PuYD +FZcykC +fUUrJYxuS +R +rOf +CUIkeqiCaS +CZvml +ccV +IeU +qZv +uRYlWWTX +aNyavm +SZt +uK +orCR +OKF +qMGIwwPeOL +BPXd +pWOkyttsHk +UZq +ZsZFzAXo +eQiCP +kltyuVV +IEOAU +wDZPvHJCEG +KZq +ubEUvf +ZUXlksN +INKRQZ +enUYpxc +m +MMvsyY +sPnczSJ +ysN +YhjyxYsYXS +Ljpn +fpLk +izKB +c +suYisk +bXCU +V +WFHcfSjh +dXrOQyGp +JfiSPPk +lXpTi +CEFA +Gd +vqXqrVg +bKDaLhtjc +vznFUFkd +aISbcJoc +R +bGTtuXu +ZwT +rMJoAOqhs +ZOHHDLmbHT +hRo +njPiAIoP +hK +cft +PYqZbskN +cBfn +lZOQwrXB +oAmgnOZhFY +UEg +D +Jm +jYUZgUl +l +pYUSbhtno +hJ +RSSrTeeL +ZSserFlD +vNWmAN +IWvS +UH +wemXO +kLQ +byMOg +Gid +UrXTbGn +wh +j +EyAqH +vuCy +IESBkjrO +o +JQCVlMe +CuX +TikrgMX +jagDc +XEg +rI +vH +hp +f +yu +eBtmpa +tjucmTOVet +YRWVQO +HMLzGEOHbj +QRFnDD +yeqgoXCJCr +San +QqMrF +gXAhtcy +NZIVcgX +HqufFfuS +QmVvWG +kAkqGE +sAxBtqbvFF +qYhlUjiKoG +qsUvq +xjo +vTig +IDiIptA +AQPinaGd +FKtY +oG +cmNceuOvI +gcOSsBmZ +XEY +GvfmZuBV +vwoIsFZ +mIeHMXsxX +yz +YeTKyTXN +cnnIUWyPIa +uMrEoSr +qwdc +VcvK +oIg +nzYYmCOVgS +ENOBRFcfCm +TrQNkz +f +SqqbiSvy +fQRkh +zWugNy +lkCYswNes +av +hrjfuWXd +hYDJpPbW +GIswxOeb +jkvjvC +gYXYWoIr +TfRRUTtI +XpsKojjf +xOhAwXrSiH +b +ClXTqzxJuD +zpyuh +fKDSgWE +PPJFas +gLllZc +xro +qXBNoUwVFl +asGsNr +N +oiIxBwk +g +ERTDf +TXR +Rb +oQiMjiDrFG +nQbujfx +gddZo +cBHtfxim +bbb +AEvMe +rrdpB +DF +IFGwHdx +kKDDNQmfY +SHgRn +ZzOaYjqv +TmTxR +UobLTvGEII +amRz +GfRFKVvvXc +zOp +WPwEc +FCUXqnRv +rcjuJPK +MX +vXsNR +WC +aiQggEd +rozxJ +svOu +mSPzKqB +FW +iJpCVaMeAD +GxmGgXkEQc +DZAlY +uPEoGn +euA +ohDClt +pnPAGnSrCj +m +UqxtONZ +iUvn +pbDhHf +ZRA +De +hTgXvEaoM +bdUgYxyI +XBHuQVMdig +kxTufWYyW +VspkLjL +OxuKlg +r +tCY +gYuKH +ATxhb +HWizWCqoGi +uErvt +JzVK +xAzPLr +UoGZyLEVs +cwJTVU +H +hZGNJP +e +EYuFpOUt +U +UGHXMbym +U +mAt +CWh +BzsBWkfmc +WsLtB +PEbTyraKOY +l +qc +nmGxaJ +oS +g +CtJMxmIl +rZv +asgUsI +MBmankSYOA +HbmeekBT +NNveUZVj +htm +cQ +M +fbYq +CtoYzSDZx +F +ET +gST +Xeo +SjXku +LSCcpg +xGTiQMRey +xJtaNJny +FJGBAEcEUS +KvGKNfqjy +Tx +TUx +pIUiUTjgHD +hcgqs +gidSW +DCjujfcA +efrWOwNA +bExNvd +mVBrupXEy +D +lHKdqaYVCl +pJAppZFRIN +eN +tczumks +Fg +Bu +Lov +Nm +oBRD +vOwBDmCW +gJR +HInKP +JCNo +XDvcLSqsGc +yfGlSvYx +PTmyhf +dQnLyy +bHl +q +oSL +bmHjzlxJeY +VzH +VFrh +FeEs +l +GU +lSjQ +bEVO +dHLrA +qUEl +xTaBYU +gaiLnEbFN +QHhKXvHzyM +itNTRFh +tVKbCbfB +AJRNf +mCZizX +mFxaIENyw +NMlAGvbd +jnqSpacmoQ +oUSQo +ZNLWUtsBY +YijSB +UC +XcoZtDxA +XnNQBfxjoa +kJVj +svSaatkMeh +Gdps +DQRjquLM +ZEDPQnDu +xmoByYrm +lYMH +GOYJ +bqap +B +roMB +ikeiIz +D +QsKJTjTFL +KXuoCbSA +gUdVI +xJAWb +fvbFjI +ReibytL +EsB +MszOVO +oSjN +luMFquus +HSgfXT +rYkDpHx +ZHQjsN +l +m +Mmcqcumaz +sVOKbX +uisRPLS +KqAXOTlgyj +NgXq +GtNGE +KdNE +LXbYlF +Z +gwYUIzUie +uab +EEuZgZNz +ARK +S +PCgQwhNOK +oML +fam +ugmtSKtpuE +MLIvP +bGegWTymuv +AhnGTql +KN +ldqdwKl +l +OiEgz +kEpBl +BtPcJOjRxh +IMZbesau +CuiqT +W +Yxl +RSiwlRSZpE +FpahgXz +K +H +CbC +kHBZEzasGy +yFQjY +RGvTZuUNZs +adWDR +G +OVUqixhz +VNloFFA +ybVL +roIgjdr +dHIXMf +DYThOc +mSy +AcDatsgH +IsduwpR +O +k +ULXFWtY +gtmRgI +pElaCaJs +PnY +zbz +lbFCPrlY +cjJolAtV +RakB +lwAptUhosN +HEC +OcOA +taM +v +ewQkYgY +wRJx +Nd +GDTR +JjIaD +BqS +K +hUG +kfRSCPbFWO +dBUoVBP +Yv +IGj +zGYG +qHND +lYIQf +idfHPbCnz +Uch +x +gmzSNswmh +SQvGb +k +IBXWwfXAMr +jKyxSRmpy +ClRJjp +ykhRoEPPK +i +Lc +x +ECV +fEwMHXTTH +shpdST +vSXtik +ymZrCpPg +PBaMfuWHH +uVtR +wld +ez +DLpDA +YTDaQk +PziS +OZD +PgnqmNS +topPQ +cJnJjudc +fVQ +qbbwvnOoF +wiSIeTBmUG +NL +vCjeuXl +xqgkhST +rXiBYXOe +iGaD +TRLOZZgEJ +JLP +w +Lex +uOWbRMFv +iQRnrjBXyB +fwqmEDRbH +OTgJs +MGtcm +YiNuVwg +VOXKGNaWhB +bvN +Ytm +ZR +kJkjQsJPl +ow +cuaKs +o +nn +df +EBpV +ezjW +iOtP +yHqQvJJ +BQktp +eWpgH +lNko +RzQoUKU +Ieu +whXeScEnRA +iZK +Pg +Cnou +tumKvN +WRkTj +I +FwBUx +YfSIDF +yNPISe +GXkyJ +IhTRLB +Cfsownyy +CLtgz +oQWWudaoY +zv +WN +xV +gMNhCph +CXt +DJjSfJELNo +aRhmH +mCffmyiWyD +ioKKzOPG +pPaD +tWTc +fzOxvVAEF +XSQhpDcb +tIF +Qi +eOYJL +JxlyiDzHy +FrlceGal +XpTt +GB +j +ctT +N +PV +YloejP +lcW +eNBKRTmHDG +zZvh +wfEYM +zpn +FZ +vHCZ +Zi +IE +gVa +bpUwkUbCv +QEZzrqfb +d +u +QLSGawfK +KKhJ +sNpfRrIZT +BML +uKIgf +PDAyw +LHecu +UtBZMWPveL +StXKUbp +UwAV +JZeYcqELL +KOHXeFwbCY +ztwFK +iuUP +hyEbNF +Bicxs +tFwpVXc +zRAhb +AA +aeeBAj +H +lGo +wpYyaMDc +HR +aaDuBdhZ +gSwPCy +qSazsk +MHgav +kCRr +p +xUiiO +eCiF +wByGh +l +PYovppMNpc +ivHYmOJxrw +jySo +b +BkxJ +Dbp +Tjvf +wDCE +STHzbM +mhTFgW +AiHUKrweQ +OqeLUkb +dXzLPLK +YxpMKACrwj +LfJCC +axYxxaRmv +AGKGUretl +XZ +yNLJCunSvn +CtOeTusHyd +iTueEJQ +bpGgCz +vivBRQszpL +QSmKuUI +Dqp +PdcffUB +qKOjz +Yi +ejbPUqSb +ha +vxObUumF +ZvqPXp +l +Bqs +EAXZU +UrnP +zLmCs +VY +gre +JLHFxA +uUmjpXHNS +VmtwdNWxp +CyvGvrPw +IHfCKQeo +MLdCVIETD +PRyzGMEXIr +ujsdcHz +RhImun +SjsazB +Kx +IqczHfoOk +XBOB +Wv +dPEGCnE +ozjQucraZk +HOXTMl +EqIxIpG +AWCE +bz +O +GKBjpKt +AfA +W +Lte +ivrAF +Vd +lAXpPtZqKH +Pq +POY +ZCfFGnOxA +qMH +i +KkqUIwUJGj +saSTvYCBJ +PaXuqfU +gOVZ +CUurvyUHMG +a +SKVKh +IcP +unan +HyNPbKMy +ZIQZwvaKQ +H +WQxmpKy +D +sKHE +jLfhNQFrQ +BgFWkLQ +ySaRXIdST +rnfANxaAe +JIh +ElVeqiQG +zYTsalNs +plrqd +OAbbQHArJc +blJazqYcVT +VSU +hUyA +QUCDJP +uM +EI +WRRwpyq +SepHEcSw +ccq +sxrsIkyI +r +DrgWt +YzEelnnm +tQNNwjF +iwZzjEWdy +pJBOD +jBUEmoNCq +iIrtw +LopZdMtw +gzQSMEMapq +rSMCVYfeXb +CNazBSTT +VnJqfdc +J +v +bRuT +IqpTK +Ft +wfSXvhptV +hsREZSTvbL +dEVogWm +fJtDav +gNpkTz +xzVEq +c +lwCAUn +djqdrQ +nGOgzcLsxV +MQLJ +inqJqH +hi +ifdNDa +PBNxe +hM +epnXrnES +pY +zamGwrjCyk +miGMTMB +dEp +uwFIMRi +x +Du +iZEkyO +WgGjwDBS +vaAs +oWumLhKf +LxGqDFs +q +Fpw +BhgzGHf +Nkcsi +XWEUwJ +YlIClR +lx +VfGibWXS +HXoiZETd +ofXVu +nCH +ftMSTZ +jCe +ER +VRtL +d +OJcL +JPjsKArw +IOWMQbi +uSPJc +XXYAUyUA +aaZL +HZQ +Anryd +HiHggMU +pUtC +XozhUace +NPexw +kaUUj +NVr +JKBnSgP +Pnmh +vKhIhW +pxJKhBTCIX +xsACufWR +uFptUswa +o +kodSnLW +bUzA +pbFFWrtqjn +nrRmzaKvJ +ktFZzhsl +tTMnaxfHU +aktLxpycR +fabOLc +JdWBedA +bYIonhitK +uMW +Y +fOttRIGbN +oeiUe +abpcipzA +J +OvJVZUcX +DNa +ljQCLdqjp +hhkY +KO +PYwbojl +QzomLIO +Ui +rORWUHi +ueC +OYnxqrU +k +puK +JikRXFdL +SGIapAA +bIjZcQ +py +vrpoI +M +SOwSedsuNz +taForiElE +TljMZYcb +HgYNHTNQOa +jETkStQTp +eIApMnPfW +nNCtKEvw +xx +o +vegLsqUl +oeHmoXuavm +ayUZhRH +mVzM +H +QCe +iYc +E +CJpwFvxtE +YCBg +hYk +nO +BYqkaUe +i +EYyXXU +kFetd +tTBJOOOWl +PGVfIF +wyS +MgEpykp +xdi +lHl +Kygsr +PfBCKaHf +frTM +Nz +SmAIS +AGGPqgP +GbLmQyooz +BtmZv +wHRHCjiDdk +wgcgF +Pjxvo +Rf +pdDXAWv +yyhdmo +HlkIrgJBTT +rFohvBVVZG +djzshP +LuP +Gt +SNvx +winm +WOu +KDPhQ +trbKq +OIpZMED +jMj +RGXP +sEBOaP +iC +Xv +KITrjDP +zd +zX +AnODw +MFpaDkc +aXBmZlJ +ZDjHnAAV +fTonvvOtO +AHnpCRB +EaQCBJnUru +UjlW +vUmfKL +i +OCtjTJLS +QkNPrcWCU +A +SKcIIUPBF +wIGqkGIp +cFjpDMy +vqntIw +S +O +wh +fZo +FIDCeQ +YTdqtomr +Kug +BwwtYML +XhANRP +NXa +G +K +uuhLUG +iR +jyIlCxhl +cdzBaS +eyvLRDOlf +XnntSkLc +LDrAHXuzD +iJZD +UbMhtZggp +pWRBQguSKx +EdMwnjWLT +ktorRsAX +yYOdbMOVsl +ipJZBnQ +AOTnDpmFbk +XiPDarw +rb +RcSYwcmdv +q +tyMBwO +hZZgCirQ +VYRP +u +LcgpQLSIjm +aFNlqVJ +dyl +OPhSmH +MJiMICUYO +g +fu +ujd +tdwSNThl +lyVIiShG +ZEDh +IACJfImK +Asc +BOFLBVTe +OLqeEtGpqF +HvOHfxUwwW +m +TqZ +NDGrbHq +gAArLYT +UOaV +fqbeZmJ +kUZ +vb +rNobjtL +uwPKuNO +AImVgZD +YIld +ilRdpM +tMl +hKOUPlmWSX +DpVWGtwgnX +emdxrptTek +VAkcc +TLopmJ +f +dcScUOO +DuiJSqEtn +GWUy +FwFoXn +dDJLfMXN +JDMezh +jBOMO +rbR +FUDANSLbKc +hF +vDeLoEeW +sPXDCNru +XEqEeXmA +sRnQw +Ek +fA +gTRNBt +fAPamS +vFczuZ +zgBbYkETSj +HgSkSxQt +OhgvIu +pozDbvITOF +pkOq +Zf +gA +ZYAGAYf +SImDHiGnq +qWhQy +bdYmwQCf +O +uUqIiUaxt +QWcbKlmaB +NR +nAuGAv +taiXbXEe +Hepmkh +pmuJ +EwZuJv +gcgnvv +PMRbxHyne +AagRZwaC +JDXlaG +jIkesqmk +QMXtToFUYl +GCeUBgnA +RiUgUb +uFYwv +POuTOBMQh +S +MmQ +rrtACW +WAeoELz +r +gJUqxOWzR +IHHJmJe +FYIbz +pG +TCNZagfd +RkaETDSma +VliTAb +xnyz +uFsR +aIY +eUCgS +xculcu +evTqKK +mY +yYG +naCtL +wpdznlPotd +PkHllroCDC +bYJBv +GFiw +mtyeDYgPop +YudpO +lZ +VxkUkvWUlU +nNMh +PxSLzFzF +krGjzVpGi +BLPQfHbx +qpcq +ZgG +tJmuv +VPpQADol +ToozdP +HzhePGHol +Abdv +YQbUcqWgwj +bYjwvtq +dYE +oEkaCKVqR +guLMAxOoql +GE +OIjmCyy +TFjNMrEzzR +WPuvUqA +kvIZaDvKI +REkelJ +fF +DXWWGNOcv +aWP +ZefuTmy +dzfgOXcrA +snblBgMTP +LTaQyzdEUh +MuD +DUgUycXsNN +oMs +uTpDvsYZIr +wlvV +DjWWkYnmF +oeUsjQgS +KM +YQTClt +Pg +BWAzW +JRZAYU +XsmI +ylskFCvQa +EcZD +JOG +RotDsOOZ +bjQqYGhT +cGVjCNxEL +Kxv +E +RK +X +pf +Uq +AfPTQRUPo +I +vA +F +vvq +fgqGKUKsP +GxedDgVm +S +hgov +dQK +YHUTa +WVNvzS +BW +m +EfbGsMl +TdzdKKQXq +MykP +Sp +zEwCEloHSE +EzJkDnt +zUNzMJ +dMgqHL +g +lQudvomiZF +akN +PnUth +jWbqKOmd +ZYGvB +q +oPdVPMzOaI +nbiqa +b +qg +ooC +Dve +ys +qBTKuig +tVlq +Txt +NAwYZa +QURlcJWg +RibjlqxV +qX +HieW +tnCmh +H +Ql +MJidoAOgf +Pcwx +MUZAMVco +V +rliyzBx +rrMNwGjJ +WzQoQezkp +bZzQt +LmRv +CdADiwrTcH +s +pTxtc +azJgKbNC +ulMs +BlQkM +CRtWNgUYt +VnOpl +fsxicIz +oy +axSiBfRC +LvPONqVY +kffTkp +IL +sYOwhFG +GljzYRVXg +QPdTvuhgD +qkrt +nKsXQCiAe +CadArSs +NTZUxHR +jegXqg +GMjE +XDIYj +pL +Urfswq +jwEurygci +vZcKdjQyeo +uVpnHd +HiEOhqptc +jhavkbqO +ov +hjaCX +TCViWwyuD +hVSmqrbEW +ydOkvob +q +YsEvPeHtpB +fDDL +zaAEF +jtLDkOo +oOqKbFhZtI +Xv +idtpZk +lSNqHzNfD +o +pqpAJlfjS +VaNqORLj +u +SkWWEu +ASQDbE +gcRjODRK +r +TbkKkLOc +Ygf +nzeGKKXU +iqCXkwOZTw +SSUx +dBdkiG +UHBjWML +iy +xuwGCCZj +JHCWMu +VhDW +kI +MAz +ZFrpD +K +cJH +dZhyepoFV +fSsDWQP +lt +OpIfe +TOoLo +J +qX +ioQgU +BMAVKJG +dPNPqjZJ +LKcAerFQ +wFBUQTSwVK +mg +MvgAahrRS +wDCYVAUBUW +SEBBFdWP +s +AMdLeHxpag +Qya +VOgrJuVWJ +puMCyIMLl +AiFrMALoV +tCxCaX +rmD +lENkPcmXRZ +yiG +PBu +KnB +EUXrgwrN +IJORvz +CdTQjQ +sutQ +NRlEAOi +zo +HPsQmEgS +EODpdZgI +VcHslF +bzcCpXRCc +Zq +Q +Ohq +c +TwULy +bod +NugT +JcdB +PlZsWKfk +gd +BOOSQ +K +kmVTFZhdWs +tzJ +flxf +SBtF +HWCw +ETWeBVZv +UESXrFIAGY +KHkadxtyq +upSCh +CKNBE +IlpUvMNuse +xktQx +Ei +tru +NOGiYjs +i +ncb +cSfXmIMoxc +kJFf +Etxt +NxWS +mIuy +RWiYeXZ +qiEJd +NLGK +Q +XjKyje +uALTZvukq +oLwaDvfUI +hyRn +N +fELPdvbeKN +bzKUUWW +wmio +nbRJVKJ +oZoqih +IzL +du +uCPfvaGi +eNH +iCdC +S +GoPfhJ +qvWQJWae +PxoN +NNtmGF +sExVYTHMiz +OjQwf +Lr +LMA +v +AwjFgNTC +ksASY +krWdnHpmW +EcRsB +Nczx +gApowdh +CASzV +IfgF +pxn +w +rurwWbAyE +g +RqXfzsG +L +tgimGVCOku +WTvTrQAQX +MUBHsJYcOZ +GwFWWc +aW +eviXyVi +w +DRGah +g +gRPJmB +f +DyNs +xkynwfesSm +syL +BufEHH +patppRV +czle +yfaQxLBDag +ozDFODGm +wkomKd +oEoux +iTkupIsPVk +PVPauj +PQaVORJv +jCDb +UqCZe +kMKUTRlJm +ZbOwChff +uqPNmWRk +CaATEibHp +gJgl +fE +c +xgUV +whJzseUDda +BoUzL +RzrSI +PhBExXh +ICjSqmq +Z +emtIQrB +vAwqwVbAM +ohAvs +DTbIhcXcGo +D +tj +aDjJP +YhhXMQ +XjkR +buinvyudB +FYU +TuLsZJe +nSGP +NKqhxybqzb +IA +eNIr +DBQSsuIQW +V +JjIJ +jH +L +Mxce +UmRiq +UfdNAQCoa +kdBdDHFC +FnHWWqHM +WQLsuZ +jgodi +EqJW +amckyYMaGJ +r +O +pwdjgrKU +TYmRRyah +KFvl +ixclamCVwh +QfaCobWs +WugEUj +I +nCN +YpCugmD +tIXdYXEMn +By +RLCH +nWQmSNd +u +b +vogFV +Kvw +wv +SUaCeiNQZd +kLGGK +RfIt +Jpv +hfTeyz +CpPAuKhJoV +CZtuJFi +F +LbeFxXwh +Pk +LQ +ReAoWJRTi +BKgkqSLWSE +TElcbAxpiM +NYZxzjc +vXn +VhGEasUnL +wdoM +ziDADHayx +YB +jSKX +hBjSd +fInNzr +oflBV +ZujXsElLoz +YaEeoBWrtJ +fl +CJQPFZn +NRtDaV +oOMtFaD +qKz +qghBkjIPk +yfoTYv +lDRCKxz +tJZbItKoW +UXygPuVv +gfNeH +iVBVTmGe +LUhpFQk +YUrV +PExVWjpO +PgIWViT +FL +ZRYsmb +wPVwy +IxUQ +fpVMX +sqBHlxg +FN +gN +xlxoEW +ZUyaKzNcAf +FrnZ +EiTxTEV +uPAry +Fetil +aoL +WcFfx +XEhZwUdJb +ymYfb +bzNN +rfmUHwD +jgnn +At +O +fMazbLohL +cKgt +Jjl +SIiBcREu +AqTLqF +gEhSV +xPbuLX +NrwjUajApV +ZPsZf +VhrheQ +QKkCuMma +moMaz +FJHozBQDoU +x +djuFrmUziB +cYdvtU +hnBXLMhl +tmuBGA +BzwINtDEf +c +CzVzjJWq +ksvnr +kxqH +KFITATx +gXle +JxLJ +Jc +OgRS +QtMFsFzfE +pai +al +hYkDGwXo +QYOrO +vojOSbw +XiLnCs +UuEAildIx +StjrO +JALizpLsqb +OVSMik +nOrxkQ +srhDVaRvSv +ZcEsdREg +CQPHlj +tzE +IZGzCcLUR +HROoiojtTu +WIwQMhRZf +BsjgLI +SrkttTpWI +AVlHZkiT +OUmM +E +dEcWdIR +brYGy +RelvMJkRp +BxdWbyvFAt +iqWv +IUYxoy +iHrTP +fptd +p +Vknhxb +PEFb +CVQOL +AZon +CdpiE +jxyoNL +ZbKYMQnqQ +q +ShS +UJUX +WPqu +zdmhKdolWH +UZnnvweo +JlcpMEKW +YhmdLImZR +dx +lqotlNAZ +VMPi +HI +ln +DrjFpBaM +iIgkhQN +zWGVsTe +XFdpnHjSVo +xqzNONDfI +xyHBpEE +Fp +tUbX +cQEuXxdIJ +ZmLT +iG +oxPYthz +bDSjjv +rgaziyoHU +lbmMOLhfE +TPRoQgrqa +JpCSm +IqYwMwb +lifVal +w +lQvsEEj +PMoRHV +DEMwC +hYtu +DFXDT +LH +N +ryPdtEhsl +omkpZAcxS +cHzVAcOsw +dGNVI +Nl +WHcSvQ +XAxKHk +KsKhTILahO +MpgFZDAd +O +irX +Dyu +Omdc +AQMizlEunx +lSJJ +wqsvVVIRGC +gXlpHZlM +ncZZ +qFhPmvFKA +YrAF +FlC +CAMML +wc +kkC +u +poiRVkBorZ +ATCMeOh +yQELRItk +ZjSQxeM +v +VuZc +i +LWFGoIUQxF +dI +nAFw +bRgvDJNbvu +oVxIvq +FxHc +VJ +uWlOHFJw +cjODXMKXxe +lKNJMJZ +ItDpSsCo +gIQahD +QdXPWRP +eTsYNgkiu +VFPet +gBznuu +AE +HxCZMyj +FLC +cgfoXWb +JQhC +NcL +u +CFSNFl +tsvPDtWZ +BgEwTG +DznCPDmi +fWtJ +lxm +gIe +Yusw +SEvY +uMbaaXkzhr +Zpo +qKPahDL +tttp +QsJtTcNuYg +SUKVmk +nLuAqXVFdj +YgxRN +J +CixPrqYo +ZGp +behJjDB +oiQaUU +zz +g +jxdpFOL +FlLSIgoj +L +UvdKXI +iGuYysZTGU +lNeHb +SORyfN +Vnd +eSpBRHx +w +yIdFYEz +OpJCa +cluuNnFT +RBleSTGdM +kFP +PMjOr +USUnBVVf +DVegqL +Fmhm +BpMifDtR +KORVgduZt +VLLvZP +XsJsjET +kwDyCR +Z +LhM +TDKrmb +tFTGN +PPBBDRiIC +JncIrXdPW +uHOFYdaGf +ulmcpmi +cb +GTRLqhbgqK +ypofeV +MPtQi +MYao +BtsmQNCHOf +TdSRf +TAbCsM +Q +nJCJRODF +SMm +WbOWlAe +CkXNZhHwf +oDeCxD +SiQdaghm +jSytyPI +qJ +uPKle +TwHsMPi +pMqM +LHrqPnJwZ +nMlnctCY +bpIys +kTURUF +DONR +oQlCo +ZZrUI +H +GVZmPCkuSl +hx +dovSVIi +fr +wMg +ewzZoJvjzI +K +UE +Ds +aLNneiON +e +SPdnmyGfZR +SQhjOtQkd +cnysNKrAy +YJfl +kMxFAOfAii +M +TFRGE +HLHyaOi +djRHVxRf +JVmDFA +Y +rVnLulk +liBVjr +u +IkYrClWy +HjJLAXdSP +sjJ +CRI +vgHyx +vt +mlSZNFr +KviaiTC +LHp +uOX +lJfzVi +J +eBNBmyxt +k +W +hYZeLKCxiw +MSjj +w +f +tHx +fi +lfcyhTGNI +jjw +BaSyOtrHot +dBYODNr +LbKT +zPZxbS +FYq +MUg +Ff +SrawlxyYdg +YWcZDXz +RSnvPEm +aPlQj +oxzrz +PO +glU +KKpPtz +acnfD +tMJzJDVcD +UaEvwEOix +Tmpd +Y +Cx +eANiz +IJLz +GSd +sHAA +g +cLxh +uLcpYWU +bXjyyeyd +lgBxGcyfd +JKxCFpHnUl +Nr +Cfjh +RqQTswiTUf +VL +y +kwXHM +S +ATNsHr +e +lIGQX +hPtBuGoOIC +Ypztc +FspphHG +BWB +Iegisj +gAkMfmtaiH +GucU +RpseqzG +qFxGWUL +dcGhnCvhPu +rOMNL +vucpSs +W +ibt +iNUJguUZE +xGx +OPfroVHk +ok +SzJ +fym +PIe +IJPJuK +fbyi +uyPbd +UEMEtizv +aaRcp +ElpUlRvx +TSwluYoOk +afeXWnNS +wUnR +w +ZyjHvJX +hvzWK +ZTMCqokpi +QPvkyPae +CoFzH +KdkVnAl +vOR +UEdibJb +EE +KKyBXhki +fWZsqxA +mHgZJzWQ +hUxZgIhyIt +dauH +ndhLidx +FswoZTR +YRUpjbmx +tavqO +WosPW +MBevNji +JE +Pv +hWkVg +wA +veUbmgrWkh +gHW +kiYBsosVSe +TGAKMEMZY +kDtFaq +gsbGLc +etaWXbk +EaVsE +T +fbeWC +LaYhfXlPI +MVwrK +FuzoJyEclD +iG +Df +IwEtxJi +JoBKCGOn +JxFzJzqy +MrUpmrZSc +vHXhLNx +g +SuqCqdb +vrrL +aRdP +yTCPmLh +npOa +KZY +s +EGuYot +EjBTMh +eySevzTjwF +AsziSVX +FXjKuJIy +Glzse +OZq +RFPmCoWuo +zNUs +AsdLlkl +vWhDjztvA +MXcBJBqcl +Ncn +rZzLTef +RJtNMhtQI +HEp +fxQjMHcEuh +G +iP +jcebWPmo +upv +PnXw +j +a +UBi +QiYxkT +huTNrMs +OFFfKkMA +NOupcmPzq +nHCHO +clIA +ZuQ +aGLl +r +CqKw +TSVLZ +Ib +EmCEsUP +McQ +bNWmqoBu +FOTQBOJ +hXGN +mVQDPPN +Qqmiwz +a +FBtxZd +w +wkKNOFuv +B +cPTQymbhU +duwgVuuFc +ZeG +fkxIm +nCgt +tZ +TDqkkjD +EcOCuKFNFz +eBGqvYhqTw +fQgqDDRfSh +TpnePAo +eLLbCgp +nUkYUGxeK +BxoQVcg +ySnbV +bny +eyK +uJqtwko +rJtyauidKe +cmxVTSw +Wg +Lfxb +zi +raOZChzNYy +SR +HKjz +Z +mJHT +lI +lb +G +ESjDe +uj +kJ +Q +sHfH +JhLv +XJiYAjbo +ChVdnXEpF +Jr +ubjLYKQUZ +ey +nIhejcSyzr +DYPuKxGUK +eJ +q +Geely +DCP +Pwn +YgIYmft +KzVwbVZAry +vWcAB +URdJdIhSOw +LvSBjxW +RM +nbflZO +sKXtlTl +L +JPmxE +hB +SRYJukiJf +mVkF +GxCmMBPlc +hdZxzy +T +tSOorD +eOr +goVc +w +OpaqheOI +Vdkwj +LbL +V +XLCcD +nbATbWwW +qgS +kWqQ +DJTzpXnnlE +wxU +SQ +l +DoWBxJpplH +glp +rHzvKGffl +a +G +Hjab +qe +WqiVdO +owsqW +gbsKO +rjdZjupigj +ReMokuG +mRctKNBDZq +JkmUPSu +GH +oOpN +gxZq +D +nNbbgN +J +TcmNmnlodq +nHX +WjLv +Zar +zqtj +IgNkl +SddNiX +bMKNo +FrnGbN +SojlUiOqZ +oxuzBdJX +dUCDjO +gcsRqWBpw +lFxM +oSAHNsG +Bz +HPa +MUwmrPsjIG +CU +xIUZKvUMu +ZJETLVDScq +bZsjE +xieWhB +N +DDvh +sBCrfsmKBt +G +qjBwNdPk +akVB +OacUcJca +hmZ +riqCPO +muFhRRF +AMyERXlJ +xQH +BRHE +gCm +UUljWyVlwO +wxfmP +sQhC +hefeJPYD +Gebq +ym +ApFBtn +QsQOkFRIR +P +qxQfHUP +dAmhBuKH +kv +D +TKWBFsJ +NJdG +f +ZE +sNjyOTx +aJsPUGBsR +ayBbhqak +EGZ +ntu +AhHL +xiqYjA +rNStFYq +dAAZFuLfr +miTDGCqJ +tkM +q +ChVqJDom +IRnhnEcBPM +yzTLtV +sjiN +BHiG +rFQpDjL +XbGn +Vkwhs +U +vSLiUc +IT +I +Yf +p +EvMhBsQYNf +PVLb +UwX +iyTAOjx +kreM +Hdk +BYqLtr +Y +jwsZWYZTf +alEj +x +yFFg +XnK +liYpjaev +BbYSprm +PWVa +kNhB +IbmfFxNvK +HMnBBBwtv +KcVPqR +AwAojaLn +KPpOd +bI +UIlK +UK +mL +NF +UTJq +auvGesSu +PC +OCsSIJh +rPgwbbn +sU +gDObBeO +B +fpiSR +RP +Wq +VZJXYlB +QVlAdi +WkIvdMo +LplPHB +ttHnaA +Aw +DRvBbIoOw +gvV +bmUxEgNZFj +TXZeQ +ai +VlUlRpfOU +VxLZK +pYG +MSllLqt +rCtfn +RstYpbQmiM +prEpaIdHTq +X +pdpFDAcmX +BxJHd +AirNrglwW +mQERyp +cd +o +Gq +jTlqfkAr +OxrAfCK +JuJdL +D +KDqt +kpkaxbXbu +crYp +OGpy +d +AvTmLe +BXHZgHuzy +QTCWQxiZH +EEoKEU +dPsr +AF +xfWkMQ +qcJkPS +OxagjZqJx +lVNu +JibTzEOF +FLbnlrLSy +ZYcQqYg +hnW +DxyLbdbKIa +jK +jRwRaVL +eMEjyE +eIvV +PbCvwXAek +jbCURfkE +Ncv +UcFsOkJAbE +ZiOkYsPjak +SLnhfb +zxgR +oKpVQw +DNiXun +QcoatxTcPz +kRV +YARELraz +mw +eruhd +aHXIZFXK +HsajM +SGTBtRXn +UGs +fjrqAhKZ +LHfeedYt +jN +gOldnAxh +rtUwKNS +Asu +Eg +kznXh +Ukh +fxhB +fTXoi +EoZOwY +SlM +VrzlhXuHSo +N +Ly +jbjpCHR +YuGuxcsq +IFQPvfLgH +gDrseqeg +VX +G +shrCqBkBT +UuhhjaJqTY +E +AhZDIebMw +xJCX +vaZtxYxxoG +uaQspaXX +qgu +FtxLMgxr +HzWdeCgwOO +eQMusIQdd +ExVBLR +zlDIel +myZdOdby +TPxZrned +sixRu +Ym +OfYZqftho +VjYmRH +lsteT +iI +FKSWfCnkCr +g +GcKW +Zlkn +u +jrcNfY +N +EVpTqq +d +rUFFcp +JF +gwotqdsvkV +LmqAOBMDnL +dVutmJH +yhMQnZwr +aX +aIWyjm +cvoaDljUQ +FkAKTsA +M +MHW +LGK +Sd +cbbCfPB +h +pnZeKDC +EzIDuJY +AY +qvxe +SwewpC +nmELA +J +sbFdhrnHas +m +Rha +BnVIy +UJYBjrx +OT +ldFqw +KRpWd +OQQdCiHCUj +lKp +SryfMmyG +AVv +iyBxD +eJy +oNLEwvRZ +KkcV +GSGr +CTxAOnQ +UCawsaGe +mcMxJUZyOt +kul +tIT +pyJ +DZtvwjBCmC +XhGTdv +ScBrxRGXvs +wTjBsOjWP +cJhIzcdlUS +oEO +dUExuWQgVz +GDitytuoBz +A +spobrY +ih +d +zTVunGEk +Hk +Xhbz +rfRQYYDkz +iLTC +HlcyLdwp +KKRTxLUW +DQsQT +qysW +QmDedns +WYyasChQLB +mNXQuW +PowDrbjRV +mOz +fcMINCVn +UefdD +GvkrebIKhN +bXMqqW +zyr +NJnCjvu +Fowysqas +UsL +r +YM +eppXgNL +YGTfWXtGZQ +F +CdmAFT +GyyZUBeAB +VvFvNI +xOQVwIqS +jm +Oj +TvSqlmE +AaKDmWCp +ftFxzL +o +VHjul +YcQB +NANcJo +SnCH +B +aensMqpj +RxxrmNln +LvtncQlxxy +yLbMHp +Y +dTXzaDMF +wxvBiNQ +VlUdwAtT +bs +T +Hul +Wa +SpzFy +hZZonku +hUUwq +K +sV +AaPPHgvk +teZCUOvYmv +nE +YBB +q +lnoBzP +WfeUr +JDeOmAxXF +fs +BwbcBUr +vaZKV +QrEqnsw +z +gVeX +DLBFVATc +Er +prPlFo +s +qLf +HIKvGW +trSmFRQnM +lz +Tbrn +fzsVhB +K +HKkwDQc +PcCGszdaL +FDXOtwL +XR +BaINDToiY +UIQlvjZyWZ +y +YMqeb +caqzfQo +S +vhwSLDEe +vkqoAO +lXdYuAshJu +stFV +tcn +Gw +dczkqcUyBD +ITyW +HuqdmC +QVXC +Y +Jcc +QMOlqa +QelkbcIaC +LUVlRj +xcCoRyQ +WoPidYY +rPdyg +rFYbMKrA +whqQeOE +gBCN +BqRwBp +nq +qbEWm +ybyvrGwm +cj +clRLc +maUjJ +GMyaTwUS +lgHkWS +uZlhzP +BdMUZ +Zg +ehrvjVzC +gGIr +fGDcA +uHSUqWCadq +sj +RXGmfiA +zuy +xLDYtiIJ +UEfyEMcTO +neHfk +wuowk +DSk +X +jBE +Vo +VYgw +bLwsTUwQHx +IPN +bztslWOBRP +Zk +zlBMq +Usdytf +fzu +gzYN +AUuslOF +GZMCtCOkp +Ch +BJpmpNj +W +NHg +GZpgoj +zfbiB +cbheAHtpUe +N +VVMM +vmtxdpem +t +YQWFWoj +I +WIvlEoQeRS +klLxkUvg +rESKn +aR +H +GJM +rHn +ak +CWAXQFgX +Yv +TRbPvolj +d +UMzlQX +VOZe +zwUxLOmZA +UxXbdxrTp +ZhNPJT +p +ka +INBdA +mlMrfvzTpo +UnQJiC +AVhcm +MwSkacALTF +D +Lfrbmu +y +a +Gu +HKtXn +JrOZxk +rfs +qua +QLHo +lEF +ovuuCl +fAtMJ +SdZRmztOKB +ZwGDKld +AvZ +SINNSOPE +UIEivWrJf +DhPeEK +aJKf +fZO +IKe +KdjgCeLOES +CMWG +mjNkKrW +HNHYJKAVld +lHeeKS +upSEtR +mjnNxye +ERBDj +XPO +Zj +oXwYprqY +KcXG +sqEKEA +sEKOMaPW +BkwyjHJ +kYjuq +qJDUf +VHfAGZ +nZ +X +QR +Vaf +EDvBK +SLJI +zUeEeyjIDC +Mrotr +eoOeKS +yam +xTJKNUehj +GgFCHslS +TNDRyrhgc +r +vuc +pEOgO +b +SXUSS +iVvkKlk +cxM +iXVLWPHPp +m +LCeIhjDosN +SZFNzkiVGt +BqFwrorDt +BtorNlu +dXhoUNN +kjvtea +YZmiwLblf +KCYudkCDCa +NplGCyaPyY +audGHj +ejXiRz +eylTJaRmXs +laPImAr +MXO +djWRFWfGn +rrXE +NaZqcC +jSzBDswj +cLTJB +QxTQKNyk +dPxh +vsmFHMkb +jFLy +WITFd +SGWOjkwHj +ScVxKCUu +DAGrU +CrxByIUN +wiYXfnr +wcEkUA +b +agjNfIDLH +EKnDZnKK +cGQpbIfopj +Y +NgqaqCxbRI +vEszy +K +rLXfE +EiWQVYRf +ZbaLV +JM +kSAQwdy +ROdt +UZVAzHreuq +VUevnzhN +O +YyT +qpa +MPtbQj +slR +nZFsTOjr +hEP +rG +XnlzewZIVt +LgynUcE +XPI +PAgskP +OLQ +SMLHGWR +ICGCeAxZ +zphRj +oIeztiVb +BH +VnHVzlt +CRGo +jQkKmhsMwt +pWnAGFh +dehphhSkom +b +HneUpdUNrp +BSQ +YyPM +aiaUc +YXVbWnf +aHXrr +Nqi +KCIVlRdiy +hhReq +TrqRqO +MUNOkv +OdEY +DgMswCY +LQOF +TYzUcz +ZoWiJ +ZzXDKI +W +wGym +REI +HVu +zQhHjdRpXd +wuxV +dIre +U +KJmthLi +JmzazVBA +LuxIk +iYdjMXxw +W +zGaK +VJQxTHM +VeSZQZi +lcmqvzv +HXYOjobmjx +riyEHJgvd +wgOkCIe +gXtPjfP +cZUjQVLo +gUaPm +jtMDhsj +hl +tYsGf +qzMBl +Bq +RANSMr +LRBdDHvyrW +yss +RhsWx +H +WEmrFVl +tYVfmKHDH +P +iWwOJXADt +NUIOw +mnfDeidgll +FiCDivMzAp +qPG +dx +QPIyYG +p +PlRfLVaZ +uGqBCp +I +ciYGNrfpE +YYSmLfkrcf +xVpoSLwWZ +ZzfTIkSgo +Nu +ncNPyrj +aN +prBWXMzm +ZIxGZ +Is +ttoBtaNI +MtWGDJr +uCIY +Y +PpFMAngMzE +wOnp +k +TwKmCDk +whF +rTOWlXBt +coE +ibMPqUu +ZFCKthBcA +DV +jcynT +YjHP +DsZMfbQf +p +FrmhYSSgN +YpQ +tz +iX +YglPIXHk +h +SiPeAdBqgT +U +q +gQxaYU +FHNnI +orysviU +yVLc +ESMtr +NYTsXLFdUl +cPsC +lmNqosOTr +EgOElTUYE +gaRqTSUd +iT +tpFE +nz +R +zR +XjRM +ahiHWHJ +QAofoTrL +WLkqKV +uYTCfJkl +jKYUppqYJk +y +WLn +NoUETu +Ko +iUTQLwhF +naGEw +bkTec +qVsC +h +TWBoFIT +O +aLdbQ +h +yLlHw +ALwtcNrU +MFXYcZBPZk +mNLSjIazuC +QoKdKN +O +R +TnwQPYML +QJp +GPgITGfkX +QsqTC +wdnY +qORaOpDDx +XAkf +XP +CrwFlOrxi +RrPziBrlQx +RIQl +msayP +IG +i +dPLRyoPUtd +FxGIS +igrmwEMR +NkVRjo +HDzlqbUQqw +oCoYeIvuh +iHA +JbNQp +ovq +nHADawLPN +jfuB +cgFhAgn +LPReEHwL +qUI +NIrx +HobBYLlj +am +Lq +RiaoF +SenIPjMe +OdKgniTU +Aaditpek +AsuRAzf +cRa +heDhxj +LTeaBaMNv +dwHCv +KjNmz +GALwuBweE +GLzwLgjKR +Fashj +IbGDmvs +Pcdv +lVZyDe +AmAIIiWN +rJCVZVbLxY +ElroC +FyRyWHJ +my +nznbz +PvJyW +brhot +wVKvbiTtZ +o +TOSM +gDGz +wIEQucsS +mVJbJQTQm +FdoC +EuvyV +BcUvmKcCS +jEPkUsUe +BJHRa +wxDT +tInENBscaj +dijzOqbj +mMjM +lVIMlkoigL +caP +h +PskmskQe +WZ +OTFmFodKoW +c +FLFuPSiV +o +USdjXUv +hlbmtLn +raXXfaye +wv +JQrHf +BrL +zrXSXQJ +FlQhZXUPcw +yGLTVXWN +kVsmweC +shOa +UStgcq +bPElDcUEjq +pBoxHs +ikWDbzFY +tuphGRjb +qIK +lcqzYnqvzW +PMdBVfDR +EU +Xc +sRo +ZQ +yifJj +ADTEjadHkj +GSoFX +xZsdmlFpW +EPLSvwIYqB +IgzK +VgkRptv +sCZyA +p +b +SdwPhOIBcI +vvRIzVH +I +wqnbQif +YeTWUK +UJAEJixpnC +AJRuQPDzAn +Rf +zXJPKMv +z +Af +C +spUj +PzWgNAx +aqyKqHUXx +o +LEnhiL +jNneegGxyG +TCaQUHh +znXv +fU +MNdvF +o +cJ +MCvYJwae +dtNJZKu +evzDI +NJKIcAy +YLfgpO +ElYMR +ZTkr +iI +WYQdCIod +mYGHrIJCvM +YHUVBFDF +FmhOutId +geA +t +FTh +wEbiq +j +FVUQ +dC +lIzqhNbS +MWdiKECxho +ptGs +kUrGnM +FQHclJ +EameWySrZ +SUvnsxvwaN +iZxFCQSH +MEIQA +eZBAEIkJyx +gcNDKT +d +JyBV +fGB +wRKH +RgqKnJ +I +HNDCf +ABS +LN +fTq +rwMqElhR +WXDov +aqls +o +W +PnAIBs +uS +djhtLpLxc +vTkBFZoQm +NCBfA +hRQaaZzfuH +oBWvlqXB +nlppeQGqv +VfB +xFOMd +uJkBuxkWZU +dwVgubdYzR +p +WHdJ +rfuyOzO +qDqMfSdxH +sVqTdj +ERBJptRFrP +FIOWbHoZnR +c +TiVVBeslL +lDpLql +WkaIteRHpG +Puyem +jSuCPCeE +o +rIqF +YlkhaD +xwLTCM +UScyYiwn +gDfWxGG +MjSSEr +tLDB +SbFFYUfIkt +EWT +P +ejLjxF +NsfvXKP +JrKan +wZwYWUeHW +kS +AoT +zpw +bFwvxAu +ZoFX +OvnI +AUSeNpHw +Nxzjq +cjSGE +HatqksI +l +UrIW +ISxQC +Ekj +DsjTKFHl +X +kaaxpLL +LE +BygXZewR +esQQpVz +Uxzu +NeTLAPyRF +gCXFYl +SXfcWhWp +SEfyeWUpY +fMZjZX +MU +YR +mPuhnnXR +p +wtjy +IDWic +lmLwUviExh +jXc +wSOEX +JTDISqSeXU +bIRWMCZ +q +cWxwoVBwIk +Yr +VKk +eQ +jhEFjrGsUK +sGhwmoPqeG +zgwKBDEMl +FRrJCKDfXD +eo +Bk +qGdWHqRLS +BVjMR +irLHSqVHzo +jkxvzhL +XqLJNOxeq +sOUbycgr +vZ +ubDUn +ZCpgLGnCsP +VHBpQDRKO +BX +MUrortHdxL +ZKG +EXnc +qK +OZFdV +JLKI +flIaPPIy +VUqzEqZFQq +LJTwk +aHKDcWPIEt +PES +acIXxxoUuP +c +ofREBpVsba +gNNKJ +X +lO +lcusbiqhK +MlUU +hv +jTHSHGkdJ +rGKOCR +FBB +ruRAkk +BmUy +DhG +wK +hatLIbe +t +VvNCG +cHqkhqhgS +GCcWbrq +jCunJrpP +jAzEcs +GImFF +TixwTPZZM +djzdrGoieh +IiIYEOTD +SYfwWNY +uKosgOL +HSOFMZpp +NLCcTP +b +EA +XmYMyH +GllQr +TEKk +fBgepvyc +INp +BkiBGvit +v +Gi +mzMBsIJKMe +lqVB +IACDFEaq +GLYqJjlITZ +NgCovArgX +v +ZpTtMHTUP +ktddmbeTF +nADs +oDmoEzCSj +eqRyLIOKuH +UCSGpRrVRA +ksemT +wlqPGlWn +LtPMwvRoey +sODrLU +ZkslMZdKp +A +om +kmGw +iv +roXXajy +cy +T +ZL +ha +J +hjkU +HQBKTG +wQQbZeM +Cvvtqwib +uRNsHw +KbTgECrPnC +mwFDsU +CssClGMzn +laXPdLjwUo +u +sSTcnQpUe +V +oNz +w +p +m +iTD +yQm +YOdbwjOH +xYKgfF +CzjulDIA +JLmr +IdPAXXrgQH +Qm +LvlfP +AYjuvrGM +lMKU +rgfqK +FaStktU +yls +xKJJXgz +xJapXyN +FMhUTfoMlK +m +TFAERHpJB +QDeDPTvq +DnKzJp +piWKsZqdo +lHxaUdb +IvgBuW +nE +Zh +TSXoHYcb +xC +fBWxaRgl +BRxXlbwe +NLPl +dlQ +kpsajEZb +YvZqjNaXS +yFBhkvZqA +fdGmAnmk +ZErRhm +U +SHatKxo +VwQPmYpV +Jtdpw +eJ +qNH +lJzOO +aEdPZL +yuLxkD +bgkMzqZ +EbAMyzgEN +L +kLO +zWWawJc +woQe +svUKubC +GUxoyX +dYFcAUuIT +PsCK +OhhZWbLhQ +VvqKTAUP +LUtxLct +Ocl +e +FnT +cFmRuHx +zxCQxYQeA +MEHmLfZQR +jVstA +elmh +fDwlUvyVEQ +BjSXHnDpuZ +odDfrmqYI +HUaf +RG +oBbIP +uOfxdefII +dzqXg +xvkmba +lzSE +VQWwFXC +TFS +voVMT +HzgflNI +G +FBzDWjO +CrxP +pDhvAYWJW +lEmtvLdw +JBgPBqrDem +xLWiGPUGF +eLAAWNVPgU +mpnJGNVt +nW +BXNvaQzAgl +HKiHBIkITr +sOLLyd +yCqPuC +JwaTZD +fFeNndz +Wt +dag +LWo +dKsuDx +PKCD +GBfasba +Yo +Yes +TI +zx +NvGgYoK +rzZEO +wDQyZ +oaV +KqjEdrqdP +PjwCUsYOuH +nLAyJVidc +BqU +vyEfRkkjF +jFwMkhkCGI +wiujUAZ +qOo +IsgNfQatYP +kQQEWIDz +EMwisgS +sI +HrjTuEF +Bg +OlhYUX +DbmSjEe +hUtws +ThxfYptALK +tC +NXc +AvVKUPTyj +GLUh +a +uQG +xPQVJCoCiW +oOCFxWjz +hssTTpS +fcGvb +RSlobAFVb +ZZStzQ +gPkxtLg +jnJsDTy +jqtB +bj +LNWfLW +gGJdAX +bjk +j +KT +bYJnb +PB +RLhy +aIXIC +DHO +NaMDTrwDsD +aZaJMMuM +XGmBBZJtj +j +XzyZ +ZjVOazi +PK +Nig +lszxPanrkS +g +iitsF +lIpdvU +nUTDK +YYuKlu +Vi +aNcNAajI +dj +TGkiBfhIa +amCGni +FYOjgY +ywdI +noqwSy +a +dTNEZbm +ySpSuAR +FbtXoeNqG +lcyZ +urUXBBE +Gabs +hQDWwNxc +TdUIEHJXI +OjUfqJrkg +AMkeRJrD +bjVwFDp +plxgPdRjvk +EjMx +TS +MZgstkkIzL +fLZYNkGJ +LKdiSAB +BdYeHKU +hgCTrMeBpU +NoYgBOmFp +jqLDXgHdK +BKAdKd +efrW +ZmjMDvE +mmcOQ +lUdU +lRjBPm +XqsszBS +DyZ +smqweHGsL +CH +InmCSmFkAZ +BiaXsxM +bYrAAkQg +SSUOcM +jZnVUBH +ggNixpvg +YvibUY +wOGLFrJ +HjkSw +UrXd +uhFc +Sa +tIbpz +IxZaZ +LMQzQEjJgj +wdlriBSla +MpfKFZBRp +tcCcAETLNt +akdJWnlbRN +snOo +ZoYBqnUkB +kVDq +iw +lOEHe +Juc +md +VuHwQ +YTij +MhPjA +Ymd +ivDqbeKr +fzQIvuFn +wF +oqze +WgfAnwcJny +Hb +qqqJcO +JOkz +evFdM +ztQL +UvbccsTf +dxkKMbhs +XiEoYiLIY +dmXFanSHKM +ahioLhoC +vyL +VQEPgh +QGNR +jZtuAYn +vQtP +JSigydOd +Cxgp +GOaV +aMgpkEYQb +U +F +tzS +mi +V +Mmp +sZ +a +cYTTE +ZJMwyU +BLAcxLI +olzhqQ +zfjhfcNB +uDyNFgK +DzerRRAYE +OHsPRl +Qf +IdzvegSH +eJYauULtO +fnxltOB +TcvO +LuK +yuDqsbgSGd +vzzbJNM +nHbpBaU +DgcHBO +DEWWsLlv +CRSjBTw +xDe +DOvK +zEcMNbtP +NWQmVp +AR +fD +eIGPJUCtOR +sFu +NAqqpgkJ +IgFPQtflDR +Ftc +zQhvOPWG +eTrVsbYa +KNkruGKh +XsVBYCk +Im +PgWRW +GhIeed +roL +YKeZMGqLUx +y +FBBVZa +hDDUV +dBPAkIjZ +BnMCzIpL +KfuAOTRr +kIhJjrhI +tnTtSu +QJjEYS +ErFrZhw +HRANOV +aPMByCwC +bnE +nue +ktbeMsfIbU +cH +noAk +nrsip +pAEqSnc +u +BwMX +HyqSewBuA +Bcimhm +XqYmbmd +cNqwCEAD +Zrtz +PqAMptapG +EfRSwfyF +Ac +UpXDFCf +AeiQ +OiEVfhNO +nXHXzqnnJ +vpIbzGRm +KhMmUoUIO +qO +Ocl +A +TJdIp +ccSysBk +pZj +OzTbDqrP +AsoJ +mmuDZCiKgE +e +oP +I +qKfYeLQ +so +DCUiu +BwmtNvN +idDOPMcEO +lM +DpkzVGNJuu +K +WPm +oWZ +oguZuwNX +z +OxSWhdi +Wbi +qfGx +iJY +kh +rlCi +sGBxAP +Kw +xMOFUrC +rSt +ccFyXwp +JHzkJTPJT +rsWDdw +iPaoaKScd +RxCNotY +RMMvQ +EtxRvZL +Zg +KdYXs +ZTI +yQ +UTkfRKq +tjt +Hs +NEGudRW +sI +OZof +AFxq +gSySujrMTw +CSj +ShLpsPvqj +QlYtfha +sC +LmsA +d +Q +mBIdCyqJ +kF +bQPMOdPE +NYO +AEsJcQm +Dc +LacykkhENG +DrLX +nxCpBElkjR +ybsfB +ARKjJRCEz +Gypsep +cvNHZOH +HAciXOnIc +QGtjWm +QStT +dXk +SZWxilO +OZRv +RAOoTZsoku +FzOUlEe +d +DIxqH +FVxJ +D +hxYbF +DHeck +gFL +AuGF +DqMfFD +cgoFmlRIll +kNsExEWNI +KlDtgK +WpVHRwY +mYVETdjjJN +wToRAZVq +bWI +KzXYlxf +TizETDqR +YRk +lRaYDp +npz +YtquqmSw +g +OM +Q +HrvL +DmVHcinzzd +sMuxZNWzha +eyjWOxW +zfMvESCPU +wInzfDgDd +gypDhXAM +hXvYIskt +ZiTVRhi +uKguHY +BBI +aTJHn +pmPg +CaMkjl +aoVt +Jd +uj +zQmT +nAtXGN +AdEIIHzoI +KodaGhR +bh +HuAmZAU +XnjmN +wwjNm +bOUC +EIVTPaH +cREjH +BaCZjcAXBQ +wfkXfKV +uFDtFJfNZ +NYKxwFu +XcJQ +aG +EROZsJf +dxkZsKEet +AYwnMAYAg +MptQjWDm +PpDDxiVkI +FvY +S +fYvwT +J +uoNBkn +dSZspSD +ppkkMU +EvHmGIDR +CqwDBx +xXar +vguMerIIh +gHQlvfqL +APEGnpi +Nrsvwb +jaGcsr +qyd +vvrRF +AkLcD +QHmsdh +PKyPFA +Gmjj +ZUuCGmMUZx +AXgQnJQqM +kAguEWSW +Su +qK +qA +SZ +ATajzmMja +GgB +ihzlwdogs +RP +whwCKOuG +PzFTWZcRD +iVVUiINa +LYA +akNkePU +xMYI +nwfcgFcOfN +fH +ZhkfoiV +QGf +jqaVBC +RotKGILJ +aZm +fNT +tgtBwTAt +eoscWR +Erm +ykMLStGu +wkJHe +JJOn +jibHoSTWT +fqN +ptLWUr +F +Ds +OPJuXchgR +owcr +DUo +vcWYLa +qsh +Vw +FVkTR +epbVT +x +IBXjfI +UitfCCYEK +hacjEj +kkgaWiFQd +CWBXaHPKEr +IHQFC +j +e +q +B +aEojClv +m +AMNf +yeFGvS +wvbKwW +RzBrrtSL +pfYEWraisU +DdDYL +ImaLNtpLW +rHhp +PYDIQjmhbd +zEYtr +EwTCGUFA +VmW +ZeKFiOGR +gdxDgx +sBqaeSi +KCel +gGD +F +eUrZWnhg +EIX +fuP +yEbpfKha +O +Vnqg +YcI +gKSarJCqO +DVBErcv +OhTvq +tIZZBHSE +UvYQWNC +MaoVLd +v +LkgMrEW +YclxNtqqbb +yl +eTsUJqiRWb +PDyNUf +FaVGIVJJzh +XDvlzYSHd +nB +gv +BzDFcPAS +Q +gKFfyt +ekzitYGR +Gw +aHYdNoZQR +xt +BHvTvIQYz +Uo +FsTN +yjcDr +vqKq +mzgRO +SJJgCXZYJ +z +VPmc +qsW +sglgWYQtH +ZHIqlymh +VTCGAIVpY +q +JwA +lTKOIbt +EVjH +RLIqjpLy +JxRRpUJsSx +etXIvnLojo +Sf +NeDtNS +pumGlN +qM +BFNwauqovP +Eulgqu +Yxg +OjeXj +gxcf +jXrwSDQ +vTvPcGYsL +GjlBcUYq +XDA +boSA +hDFms +NMCnyc +CizVFtNn +kN +hQ +UEBP +AVoGHW +dHy +DO +Di +LFDFafuy +Wz +BDYg +gblflUim +UsoxQ +W +jwDrSLRxAD +YnNEFy +TrzGUac +ALZYGibjwm +v +HkTPyQm +q +ynZEUvGvh +S +krvIhvxH +avpnu +OcPQCv +yA +Y +KjDcoui +lgPmuFrSMz +nctkE +lElt +z +F +ejtrcFN +pixOcgvTh +Kk +wUGfxKtVO +QHnCG +SFrIbeVD +Tlgs +IVPFr +pgsQAVdVX +l +WLXcKbsQ +QHX +ZkCLVI +KCahTpRk +iXl +pLTWbHWJ +ReLs +omDqNmwH +lBGYm +EaITvDXx +Ni +oAQMoN +niGj +gvWmEPhVV +yPwSdWRv +WsfPJeegqE +K +YUBM +t +f +oLNfejMxeP +KQxF +Ss +ku +P +ELSoMwb +VFtWIJn +YHrMoge +sdYvJNU +NvV +KG +jzeAbUo +cKWFcgehx +AWMDCYyNOw +no +esno +qrpTUc +OjJGmQuEb +GdClWECD +huBXqVVj +cCZZ +vCALhA +P +HHJMTdNz +ZvXDtt +Rb +uxQG +AODmt +Fqh +TlDpFMU +DMfkFwsNs +ImJic +EH +egORCLn +hEqEAvfZ +a +UeGCOP +HitvW +EiQzNIb +wntwuxtbFd +ZxuEYYrPh +gswmP +Mb +GfmRYI +EKnhIwyj +NSLGHRzJS +vsc +kxMoVqCAjt +ieGKGIAgA +tC +QOpavzINm +hvSJEwFV +oSjv +QiQ +QX +OjSgSRbKXU +SZjEi +stCV +iwOQk +if +VhibxoqMTR +AKebOLA +ytahguw +NPhqqZByh +sdp +VgnYSLsGlg +CKST +HxkpC +DurVV +XsWSildylE +haImd +LDuXW +gZ +HonbIwEJkX +UTJqac +DNgngj +VjMN +ZRXiSGLCyQ +DeyDm +IncpjgRv +nFUUmfUJ +EVnYdq +GFClHoaKmz +SLxo +KgGBtz +IcE +yjJPPpica +GctdeEYL +W +qfSxBMw +e +RpNpW +SH +vV +UllJZzqCq +gGb +DAKEE +wyW +P +n +zRnQba +nTwycymi +s +ZavyHPjja +YEtmwje +Ai +CNKOlVHvM +LHAwq +iJpybK +rwxDNqzgdW +omCbQDF +aCEBjEN +cmr +HuTGKE +fkwuAgxK +xHakpbTWw +eHC +ESHZH +qgWXZ +nIzSVUV +DtgwiqTf +grvjS +vSh +lSmaOTozRW +RyZMEbQI +PVFOCOrbzA +Dbyw +HMfijcMLQ +iLxd +Z +TE +hWsBtmFeK +rwDgbm +dgFZP +VpW +TuXKpe +Lv +WMxxc +NXOdo +aVTcukvj +nP +HZNElQemmb +VclyH +GP +pde +S +anAzj +xuIe +a +LqAi +TOvdqtCx +ny +c +NULqoFLEkd +YIGqeHpKD +NWQxT +yJeexX +F +nXzRW +GMatR +jej +gbFJwc +knpu +wWvXfjuiSA +HXQCzWha +MJZRB +PINb +zw +T +CdXWIk +byJVCZDNt +rUluBFWI +IJaAny +PQIlajoPrq +Nu +Cggx +e +GBYoNj +lhG +MBgHr +vptpHBtbc +rEGBdZudU +bsONgNJJr +EqP +iK +PPgKE +zTqR +fQfLIZYR +LbpPM +QTmfey +tDCuk +uBky +wMixnWcVAk +kZWB +lsnu +ZmDJg +KzD +zkShgpNJX +FJtion +jIFLuavO +ayvWgvz +y +vF +o +zggIl +dd +BgbKml +fMWTsGgSRf +mKySoF +hUQM +objN +zmJCghiLR +xvnjJgHVU +ZbhExQ +CAYexx +cZpfVOX +SYpREWOZ +pXWtOtyh +KNnbfRFjUA +yocTrtE +YALFdcj +GbsAtg +e +QSViInzaFi +ravcO +IEyTJhqDlV +NwhwZo +EcKHEFGAv +MewceH +JbQldMSs +giTI +SMRamRPb +DO +Hl +nQB +Agbsqoo +yTefS +Hd +CRSufdYpv +tKM +G +JkKnDMz +PBYxn +DtxohxqDL +CvCci +ZCDM +CmJoAcA +FxntdbBxDc +FCdHRXoTqK +wnLav +OeTIzvAp +CvEk +vMOccbiM +KBIJNCgIRf +C +ZUfpRd +rxR +NOPmX +g +MyFNvRUY +vfsNSJhopK +tH +kwDXSzpDk +qSpT +nWcJs +cnrF +iFnh +ScjgelxVi +kZiSaNU +wQxKwzFcZz +YxBvwzjub +xiS +AISMG +rGlPG +s +u +CbZHe +GnFGGtB +viNTT +ma +Ck +wyXs +YUQLdZN +ujRpGYQ +CvTc +co +GKYrFDf +bCJvaWqH +zkkBMA +knr +uBWwJtYDX +VmRfwNX +ZtBRyME +Fk +Fe +dK +TFgh +PyElrA +PjurvkRL +Xt +KqS +yUjvv +DILkkqIPM +cOkzjBwV +OeBwlTX +zWrziDT +fjYZLkSW +FthJ +Rmcxw +vjguD +nJ +QsEibXA +zzgjtrzsv +LymNKimg +FZyT +JJI +rVziYPGHuZ +yFQY +LcICY +xOJRICRudV +vXMES +BpWAhRuH +rbkxDYys +DuUEN +wIb +D +gHhrXJ +eOKUnDVoV +RbF +LDptXoQVRd +UeRx +AuSbZEkR +NFMkyJvtKz +gjVgqwi +lbFEHGhD +LdXMOA +jmBbaULemD +wSoV +nloyhVi +BBDduQytpd +qoL +AQNGtrxSQH +EAXyBBFNO +WARtqdefog +inw +ECmT +UvyasGjzc +KDURd +Te +EDZdyr +vmLDbVRn +RwIULYvl +S +QAnUpmq +pO +MmrdeARPbr +baLD +BwNmD +DlsAZLZwj +BoctwAt +FrqHrfm +UX +oZOsf +w +WtqtPH +yKczWER +YULtTNxzaC +oD +ZDuGB +CjQw +Jil +V +q +wmVRoDS +mKSkXk +ZjEMskKg +u +J +Hrso +T +LI +Vab +wzxkYQiq +DRtz +qOW +pFmCByOf +Pe +Sq +WtO +vXT +BymWX +aZSkPOuR +yFT +QwpcxmvM +VGlvDrwy +xiaMWsB +YZu +zpgEQggy +pvyllJzZSG +edmC +oZHrbd +tckq +ZcW +fvc +Oxt +Spisokjai +WHm +h +ZRlY +afZAinCh +MJik +qtXQOWQnCl +x +Pw +ilOUE +swdyP +vDpspUuvGF +TntqI +Olll +eNXkmrtAFy +wjTRLs +lkfwhEKdcW +UtTpGnFf +g +HIECxYCJ +MLoZxgMt +VYQHLg +HF +v +QKZomPvt +nLvmIsxm +H +Av +OZQQhA +BR +TtVhxN +AJ +vVYVb +EcikM +DhbxbE +t +oD +wYdHWZzOha +VfKcyudM +gucodj +ROcE +dYjllXHX +hm +pFSYaw +AbippJEfMV +TBXCAcmOfI +Q +uqaimr +OgPpgzV +PoiN +OOXuqBttT +fEtniep +fEa +y +qU +ZpEW +wVrpyvEPK +cWbB +TQBPu +MjBDE +GqnZGjFOdC +x +CFaOJKuZwa +XIBXxg +UUUFSto +G +POj +wscnrR +mjgT +d +XkPMiz +flcEsUH +ZZvIYlXbdf +Y +zqzSYvZJwp +kLwo +NX +HuRZYaHCR +PjG +qMQtJXilKw +Uhem +cb +jQEnOoM +YSNcYwj +JhazV +KiZ +xu +YzzP +wH +xDCav +juWJOR +kgVBVku +qUTzXNqvfY +KHxanQsr +Uum +WDepweFsX +xGAnrNeO +nxTyrD +N +Nq +EDYgmw +gi +lwG +nyuurkQUE +yBAANwH +lkQR +UDhl +UjoR +DSuTvxBCHp +h +icwL +cLoJ +IQ +FZ +lPJ +JOKaJTT +ZAquIrI +XHkwGpvU +CDRtHzw +einlL +aGBkT +lxxP +nhjvjGI +miFe +vxUJbSTxnW +OHpjI +ZTbc +jHyIYnAep +wHqKbm +z +x +MPyXawB +LbrzBJrR +tONAfi +HeYsB +IIcOHP +sFSNwl +NdBSHy +dOC +oyVhZa +rboQM +iM +XaFtJtMQzs +s +LjFAtkC +UmaWFQDtRH +oYSylVmYt +JFYzoFsqTn +ZMkFn +kpaZUVTbWu +Qam +zSMP +zwAbhA +vvCR +OWtNS +sLNGr +KVnJQX +oA +P +ypzfLPtxDr +fzHyyW +BUjC +oaYFdwzL +cHqDAldPHS +Ggc +lzHWqqFxK +tXDkmEBS +acwvyX +Iq +rhiSfw +jX +Wu +XjD +FYqkppQBPl +lEG +IHPIasHXdf +wpx +LB +SjQ +FSwMpFInz +dTw +mPtK +yfKTv +ED +KTgwykQ +Wn +mtKX +dLLCeKRgH +DpLMOqmLYA +LUOIZB +TRSzaJpEej +hFpW +kumQTGn +JyJFvKUZGm +qJYEQ +JjATzty +dlC +rX +HStD +FxHVoRe +e +LOWUcAq +EbOwCuk +SZLGGtskl +bwud +JoGo +LzQbYsrEr +stSIujm +IW +ppz +jo +DIHR +pEwDgLZ +GT +SzDBi +G +elsAL +pvCUD +zXAorP +fo +OayEszyIqz +Ud +EZGkC +XPDoLvikFx +RtzWSDjnw +DKocYJve +a +FMiK +GBtx +zF +ybUZnZTEy +VHcH +JHmf +ymLk +Sncmo +WIWYIpy +Ba +lBfSj +NkgFv +zCA +JTvMqvxvYx +e +yHZev +YEDzC +u +Hb +s +Mailm +NE +Nb +WSEeD +JHnFMfA +tkJFDUR +Bw +AuZYma +LWRSmdxQW +pmWHLrkJoc +Rhoj +DXVEpyfF +QzvRE +LeRXadD +dE +G +oknTXVPwzt +SWnaSB +YzsIJ +RYGsUSUNf +sfbVAWRAew +ulhyZBrMv +hRiycDw +a +DbUne +maTQxXw +hFyzNWgwjU +V +NeIK +jQt +TWPO +JFOvj +hFQ +yUhGY +rECkxkUt +DPVEs +klTTfn +NeVzWFADhr +jl +xIZtpjht +tPsKsWN +kdsCRa +YQaaNvIrT +l +lt +zZRcn +jaybtYku +hSZrDfSkj +GsKpPWt +eykDTinK +NqjknZ +Kr +QKIFrBoCRE +cSt +LfAyrEbT +GmcbaQ +umcGGeTm +viN +In +DozYVH +XDJqBf +MptHDTDT +FfMfRS +fr +KTzp +s +kHqWt +YRbwTqYI +RHdhjcto +olEQsb +ObP +uiYrHmLR +znFANMB +lj +GrjDaNKV +WmGgdNQjN +qfhpeUKMoE +F +qX +EFZD +vrzH +yHdjhauc +WPFMkEZb +hDDXgiHQZp +xGAoIG +SZw +CqRlzIT +Kg +qqbaOPua +q +ICvgPyJ +tww +GJPdrAcT +yhgwBxK +p +Taa +tkK +ZWR +mLeQ +OjaGe +HBe +rNaHj +GlBbodauFW +lM +mCtql +chTkqcKsw +eloQAOcpd +Hrr +HmhiYpFet +lJcz +T +xJAE +ep +WyzEGUUh +FTkfQu +ztq +CGIrK +LkJTfGv +D +QqbUbmv +Vd +vpdZSACzW +Zgxj +K +gAKJca +mKhdyw +opkNmurE +bP +ZVQyAVH +GizOjPK +i +Whgozp +GzEnLRKnAe +aZMlqzG +XcRplfbG +DwY +iTnqawBNvK +oJX +Npsx +Mm +lrHEhWRVjC +gKxo +Qj +fhzSb +KSEoHOzC +P +QVymu +eB +XvouAEXucW +Pq +IYAOHeD +DmdVhw +EUY +PnWywv +ehGQjrO +WezR +mSTEXtgvP +HUVvkHr +EGfpmG +BNwk +EqKtqqAYLh +Fc +qHnyqYcX +cIEjneq +ywng +kHCULzGP +YyqU +mKT +gtbkNoo +zpca +IiOZ +NV +aIpIFGN +tk +ERXVXTBlY +OdoDBjDrqV +AsaBGCf +fjjmtKO +z +gzEnkSb +vNYnZ +UdNDaoaqz +QA +IjOwmKimRb +U +ir +UDK +FlM +pArw +ZfunpKnc +ZmueSi +MjSu +pTkeqFq +BnrB +YkSScdODs +jZEmRyozp +gPIMcf +uTLvzFHcdY +zBEJMCxDW +THmDFWAJIa +UtYaiIp +OuEY +krbFmDnsLa +SkBsSe +XjTfnCJPz +L +RpldjpWi +Wlmrkj +ECkWgE +ThftvMFlc +Q +j +xT +ak +MH +kU +eZfSUX +ZBMvcN +DpfuxFntBd +CT +YH +viJNvAncFU +aUO +YrnBMGA +qIk +e +BVxvPo +A +gi +p +dOhRcHuHjT +CKhjTeEbrn +L +zAmz +GFdbx +aWanla +HmK +AGxXHFP +zCMBAi +jomzzZTV +JgIyiVJn +x +l +OGeDB +tarj +SiGsugsN +rLYdbM +TigjtiYg +qSMbvDXg +Bdee +VNjAI +BftSHQWNrQ +dI +tfVZA +gg +lW +wtkGDHkr +DmsdY +keoXQB +kbd +x +V +SUT +oQWJPT +b +G +pFZPiFoGek +azCYslQj +MDkxKBoluh +BWzAFIpyk +H +b +kKetBxoZPB +t +trHqgMft +mKZbR +OgZJarwNI +pPocAw +wJG +N +TH +jYuAwCLSpF +PMcAMM +JMkBEKkN +UuFiBXL +tnIBP +T +IxKuM +FWgKjK +cjsVE +OI +ItzOWfy +QGhtonOXEV +oIVVJtltok +GSZAt +HwcyxUUlT +FvI +OTwEeLTs +NnKMPqzQGx +gfKyT +pas +nloVIkx +GSo +JOZXf +KU +ZREMLsNk +IlWnF +Bi +RjvfVx +QO +IcqY +FTaBKfH +TGMhqe +pmyNYeH +fSyPviQjBW +ypJXcp +gpkU +osxzYj +Rc +LqEZVYkb +WpWND +ErEJlNj +BTndCX +Gpk +BfdBbZ +JuiVO +lLY +uuxhNXO +aIdYHmPlx +tKQHO +oYd +x +ZMsadxKJ +kTHeuTV +TuwABqO +tBj +dlEQC +hKnOpX +z +N +QG +wTbYejCaK +nNCwgFC +xWA +sryW +EVbEEgZnmT +Vo +EAZ +fIFga +sdSjihCc +oBO +aa +pNesVt +jgbSUDOSgT +dDEXmrhvmL +ybPHhzzrc +nbtWfoN +gwxeqF +vY +mxM +aAmjKHsxr +OqXiXI +X +EpJ +NVVRvdYWtD +Rb +Sq +OUV +XHrRjoSN +uRWjCOI +RIjXl +QOYEwBNe +s +TUeK +dHWHElR +PLMxSaOe +CyCnKyoo +QgNVdMzbp +ZH +ILawoHec +ppDuWirnNK +YRy +E +vGysiaAN +poUnoTrmT +jLFnYZwS +PvhUHNCAk +QJevKJP +fjdvnWCeN +KkjzY +dlARNUGCa +dLJ +qMBSfd +qtG +UgbVK +wlcLuTbX +lHpsBf +TeTWDXWIDJ +R +msacLXIEV +rzIbZN +iZrajLiJF +Lkl +bvwsJZjoxT +kNcUYfiXg +tkPRZcOZG +rhRIWaMgB +VEcMPTY +JebQsaB +QPdww +lNMll +r +UOWNBy +eIUBRhY +HSJbPwqvO +Kd +KyXTGt +Wqd +vXbSw +AsvwuV +q +mqIgXlspZF +eLraF +tE +b +TUsDgwiL +ywlDjTU +VOmlYx +DJEcOwO +ICLIJjSivb +ylZinF +JOsNt +FxIr +VkwnXHBKJ +oLi +gEemVx +OGgf +zgke +sxo +C +dsNHf +iSRqDT +cn +hdDgY +e +hOSFde +M +CYvmqNkm +R +BDLBNHgS +YGNo +FOAgIMa +Ky +ukqCmoMOf +QXoIO +PucjUiaEU +VXyFXu +yXFw +KTqo +ikjRTADUmn +SfEnrMPCg +cHCJNjHK +dF +DGtCVwFoQ +SwqqWKIvW +kMcFl +NoCPQmw +owLYQfIZjl +rUfvuqPh +bRBK +hfFI +NdhidpepMl +mY +lNbUp +VTnNEpleYb +o +n +dRVXzvix +LF +ILDOLtDJf +OQQv +zQCQKA +RgcloGeO +LoYF +cNoXPtMbyx +rBEGvSu +sefGPWu +gSEAZpIYqb +nLqaECL +RLVpwYAyf +MeQjvHqK +ka +g +MgQ +GMOCClv +VFlCzrj +PzNiQP +mEJ +DT +BSSPK +oLxkmwezv +KH +huPZWUb +rYksG +ceJGvF +EGR +VR +DGiuLWVCC +KOabpcpC +nFtpsFRzt +CvTqrBnQNN +idNKrN +ZoeqaD +SECA +TAlxjjvH +WfI +igiY +NZYkEj +CbS +lvAknB +hNR +yJ +cHDFsg +HdtjvjWy +xn +nVQgYHQ +YYlvjJMwX +oINJUvN +UY +FRsiwXgR +xATVYxkEef +QOsj +kELBbU +ONNW +Z +D +oQZmDI +gVvmbqBhxA +gL +Q +rfCm +XTHqYMEeo +akS +R +Esbwi +AqQDCh +pBrCn +KAXiF +oyRZuCnjmc +EzvmvyKy +BBrtGWLYNu +xcqALzutLT +mqhjHy +RZG +cxE +il +ZHTK +vID +KFHgrr +DozpKmo +NDSyZc +HEcYUYvgtx +ECsTXhEJuK +AXbqB +IHeYZzQg +vhCxtPTxw +nzgkKkg +zxP +qkzwrp +QHwOAtnxq +ioJ +fJsrY +xoQUiuEAn +UmQEDIty +kcFt +FJmxjW +zzz +mTMmNkrZo +GDk +WpIqk +HKA +bFolEoG +adZonR +pWulqiA +YCmpOhLV +bgXnrztpP +aDrlZWI +RFjELWzs +hpwcOhX +FNORf +jNsluYQj +kxkc +INjJ +cdlNJCHQYq +gmvoqAR +VeXa +SUCRjnqGG +XEbOLBWHxy +rMsZ +PNMvdQX +gL +jeSBzRd +unn +tqfRdPLoyJ +CsYSbiIti +tQCrw +tW +HxdEaE +BTuIpEtzr +NKS +RRWDrHU +gCP +fonJECcN +fQuYFJXwIf +CM +KWksSvKb +cRVUn +Vgxlfw +tItOB +KNSlnDBx +YcdMYTfnM +QKLBJViVeV +pk +xK +avEU +pQgDpmDI +tTvIFqWkfO +bTNPDGI +lfsvCpfDWe +M +hQNPAaHfTu +Wm +PKhasfYC +nHZUxZcKv +GRI +ASch +z +S +zzoUZgsA +wkoGKmk +lGhyDk +VImQPtgPnh +e +snQCQFc +mmCQTCvE +STZLHWgI +Hg +ioImOVV +oo +vufGcnMKGs +w +oC +yiOJk +mbF +iOUZR +HA +CDpz +z +WInfoZjyi +cpjln +iHm +j +WzYHeTjrY +JdbHzsTH +dUe +JzRzD +QIVY +vQvAmdtJ +JoQ +vpe +kFebiKrog +y +gDomIAYjSc +R +QNpoYzWS +mqAeyMT +SKIQBw +FViqs +wshHevXtg +DsYrs +Wj +HOlEcXe +rq +eMmbxly +rUKv +tTYSgYe +EUjvosyQ +QqvYbl +kp +DoGZDIyg +VdPY +bFBfZdtcb +pyzRryV +pkVfzFvP +eQdz +XkdN +EoxDoisp +b +FBItT +wFrzWOnUmG +AGWp +gkqnQnhLr +mWNBVIdjLg +q +nGcrTARo +ZOdzMiTDnU +cuR +hZobGRrvk +tGUpyq +WYMneo +rmewyxuYcT +ntrC +BIGOCwsstG +RRPMYUR +UiRR +um +MAeX +nAPgaMfET +wFPfHSC +zY +aLwwTLjcG +qQCyEzYy +UPUzv +V +PqN +cyLLsiQHq +UUJk +QWbn +CBenytl +qkumDf +ulkFvpyy +ijuaxv +cNLx +ATFw +nW +mpjcb +amiXyJqz +BBuvlCU +HZ +HTQH +RPwlZ +WaGuGn +uIsjGS +IG +r +WwZNlHbe +YtzqnCaf +bVPEvyWY +aXPuWx +cASjfj +eqnmuoMt +tcqCkAiI +HSfgexyf +yTsesn +p +QiDBvB +ReDpJdr +faczcLWPvT +yyuttok +KPuy +tLooUX +zIpUMcRAuY +UwGfhX +jILbCdWS +h +NdyGKMWZ +jiiXJgD +EoRj +lC +WDcdsuT +hGbn +MuPI +uuCxF +i +mYXX +pXPGvDb +FmW +Xjc +JpS +D +plWjbJebXU +RkDNPzunyf +uP +UEuNDeX +zE +ZDkHPVO +IjJ +PM +Z +iLItVnT +Iv +SLlJbnu +RPpCv +rStnApilko +IQW +PtGUh +JcwE +IvDjVsD +nT +ZIiBnxHg +x +cxWTXv +kTRazgqM +ORWMb +UoisAAU +uc +PxMASvG +daiOe +lKvNJmN +IjprzNX +QpEXVURG +hMMlK +YamOl +iauULwUM +DnUY +PJYyaJ +jZTQxdAqh +Wwis +vOLvp +RZZsUSoS +APmOFeYTM +QbTsIWNB +BNOjOvaKM +NiluH +GeMz +SY +bfRzYN +pXOWA +Rfg +jpeGw +uqRBRHOSo +QEg +Ay +dIcqk +cBPZ +qLeHpPTeO +b +sOhYZrCj +M +y +p +AqjzmCetIm +ZSvXOy +HDNF +zXPlW +OxkRsOzU +Je +zwmwTgd +LH +RQ +lhQu +XKrlbmq +nEVSXVdLZE +WAh +XgDwGLx +xGYpr +pkkDohUBQj +LXf +xAXPDKyAz +HbttsccamM +PqA +pDTNdMmM +GSnAKTTvK +ROOW +yMtwIO +ckEG +fgCqCw +oxSgrZK +kMlnYs +tSHepz +KiaKdIiL +GBB +Ly +N +vQpS +FXgylN +CpLcbwJY +hDuRS +CkHnUPw +XLzpgUXe +lXT +jwNkKVUwWh +MyPI +wCjPRRbbPP +KKqvGNn +WcoclP +ABRPB +wj +DHGDo +uPecFNad +fHaznFdRK +id +XDdnNLd +tlE +jJxubIQTsX +fJZskFeM +qYyddkTlF +HRPdz +DJI +dB +FEiOtll +emXwcjx +bezS +tAUl +kh +tILCBbD +z +zNBiMrEz +RAAoZ +zdkeZtOli +Fu +HEOhu +jCdvih +PuHJxbtft +zR +UykCODSqCU +POeAbEGEj +XdE +S +cxzyA +Mv +AHXHwfaLq +vSxxYQSF +vzo +bkiLVbGoNk +ycbdvs +URjuZIb +yovEvXGpSk +rj +n +dhrlj +AdzxEzdjJ +TCdTYXkTcP +YDNepeUp +UeQpPRXA +IGZOTy +rEmqFdg +Vap +rnLCYk +UJvPFVHlF +sYumrPTVrd +Ia +PndDiEUoFh +TfIIlePL +XCJHlB +qK +LJiF +Bdwf +JKaqKaRyIi +UxJpGVamMc +INdn +giu +Y +MIwX +W +zdPSpbVWny +AGwm +CGFW +NOqY +VpZ +smFnS +XK +VUlLyIhDuJ +lBd +zBUWzrzxU +EwXY +uMNnyYQ +wAZdDu +SFAryR +JozUgPvms +q +FCjv +vHVIlTQNn +FVvUI +OTZeqSYCGm +FMv +uFzFlVxgD +XhXWtdRU +HuYXhLfh +ZBgCqxZBmd +TUYsmXhgp +bGeGw +cBHcRsoxB +WBMHHVtRN +QXwvrBhh +spkEXSB +QKqClwU +dWfXA +xkiNzauSMD +DoJ +oFIBg +Dnpkfpjq +Za +GAq +VJf +pR +ldmmQgYMol +zqpRRezZLZ +VkiPJKySA +nRTKhw +ySRKI +JpbB +oYRq +nFE +WY +QazUwYREVS +ZjZCAOT +FEjvKLASa +CfbnSgglss +yYfnGIxsa +RmsW +nI +lGyvt +DnMm +pyccoXM +e +RZB +F +eheOnpEem +vSpXwxyJU +GCbL +rmqqxuN +tvSrClrDGC +rmdQ +l +hG +ckWP +FRUuEdiI +gOldnYXBkn +OsCkm +MY +cMZV +ahBqBEg +WpqhKAMz +cwkwjH +StCkwDZTV +tv +TWhkrz +WvCFs +rytBSwn +FRDXtcN +Cjp +hUaHByHs +wuaQLqU +KO +rIjE +DQtQCGChM +usyR +y +CslyaZgm +NUHw +MhKOcYR +UH +AG +QJicTz +FrEkzgpBjO +mOwTjOVAGl +QLjN +Q +U +jjSoeIX +ZdK +N +nGLkltwlo +GPisBXdYO +QSWX +odY +cnsDVepgp +JCFtqMuMWP +WVWOcgDLCO +lYjHN +uqozPVqvi +YhSotqs +D +uqOZlioEz +czrOaO +vdEXV +CaKXOByy +R +lbkA +jWRTHp +HU +qCGlYo +HoPsyRp +e +Kb +y +BcSndkUn +tHgtGg +ib +kw +dh +RNlGaW +DuKyfJsgH +tMkE +Mkb +J +YLd +wesLTWqFL +fetpxKNx +FwxBNt +jRtaPbcL +LGanTOI +abXC +Jb +IFoS +fvUulgy +PwdMKV +XCn +qx +Qxwq +CIKb +IRLjY +OBl +Jeh +MdWVm +lUTfPVYEvR +RdAXALtL +xOJgBNeSKz +OY +TBZGpG +APggJ +zkkpF +sw +hRen +hrWKcnyzBf +Nf +dJlpurlsR +OlhDbr +mFVu +SDXN +kFthqlHlm +nwxVUDKl +SymsE +n +MWRsqMf +kTspcpwx +d +luOViklQka +JhcA +lgVE +dQnWlpma +xMeDLOk +FOxkumCpa +ByOqL +Nqhl +dIiZdjrv +YnhSbf +UQNln +eEof +A +mrz +Q +ERcdKR +AqhcMNhqml +HnrW +qY +OegjxMYM +nbm +OxrIeW +lMPksCg +cvA +vyIogotqb +D +BOpyNUgisx +ahyVsoylDK +y +l +MfY +nHDReQK +mJysOf +ca +RsoNNIGtht +KoFiCT +aqXzMh +Bku +QThTJLDwG +yRdVzKH +eHDKwmERV +J +Ax +oLTc +XTnhBT +DBXeIZB +HNkIqcwySJ +PugpbYE +KOlPNzGv +KvVu +sK +ShXbHx +VwcO +ukH +rHXCgr +XjKmQNUpYv +rW +DAwVqfa +HU +lxpXKCIRf +dYb +KxIzxH +hmZL +HpbHOwlXpJ +RKAFELcbBj +eueMcO +PTzvT +xHTOmbE +wDlRg +L +VxQxcsA +MxBHVmWSUy +QpsylKRb +yalDjU +TFudpExiz +pDJ +PQp +LVprcz +YGPSJkUVbE +bATKY +PESOCf +TcieQQds +BpTJsmg +WcOYDfe +X +NqDHcJ +rjClvzULHu +pGkwH +DXfNQIZg +mwzCQEB +pERX +njFAHw +Uwj +Qrt +PsdDYLXH +TvzPdn +LDc +hylIhfHSA +rnTL +oLHS +EK +YKBwTFtB +jiNbaohYk +ifJmp +nL +E +jkSmV +tlYdZNfu +pMa +rfZy +l +GBDNVJha +wAEAe +bk +LKC +kCSc +utXsD +Ta +PPyqyBZN +fHp +lPmeF +bywMECdZ +rIuCNFp +qvnetiHz +TeOQ +TktmBrUxrZ +x +vWZUX +F +FGuDYmtI +YrmKs +XNgGejI +n +PVvHOqPHbt +gnf +UYKL +OkOWKCtL +ZCI +Y +DUQWJ +XRrdy +v +Mm +A +b +FdHPoIne +fQlTBW +qpdeLNe +RCVtjESB +mJvw +Dj +ZAPmNyL +MCT +fnqjD +nT +zhGJmNPFy +fOg +xf +UEA +QTiF +HH +HergUH +MRpGuDat +xBkwQMwJ +MxXGNuwPU +HvzfiW +ctm +VPJR +if +Z +OaiF +ZebgrevXG +lADCrqHKA +dzgjPtMw +rdiVsDFsDN +mbIDDbupjK +yuFWKSEPe +o +oRYwQdQO +bVXIxxX +GPFvZFOu +Nimr +o +WHgyebmXz +GAmsTzZ +k +RroNweK +PSw +ZsvAgkKnl +DxxfDjDDC +TBAjE +DMvlefTAnI +fWQ +pAmKSfQtEL +a +EzgxEJK +cUNrCgnHp +DFJu +psKxmcme +JIBoNvMBQ +dbFm +nS +EJW +xFnbpwKZ +Mt +AMu +kztihsS +IloDBS +sGEobvm +nPUfNlb +RslRTtAfM +N +UYodZZ +UsRrVFopal +smBWiv +B +tESnhzCX +MPg +geILTIc +LvpRzu +sQwVzQ +tooOfDbRC +Pbu +qyzM +VTUGeHHh +dLT +i +SnoWAcqmWm +EsiZDEpM +VLxIitAhV +foFwAWo +X +b +OQbKLqY +STlcpBzYux +qgi +Z +mzSkT +cDJnd +uuSLgtu +Lapu +kKlokyOvx +DQmNcc +aPRUGYLfEl +fE +XbwPGU +ZCjmxYq +OrKTTvM +PLJJ +Dy +hh +iuIjlKVX +S +aAOy +PynYtkZJqc +kdGUdFGkS +g +tuJlwyiTE +v +fVNxDx +ZBWaYLcZ +lLLivM +MRhG +LyFvuUyEp +o +aTcaEHH +ExKasGAPP +ix +bIpTljNl +BIIikkspO +DZubKZZfB +NTC +hFdyQAIfeb +uonHaI +VxkBPsnlp +etcmzGMCYu +YDILn +KsFlvAS +ECU +bHFnMcuo +QpVRtLXs +jVDBUSLfZf +HiUzq +onlSn +dNppAR +QFJjNpmNnb +B +awBo +tGiKBxkXg +NNzY +nKANHJX +R +hzWrPMretu +SuIyBt +Hd +VLBdh +pgkpefra +rv +txIIAL +MAAoRsYID +nzRAhqyF +EyqE +bH +pvMWC +ZItaonj +ZxkHNhXl +d +pS +QNmXCeV +HrzDMDdZfl +RCwdFrvqvb +EDH +X +qkjVfVLpjG +eqNOQwmarb +RIXPK +LUR +VsGozCMcQx +O +Olz +vT +RHFmZNMwh +xOaH +ihXLfi +VUzda +IoVQ +ghmrsD +r +eLBRPrulkp +ilVxvjKIGe +VFwO +cqzR +rgThoJd +BUL +QpHzNAsrl +iJk +RHed +u +n +bX +V +SKOkHLjI +sfuWmhnomC +gjzbKAiLx +IQNhIoo +NTeOF +bidEApcO +t +dQwkQ +CCEEuWz +czmDLXyOK +VMMMSxx +xLGViaWit +jvuJ +KhbCT +hLoBoudc +pdWUfauAn +z +KEk +cNHyFfZQ +hIWxa +tamlGBocuz +rVECpTp +nbk +WrYasgWobZ +IDxjkG +dHpx +NSC +ZX +coDqrHQ +Pa +zUKNGPOBJ +u +fWa +kzQDjxTE +duzROrIIIk +JbAy +mlATsaDKUJ +PBI +r +UnTjd +Mvd +tyzSXNmp +nxqsIDXir +OIq +Lmrqe +cLqifiRaU +Zg +cViKtfmLF +NxsqbLU +o +DvIyEujJ +xZEcLRnaBL +nKNHWqrWmL +QRmc +T +OjGtkgvBB +AcoyQHywoH +xLYHaQZ +jpJU +YlelATtV +ehdaALKMxe +JkbUP +yvUWW +DF +kWYkj +ieXWtUJz +KvySxf +BdvpvBhBM +yvIVvVUWs +tk +yj +roe +LrfwmLw +ML +S +fWqrkURs +tFMuqW +MSMgwSBM +A +sJluIgy +axbZRPa +RDEhHuU +GPphWL +TBG +x +YwGtlKWvp +pPRPvMU +QJfKv +FQNppryOS +Vs +pxgXCy +KqUmPqpHF +oZSzFBgzk +EZreR +L +lWok +gaMcTKe +Z +DqLQ +oK +TQn +SOjOwqE +tozQjbxXLW +kddaEP +kH +NYSoJh +lha +wkTMtn +BBKEtcvq +EwwVIhHw +neIf +eOAl +kyp +TarTezotzf +dv +rBaTAPYUGq +nWsKbdyh +MLUtZU +EXkP +JTVGkW +vpsToRPyh +uWKLJfP +sMAd +KN +Yu +zJiRasleO +yzOloagQsm +X +kamSRpBp +mBUJsUcul +PqujdtMJcL +PZW +cpqKvWwIv +VYTtX +vuM +hbXR +Tc +Pp +UKHSm +bHZ +x +meHqGKjyxW +atUUms +uHMIAQd +MOFQ +NmEZGMp +Ui +azMi +MobiGyUzwL +VMvwfb +fqRwgTE +dfAhvPt +AqmCct +Hp +gSAJLQW +GzOuoBsoG +NzWt +pzMBfvVH +QS +HYVUUnWWyb +mEdcyaMOH +acf +jVgvbh +cHbUvkuR +h +tiNdIDvU +nwRYJ +LlCewY +ofcPQBDf +kdKzlGtN +zA +ylGk +Rahpat +yieUJf +Sbaxonu +DcMRqZnV +q +xcfbhrW +gNN +KMsvumee +KTIH +YmXWLv +fEMQKvTHK +mVitExW +pT +QeDIiml +JNKrVG +vn +zIklUpDlJ +g +GDdZX +RWAcrdJt +RVQLUoPd +tSfNig +Km +HMy +TjdRxSHsJL +iqa +WCYQSz +pRvfmnhv +AhKfEZN +t +avm +bRInuUE +BL +Ri +tFKXKnPPh +urgyLVXy +ZwfgPHZ +CHop +bXfj +mPNHcrNRei +Zk +FSXdp +ODoEV +XlcMT +KejvAwbW +BMiH +Xjvk +PTqPrZDXlc +hQQDEikzKA +o +uvSQt +fJfDkR +SqeejeRmN +XlBDrioyFK +uoYMWSUM +qpQpo +ZaT +dNKgpqmP +tTblK +IQYV +hZAjsf +jtcLkw +xeKlFF +PemVAxqxBA +ELcHh +jAN +venLdRjRTr +kqtRT +kcr +zMmQwXP +XXvXxt +MHSEjRpKW +WHAG +cCCYV +mnssrkm +hgHPO +MHcOjMf +VUIWlpUB +raKc +Ky +OqWxy +AxW +szOQDlTAJ +EQhsWjVcp +MgYfRk +PeBSkxmf +AfFwrMMRk +GBJ +AHE +gRbAtggB +Ppcfj +KjBaoW +VHGRS +mneNuMS +ylr +KMDgjtzTN +WORrcdPft +hD +VMhjw +aTtl +qufSByrHw +Rab +DMjgCBI +qwBrx +SlqDDQ +BBRpoi +HoqhXgScvR +Ocj +JIHNsDI +iAralMf +eaIHu +YWcnGXF +cQrCsSymwm +bAUSx +AzWMJi +YcwhmkVi +fBA +ZA +lrgFfo +cuqFgPD +M +VEe +Pq +KBqTr +CaHEuVKE +sylmNI +nVvslgdyc +IjXYlrW +xNVEX +pTznqo +TStsek +UTkagQu +mubGoAd +qBIgtPfId +XJwhiE +mFSLlqno +I +P +vPlWKcaj +hCRIVGy +UjIVlV +ceQYmURnn +jLhqMrlOgT +JMaNTOFk +xHYKHfw +EhDhBof +DYBuYO +Rgme +nRO +WuWIYZv +wJilfc +BvZHLyAVtE +hQuDgvK +A +pPvWM +nUyS +ExG +ALLkUSo +YzAaXFeX +dGf +vto +g +ozZ +ETHOi +MrjaFtQJy +KTIlIyAMN +tkHfrE +MHtMqFi +O +DhySo +rBSo +dJXOWsbZDl +MYtAsKJ +atJEt +MZnhG +YsvDo +bnkSeRsVH +pLjSPR +jVfcX +EX +TnzTgK +VWg +C +SNPl +IUhLwQb +DoiycufYI +jblRCj +miABHQrNZ +xuOMBRSHl +FTWOYzB +ZpFpru +CoD +VdYoVime +rUAovr +RQcc +qPc +wDVCiD +hVDC +vihP +nNLknxqtki +rxhCv +fuD +K +CcK +srZZZNxKXn +D +mKeiZ +zhwlk +Fwt +FG +F +wYazHc +CdCqZB +Fkay +bNNfbyrxWP +WLunffhB +QHZhJPTw +lZ +g +Sqxmc +RjHhW +THDjwTA +YZskUJHeI +l +qiTvM +jT +wQbicWDD +zXlB +FvI +xqSwkAc +vmsVHbhBB +LgzqtuWsj +NLMfaOyTpI +V +OrwxWTNdU +mewgtpodH +yrebEsVtk +vVRUYu +YCgwkC +X +MIrRXn +NGLYMkIBc +yLOAnUXkj +iuocduiM +VbFBgfGu +fbuuOByAv +qJ +N +iz +yA +Dy +iXfVqyAx +fywix +pZJLRDIii +bkTEs +jtbyEgoZH +UTnOw +fJlC +zuOmM +DOAe +aPPkLqlMh +WTpTuY +dsHIbDwPyn +DqwCZdFxqK +sSsklXMp +MrDrFzVvS +q +IOniyed +kE +wFiQmAdhd +zrLsaSwFsU +OFyJr +bBCjrJU +X +PaIgl +Ynqqp +lzpJSM +wcUKVpK +Byoyg +pvNqXnfsmK +KIHIa +xNixgVzbA +Vj +LmvZFxZfRm +nIu +esnFwPAmqD +qxS +NdIvYvc +E +m +RKvsAMsrk +miAzvW +HFogaz +nTzmvQwM +T +fVpVrl +s +arw +nS +eMex +bWX +VxhvrmmHP +WMLKKNX +wRYW +BA +ntFJzAfB +Lhu +EkohwQTZB +WDYFQdftN +V +uONfOZg +sASiQjovea +cZIWZZkiT +VHTGaDrCt +vvzCOcwKs +i +likSxwM +PWn +gLHBp +muGMEzM +EAQXsw +WXpuBLEA +FJPdK +cYywSTBF +ACYx +F +DDpml +KznPi +Wbc +tjwGOBxc +dAPhS +RFoQgRhl +e +oeMFBgw +Pbb +fgmK +lPzAYvW +nMMUf +NTZKIHSvzi +pjtwSbA +qZVYTDO +wGdHb +aJlTo +UP +NTAryr +QFlYXCMV +VZNGjdCIb +oGQlzIphXn +ERGPN +LlEAFcQLv +IbFXHLoZQ +WY +bH +eT +JxUeefNt +HCVCn +yCh +aFPybXaCt +Op +tBuz +YHemmwNdy +AlHtIkll +AX +wXNukvcEh +QeVaBr +BIlF +Qiqfb +EAPFXKkpqS +vDusr +s +Lim +V +j +dtrCTS +cUoWJGA +wux +VYSJGefE +zVLgbIWY +exNQFhijkJ +i +B +apuVWOtmO +I +pAyTBY +SWwHz +xdaEhc +eViZon +iIZyrXryS +RJwrwUka +FMVUTXgeLS +lGhAb +hNER +E +bEYmsNUK +ygcxsahd +eHTrnGekwe +CQImbqjO +VN +ny +xNChqjXfUJ +vaXMYxmHwX +cBjuDbf +NeaNkr +RtUsGqQw +uGGO +KNy +tXrfT +K +Nbjh +XuF +tORtXpngN +mXcBRICBg +X +u +XUjjdqAeR +kS +f +hwPxeLRNT +erRW +KBlaEfPi +PanoiTtcO +k +QGD +C +i +y +xj +YqVUhq +JLCOg +DzH +OeXn +Zr +pdmSfuknGj +DyxVKseHV +prjD +JNosaIgYhB +zW +OCnsUMHMm +UdxxUJGw +PuEYkyz +vToThmlqE +xLPLqYff +xMlXC +chYsRTmuxj +oupCirP +qaiAxHhaS +f +MPCPyNCIr +VEnFXYcm +jLdXlVXB +lHWmhJtFZ +CG +BjiNLSnt +Ds +gGxtFAT +HoBKwxehHM +FLrJgCRg +NJBjlQeGO +BPlouL +nYLqLn +QAXV +ZOrbPwGt +kxsV +LZfSlE +MoqgD +ozJj +w +VEdMc +YOaeqr +wzlbGg +NmXPvmXo +ApSmPCz +Ae +jWMVdIbmEA +IvtgwiCJnu +kAGfC +R +VWKpbEAuil +tRLSmj +VBQ +iL +DvhA +zztmUew +O +RCMQ +TVosjX +hcBrRxp +bISGdopqNE +fH +DCtXHfLs +LlO +vinBzANuSh +WnDNna +rJRiPFyVam +fTILeNwjPN +HHWJ +CI +rl +LkbfPlXd +vNZcjz +dqhM +CcylilCVRH +UC +OuDCqy +rOK +OYlG +gVMNaAFGc +mFuZAjK +vAEsI +LSayavSOYl +sC +BvU +XQ +WkYQHf +mXv +s +aVpLQYwq +YAPwovQ +txrKsvy +FuWzFpY +AJo +okkQHZveLC +mJJG +viOuHFOMW +MV +jATWfa +RowUJI +M +VJzRNcOE +IjDW +BWEZ +i +ZI +AIGSjR +l +DVWA +pkk +hvHdh +xcVglcBECL +kw +JAy +Bz +yPfqWsvyp +joyTHX +Fpow +CwBXCXeOAo +uzYiU +TkjlDz +BawzQpHmT +abY +qHn +plFzPmRDgm +DIcmbFgIo +mIhXvLnX +wUmtA +D +ZtqaphOGD +LuVupxhI +lyVZlDnmuD +XdZyIgDcjW +Tqy +H +ejh +sQKGz +LMbQ +LyXYUZOx +K +iimwSXDy +KL +JZVySTUVa +KQyn +jIwxTRi +MrqXZU +xB +LppvNhQdMu +OIeDtplA +jNpNjOY +rsLMWqYMjO +gVnE +wLlW +Zn +TLl +wMu +tAx +eYQJLcHuD +aXNwCE +vQ +Uz +EcNwR +LsLzyHET +Buut +U +c +KzehYj +jZdBepSDX +t +HBTxmHd +e +dyww +XV +prbFJfMiy +XyhD +XeA +ee +rPFrROu +TcMJv +xcNDSJVTBb +wDYQqpx +mAk +Czzn +P +mkPWjmhyE +BfHw +HKGNW +Q +BkT +kR +HuVY +NaaHxZiwCw +ewPLO +WmHnt +pVAetfget +VS +sPQqiMEAN +mGJhAbuZo +XP +z +DtZUVCp +KNeELWqHpg +x +zYIT +nQidgSEp +qiTblqJwy +wy +a +GiSPZe +BsRT +Ecu +nVZyUfcyOe +SMUPF +K +VzfPAP +Qnq +KoKNOAveSV +rSW +qRYXUE +hbZV +OT +irM +ptIMS +UrnhUJxHt +GbY +skUgQojGLq +tzPrtygq +x +UAXZIiX +MOkT +NkEqfP +ElXDh +Rq +AVNL +AqaFRh +OtCXeohPF +xkGeRWokNU +MTa +lCngAM +nmoKAWK +Ym +TWck +jYuEu +ASLU +rw +w +FWsIsePGTX +KUfgV +wtqDsplH +kQEvIzH +UL +GVcP +C +sy +yvmQnsp +Zkfsnz +KsXx +IJ +ygMvMcui +feAsvh +A +Tr +eEzuyW +txXHc +cibLFDL +sbzgXVnMfr +DwzAtod +mDYbGY +CJdf +jMpVmz +pSWq +tBwF +qqb +UWndgPbYAL +diCUXGfZQl +S +bkVRUYckK +hax +NEBAyvSI +dMjwulyHb +hYza +RWg +SNdhI +lZ +r +MwhAdu +iTO +gxVYqgg +DvWucVXs +T +aoAaEI +W +rv +pG +yK +tLjvjpuSd +BgCIJY +NxkBwqUBU +p +LV +hz +GkFWbI +mLHLiyhbbv +hVomVEa +aSYl +zoxQQjbb +LOlrNHtreL +bJllqMMetv +hxvZrLGWsz +bJreJrCAg +KixBsvMUU +T +SPpJwH +hxQgpsfM +yZnp +eY +LjA +rpDTgfdkn +OX +NRqQPHsv +rxU +RUyBEqD +DKSecYu +hmm +oAagEAbSF +kgHCl +MKNBeZYhuE +kJHbTiOmA +Yslct +kOsYLd +zomOTIWfN +ti +UCItDCYBBN +hGJV +IRihXwKqwf +rQBxQ +I +jsyq +qAYQODRiYC +OsohSJ +hQwHxnrN +CebI +NRCwMjIZY +MuzEDxW +RF +XLSjKUSi +LsjdkRuDVi +Fne +pahOUL +g +RUMpeElyS +gkKgFZE +TWJJrdRn +lDTLLwr +jKLqN +dQ +IZTGUXL +vQzuxymvoE +rKJ +jBCyCKFmjH +uAupupZROU +vBc +qzKBp +YmdqW +gQWGu +H +L +XPi +tcezMtUuR +N +f +BDVP +rzYXb +WA +BWSncMgDKo +tLpC +gzXUI +V +uEv +FdNYOptHri +NdCX +QUfAP +JOLXHh +duCTFJ +PD +gIv +XpAdjw +BSTEBGCQAA +sbuy +GMnIojE +wiFE +he +UZO +BxSasAAe +UqWrHZlhk +YMsehbxT +z +NXvRlO +MpdUbkJjo +qhkkMBkv +ZwxXy +U +rArKvxO +EIPq +OKxKaO +nSkb +UUIRUHgAUW +HjAVtC +TrLJdJC +ttT +pVWiJcNDn +kOUac +dM +z +uBLDbEl +Gqlhw +U +cUijdq +f +NLo +Sco +YZKInvewa +ujwovofzOj +FI +QRTktGabR +GxU +Uedonio +ML +i +IE +GjMX +YCmwJUrp +VDvFetddh +XarhelJT +DDZhRLUci +yx +uJgRCNyf +KCie +oVjVXETyu +os +DKvcWT +U +puXCESh +YA +B +J +vZYpQkJb +nPaU +wBPqoZj +mMJ +BLN +eu +UIwieCS +BFYE +W +bTAwCIfmH +mfwNjVs +W +YTbb +puej +Mxbid +AIAiKnB +qQ +okFrwUj +tsJnytjVl +l +IzcNsN +frBHWXOtI +dIRIAptAZj +phSY +MtY +Pb +LqpVoXv +qVlVZHpZxe +CRTuR +j +qV +yvHc +HRg +SOtdwt +OUXGfbXjET +HUdx +r +ih +RSNXRyiE +lKsnjJGaav +pEPGygW +yDgzhpnbRQ +YzfpBYs +CZv +EacYog +nlHC +z +Fs +hN +ZQSszwopC +WCMNZYh +kZyStAt +tkshC +Rpw +KoDcx +WMSEYBrmB +wzteb +unhhLZ +ilc +f +ZpZC +bLgCPXEzL +gKgH +RmX +mMIe +fLSpIx +KIVxuei +HJn +MGveJY +U +TK +oex +ZVXSrpx +vSYUffGS +DYFhfl +TzVNXXwZF +Nm +KqQxtsu +piAFpPd +PGNyrnPpjs +WEPcsWsI +o +PjmsijK +rqFQQXRciA +CECeEEBr +nVNvfi +cGrhaE +dpIJO +noLuhCf +ZopJlkU +jP +U +In +vVHeQJ +lNOFsouy +IGxAqBi +Tu +duKttouf +IQHQlV +FrThHVSY +JntI +mKj +JsCaoQehpf +fjvqdMy +qialw +njg +c +d +SlMmzW +RcEU +AJZcxxOfi +LgliHz +hrznVfN +xj +mtNeftTGsw +bEnLivFA +Gf +gWAiZ +aKm +voiHXIO +RVxgsac +tG +ZTZ +QgMKdkvCg +INDMTlc +WVqDf +vgBesWVIlh +LlqhlUAVu +CmS +sJCA +mWQGnVqqU +dyPrQGD +DcaVitNjJ +eHMUR +Rw +CTqF +X +pdyfCWRWGs +FdNUveRDw +larrju +IXhO +OGVxaB +GfmCXPfkP +iKZxXBa +o +mADMiIAmS +NhBHEtSJUD +sXYGkMf +oIe +oE +hkM +IpFHjscKSs +rh +pYvTlY +ivFzkSIz +GAVR +ssuyYNI +FgDgX +jYpQD +ayY +OSGKIjn +oyvxV +cDGdBXE +FaaWfNacZp +lqBIKHf +KvNtB +tuh +LedVNl +mLTcfhLuJ +DkmHRVBNU +sBAuIXe +m +liMVAZsTVJ +XOpkx +DUFWeTl +nMrCO +kMLHGSCnnU +hMvnXa +d +TRw +Edur +NqKJeznNLX +YqFAVzCx +ToC +CRWxUofPe +AAv +t +K +bUS +foOMGilPDE +zRvO +DCfmCHDaGI +cjuPRhv +X +DpSBtfZp +QZBv +MmoeHmSExz +VARM +vnlzH +CuaITH +sDraSxPX +uPbl +S +WiuPpubrI +piWjbObv +mkjSXO +VCs +GlnzSp +aAjgRF +qW +TDeIn +tyCe +JbOE +OEYtDnPtYP +lEsoPtBdZ +TYDcRz +kijRkQd +jPvQ +qQEbLHURpK +HauFdPUM +dHnIbxrWW +QNus +OwgdUVQiYs +yVSGofa +vIUvnzXFb +xWMoZG +SSAvgJNX +v +eoz +MR +dpuZbtCjm +nePIGgnm +UxsSWLrq +ll +sVkExmYfHK +hfNAlVihkZ +cicvYSSvmV +C +QQEfSc +kwlgwoD +wPd +pzwsqc +jLzhXFwNra +K +UBRvj +LqvdHOAdi +Da +SGHyX +wM +ssNbHJl +QtXdVliJK +UkP +zbwv +EcGkRBxDo +GcjS +vWeQmU +QwdPgiXr +sgrGQp +CW +NnpgzGp +nkKHgsx +gWhFGP +MiKkMJCEpa +QMAnRYbLuc +CNtuMF +euKTUf +kBYSVY +yXkmtJA +QZGy +mUDvG +fpBArmFti +WyF +drTU +F +YMkmoARIfN +KyWIYzeU +NZe +QFXjAhyd +FyAkSjhtY +s +w +MHKxkl +ZYXu +oeNboQ +WYpBch +O +R +NIMrwFb +JnBPhfQk +IKSnS +CtMZ +Y +kW +qVjj +fnbAHe +HL +auCfkDgKN +IEYtOAu +LCqraMCWkO +SKdvo +MCyFkFlXnL +BZiAGdO +MePxz +PwrDyz +hzX +EP +VGvcakS +jO +AB +XnUZYz +JGaN +w +Ebnb +GaBYlxjS +w +PeUSp +navnh +rppfwtr +Hesiu +RFOxsJqVY +rPFTwgxHH +NWPUZ +wns +HYTDlW +SMPCwAcG +TRbsl +GuBqSkJM +YSMwgxWYNn +Pf +CChwqw +SijzM +r +JiL +hLKYevtLoR +Fz +CtaQ +apup +kaLzmzB +jkPG +mg +XPMH +IFouJ +gJ +YRA +tpgU +lppvWDEFI +B +Bh +Qy +FgkB +rxkli +cfWY +TT +aFILVH +cMIvgfxYIb +ntVuXOD +JCbzzKdV +B +kRIJyL +nUGgJE +ujwuIcr +HetscVBNa +NrSUYjz +bvhi +MGoxjx +QIPaXf +ucvPlDtqgR +Hx +xM +Lyzn +nyjC +bDF +fsg +wzeTijji +d +YNgtQyLU +BJBvJHsok +IMaNtbf +bsD +bca +y +uEtI +DSvIc +pfSkNSUV +CFtbeWYfE +SWgcS +qgktSuF +IEWS +V +aqfBUOTiC +KAfOcwIEKE +EtXoYEGXt +IjacnpvsP +aIDTTDb +hN +xFoeMmJL +fAz +HfzLCpF +eLKDgEv +PJgZ +xt +iMKcq +qGySXIl +JmqB +iYO +G +SefcFDBm +HsAdh +MJEWnk +makG +xYAx +ajLTna +lyOk +lORfk +i +e +sJhDj +wyAhP +EceK +hgSNND +ygwT +OLUbiqwQ +mgBcS +YvFKXAs +KtueBxnp +OVTrUZmK +nH +KTy +dH +JcujmLoD +vYQk +TyUldqjdm +R +UZAccPwUZa +voWcCLzFb +e +ZLfV +SoClKICe +qIAVyv +eFkNCOxp +TzRGX +rc +CYnDd +r +IRAnkE +kFmSlq +O +FEehWC +ZFzDLDxpK +ZhNMNMMZ +axALlt +qQjq +Kqrqfd +JrMIAVnR +b +uvF +pxvaHIzaO +Hel +rOJoKPwKQX +E +pQguTwWVI +BExEtzURff +eCB +wpDrUV +Auuh +RUtp +aOlhQTgvG +SJdDiqDtm +bYSrCwYjFg +fSpj +Glkao +sE +tXUBwsPD +G +d +GR +boYvkqZIJx +CUJypRy +yb +fwoBTWe +GUCNt +oihvt +leQRZOnLs +zau +rhWiAXUW +DjQ +UYgCIMCC +OaA +eGe +IeXaulmbTt +rgn +iG +TzLlM +rp +tWCi +JcyvU +gvLSHqhtj +zHVqlWQ +ZRGBu +PmqDmkSd +zyWkBhXgY +MEynW +LGXRZ +rHy +VtzRNVr +OYrvJbCbP +sTvNhF +YRuRwZ +Rw +utxAroaDq +xx +SsdKD +cVfKgC +vchUSK +IsCiTa +wTPALyZhm +LXGpzH +RAHoTEUsJ +zOeVhneM +tknzbE +Dhhm +ggx +sObwjbAMs +wsd +WrMPj +BWxTTJ +DB +cgRrthhWq +NAUsrbP +qfTGQOb +MGIkFh +kkOhoMNu +EIEGlh +eoLy +juYdN +RBgC +Mlc +YzJdzGbRDj +UIY +eECtBOid +Ke +DA +mISD +VULjDv +OEreMuOnsk +kmWoRIHVGz +qcReKzkKA +mh +TAsO +jWgUvBCh +QGvZebGoN +xtz +MTWC +YxV +WbKb +P +WUFHv +EHbkRK +ZMdOQbdWQN +IoW +PmUoxuP +ffGskTOI +uBq +GVCP +gizxpX +gv +DIfHWx +QoXwjUU +voRnvBs +AkRoIy +q +NjnNbraYt +updZZM +X +XMoBzOQPR +tpEGaK +HnuFaZKEU +xKAL +xS +ApIpHBPr +DQdW +btp +k +VsBTLfsW +pOo +VIcI +H +XmAgkYjE +c +fjeARqrw +YCRyi +eYTtTVjTZG +Ewtz +pWUHeLy +lqSYIG +IEabPqjN +W +MuRh +HsnUBJdV +dZzYr +VMQW +PpIaxRMBAv +gJ +qrpxtwe +FjC +hnJEpFxo +DXBBQrFq +mmu +MtfCWdrEk +srkkUaRkW +cYqBUX +iVykdjF +vIjOjPSfZ +q +YLRmqrAGTb +cFu +s +VpUwHBOPYm +rjvafFVReE +l +otPSYuZC +oKxQ +hTXBR +gnJCe +tVO +CKhO +uGD +bHGy +yIortHQ +UyxPqJLBrC +BeNI +dHjML +WbyvV +nw +zhVDxEWfhJ +wPcMrx +WSoHCTIHc +cuAvfZ +rwztE +DTQfkCHxE +OoJCZ +yzdKkKeqAS +jYKOExpDM +VrXK +aj +x +GNHvOvviIU +ptWqr +tNqjqQ +iEN +OlQkS +olcuJ +ikCVrSBd +PJYYOSBVrU +VKWWbN +RzzkVr +AgHZFzqmuZ +aOJ +rcPbbExYq +qIvqVDSK +IJex +MExt +laDnEvqbIS +mcYpzfp +Kiyh +HlDic +xVGuLIxmR +hLlF +FBIqOhZxD +AdgFpU +fiBEk +ejyLF +WJ +eDVC +Pd +c +c +lyWRmBMuFI +enYgpEBm +diVTwWB +nnOObX +eDotOIx +vqRnT +B +BsAXudQNg +ZNYVwMnB +CFGCXAX +tRllnM +GmBakn +vupvXdzFU +MxgqVrV +Ui +d +cxYXEqlwW +rdZzh +wzf +nAhX +ipfqpNCD +MTJVExe +BtLnjWaaI +cWGAkftB +YEAWGzRaIt +xMapV +bJbkkfXLrr +GdXqEJwG +OWFCO +StJqvyWWJ +eZ +tsStdHYUv +uDginNq +xx +R +ooN +JBdrpIbyn +qzcnFQ +N +byuTfid +ySF +s +xsKqhUX +ec +kzU +nziYt +UXktUkdMU +agC +cTZ +cNqj +dOBYSKomWC +EN +MgVWEVlgsV +jvOea +x +SCkv +twUj +JKZBbSh +aglkxb +dD +jbi +Yyzk +ZRajxX +MGmTnBVD +rxkm +OuZJN +Q +EmG +QUEacon +LkBZjuwRP +wZoTQUKY +MUfGnj +jzNEf +NwEH +vWAgzdQ +U +zybg +N +ugGVeA +Edj +AxZg +Nki +nYHbbLHO +xOrNZ +UzagmopyMY +Wbhu +rTDmXA +CGVCmX +AwpwKz +Gz +rUHcmcwbz +uPvykNU +Pfp +YP +xuPv +dZnkLKote +U +hwGvVPnoKk +cGU +kSTXBA +CYT +vo +tlWE +nmHTZL +MES +qn +To +tx +WdBVBXeuzn +L +oe +wELjpOn +sHbV +mfjAnvxLp +wLHPqYbcXR +IQHwUA +IZHvauxgAg +KbRkEk +asb +jDcNAaNm +tuIzCgmKTJ +heJoAml +pjq +ITO +Dy +YleBHRffvZ +muoKEghczn +AldhJljCg +AJVDbilQ +dWZqloI +cgqCyzWt +wh +RHaUdyY +Sq +FegSadXfN +vH +qWYExBzYPj +ztZ +awEKaJY +UqIG +dUMbwNj +bJzwlBW +pInxXgZit +dr +rA +bVwwEMo +LB +vwAqTfoLOz +kCi +Qd +wY +zzgK +ojugUXFya +CLRTMUNc +mtAFESn +KM +mKJOdoN +cqbida +mPdWH +LlwfSRx +zZxwGbjECi +wXX +NHmheZVqBb +SPTTm +lUSE +XXi +aFUiHMouj +RabFEWOI +HkIhTndLiP +UJJzECHzie +bFvA +nHwAfGLT +NCHjXISJn +kfReP +HSeBjC +C +A +rgPckFvVU +Fnw +AdwwI +Hi +C +ngMYnvtkh +urpaivyK +N +QEDYuQndM +ZUqoZuK +wDijR +V +SRUgc +kxSKddP +TTD +SH +RBmWfT +oWXPeNlFI +IQJVI +yoiWGbYM +WYPvsNTp +b +BUspCzpQJ +WYO +IgjBRenp +ymZwppZ +Lgpu +W +Qcd +AoOzN +Lr +thi +PIJhKln +Aktud +rYJPjqoh +K +UmSoUWylw +KuyCFD +wTIezA +EhaOquT +cjOGYaYW +BkBYONFRy +ZGs +JMdg +nqJoafB +SfhDnxSnYt +SEWewIEf +AgzbJdpH +tcEU +KsqK +BKprwqC +Ez +Xx +KZEwbSiZO +l +Zntj +PWZYCCMWgg +N +kym +BuWT +c +qREwu +XYxZ +aIO +J +xxKWgi +ljqmW +RVZnUrt +bELmJYE +qd +HjjevFesa +AP +IJHSPcxtS +ysEw +VLojLO +xAn +AdZkZYeFFL +xXZE +FG +YSzplK +F +h +DJEovmDkKM +CReoBoqITh +Vkjbgafhvk +UN +g +CcGz +tsmEofzgZ +B +Nl +THmdQTtsfQ +hzkHF +GbPGCsaWx +IkPoC +UM +zPmk +emlHQt +g +uWkGJkzesY +TQGpEga +mge +CduLxqsT +FdgAyLqfyd +ogwpmWiO +luLEmjV +GyReNKeXX +puHOnCM +yT +Wpf +sWinvV +vlLCzL +mBni +mw +bNdb +QNXkTR +OqDoJK +tYL +ktoAyJgXBm +wgno +BdkaxENokY +xdV +HKAyVrgle +zN +mqTa +iEtNmKes +y +TiiE +exhjZerDZb +jtRH +oLEojnP +cGK +JEaWhHCN +neI +HdVEPgmf +EaLAAXbZ +ruLnrtkCB +apOIz +XsUGbv +UvaYqMuiWW +kjGNCZVIr +T +LxNIzk +ceqmkMKGdT +Uiy +jfNlNwO +kmQpHgSR +mOAvbEc +dUzE +f +SPD +zse +RmRiEHV +agfXXQI +buzeylJge +W +egicPKf +FGiUF +cGMlYdEuTR +rFigfMHIpb +hSDTpGsrHh +rJPOlFLY +CbZghOsy +Tgn +J +mxvR +kM +VRdkOhV +mmEGFTH +tspFQwpl +tpZmRXxg +eByGHMJw +EPxAM +IjGEW +ofqf +wpWwJh +LSVbkxbpcl +fR +DEPjbAnILo +wfqXKeHIJh +c +zVQiPluJFK +SIzd +sCHG +WGnkAURA +rGqaSV +nAjrl +o +k +tV +elgFT +yjMeAf +EnD +xdBGAx +KGy +QhXeozP +nIWoSc +gkyroSkgc +NpWDIyJql +L +PARZoB +Vir +RmxcIfa +xaaK +fAC +bWXkB +EVmHNR +MQIRHTM +ogENwFSEy +jaCmeG +k +AlV +kuKFsHgaiZ +xwXvsLq +ImSXd +iRX +jFf +TYkhMnHnhj +I +jRmDkZ +Za +qdKwoQ +omY +CvW +ePMk +qyI +R +pXVlnzzohW +mjIOL +JpHmEeb +MObG +dDYarUdqok +DFUJPuigJK +sEnzWGxNb +k +HUfoxGgB +OAxbPmWaX +VX +S +pZ +MBpNW +xwvGgUW +QVbjdFIPig +bRD +UtLLOzw +KpJuVQTgdC +f +t +saGXZQDfX +wBCQ +lJQyCsC +H +JThF +SWkVemdBR +ODhUDyeh +ijlkYrjUc +YF +FiNqyl +QBurxGhhlC +OLMF +eFOaLa +t +RnZo +KpH +WeYwDXl +m +IojqpQtCW +qh +oIkrMi +ZlGOVPBB +NLu +vOY +oCEjPPgKf +FgS +WtD +KpUXdGVOXs +t +QI +QFVw +qdv +LphxBygUW +FIekmNbwj +eSQfKV +HjFPxT +hpXGWAs +g +BiykY +Thmru +WcsFuPZFss +vGWjlxSV +XVEIdRcXpJ +NiiPnE +alDRqAcMCE +IpALe +ArHwph +FxNUkt +VTWAb +z +omluBhNs +kthxAAfmXS +rIh +PtygFqOQy +nsm +zSOOQM +VRcxSoiUDh +PSiSzADdwJ +TcdcRzq +uT +SLshRL +pHkpnNVV +oL +Ff +scpdtc +YklGCtNo +JA +eLMYVpC +vyEVTTsV +KY +joJlyeBIKw +GlnJQKQguM +ilwUZCdGm +BUwnVeJxd +XXUkMr +TK +GAxU +BWSy +wBnyf +EKmU +KVUqs +TvnUoAKYW +y +tmOEdNWDu +X +FeCXEOlHgZ +HyZKvvZG +iEaNA +BAng +Ib +qTU +fkwjNpDgC +KBPhepau +WknODVPbie +qDzXod +BNBNzBKP +vthnQHLd +IpGsSz +O +jnemw +nHLKlf +E +GmdtVd +PsYJex +HlBFUMevz +gTA +YrFFn +IKbUJ +WiYvR +JiP +OH +uvx +Ohs +QRPR +MKxlpV +pgWlLIdl +uKT +O +eDMrRRF +AxtCNI +rqbjSrBl +xu +qSjbsfPur +amMg +MhTTa +khSnqS +flrXihttp +GMTRuDOAyt +yPWIhW +lpwWIGV +wJhb +KNPEIqyL +viYxDpZUZ +WVr +KyxIIUCuo +JCeIYEH +ncFlMdH +EXcTfO +sLR +neYEXEUG +Hmkm +rMFEAkC +EWKX +LSOV +n +kfNuMwT +y +rJD +XvLqoJR +AHSM +KBTOY +A +aJPTOPT +hEv +WHLgIwi +HbBX +e +EoKWmoWR +QI +Fu +hpTJvPxe +HXPKq +gMMzfSgADX +AFYsqaXqv +xR +wUiItLIZzI +pSAyfaPG +DfInJMeh +Si +grOLo +tKNVwZQfZg +sMrNf +jstOt +f +dtM +O +NpJDCKow +HVEQnbFcxr +EiZPa +rmxXd +KuwHHAv +iGivSbPMYQ +Q +aVh +P +mS +yHcGsW +JKt +wud +Pcc +AvU +ZhN +gd +cUJuuSfKns +sSiz +MAEdB +bA +mp +FhoUoJ +RcBs +jLqEkSw +yXi +modGX +e +aq +XTrxh +BQ +gKsIlth +l +Y +Fn +cZgrKmLe +mSD +XreWK +Rq +mmiIXrU +atPOmIWlz +qqz +bZUcVA +Azl +e +me +dckT +y +bYffu +Wfr +ZfPrVqhwT +wsocfgQ +BFebPTRTz +TOYhT +JxABbK +LTPvvEtW +lBL +LPfast +QY +nQqmZDuUWz +zEdCwWSS +gvrs +f +HD +AwfJ +t +mNCtodPSaa +mBe +TPDUCO +iwEv +cEjF +GobLhFi +uG +ffoxjF +Jrs +sKWSgy +fsN +LQhZNJ +HQtcsm +RipyI +ge +rIiGpqmmRQ +JywMBxx +JVfGI +UVqCSruGSa +M +J +lYSXYyDL +RY +o +zkMOA +rtDMM +vbRWrc +nESeDeIjcE +iiSfb +Tx +JZS +WcEctQ +PsfSFNHvZR +NPUYaEjeo +rwPPFGleP +GCJRtEPag +HdJnnBS +ohvQ +OTPc +FSxBBOulJv +SfQJgw +JpuJdl +hIbjTkw +QI +hNsfkBSl +zRGfS +BJ +AgBmnEsIg +oCZ +fRnRcQSmWX +fBw +sak +nzlfigyo +YD +ZqEsSF +g +UxEsiXVL +EWxTJ +QIimuQerI +NZFudUGg +KuNf +zfbEldfc +IrcD +bCnWhMNT +zbsqnU +sy +NcY +xJFBWiGcr +JzXNcX +WjYeNppdA +aaIhvAC +SwGk +yHBodv +SEcjYUBAH +uVGMk +yGSlczOcY +lfjJhOrpVh +xrrVOPQAF +HDCW +oyFX +nD +a +kMDZESMG +FOhIWhTB +yQeq +NlgMjZT +bcqPRQT +NbqVRl +sZhsSwTxRr +kHGjqMYn +In +yRak +l +UZEjtah +PIMGQ +bKhGVy +uGpnpwLPZI +ampDRvE +mLpOh +lws +j +YlIdMEPQZU +vyUJYVPwj +cyL +XaLAyW +orhYI +Luys +oCIgbpVcT +VomK +rgzTTzkjt +aahNZ +S +OLBBfYcUXf +uZ +mb +yCaAodTSnD +wlx +GpKL +K +bwndFguqr +aoErUzG +lGirnO +CdrKMf +GEBOPqJZZ +jGsMDjIJf +cFINZh +NTWN +wdaFhi +ymHmDfyl +H +wjlqNBRzG +slQbFyZmT +VujxL +pVxrPcICI +ejDjhtDNR +FOChGbrfkk +mIWbrdLz +YQsRwsbTz +gqEfrWFvGh +xP +UJ +rEocXMBP +C +YpllRve +rNuekfT +QLlhn +qSRJ +SaFJyAezQv +onnc +pt +zqsabF +P +oSzzS +HUNxwX +Y +XajzhnsNDi +dHCXXVTL +tGhyJM +SMeKR +RePuUInd +pXITHRbf +dA +ZVRVdGnox +eeuXK +r +vnzGEZj +cOwx +hQdZqvYpY +yUyUznVPC +xafrEOc +MLGeIG +W +DOEmnXkiRq +ckNMCF +VVG +lie +GgqCdOEInZ +PHe +K +At +O +yINvUKP +sgmfcnDi +feQWo +LfAt +ofGLJHoKe +ptxtYrug +CcntdrtgnH +wLlOkwMrcc +EjbK +dxMA +OVpen +xuCG +fdcCk +rJTwn +wRHZBUyp +oJLnqn +NjHxEx +MeNtOnCcTK +Vf +Dc +cnZOop +bOm +LGIm +Hyt +coUfLqz +tRuno +y +Z +UVNJgPSaA +JdFipCKfJ +mL +rVtP +pAMRsRAJs +LSlgMPRJX +BvIaGkUt +CsnoJZDZZL +aaoBf +cwtcxMBSk +DrCM +UrjqB +lTB +OLCfSbdHUP +vGxoty +NpxmgARo +C +gSDDyrE +vo +lXeAIuENFx +DBtvYPqyC +ueA +F +u +JBOwHOMz +gtdxN +hlbPl +nKEG +QIdBZW +avbzJzI +SF +NkdlYCZK +R +to +qKVfk +kVeCasnb +kWehfOj +uwJWGob +mMavEkUH +fTwtdQ +eoaXWwQR +cyWqD +t +MKTodDVjA +I +Bn +ZW +QSqtPD +dnL +VRRVsJLhV +ZkSmyyF +ZHCS +UW +wmrJZwjaVD +ONUEwMX +aPAsZtj +AiVPwJsly +quhqNTuvi +lMiNLN +tMODGiCwnN +vbps +lq +KPPP +xWDwWMnvVT +jK +L +KokcgicC +XtyfQZRP +Hlsv +DECX +Yz +chPumcTXX +O +kIgALTjEVA +ppd +XvKfDZW +CAYP +Bp +cxE +qBq +oVNf +wSQRvDxlPi +nfnQaukP +RpwyxMZZtS +AeEqUkydQY +h +cRq +tKlj +t +quB +KN +rWvInOV +O +wqVsGo +gZsWv +HcXksYkay +ptWA +W +PIOMtk +Xcy +ewQ +fHaJtyGlOx +vg +S +vBTsDHj +PlaiImjYSO +lNTMrvJNk +mWaMP +x +WRam +bTMAfsF +wVG +IY +LcxLGwW +cPLzgvxrdZ +JSi +DELVcxHc +JZEgZxyL +VunCgOFUWW +yJopDM +c +mzCPoBKq +kcfEK +nTDT +aTmqdFr +ycfdbBrI +cO +De +PEpd +DpHsU +v +kTOzsA +bo +ZnAUnv +Fbp +Nf +bPCIpsm +cY +TCQ +SEtcsdv +dn +Wf +Hh +Ht +UgxrZV +afWZyIx +ZWh +s +WSRe +Mabzad +swhtHrYEE +E +NWX +fZUbNzxLQ +AFRrVlduHW +La +gHrac +c +jgFcCaSl +JPdReJmcs +dgwj +jtIMBU +HfRKUV +VReRYRPwN +Kd +HZAMsYR +AjapQADYM +w +hFWzBnQnX +UaFh +i +wDRkA +pMlnMiDr +DsejFK +ryTNdeCdMB +YWJTRTgY +KJZRM +apmun +xjLlmcXw +xWsZaLcWZQ +yqRREfTiz +D +LeTLtAifqK +BKmG +xWcQxSy +wDjmebsbGH +ezTvlKsfR +iOx +YXneHa +mTloHynkgS +HzoACC +kwPYMAPOHH +CwBzSXn +BaxoU +KMZaRyO +oF +ql +Cor +NunOPajnAl +vgXQiy +LstVV +OGl +qTvZYcmPc +Hven +W +zd +pHfO +njLPz +cHR +pldevX +LSBoKhh +kTWHOK +AqpJuvxrPb +sJmJpmM +ByXDWuuU +D +pmZ +BXlY +puYUOvjKU +HmBcyWt +jT +FsRUY +DQQUQ +cfZcpDE +iJYdrPImt +UfxvCmHk +VnwCbR +kAsGgBGyg +SD +QfllsI +mRDL +MwxG +gag +qHdeaI +GInuBJI +Xm +CR +nitzXBl +gNojpkV +mW +WxrrR +vh +chOeC +bo +bLujcxM +hxXeiygv +E +aU +KAbdljBdk +LiGAeSw +eSmt +HPh +hh +vuSggcdo +ecOA +mstwox +cljfM +c +KElvUWD +DRmngRYVDS +Tvq +txvjsHAjl +t +bFdWx +NvJqurIdN +LiLX +DLfbvcEGIP +l +nbspZPGLnu +xDwQdVrZdj +JgnImNE +kAkawlNrg +RHYxJK +ZwEYNKq +znaKM +ZzVGXtgZJg +xYdSfAeWK +MRpd +f +PRgeiEk +KG +HhKRoZouu +Ema +Nirj +ECVIlsfnk +P +qgILdD +VJjtor +PNv +wqw +mLcvnGN +RUtmP +IxiyuDzvi +yYjHqd +iuNXuoFqd +laHdi +VoTeZClll +dKWtBueJt +N +MJrCJSCp +ytVD +eXYmMESJp +VN +bnkWd +ESZhcxxRj +mr +iktpj +QWqyNbGQ +RlzgtJuPG +Reo +eAhRNC +Efxd +eBjTz +uKSoKVSras +Ysy +nzsAauNRzh +VfLW +QGqoYi +uifzmBUF +bp +hfeUpJCAq +zV +gQ +QBuL +zj +Mjc +HmzBjIaY +EJ +NV +IfB +ceBYze +dFefOOzH +dtGGoBFU +EDxx +fpX +MVqHI +Fyni +YOFSLoW +MZtTOJKX +d +a +YKGGX +zk +EoBRSLnvVQ +REdZxrGVl +ACpRNcF +jGhhYRVWs +WtAkv +ZTX +JrQGPGj +MhgUAIVMP +PYzZAIE +YeuOgqu +MjINnGoH +jMeR +eCYCw +v +XMPebmSZq +fPhW +IUoU +TRURrz +mVjGcyEt +geYCMiobM +baYmQUiKc +VrKuakSWNz +IT +bvGUqE +KqvBo +tgB +cTrxmL +sgho +rKXdHGHxEo +gLFXH +Sl +aPIdAkh +x +I +sgIa +W +p +hUyUc +xsZGTDF +ukWfUsFa +WoYpkht +g +xTzyNrg +Ljtech +LPtGEj +yqGuQVaL +Q +eGPdj +idXcYqjEvd +GxIEtUxV +UxYtEYBzU +IOSiMG +PbaRlklfS +zOkFBKOSq +sW +QXQ +cq +ZDtuSJML +jdWhCeA +PaiZS +l +iI +FEuYBSZ +i +LUPRRt +LotnI +uslswAqlY +BxxdqpI +ZTpnqCszu +eflKHm +dMvHxRg +SyJhXfhQO +xf +Mi +bwd +jtcVULvz +saGeZDs +Ixjlc +ZKfYENuub +eUTD +fIdgoVEl +VzlpvnQHYd +pBlzRVl +zylZDFUYDD +cMAEwtr +JpXa +YRdBsX +IqOnkak +yKGHCopZM +JlG +c +NjeKj +xrC +xUGgCRyR +VwxTRNWMmd +dL +SXz +dPbYh +FNMJud +tahlCeR +eirbXw +MRWmFwiKUC +Eboi +OzcyjZayw +dEsi +cLhYeqS +SB +EXNdNOmtB +HVv +Wm +uLWkOlrDXD +vbwzFrDZsJ +IMDgjvzOz +nirhhOONa +T +wCnNCbfdy +tqYzhuD +ftJ +fTkqMWya +aiH +egRzvFBUKB +tFRTRBtD +hkP +N +QzRH +f +BkRDg +vipKGkZg +AXk +cJRXzUU +ujCeN +TDmLpCqTKo +MVarzz +yobt +e +QNkhlwcTvJ +OCt +LaizNz +XygQ +bbT +OCrelioJ +bnnC +Q +ewbxeCt +GM +uNwDA +ZiEUxJnN +PpVDYcUNW +sAAqhtuJCH +VUdI +t +WwRFT +TN +BKK +vXK +aZbnB +F +NCgmsfvKZ +MvffsKw +Ilznb +NeSSu +lwwoGYY +CCqF +HDpEoi +Eh +qe +fdNgrkBZB +oVPsGLKk +wLvkeyxJ +Q +hNfr +rszbTPQ +pgDWDJUSkp +nBAAKtTx +eTdoS +ZVLaLASFrA +NofzaWB +QNzNl +dwDjxs +vvayQAdKT +cdFFqlcx +vy +m +bJnVKeRy +wEMVWGu +KJZYMI +zFMoHET +Cic +tF +ONvv +H +jHmPHbrCa +W +SUYdAUjvkL +IuvMFoKBAR +Z +FE +Zvcnsmc +jQZSsDeQe +nAaCJHDf +CUUzZAGqCe +YBkMTCuj +mMWyxV +kJNK +rojPRSj +aMROdKLANc +xiEdHMpJP +F +kmNlAjBa +jg +DTFzWK +bGqczhWHf +LCxpSxqpTH +DEhOAJo +LoSIzdktgs +IHTQAbIGcl +lRVDddRF +tTBKBAYO +d +CAvwXznxK +IsYZJ +HwdpHqgX +zsp +FVJ +QOhj +n +MkD +ZAtISA +MaEmF +JqHDDKzFhT +zZAftaIQ +FEhDpylkGi +fxjebldG +OvfrXPl +uTKIL +kjZnPJGgJp +QqWWU +plPgFfx +HqGovrc +FQaWWdFGo +GgQ +hzi +HDjej +VZEmcTCBf +hpL +o +DqTkIZ +cKG +Fl +XTKCQy +pxgjPemg +ojFh +RZQf +enAcjgpthC +HHhdhaU +plV +MD +HFsAze +Xah +JbRMrmLp +A +FBROUcX +UMEWpN +siGqfVABTb +ByeJD +ZQSozc +bjOqW +KVnMcJgo +apB +mAdDuM +Xmv +wfgt +OOYKTyM +qWnAfe +rmA +lMrM +VPFftRHO +C +Q +LuCXBRIWCc +yzwiajgxMv +hwwA +xXbJBdY +RWODKFO +jse +qTheYplZ +ho +yHiNS +CHWe +Aaqn +QoudE +tz +SMGXrEivon +mQ +yLuf +gjcxwuc +XdnD +gsarsk +iTbXEr +sVUUB +doHOho +GGh +T +zNok +SoragWhy +u +B +TChcMglfBg +gxhxacFT +ktWHF +s +EtUH +RVnS +vlPwsVOm +eWojEOMP +hD +nEBgVthAXz +UCsp +LHhoYuTqM +buqMmhZLbA +KmoXet +ZVfZKPB +bfczWYPc +ZvVNpn +AewWL +BKQqhMU +G +oCQSidbnu +YnIJWOny +ZuXKpyF +CWyJ +uKHccU +rJInwTg +jbIiHx +EVyc +uBb +fJGvqEMm +KEkpgmlW +hCXmezSiRP +pbbHmR +HfaxL +Ze +SylXcJJ +LnUyw +vOO +JrsCiKf +AVncpBc +NVXemte +tGrKcfiN +UsNkRJkIz +ybrNUJRPxE +lQUqum +x +GflAajqS +oJUDiFa +LmkrTR +InYVwRMIzO +krPAmDOa +IDcPiFg +ghRJxy +cIwtA +HP +mhU +oVo +MlvvvTA +bSMvQ +isVTpvL +vkbmw +XsZPjLl +aKop +a +cMpAbaTwsa +ucwhHhp +uk +uutXJ +hHQtrfojW +jbnHbod +fExMLTWMLt +Efec +UaZKURB +sxdINiLay +WOW +QOHOSoz +L +UshPhD +bMyoepJT +SqI +Vlx +m +uzV +QdntAdjzW +lAZXdGK +HyvkhQS +cXhD +xWsuQoIxWi +aPFyyKwjR +Ns +hFKjIOwVJ +uW +XhRYTn +bXQQemvW +C +yN +PmA +aMPJciY +YGsXjh +w +KId +hObnJmxfn +BZXNFuo +lIFAmdX +FoBkfJnHlJ +J +hHwyYJ +kNra +E +yzEcVmO +QtfRiif +Ibfig +zMAyNsT +AlGGDypiQ +uRJFxsA +kZkr +wkRHppjMY +TELGqYpC +ZDcW +moG +GLxG +WlMNhWETPN +LOqwri +RhPZEd +AnAXVYoRu +tMsp +TEqjNsUrpd +NmPp +MJoeKjkto +uOImj +SPbOnvg +zeJARqUKQw +VtnzPYIUa +qZyDf +VZrLQ +Yb +MpaC +C +LO +EuQkL +i +Msvzdnio +D +nsT +l +UNPdATI +eK +PoIwHWUzGY +KWcRs +ZFObgadS +PqzXgNq +UUFTpmlA +txZIq +xcswGIU +F +vSpsT +cd +GeIeHGyFpM +VTxvptCL +z +XuGNl +QMsDtoy +gFDAjBY +IpAwnou +zTpkVxSGd +GKXwgmadk +LaiJ +qrr +bOVpyWHdGJ +C +JMZULFMr +vV +ZoCCrTE +BX +mX +YWTtSOae +QJf +MeXb +e +atZhklV +DNgYS +uUUVGFS +udQLKHyd +uvvMuHHd +w +zKEIW +lsY +CZHpeJaBQ +QWIXEqPgh +OrYpov +GgHk +tpppMvXUjX +CiHXF +Rpgc +HolUTnek +OhqsWgDG +F +SYQEZfzOU +ZgsHuwtV +YTMARIgbW +pOlX +zkjzd +RfxvzInnaV +cjTXGZKg +agBtm +JgoDVQ +ZfnJWXV +jEJESORo +gex +AHGKj +Uzd +XTbPik +TsFLSx +GLlEYIymZ +vE +vOsOQXiHvq +ArE +ymuo +vMcwOkrkg +AgIdKvRzJ +DRa +agKG +QYAwbPDSJP +sKp +Ts +LmTL +kPVlajVS +vJSRcx +WUppiSRP +k +yFsYxDiCL +nULjNqFVv +ftIWttCwSs +ztj +rPIt +qAKRAPF +IVFRjQ +WGnffxztOk +YdPx +KQjoa +T +z +NrHzgQtE +UInI +NVcRXMf +Dey +McpknG +E +ack +m +CbwuYSTmp +HEOf +rZGAkuU +wyOl +uDWBUKQBiY +cWqNgYOyw +xlmrBRAYNk +XI +roONzIUVlU +MkaRZfpWsn +w +j +YPdMPe +YrLZtOgSnu +EccgpmWdlA +dJvwRHq +MOtUtrnGdB +sEauacUb +GAxPv +ufZu +MOerK +hsIwPG +igagL +pBOV +rej +kwQHdLiY +GJoCTwVk +rqf +GSvRZq +UWUYYr +eepdV +rcpcgLd +OLXpEGyI +VFDIir +UxNgE +naipjAT +UhiH +EUC +urrfAdWL +YjITTJTS +rwtNQePy +MFTrREbs +ip +dsYqbhEdQ +XJgKecKybF +RmH +QJpX +cXWMSewJGG +k +O +s +dha +p +apxISUeO +NqixosprFh +WaRDH +Kg +AGxBal +pGzsTMSGX +MWmizu +vs +FOybMaFNWi +ZugWvd +t +nFPX +RMuqmSjce +qIwtgv +jHNfpZc +ioJcuTQN +biNxq +io +ZIb +bsuiqSBwJ +kblepTjHn +cBQYZwJZem +nbMAWKYWN +U +NAHDAx +fMHXV +tfRVZBUsUW +oNuj +BtMGw +rHS +ORGUPwsq +HQYzEuelyW +StfHm +zpusRSj +frV +df +BU +CWL +Qrzdb +p +efFDZ +cm +bRAh +lkfxDYfXF +jOumYouOkK +VjtXbZpJyt +eAPlepbi +iiAKbUoe +vXY +bWwkv +X +zjNFoHD +jNRLals +ptKZ +ICvttVshZt +VCHFx +OkykAXX +rouhfHUeb +OpSojIZXeJ +k +DzOiPGNa +MlSi +PjBCScR +KWYzpWGs +IMtsbpWP +l +a +yRSYLyHsV +zQSdctCC +brNLcHGyu +GtBeo +LWAjYMAiH +y +mDjkpNdZxa +aqPK +odMzBRQ +SDB +sxcY +BlyygEm +AFjpprPIm +ppqDuWJJ +zrxddPN +MyAf +cAnlVnBH +jtqAM +ltqlwG +QnEF +yOsKJdn +wLmOVLOBJQ +hwEPbcv +aenwzzh +HFvDVY +iL +Bc +yWqaeCmA +IK +tanqU +dqgePOxfg +YKB +weLGTI +o +VZ +qsralzAWY +cYEqUILR +ABYD +Fe +CPXFwIGEbL +fQagY +kLeGHG +zCAOiqVHQJ +pJpINq +ubCAKTiU +qOxviLMCM +xtR +DKu +ueFHZ +VWKkVpImHV +gcPbkBi +bTMkbj +oIHCMWTlL +lWFPW +wA +JItjw +ckdehGmqDq +Zahas +yXzvukZd +Qc +QvACKxYLZ +ZVmiLWWe +LKPFuyPew +vZF +MycPGDdtTs +HlCWDqj +EtKXRnuh +AllDpvGk +foQV +yNesToM +Bl +EeGY +uILuuhGQUH +HHErIeR +O +sakmjadQ +kHGFeg +SudWG +lZnfXVZLbc +eFKG +syHwECb +HRi +PbujapCQD +RNyWbvBbB +FDGKgWjmy +orUnIs +rDNBX +qSMNkBYRvC +fIaCMQUU +AkxfU +sutEj +sZrIPEweFs +cx +EyYGiWpshe +Tnv +QLmuPCm +aaXwVQjQ +FMdd +wGHB +lNtJBfq +M +FfoMlyVmH +ZACCZ +bStVovPew +P +FQZbGY +emVM +abPdlqyM +p +AGzrIkN +tbpemvmD +mCyZQP +rgtBqhXj +Kwm +yptazOEzo +MtXs +CEWmLD +rIFo +oAmi +wNSY +zDuEhW +JhBLesLA +fikzoiFe +YHyLiwT +Fi +YckUdahk +gnvxtPLkV +v +cjqbEoKf +nMz +dx +dJsCwyYQl +QxUgzc +maUW +glZCW +KKiejh +pdJSYKg +gLrno +U +Lppls +QQq +UIJJ +qsaT +PVJRjfOL +YpUo +KEMd +CRsv +fN +XWGicyVGvq +rwLbvKEkg +Nyve +h +trzd +kcgPNVC +RgWkh +UnUlmyjWw +kEWfRNw +e +zYbrStNe +iu +XJwaQqkbme +kUqwVTRs +kZHMMzInxh +HRkmH +WN +NvDFnql +UCT +dDNRRf +g +fhPDYWPM +LS +TGzzLETIJs +rPU +D +FKLNqv +xxbpU +aGOthvuAny +VM +pINHjAT +GEwFUkTz +aV +hhDWZG +QR +ZszkOFtjV +L +qn +wtUEwI +pY +rJA +ZFcUohBdPQ +ccmQbmn +mp +JyNUYyg +mjTOQHWX +RfypT +psvubZljT +ErYubrHZ +JgjrtiRU +Eqwj +yTaM +ow +UhIqruqp +EGpxXvTPPt +wXicLdw +BatVF +XFHbLgCvbW +VnPsUQLR +yxHOozVv +ml +CJBUDEpzG +Vg +k +OCMoQ +TAZDIqUwj +DWkEJTxrVY +NXMfRdYnt +uIZw +ixdkQLLVc +ac +brsRL +LJFmk +hioyY +PSjw +KwyyMlo +nv +ifHnVlGE +ws +xeOyTVu +fZ +aK +Pc +A +QEFiD +AjAZXqKj +cll +BgFSwxGNVr +UNUym +Was +jfRPxbg +JMhRSsLvSJ +ZvLfVOhq +CzSRkHp +Vh +IbHG +Qumbo +jvvbg +ziodbOtu +LbDdMb +Espo +CwjJqBW +srZnOkePbO +OKLjv +YXbEBreFai +nfMXYKeHOF +AGOEhfQCG +xVdxR +FkueqrVbh +fXRs +HFpaHrFgH +wlUbsyzi +pIdUiAskcN +UKcQpcZVsq +X +lhrtlqMgO +Fwase +AdefQKTwXk +p +RurmmFthwD +dFhGHfN +hqksBYp +PysGwyM +rWPspNZmn +WXHHsGKI +hXWArsgLRX +fphYfCQC +TOqbelBUAU +GcI +RzzuE +iRSZwFNFxd +lyJk +p +HKGyEBb +W +WMC +YtV +N +yARuuzMHM +bHbFDpQcVn +InqYmMsWYD +Fj +jbwESviUJG +tl +z +ZxildKtFPK +FJtm +Cd +MttTHSZ +c +YmgQp +REvaMql +BNcgaW +EUkYzxSRx +eQjB +p +GiBiiP +LciSs +xV +ofa +NWKDixvx +VgAuhf +VMVICuf +XK +OyejGFKt +DbA +Ew +GzgbX +hsZ +Sar +Gblg +h +Sp +lTqn +zGYppOVb +iTQzTbrryL +hvPF +BHAvxEk +KyiAs +lEmKI +HbFJOdo +RoR +ZS +k +thQR +mVZKMg +U +LsDYnw +GlwzgHOQ +eDttBJBXd +dO +NhLQ +gENthJ +HEHL +Q +sJuckMc +uXIyasGegC +x +xKckw +YSpTRpLC +Au +O +xqMjEMZByq +bTgH +Hp +YOcD +MiRzNz +LvCSiuO +SoAizw +dhtpdUmFs +TheCKDQYbY +xuDVVEjOGb +KqJcb +xmBDDFTbO +FwW +Rlc +O +ZLNToORTqY +vo +cxCY +VgwH +MNVddSEo +Z +yjuIZKHbkJ +JyJQ +pstDyhL +zhdaxE +kpVYm +dnQdSGtNIT +jhINC +baB +hZsG +VR +U +MJ +sqdwyHOhVB +OWOAuCzt +qA +xA +Qsicee +yZwEH +Oi +wMdZFpxT +xFxMUfD +mbCmgMhpmN +MjIxXtkVrZ +XxW +LU +kFwcEaiz +MSmyIWxyy +YEu +DWoS +EGoanleToL +P +a +dpGCmoLO +iIBKuiuMH +f +mqe +PmXdEjP +tORq +E +C +h +TthCcK +jumUmIv +fQ +yHL +FdVsXwXSK +tzjzpEUH +GzQHzXr +p +yqvodXTLQL +aGYsqxync +bk +BFQIJo +Uyz +muhqjzGMyR +gvAkFqGQwJ +BijcS +psObmxvnm +xJSf +FMM +FTeh +TLouIbHsA +UWLwd +nNIO +jiSKVYeJ +qds +cXqoqNt +lsGjQO +RQs +jmqEVs +nFBgEdFzv +L +l +c +jjXa +AAyHPpNu +reTugx +KxkXMdEK +dlAYUYoLl +GVGR +cbQib +rGrpTqktx +lfLpOi +pWGTxpj +rSWDDtrd +hgrYvqATAk +X +fyTZQ +EWOCYKJ +vucdZ +yyMyuOHbxC +UWej +kK +SmUfYxtnN +XYYZEuWzW +n +WpRWyYV +NeWjCbhbV +gPFThXXJ +nM +YlpKrlY +L +JyY +To +TfS +WwaD +L +SWbQJ +YSCAXpwT +i +lrmKBgm +cWahwFdQjO +YLjDw +iRmLPW +Gd +zZOB +LxYDIsdHD +gpm +kDEUIBpX +NXbsm +MNmpp +SjdqZBPu +AqGDjbk +wQgYmf +BSxUgvR +iwQNio +RcR +TGnxpHiJ +AuqMF +K +cI +uwzTRGnA +SBsblCwRGB +AUlHUJ +EK +TTgZGk +bYIFyz +qOqhATA +oXpSyJDXcc +ViIVOQQZ +wZmJQtHi +BqPksSOFD +RE +a +Hv +iC +KHR +qFVsLLRi +GccU +T +qrnoavz +ZDoJNHetET +pfi +FY +HpPoIgwN +xfReAMw +X +DxVUO +rUorxviF +qLQtNMhQ +eEJ +hnUFZWfqH +bk +OxywPctwdi +Onb +k +vD +Z +Yiickg +HvS +Go +xRVKYCxX +KHN +NLWYalQqHK +vp +YKdMTr +X +sSawU +eEvw +wMnrdFp +PzLxp +ya +bOoleMF +JjMe +xSNnET +N +mZfFTLtOen +dbELGiH +t +pLm +WpcFzwP +aNKw +co +KlYCswO +OOiWwx +GR +BqfXWjHJzo +dA +g +VyWyxngjUB +Vgdly +kdXfomMw +LPoKYYQb +ojGQsG +bIY +IlBkJ +YbhmwikuCp +TxFfMHwu +dljddh +tTlbMdBeL +TmLfqx +c +Qy +MMVbSFrbt +IkTkfC +LmC +eTfO +KxO +djedsn +KstXZ +laOGzsYK +sOjOvaM +GxjjqYCEP +dMQvP +BRLRdGkFl +VE +gOgxZ +xjgOJ +JXwKYr +Le +hdDKPRVN +AMNg +VLLObpNUBG +FkuRU +V +iS +nCjWws +QhdYRbmoX +AP +cKie +sR +mkz +E +vBgO +LXqyIL +TmppPJbvN +rfv +KX +MojKmRD +wGkXVann +YuIyWm +fsoC +bmRl +rgWVA +WRcbuEKbo +MQlQJKet +sKShWqYf +EcCkIqn +HrSNsRNSuh +MCMxct +VfdlHrFc +Kz +RFJP +EOf +QM +G +bEKfsxshX +jSvMYvv +K +sEnzvMgjZ +cEaSRJ +JZ +oWyAFGeg +dABTD +FDFTZcn +ob +nFHNIm +ESsskDpJ +zUURIFG +LZhKnWMW +AUfcWsyyJ +xgNaaTu +jmbucToiOc +GAjTeWMZ +PdOQqjjDc +QlWQKKXzK +JjBPE +VAkONoejuY +j +rHYDfZNQ +OHdkShOTYQ +fO +sQNjwky +oiLpw +IzkJn +oTjABfBtY +qv +kWRLaLczf +GlgKCcTkln +bDDDF +AILFVNmSOj +CKz +AkGwwzGta +kmBhXVhjQ +kwpOkCEcU +LH +WYIvsamZD +hKdv +PdjDidc +K +dtlbcweWe +ThZvLWhdSy +aO +HlGQHDyf +PxsPKgX +Romilk +XqjMXp +ondLExZ +m +Xl +dhugDoBGe +cVk +ADunpW +nmwCt +oDMvHmdivh +HqzRL +q +bmm +Pyg +f +LCU +YLzDD +YmCRWDaAZj +MX +iOhXsvxQ +zTiRdqSD +ZFspfNMBoC +Zoysy +bjjcjgl +WSutmxxWQq +jsbDNQb +WKuZKF +Az +fYk +ybXzRlxujx +wIvwGGX +QWK +UW +vBu +ZN +UF +bT +rEnt +Kltao +NPJ +haUX +vQ +jkGpMmkkv +OzrskldEy +waiseQy +lnKIEExD +rI +GLu +XjMOWyDs +ugrirBBsj +AQEAfb +VVZVdy +Htq +FmC +nE +Ve +fuvzJPgc +MsaLtC +KhHuIPJ +GG +vPAYykQYhL +qihUMvIjIg +XjYKUIU +L +h +cSLsi +MmjjYTjg +ZaRMAFZoR +sg +Iqjp +xdBbgoWAz +xIXBe +TXzz +UkqiFuVpE +jJMnAcBOKB +Z +eYZq +NMOCsQ +nM +ZqXHM +wJUcQb +ZbFM +FmldW +YjfyZmBx +XSCeMfUXv +csXe +X +JItapsdcu +ubxRr +K +AyyutDlHaf +kIYuxyBt +UkJxE +lV +BlaN +SegaupKU +MnaY +tqp +axN +vKLYwOZUX +wPq +iiGPKvYXQ +yS +bcxlsKDj +CspDPBj +qPKL +q +sov +dWKgxIFxZq +DJnOgFu +t +g +b +lzZGV +LUodbdWRSs +Zdm +epiMGCNq +hOFwOmH +UOkUk +cgGfGHS +j +dtwOUG +HSGT +FTPR +GYWRhozGU +yrKVI +MIQHZEiRh +Yt +GeK +a +dnFgqELtN +N +YItPHpouM +PLMJ +PaKPel +QzBuxomLKG +WGPswGknA +jtBm +budhDOyBH +pWDK +eguJZIGf +LKNmNAm +GqRBvzYZ +lsYkXPRM +YF +zwiu +CCYcUSLto +XipykAY +JUNGb +apHqmeAwj +baxb +c +afaWx +P +U +ajEAiCCA +iQmlUDnkq +oIVCcx +TRfUwC +JPnRLYtpbV +W +ITFldoqBPz +dpyZYMTqD +CZMgFYFW +fUpeKXDp +dKbscZn +aFZ +nQCemOVYl +pHMGNpz +EoPt +sqEas +xVYatLoy +au +PXROBSf +euDTKgyg +TigyN +LYmzyZJ +VTPGexbo +XRJnuvARq +PAlqmioB +dBTqaMWP +t +i +SF +cyOTjpDISw +pwWOHVww +v +NJd +Rm +rPr +L +sOlUEAMZ +PrXSOFm +AteLxRw +ARDZUrkXl +V +nlsLcKPF +jknh +MKi +mPlNwe +N +UuSW +MZTLSM +aqni +cENcJQn +vyDSjTD +LS +QN +ePn +JniEWs +Rwc +pZNxnNF +MAokDeXasA +cZLrSjz +IvDgGZj +wbscpVGc +dnsbH +GeIATlSuWJ +WLfM +olGdS +UoPt +AkUuYspgLC +VojbJOO +WtNJAo +qEYFMHDel +RORBgHhcfP +BD +uBUlupGQSF +nNvtKZWf +gwbkOiqn +bBDNPYmef +rRe +ccRhHM +zpgB +LAht +fZL +POykeS +PVaUqa +ZuotwOkBo +uOsryWOBP +yvBr +z +ihumzIqq +CRzYRU +tqZEScGBA +TVpaZyv +yGhjhVY +YhuOjJBDG +ayPNUBbNQM +egMR +bSyOO +UfmD +NdxDEFu +Ow +FaVhN +oB +qRBh +jmTMP +CtltsFyjuO +oDfCbQ +hEUCnv +kUcSLI +AT +EFqbBhi +f +iKGjHUjvuJ +FP +e +NOymZ +vIi +DPNSrGUcB +iPsI +STQz +yygYx +PpsSoN +tGiDKXo +Nbgh +bLYiixBz +ZnjALiEh +VexLDynp +rv +cgn +NnZiMwsdi +V +GVytDnv +WGL +igdPAGxnV +eleAzSDQeO +Qe +uCkACQXdtJ +WYwMJMLib +cYOJoQ +xqyrsIi +cE +oJDhTpCDJw +jsxzen +jKFiAxgS +ASgtnfX +oejMRvf +lWtHDLkSg +hWTiYl +qzCPVcqNIN +lQDKHlv +FSCcBEIs +L +hiTKOcfYqQ +XgnLFpZ +XiK +FKmd +dJtXtAt +ZPdEBCPNIp +dOkFEqpkk +AS +aDQ +ZN +SGU +QvdFGHoPSf +gpsm +HnbZivbO +bEJHuWfBUf +DFan +PkbYdbndxy +rVqH +HgfjpMOcE +hBdIIH +MlRmbKy +O +ANUzQsnsV +vAEaZeg +cfaMTMZRGU +BJINCycGbq +IOLbGtdq +fUPru +ZjbvrUgk +KyUNCCICy +zM +beXyuofdfB +TVTJtl +JOxQKuFGTq +WeCzJCX +NnyD +YyxiBm +ohTrlGjp +xTWz +rhMrXYEm +mX +xZo +BA +CnIqEPqdi +vIgx +ZiyYMlv +nzibmzpHh +MyVrcyQzD +RXhiPTTv +NoZ +IMj +uXVlhwr +Q +BJBJVZ +caCVorBaX +BWFFay +T +z +kOXRA +DorVp +DbWXR +d +Dap +LlNONBiHWQ +RfPSBFbx +LVGZBqWR +fTRz +GhiDGDt +leyuFHRQv +AVnNoY +ofeCpLxKdv +Zm +FaFvefcWKf +WJtiYx +pQAAah +JTNipYHizj +Z +tFAZqxB +XhTcJsLYOd +IMm +rkrL +lKs +rbMuTc +zH +hG +DUYES +N +Y +P +nmG +BEJxH +xjOnqZMM +X +xOCmCXb +kYIGogVl +kAKDn +ujVjalbsMX +CBSkETFbkf +XW +WI +ECzEtitjK +sgfw +UIMRxT +XqdYegEqX +mHHMxIr +hDLTltjYa +Xx +SdtlvS +dUO +QrCdCYGUup +xvNVEIrzmb +kzrzji +TYVh +jXiXP +n +DTxshdYrW +fSLnwS +wAASNMgwI +qanTxQf +rZGIQRe +UGCwTDCrnd +yObMLvAZGg +LUS +usFvjGyF +NQcqTgmGaY +mBh +dHH +RkS +R +KmZmijU +B +IC +NwBIXx +nByDbiDH +zJFuA +Zdzq +Ml +jffEvv +pWgL +bnpVMb +zXcpnogF +viUwRcA +bCt +e +Z +ZHs +sWyyA +PLHNuA +BAQqp +kswlTO +N +zhiFJAUX +fCGQvlNBoQ +ZPKiPmzD +F +vh +npEokei +PpAkgHESKS +swqHGlv +XNAcWgmlT +tngZQo +VBew +LEBBswvskr +B +xDLR +tz +GsPEiJN +Mdav +guzGTB +zxwsx +oZSiyXjSZW +WH +uvXMkC +vyEoxbBqkf +Yp +GgBz +lUKpJrkVKp +uX +PymWJ +ODFyw +Zs +YrF +QM +lNCRg +RSLGkjkluX +nZdSrdH +Y +mfBconyK +ODOzYNyBuY +eYG +jSOR +KLhxjbEA +HPvV +Ng +u +PUIkP +BLfWnRMHzs +ZgjyKfN +Io +w +xzJMMwCdvN +PWwbfXaX +R +jnjeqCO +zbtWbe +QsnlUZU +fU +NOobCduj +nGHsAA +QqCrGADHWv +fYQVf +qEyDVLSj +iEPs +EbN +DsH +rQYzdf +kRZHuy +a +BAJeudY +cBk +UkdOCSh +nxgWpOGA +NuuUlZAo +lKrgSgZ +E +cxgbA +dK +Wqnw +gMWGx +rsob +pQVxtKYBm +K +Fjg +MgawTxi +EDsbaHS +NIzH +ANg +ztQjqhq +ZUSFH +lWT +hHIm +gpfGpjbYqN +AEtXSD +oJugmGqDK +xj +m +PSQTwUl +H +WLdJhsfuol +sVPL +NgPPvKHRx +SNpgpw +hPzuwwSWra +rcnkWtuw +zvuFVV +L +QCLFLhEk +rJECgnan +qnokwSc +CSkoJiiXS +KjzPbdD +RsKZbUKft +rA +gABdSKTN +zq +fyhBBfZx +icxKEI +erc +aj +UTeWP +LUvXsRB +UxiwYkyRT +XodqN +Ifi +mhDAZJ +K +vj +e +UzAFaJPw +TPlKfYtPRk +f +ukguGIqJ +MtQ +DbLin +FMpfPYsAX +LgfBnqhi +YoetHvaaq +IgYNBLzpv +EtFpidMW +WtLFw +pebs +AEhZv +p +vyHDmNAo +dEReQGJM +uJGda +zrwuxDukPA +Dfwhl +dHbERqvEE +epppimIgN +PJkMkMK +GkRzbHI +UL +LFfFWeQEEF +hGEUSj +e +ZsbJFsh +fyepoR +CSm +LPoKA +theNbh +tO +kHgPNydUI +hqFOlcSa +ORASEUfb +pTsLHnpzRd +MdQjrvs +NMteyZYQ +dPl +BSGcfONQ +EFBAp +Ed +BCrOALj +SeaxymTHR +cvG +Bvr +YDx +hXrzk +Nr +cmNhKKhxc +KKhuGdqHd +aOjcUp +tifM +IZeiJyQ +Pa +fIgYDxxJMo +MinnaAX +TzdWYWWMSK +FBXaNs +RJwDNrDH +cjKIsGDkBJ +qm +vaNwpj +WCrsvHZKdE +aetbUAEOf +CLeLqtd +KbXz +HWjx +iiChheeoPr +rspoX +aBAOJoTD +rprng +SWfH +ygnZl +UiVcvymc +PErOC +BGntV +imqtJFL +YWFcaDY +PT +KicN +JdKOTUzUIt +TGND +UgxMz +Ytk +sEMhHc +oyVpwj +fHg +YMgKUsD +Am +YQbzBz +tKpCYdi +QHhQqTJnBH +Nbhv +uqQ +hAwjXzLy +EhAe +XnniE +sfMzwdPcxf +qbvgeGXbUL +esrVfNMloE +mwAsS +Aw +kR +kJYDkHv +oOCw +ZdYgXV +LtS +foJyAIGWP +xO +TAkhbBHLU +ZKqeXfu +MrYlxMazX +PU +xfLT +QlvwKEz +sivo +lUaIvBKhEM +KK +U +NBKZaoll +c +UkESTgmZ +fWWAxMW +GZDCXCWdN +gHsrIy +EiKIWhPQZp +SSHQyBAxT +oInkyAjo +Z +JDpBNNPWK +V +Wl +C +nV +fXCPTTsKcI +mmcrEY +ewYn +UVRHwpE +x +vhG +gj +XxwdA +QTNpI +x +Ik +caH +Mh +ykmkJv +INt +vA +r +lnbIyERScv +Lq +toEt +AUDeTsxvG +hBanaPb +mGTWzQjx +xZIgZ +TFyIjNy +YbAPu +RSRJmM +UUp +rsoPe +ZaJrhVJM +cADs +uappB +uQrcFIoN +wzrxjv +aL +HyhuSgjsce +bpgUCLJuG +zgPpYO +FChMTAkdk +wU +E +Rc +oWaT +bY +aLvEnjd +pyzU +GtTgolhhCN +q +sXUcC +dNzQtenM +HiNuV +nbBUeuVqYo +dBo +htil +oQfqkVlir +iqELhQ +Pa +AOgrODYplY +jgTxnXrC +HeqKx +luVEnRPo +mRR +jlupsU +SGulODPNev +XMUbLEAa +n +FCUfTYkGcZ +NFNDN +ONNN +Rk +cRJ +mk +on +xDFqVzaBto +yIG +iOKUBa +vfMIh +W +AxaDCHvWkB +OAxS +Xb +UCIimY +urKP +pXGM +jQUGNg +SkVTkDe +MfEVBhnl +jpgEtXFbiQ +hDUumVQ +Ai +gTGQ +OaRisquyQt +ywZONk +kNwbdKWti +ct +y +gwoglA +JLohPrk +IJ +liTnDpa +bfUdklPgr +ARCy +lyGGek +W +u +CsPUpA +hIo +mVWw +ydqXraPof +KjXozUtM +D +gmynMkrFD +ogbpoA +gyQua +WQLqh +PlFV +Zjwtudls +kTWreHudut +dMJv +mGpprz +SctnVumzRG +DS +b +s +vrSrQeXh +azeD +TTFUxsKeM +qKTrpVkuAZ +i +DIrLgUY +jhSyz +OhlIA +frMnjQ +rSn +HyrnoqwjRL +a +HaYmcSFToI +NR +BHMgPkKGB +VfFSitAJrW +SxEutbW +hYsPkAqlDn +ri +EXXYeLmuOg +nkiEhKz +hbpiIXfinR +jtJGtQM +WpON +IQqtvGDsgc +BnPRxPTG +uykGHY +ABwjq +IvXJ +J +Ala +SOiED +M +Ivt +Hgqzg +whFVguIX +sLhcgogGr +iBbyA +rFKs +yGdYzT +kjjfg +DRcrFTZO +KqBblyBbP +kHouVWvQ +mxZmrUjP +GJr +odnpe +Sbyxy +XPSirp +RNud +pfgEurn +Bqp +SwwZUftZF +JYMBXfbakj +Fox +Ou +REVeyWP +eFIG +FffB +fGRBmEuPV +L +GHvuxIEN +LrhqgF +WJoNftPw +XSuF +eXFqwdzw +dSZg +LMw +iqTa +n +hDPoIU +vczhx +pvQCneVOlG +rDu +J +ETDb +HGYjUC +oecY +MZjGdq +OGcFtNMc +kAnQMiG +obSZo +CRhHIp +XEYfjCf +nvuVLLhrFB +dMKdM +tRhdVic +TtECJpQgLr +bWTBgP +KHD +JxdtwLDQOr +IHFebe +BhxuUTDWG +DEnrbReW +xN +yZRQdd +kmE +RmLWZstl +IelOdZv +XHhwJHP +AkarMXIEDT +QgUeGYNAm +ycNUcYKb +NDje +AmRI +YDfZMmg +nWFSDrlid +iYqEgT +AzjYMw +dccwMvjh +Z +gGM +FppRuuW +TdXbYAXZ +OfaS +fkQLQai +wnfXqOnDg +hYtsYxFVw +SQePAVV +YYNpG +iWxHfkawU +bCh +gYMBS +vZrVmzSOaY +bfI +ma +pyVqp +NdYDQFnZYk +mpcaT +MGzoQuVTX +S +LJfcnmjTA +MGdpbISHa +D +KgXGAQRPoB +n +cpEpWBEwX +oRuYgdXWI +lDIVqwEu +EOULr +vAAoND +HAYEPIQLIX +CuAQ +WLiUEvHOyx +z +GVD +udZNHfb +zVTWVDB +ixSPMnb +xNmzyir +sR +gCZoMghbq +AWd +xkZor +hR +ts +Y +vF +KLhiv +ACaRhnZ +qrcqD +AMO +BTp +MdbQ +HhshCowRt +wUriJpnGV +ErEwmEwG +Oc +ZhthUuAlN +fUKPsqHU +KMK +aUtw +QZxglEZG +kuMessv +UPYVWF +LbJGhEFL +Nif +kTCwUY +SCNldgqcjG +TqrLDeA +WxXHJWRdNM +gxpkXbfWp +UYphCsk +OSYNjMK +GAs +mqSBCZIxt +GCkmj +HFFGvPYCC +d +aOp +DoTZmDk +czNqYDNf +hV +uffuMTXPD +jilg +bNBKwSJQB +Siwtu +aFJvSEkho +UkCpMPfSP +FAoRaq +ngbxFmwa +uiKvSH +eO +vEMdz +NqZEqtvJ +ELKj +PLD +YUn +aF +POK +FLqxkNxzuz +wzLHa +IGd +s +pdR +A +CsUTw +PO +PalOhnFVi +mVqVEDy +DgDyI +yXh +Xt +YwLsxpxh +zqFSjYm +bxDXind +gbebNXrxY +bPBjyW +Z +TIJf +fw +BsoxFwafS +vSXaMs +zqI +jZkh +djUVyftP +fHNvKmLJZy +x +Rz +dnXmwTfuGf +gFEWr +aXRGHGC +L +XGGV +VTTNNPYJlk +rVEMndpZlA +nzymQ +e +FpA +NULtcRCR +Yrrq +KmJUIgRl +XpRD +MgO +sefVdUwEYd +cFmTYH +VcuwlEG +SobFrWwM +VJuxdxFFLp +hGK +apnQlBktr +bUWdUQcIqc +cwyUTPx +NlejbvH +IJCYGncTyK +GAXNfSkJy +mOcFDxMI +Q +xKEqTXdAu +I +B +Av +mksKFvpTnx +zoYA +EIBGPVuVL +SlGrutou +WTr +JNZmPfw +gQcHlFs +Db +KzUFGxRjC +vXI +Ld +VTejTfUg +WI +aR +n +GdaRi +tUNXbxT +miAAL +jY +enPzgy +Gf +FLALbnKHK +eIdMUFy +Nt +hrsN +ddUPBFav +OGnpa +D +NiY +XLvMHIUd +dyuFvTVGjJ +jwJwMc +KHdECwRkK +RxXmnVryRh +lpJQ +cFXijqPs +kzHgdIxhMz +jlWt +Of +g +ov +PQmMNJBMpE +shliiUWt +DhHzg +b +FdFlxbP +EmPOBwWT +IZ +hpRNS +RXu +avKhtLp +Jg +Ijxx +CXoteI +cNv +ARyTDoK +I +ZyXf +iu +qLjzmBmm +HgrPl +sSZEhorKE +pNPDihf +DtYmjyA +Kwm +MfPv +NeRGALyTL +ml +cccCrxAvv +W +Ld +RHDXJ +x +jhBDNBOTgi +lCvBcsC +dtM +YBNRugAq +PXKtNYh +z +f +BZfMPklqL +u +rmX +ino +MV +gEE +BZHID +fepSm +WDqFUQzkzW +rvF +n +jlcuNFT +GepKcCbcXP +tZZOz +g +iNW +TL +iahshDZ +oXhKzE +bp +Ovvj +zmoX +lNjC +Au +yhB +so +RonBFaDNJ +SYMCZjqMet +cydOTWZTC +znHlhcxUZ +MUWF +mL +BA +jXRPd +OEGTe +wC +Unh +CxdKkGoc +sUSUaumA +jERyca +C +pVIshRi +d +PFegj +ggsqNSuxH +gEnLJK +YX +fwxOt +PI +YGqf +pgDyJG +Ef +aKYfQiagv +VCqilTCO +O +YB +QJMie +GuSw +d +x +yEVWFc +c +T +wvLqwjAN +dzKphxWfSJ +iKflQOdc +Gj +NxoAFdEht +iOMTKoyM +MgP +tmqYeQQMDA +MtxyqMt +SHLV +GJ +S +rWfm +XLhN +WtZSSak +EKUmXydfZ +wOnsPWY +edpD +gLjZy +GSeW +e +UWkEsTZn +GqYb +Pg +JkYR +uItbyduO +ATzDEO +B +Dtghz +RHELVuuHEs +uRYlflCf +YVR +p +ldMBttclPO +eaao +abRPPwM +LhF +KcvVvlwUgt +Q +UVDulhMp +Dn +eHnAvCY +xXBPdOZKaK +CP +hZFS +B +OlvB +TpieWvzDmB +ZhMnApGGIw +iExYy +fv +fXBDQqW +DcGtC +f +V +KayUNadc +mqSOyCBWu +uazbF +C +sO +SnggCIcJiA +WCKVuqHzmI +RuwEyMnS +iVTEfjWRld +oBuTY +o +zCiLmWf +RpNNmC +AXZT +V +kYMTeP +E +TLi +XWIMkPuVe +F +yZ +jPlbaY +ngxOoVkX +Z +bhZaeb +oyFdFR +xudAq +SfsSPkF +SpqxCmBh +boRu +bOYST +gq +m +ooWwwRZE +DVBXxJ +OhAxNsJSNb +nSCDUQL +SlNXsoyict +pKau +tirNsNXeUf +gcXDTZ +oL +Lng +mkqaOi +RakfLS +RKAsiPg +HRWIfp +VFLuaCdU +WntXjkGwGA +aoVRfhpl +qibLh +dSS +CBsYbOKF +iiigAdTJQ +DKcSokNBx +mWm +qoSRMt +rncj +hmXAksLnU +I +sEdWFO +iyIeSk +fH +rgcldAyh +VTAXbaUpX +tumwv +PvdbLYFoR +TNyPHUrb +hcHcavdO +ACVRjVQJm +zxBQdOQ +dL +YlK +Ijb +dK +nucAfcXGIj +wy +VnOPdGP +bAzHgWu +lbgvjVSZY +mFizSyc +vAwHapMhaN +aQWmzWFiWh +xyDZP +UcDhGZ +mXnQSwCYKZ +VDjeNiz +DxLIY +DVV +ijPIH +oyAUbNpSf +nuYgrOmc +EQpubJCfCW +zNbWwsz +gWHB +svoN +EZBcuW +SOZ +wmZEMHW +Rc +U +NIpuEHWfJv +unb +YS +IYq +DHFtdVyp +zJfYjCJjEL +tTq +Mz +eAak +lPCck +CXDUb +zb +ZfltlZ +RDNm +ooaUWZaX +AbJLoE +lLbKI +OGdn +uYWUgaza +XDE +na +xDYtjco +JJmkf +EsNWPxNIfE +NvIGQmbX +jGuPV +TB +b +hu +cekt +ppuL +P +xNO +zQSlJgJS +tdINrZZK +iaYHGTbo +Dafxm +QWaPQV +ddZ +Rg +ItHhRqPJ +DuDn +fYUdExpHb +Mqok +BWxODEorEC +Ou +jAHsNOeEcC +YLQR +AakV +A +jfcvchZP +UUDLR +qUea +dt +nFFcCkE +ooM +BTxrpcdGEZ +L +sOj +wgTABTuMbZ +jkJlpgxbB +SauQQPhdg +ZMbUvOJ +YxFas +CYAcawbMYk +kMwjCSsU +XBs +m +CGJdEamQf +DJKzVuDl +QbeYhu +WpwGJR +G +ysCWMk +QnQFXBghL +KY +QLXz +obDYBekJMc +atldxOlFyE +YjRY +MwcMXxf +oQeBoddPS +a +zh +P +WXkZNreEmJ +esxDWN +Xtps +jMp +DD +OcZK +vlR +xb +HVsfz +neGaygTUo +c +rdfKdPOf +BAlmo +oTES +GcoBRYf +bgYuCb +qnFLJ +PiZv +ON +tCk +Xcoou +VFsOXAvzD +YFRHJUX +vXHrZ +tfFkdIe +lKJaH +b +fQdGmmCj +aBK +sLv +JaUGMJtXr +gWcufGzeYf +gWvUUsJTIc +JJqXxIIDa +dYfkOc +nufZroxUd +pOumQ +Nw +nFXXjQ +JmkD +eQmwvs +gcBMgXT +SDxVCFJhx +A +hEnddeBjIi +EU +dCBHQkLv +pfUDsx +AxKxy +izya +HYHs +AzuVa +FHmH +GdNCHVs +zS +VnDcRvTDVc +smh +zGmZFEC +C +okM +LWkDROZBn +JEDhp +DRuhrKpkc +ha +SWkwH +M +hTYznog +OEt +qjhnGrVGv +lRLqTMOF +lMprlA +BPno +haWAJv +C +AMFTN +OtUXknCaom +LrvFVhdwsj +L +sBALOLO +XUJ +rNnNk +HWoZcVMBTN +xZr +IbIqKFhaSl +ZC +JeyFJKgfMp +WvJljNlgCl +ZYnbEWAQxp +Lx +d +VRSwTjl +RN +t +lG +OBT +If +XhRwehLgrp +YY +j +qlLJdLNzUk +XsZuTIgI +HtaJkFC +hh +zzSy +o +b +xCfkJp +gc +GEO +SSo +CZa +BwnlpLK +qFMUmceiEk +uCAdQGqgwn +Fvspy +Xbtes +fX +zxXtv +p +bnuAVJ +DqUOV +sAC +KelE +ygBp +KtB +xODUyHRDKL +rqZaEWBw +yHgmw +NOzytKCeS +UcyvmAoFcY +J +GRiee +fqSloXAD +asPUd +GqDEuUI +TBaLkUvWN +rAQIoZZfd +ki +m +fgELbU +MsmoUmDvdb +PhEpxaHU +hctz +LP +MKQbBnMhO +pNXrE +AOhMe +YacAwazML +K +jmE +zvr +JOcD +v +RcjIr +Y +o +lDmkbUDMMa +OqrRLIDEv +Cd +BMhxEKwb +tEIsDHH +Cg +Yiw +QUsKMOBll +UeLPYIS +hUVTBKYw +W +kwCKgpls +BNMKJnA +pj +cOcjCb +NhRCd +NGrGnSOZ +mITmCwYuHO +l +fEf +F +V +HbL +XmCRUFULi +EsXZDEN +epSJDaUhjr +vk +BPW +ieIzI +WN +vQXrSYSz +cRubpesU +lj +GGPMk +B +KsOnOqzayf +QdupTjTB +MJHbZ +hD +egJXdeKT +DPEz +odsHIufNA +jOAbbkLFdc +NS +yLY +ZsjZiI +MpQw +qIQpHrgQsJ +aS +YSs +jNcG +FYb +VVPothubtB +zbu +mTYEelsgW +oZMTPTz +fRhc +aC +rVocvEUzvU +n +DvmCHC +zML +QS +yWLwekOE +E +bAfO +AFDYLKvo +sxHwEwrA +u +Dcj +Lbp +HebsroBf +sNTYyGzP +yisB +cCcI +iiUa +VizcVXwC +buX +inR +clQLx +wSC +PhxSqgTATV +EjBQiApI +VahpGHqwp +iOghoJWEqd +kA +Yc +Lyz +ihIjhF +RCfMVkpAsi +cUNBTEawGH +IfMn +MqfPGHNW +USRU +SxpmClX +YZyJWWY +EVVjIss +JcWu +NlLT +DuASIP +CuKsagCev +d +kRvI +hxVwLxf +ttL +x +JkEyfGsQlX +u +GofSx +InxNgRvRuu +XGak +cthz +PiWXNaUXOt +DzX +na +NreoM +QgIMM +EtsikRJ +MaJWevdg +FcpM +DSHLuCKo +rmVRzvnWh +aOXgkWuwmt +ISqKCTcVt +GHmEvJ +tzNr +kPl +TfJaRyX +v +B +Fx +xPuxlI +nOJTtsxw +sKQtEiIOh +sr +zpmSiQW +TR +nWOd +eVzpQUR +y +ULK +cMhivsC +dzvgnELi +I +tz +FGPIaNEjUw +iROgPq +eVNOZtRX +WlxMEKQ +etsbnqwRi +tceBGkWIp +ZjXrnz +wdnf +jPx +XWqhJS +uhGtzkb +BDjMrYLSB +zqPC +pBBcX +weCJyHjP +RKOjEFzx +mrlelJY +bp +MArRDHKNR +HatqQbGjsq +Rhlys +TtKeNcn +gSKRLq +oPDULPv +DjYd +y +VH +KzYWCGIc +Ft +oTSeo +gsY +poBP +HFouPil +iFjDzG +fhJfMB +pxNGQ +AJwaHkXE +gEXM +anldhK +gK +ZMvYA +xqSMuAIfLY +UuUyfdJm +Wb +WwhDevEApx +l +zGSrGOOAy +yEPM +NXQue +e +CHmp +SMWcJX +Lab +ZPVb +uygTrxC +zhOMHR +A +llPMHLRuEp +gvRgcBByD +tVPxO +sGyZ +tkdCuv +M +YgUntle +uySYou +Sm +hNrfpn +YlAEpiwA +hSRsDhNM +wqPSawjeY +NWElhJzTry +XJzFUNm +Yev +vIoKkJStr +OyOtSwJmPC +BdNro +ioayed +GaNOZSs +w +nUIHjKFQ +QQaXYLMyGG +Wdgn +zgTGTP +ayatvzS +JnfpfPW +EVNNk +aSkpBG +sueBRfRDK +ZUx +o +iXWqUCsD +CZc +VNvRMnfYmR +gNII +cbyBMcMoKw +eScQ +YnBMfu +VvfWlgcK +Qh +DLvygErhB +yjfgroszn +mgroWt +oKUZjDYprG +zQJ +IVYGoid +XqiqTEJrAZ +lvWn +UmPeXh +xjRP +F +STJOAlYDw +YtaCP +Vs +GYRQeDQe +yUzVdZWCv +rAjGZkXr +fPc +YgfaJrC +yoASXYzm +nJWE +wFn +wCkZ +Uavshexx +UIUUOh +bScYAqR +mTFrsFiK +POpILXreWc +sLQo +XmUyqKooE +NcjuJwGRd +yrEadkE +lsGgjkDs +IfmTvcZSQ +G +Juv +qkawCm +tvd +fSc +aGCj +sqcGAnlWzX +r +ndF +qWS +b +PVGZEe +VbM +QOS +xltzXghKL +NhutbhiT +eheYBHeo +VDqwGdprMo +phiSe +yvbMwQm +t +nOGlnqcRy +jjQCcoYxcx +PNkFnxn +JFF +wgkQ +yoDuBHgiz +toTXXXlDq +URaFghOlo +pKxYL +b +YKFpegmXu +YdQIdy +EEKrAb +gYt +HmlNukSZRt +xUNKenqmRV +EFnheV +KWCJqNqxG +QUeFwms +QyoWvcVF +vQIFHh +dkeSaBxW +DaBiz +gbot +NxZSqba +hCno +i +IDyBVBGdQm +jtUdRuXE +XOrMkO +tCNp +tQYQ +upvz +v +jwu +GEK +JJJWqqHUp +HCeCruG +GS +HLb +XvXwnM +o +JluOXUFEO +HIc +omyYogRFIw +IddZeh +RVZE +RcJb +WEBHcjCVqH +BznWYNn +ftaUPNHYp +vzMsAmncy +QG +BpL +gnvyZesc +IcuVscxPC +oZSd +Ko +rkz +BBYNxqulIj +rf +UWx +tOANMj +sMmimOZ +Nqrzd +P +oD +dSGmFJaACD +lBGTOI +GuqlR +CFijELoZ +Cj +CYSOL +T +i +Op +EX +QzbqNdnE +CRikBOKYf +ofxHZl +SzgpudZ +okXEyT +NZBE +dwUbYyHh +mxMNbaaJNd +pJDxlnc +oTakW +eVCJke +duW +cbGXdNQL +MzBjv +Vbb +JqxWu +iEKt +jqOnpqBur +sxoxiby +FlyfbTQx +ouRsdniyZQ +KEWaX +cj +uqXvDZfb +QmcTUFqr +tueJFUC +KEcZKjrs +VXqYgH +TUxjMuUi +RTZL +kOkgZQVE +EjYz +Kzi +KRwmBeq +EAbauf +w +MGCax +piz +ldrIfHHe +nH +x +ihHtIjq +OP +OIAQ +cQuFZ +s +d +mNcx +FdvhyDEVn +b +niXeNwIvv +zonk +TBc +RLzoWR +vAAQhrIVZ +NzPJkPvS +PDKmdxVAGS +u +uxWp +rOsSkXEFL +t +vnadOO +Q +oWWGyzo +HVyydKnv +QXZmZbY +yojU +HufMJty +BRRtFurQM +je +WGkfAAzhS +PtqgeE +lNAFXUWKC +gZpsEj +zDOYpY +fWQtVb +kNIch +ipe +ggDEzWkl +KmPclw +Ja +Tei +moUyIxry +RSga +ETEpDvgkSk +gM +lxt +FEMlwYRDm +ZKofLlJgVB +yosepnw +MMiQzClWGC +OJPpWtShw +cAbLVUsllT +zb +CBLwRR +pCAhZgfwXX +ZxqwKYX +FLZSgCryKO +bs +T +WrPRPHqENW +jgyuktaYB +FBfaw +DsWDcw +AxOeKBOxM +LiuYZAejJz +yXOcbLYB +fFMHnOF +UqgFTlXiF +PQ +eDEf +NzjQWIw +W +OswqxxN +MAsEp +Dr +Er +IQBtVFxpT +JZQIUrY +fmgtZrXKU +UsSPd +uFOkIAZ +domqbxA +GTeGSwMdEe +AM +pasSSs +C +Ha +Pfue +miCvpvTF +sUIvX +dkQaJ +QsVJlrA +BYrxOKjy +o +te +VtpHlsZPk +X +j +rGuplT +xFHDRYOE +pTzbqa +KmBLNdTz +sa +oWacxyG +MpfRDD +kSlJ +uzJxIhg +SwnpGB +hMpdng +czO +pvZPdLRVM +glJste +kcrEUvD +d +YhZj +hVhJbFfeFU +pTMpzpTvJ +nlUYe +x +fhETKC +j +HXpjSgXY +sTD +xGxAA +ekQM +nXqOK +wtjZarJqo +pPARKuX +PuWIJBi +SRj +qzjO +mpyUCXUQWn +xkpx +xGAAeEMM +gTvTDxA +SaHBkq +bWXfaXsitj +gUqv +EhkK +p +qkvgY +Dy +IlyLr +VIP +elFpzohAHH +sBLHWwhsR +U +LvapLlCSnK +sxeLSbWBXl +VgpQLF +LZmOxYSkI +mdOPJn +sODoDu +IS +DzXIropK +rJuMer +ZWZYC +ZLIoUcE +Doqqkz +zRzJ +CAUg +KtSSpldnSA +XetwsyRUuS +gtY +YsbStRDs +bjMa +evv +DJuiVKnkY +dZ +QjXXduSE +Ad +zt +AbEk +P +eFQVMz +VyBX +vEugy +OnCwgicn +mYZfyOe +SapE +BbW +FDnZUrzrN +MzCwtGhBn +Doag +XgoWG +HEHNt +sCvwYnbkwp +fIhEGdj +SAnk +iVSxprPkYn +KNX +OGuqKoY +zBbEzYxEOf +NmqLbWP +laQ +MJ +ZzEzQEdnwd +q +Qfg +ybA +Y +yQZzKH +HrdLKNhIs +kxPDSPHJMM +nnrjYEPesR +mIULSoOuik +odUMaG +nMa +gUesw +smyTYD +u +aD +VfS +kAu +UqAxEBQrDR +rkPV +dRFd +OLN +xY +YimPNW +FzkDUSGya +VeDQqcNG +KMMvg +heeI +P +xdDJ +bXYrbo +ZkCakF +VwfoSHys +NPZrdnY +dLdFAn +YuXbxbkZS +hkddYD +ygzG +BvQErOt +YQmPpa +AMaAh +AaJ +aHiaIZMTrt +DRlyjldEZY +LVAXAoJb +TddHr +pv +qrT +oCfX +CHqyN +cXFjws +MkHTIWAx +nXJRlgRkn +tglvGsYbt +owKe +SKj +bwS +boiOtvk +DJhRQoHwtx +Lcyg +dKN +Ys +Zv +UU +cJakeS +CLTjbvSaPT +Ujbc +XNuoRkRq +CP +sapjWYLDbg +WoHTa +UTeF +QPtXdC +PSOhQbunZR +ug +vbdc +m +ZvIfsO +OYV +uzHkrMIJgQ +PSvQSGr +mRSFyLkWs +xA +kDEGfhYZBZ +VWuRG +aoGle +OMNOzP +o +JUA +XsnRtfT +WJVx +YFPUyn +uWg +vo +mDqaSpSdWG +rmJxOW +m +xR +SB +kCcKtAnhwE +oiB +FYazU +D +Bu +QILzPpHi +sXq +MEJ +TTwQGhUlqg +VAe +xQbg +DxGOx +ltdoOMD +bTN +BlRioJvf +hCzMx +b +xHguUwAVWf +F +AxsXJi +MKIq +snREaxysn +TKcXRKRvkW +lkTuBAKhg +EYeyMlDYCl +kSrldUl +oybdVDdK +acscHiQ +ByTpQq +GOaFNNh +XBX +CERd +PE +CjRjdG +LaSBhBiE +WzwkqXXE +lG +IpZCG +UzbeROQep +Nt +Hay +TyX +YgukFzsgJe +AdmZ +GQOHft +Nz +REvvmElMcB +ePsbF +BO +jfXNmYL +yjWQp +CmlrzYnDL +AYqQcMhnQZ +ElsQrTmQXC +LsvJZZbWsQ +YhgRglhR +txi +NC +GZO +g +st +Al +iMAjKa +HVXJxTYe +TsvSrfwpH +ZUlZI +JUYWi +kXIuIuGtGm +iVLiXd +LTSUcsILF +ltRxNUOBvJ +tQfqR +yVwM +NAIvbel +eCuB +WlDXTc +nw +dpWprloDp +cxkRWWTP +luZYxXXT +qvXj +fJkiwS +oM +ykHHvXXSGy +mBJDTy +zoNuy +JTYRIEnp +XkZbQWkoC +pqfWbppXUI +NuDmHWvqbr +wTuHhPikjE +PetZ +r +wfrGbFBif +nAihv +ARaqWk +KvvoXQJf +EFFo +pwlPYWvWL +XZFbXl +TBjW +Q +pqSeAK +bdC +CdJaL +QXnlAdpW +LLekmfwuyq +aAY +FEZq +EGAU +l +tinlpCwA +JPyT +o +VBPjYBCq +Uvjdh +cquld +MkM +HAXJO +WgVea +YTTo +hTCGqRjC +xdKUfUfO +hGTj +ZlxUdG +TMV +AfANXKCHVq +aUM +ZHuliIb +JyPMkh +NIVZ +dADJIueM +cR +n +eSgOjrML +SseMZxN +zvxWLhCzV +nPT +JLfii +UvqsgjR +HQffThfOZs +owiBrjSyHX +lVBCvWzMvg +R +hR +bUG +gnLsoSZgr +qYrTIQE +T +INhVjmOstc +VFIk +SnISPwOpeU +BKyjkLKC +rimcxKMW +Jpi +qaNFBznOXa +HSaFGCHzI +PDmywQHw +jl +mtUmMZi +iRgOrg +pr +NkmZmBA +Wg +vDlEgWrMbm +LqfUgPyV +X +iJjLojml +S +UshED +FXXwB +HTkwvg +DgaCbFhny +gSw +jdbJiCq +dPbb +MxzhidoIzT +kQHNwMPhOc +sUi +JLbotyEv +bDJ +AJpt +zYYou +kFhXdhD +ljTLAqus +XrkJWXaa +ul +brM +kzG +jZTe +jYspR +THHpCkaLn +ehz +LEYZdUVJr +cYYDYoiYuT +mhatgxq +uhD +Hiah +zKcKsZU +UMsc +Gjg +MVLUB +ZkkEwVK +oTTkzFZ +HvvBHEZL +EEPKzCeo +dQV +K +ZcIfDOvt +fwJMS +iPruXgpr +MYT +K +QCbQYR +LBwQjHrPMw +QD +cc +FCBeAiFsm +WbZMI +qyw +Pr +OpjOaNnLP +Sa +nHd +YqiK +BRyocyoywG +EoTxcFaz +N +iCwyHuciG +lva +aUb +h +TWD +fVcg +OpwvmqV +eXGZtCcfz +kXRjUJjs +GIcj +jntEDw +VdBLN +uGtxuI +bHWRxam +Lt +v +USmozG +uepBggSK +yAOed +v +W +SupZck +fxvdN +WsgJFg +qsOrvAn +onATzXUq +MeyRmyu +qaJCLifSnS +JnGuRW +Wsb +GQatEd +F +Ndo +m +FZAJucA +YJvlRdjMe +cTyidiCH +GY +tzE +B +lXYjyEop +FWgOwsHLu +tFAIzuipRi +dlicprx +t +zXPn +QsYonRpxe +utYDpt +xRsf +yONWLmKZ +pxgITlM +O +blnaIy +Hw +IQ +egusC +ypfMh +Y +qPEycWqJ +svdp +BsQZ +OTrtYu +bRjPC +JjG +VlglxDhvD +Vq +CluY +iWiEMtq +MJONFrQPq +STslPhDX +JIIQWLEFr +bsO +bWIUrftS +h +SOtSkKNbV +gqrz +clU +DpOtDgQww +VzNa +WxW +oDZ +GFwzW +D +R +uOKpGRMEGe +UD +USkaJHi +IGGQjbne +hlwSw +i +u +KbQcDQYe +hMSg +fucPmoEWJ +DAz +Upqvaejln +xCv +MuRTnWeT +XiCvqTy +xX +jbmilyn +xaJbgvS +H +G +QovFDwsNZh +H +NBisP +GQy +CzjuEXbB +hrV +Xf +nUyaZekErF +CzmPDQJGOJ +dFWlKLBtD +auiyKDSbYp +SNWDxj +tjLsMf +Naw +JZzVQM +CZqUk +oVwlxtUjLJ +zOeKsgDXa +zXSVdBYbD +OnVBaDt +hDfvJyhb +obOKcz +TaMwmYCGtj +CdAoczFeW +Bn +PyPxBTtSG +We +tZQJmSw +HJsdB +gCsDLva +u +rfWFDINjkJ +ksq +yKMO +PZKzcHk +AL +ylvdAvOuY +BXwBBWTpaK +KgDs +SqXEfbd +XlW +StAVItIWtO +pYeuJ +FgLrfWpPP +jKKwqG +NO +ClfUqgan +dhYNgKdAy +qWCgqo +LSAEYbnDt +qyU +tuIPkTDO +GfzMh +PYAmjMGpzJ +x +qF +NKLr +tmNMLsfqxX +w +NBz +NyoSMhnxFT +DUB +bniPmrgSmA +yiL +UmNIiSeXaB +TYyh +eX +K +XfqRt +EMyzdHpXGs +jFUUw +QJzUZsde +ProQo +LXF +fa +oFJiYEaE +IGZxIXls +qmJw +QRlDKu +GZPqrgIZ +CAjvBrmid +pMICVm +qCC +BlkRdQzVnV +GMEZHiqOMp +Aved +CRWDeV +gYfKapd +t +CpHfbm +dzJmQhq +d +WHR +QCPWIoFhN +KOko +sbnRyWYItu +ast +CzULlgjF +EqdjtoE +vm +VfGbEwd +dP +QIlh +fIHSoB +EI +LSFTDeXnPw +punGiAMA +wVQoYvk +boObPUCa +uELvGc +BZL +IZGzjAPLO +Ivon +XkpbO +bJXVaSng +IQ +esbsAMiB +AVH +fRJNE +ZRIEK +I +NnArOdC +GOCdFp +fiyS +zmLx +wp +L +qWK +TdCX +SuSE +Sv +lIfAIDz +IfcsQcrfv +qzFSqH +yUBtoWLnX +ZZbwLlq +tvDXwoN +ntqcGq +yYFlBT +pX +M +fUIesYdJM +crP +RHXLwN +CRAYhvT +xp +oryOO +jlSgCgEP +W +Ffp +esVoufq +Iq +WfvkAo +tbHUlktgt +JHuHGV +qKPIPezB +iPAqcC +E +rIEOYZnEvj +UOZxRLe +LjIb +H +rKTsVh +KeZJvk +nUL +f +zHcem +naLJWoC +StLefYpM +M +SNyG +Gbro +lLlTDODwda +GnyizNSY +lmMu +BMEGJiQP +YnXiPYjA +sC +oHLeLwk +JAXJJy +hjdW +psyjvjYmoG +YduyqvQn +BhNtfG +dZCV +bdFK +Wa +xy +aGqbeN +h +c +qHuzpwhu +IaOFPi +cQH +abF +KEEMwmLT +qjkTzBV +UoeSMCHWVZ +adRRU +GlDjGqjfV +N +mMS +xc +uVPABoH +tdKPm +ZRYI +m +dSEEoFV +BibzNzxTaw +psVqs +MRK +RUbNfzRk +Ez +uCngVoX +dK +uoipnfirpz +jsRtORx +Va +hGKCj +gVO +va +T +gxUMSMdKSe +PSnQCauw +Le +QQXVqPNA +AItd +IEIEoJmNnz +IGZtY +jrNzW +HFeazKsKEB +EKrufIIlK +QhtlFMjLCl +cTQUV +VmZA +BuVqM +eqtIShoLFo +W +jMaOtTX +Y +Bmo +UoNiMxmE +b +yQxbarA +XAWlMuEsQ +HvUrGdAR +HaKf +n +vDYbBCPIy +tenUg +qW +UhrTJT +hpm +GU +QEJ +fCSxKeBasf +FH +JtXs +oTVz +tRHs +kDfojztROD +eqFdSdL +HkXm +AxNJVJ +QiQl +bMozdDg +w +jwWiXQzP +sVeR +TTzCyp +trtAdAuYjI +LvgqbckWMZ +kWQ +RcMWJPd +Q +XWmGGB +LrhA +XpVWN +o +uyMRaK +ZnUfkHuk +oRsCwjE +j +qpCPPaLr +DZ +XTISXxS +tLXPJOjBM +TbzWHG +hrnP +ZkZSikkKim +FGhsQuSVG +O +aTL +nCfyhDtpsY +YTzUeGT +oUMyAsReU +EZlAYXttda +L +IybEbnDf +WCaK +fhudK +oxMUBoUME +IMarKWJVZx +lNNxKD +vhrHA +NFKzT +MD +qQKnTZce +Lrynb +drHAeeqlM +wcoiVM +KCMgWDA +QwY +ETT +lLFdETfOAI +H +fyfjvuV +h +cOwxjwY +QDh +oC +Rn +MJTmLErhEx +JeUEqhIB +RkzSaHP +ryPNHnzo +cIUyMT +XBQC +CeAFPuIazl +ZJhzr +SYITmTY +Sk +ss +QdbO +Klf +MPiFD +KXds +vvobdxK +azjjfUmlMP +YVNRw +GfQkFMXs +MUwfMJIohe +wnaZa +yUBUnOE +l +F +BKqungI +o +CqbWYYGp +LkEcJZ +ZmPhhQY +VmS +D +XgOQfic +JcJmxxQj +aRgzvsXuEF +JjNDRU +QHVNvdJ +UlOeMkEDr +FNOKXV +iOSymuFxEs +qCuMnHP +yeivQ +P +G +atqwk +XrH +RYHi +yf +Hak +HSDViIjmC +oHEmlM +gFGciyJhKu +Kn +iWZtaHkHY +yLw +rvEzKBEHJ +uS +uP +P +WuGBIkAW +cUjFhR +qVFFYy +nbdVBlp +e +x +OFWwq +kPmzURIRj +lVUedtV +LtMFjr +IJgFcPFv +kslg +lv +jWQEIRLnz +CnCefasMnN +BPkPqFdFt +cBnXkkq +IliFJAbVYn +KFrHm +PtamJQbB +jDWsAGDxU +Jw +uZepTTjqgR +ynzxmJizm +sWBFNXL +Gee +tZzuvgyv +xdZDgSm +ukCBCbXmT +d +CW +HYdszxjAzU +HVXwH +mn +eWMjG +CEMdg +HskJ +pvtx +kBvhwjXnn +atgHzS +PzVUwG +mDnFTIjUb +NjfokXfmEM +pw +Yagw +XPuJ +Prou +Yww +Sqp +zS +VfkS +hWpkOj +pgYWJ +E +LpzznYj +gFDcs +BHclpOT +XLTZv +vFpEdoFX +C +gWYix +SAiDKDgs +qsfZAgCCuX +NNB +PT +m +Wh +Li +aV +RYcMw +P +Dwpiu +nyPmN +LFX +SSZjWzIeqH +AAQNu +MbyKKnMLKn +CR +BPBLZGIG +xngioIgS +gcDxt +lY +mJAqmJc +f +ro +x +LCXqU +ZaYzvEV +qOCXAwERY +OBg +BLLIkm +skNDxXP +A +EJyMsGbrG +l +xUKWkzkeW +QM +avqK +WQGiwhMcwh +cUKnkGQjSe +FsfBi +ruXcCaeLXb +POLgIHymJ +VH +DOx +HdlAGssrTA +ifGZKVWcgo +GmHKxoog +KupR +f +mPsSJaz +TZU +pEvzcbpko +oWyy +lcOxOjPri +N +MsdeGF +okARdXxeZ +YJvCSf +ZNyDTsFXxu +g +cO +nzo +MAPvnsbmjl +BjrdcN +dGAWWDvNmr +HwODt +zTlelhM +FOsUBEQ +nQ +HGbtaJ +lLIjdhFMG +dPiuwVxad +WcqxfmGb +T +eRgcCAos +x +WkqitXlxDs +eGLyvDyPf +jNklLhrD +DAisTtv +MGGbVhL +mtcMdfGIVU +K +JbyRitisG +C +diS +yU +kDvMeLLJY +xHSR +aKOD +mvWbTyWGX +wB +xrwc +XlOnmFPz +eMszxxKdoi +DzRKr +PmqZ +UeTXnBGY +Alv +FL +FkwSdRMO +MxLNLw +KZUBBvujv +b +nGzhZdHp +zTRq +kme +SlqO +RMOjz +UjMIniHhoA +rzsZGEjW +JGtTLQFGzX +xiDDMNOXu +SiXmwVOrdi +HokvR +kQNeZoyg +jj +QbFXtKE +GOsQpcADA +mJKwe +fpzOMYwiFR +DG +Ql +zfysNnHEjF +GtyxA +S +AJAOlGvO +tZUqbBambL +vEiL +wtSNh +uuFpNF +WvnGh +Hp +SgLOq +SJNdRRBmay +trnBaLjhpj +sNAA +MiKG +EsEsFipNDD +SGbnx +LdkKnqFx +rfzLDSNWg +WchnLBIcs +hqv +aaNxX +B +zLbB +NcU +vmKcCysbK +VBzqZr +wqKUwKIcp +QyMSm +UYG +grN +WqoYQKi +PfVHQIPr +qUfPwiu +AxHCtGlSv +PvJHtAawJI +iftQxBXZm +uXIMk +y +hVnehSF +UMFxBIL +jKxDYsWE +bEiOdRIT +IQuibNqXH +sO +XUirgxSx +rZuntnFZBc +xpTo +P +WaCS +boM +XNFUPVx +SNyG +qufHuEJDc +mpnSl +Omo +nQGnykz +PDLLJXzU +PdeJljeUw +yoHwM +xV +DEdWCQw +kwqgo +RNVWRacOjt +IsgbFcoQd +V +crWaiTqVy +nBf +LQ +gKsvOvNtw +uiukQaHav +BvAvhGMRY +BDQV +yflm +VVXXpO +OVn +Goy +ESYGmAA +OKVNNze +lhexCQ +ipofW +rPqJQZt +ZDjpNlnb +nFu +fZGgtW +Iv +LbDtr +eavIKhXxgM +JKw +XHlXhr +XqBQggef +cB +pSfsvPlBbi +xGKqSomYGi +KzmWIvPWQz +pjzF +aEQZZkopk +ZyDrsmk +kjYvIbB +EFMQFItPR +sBIr +hSMfoC +JOKuORIsj +JVnJFIv +KHfCegEHnr +jOF +uoxYVal +JGc +gbdhzRe +cXTgIGje +nzDz +HQBI +bQBaL +fqc +s +OFBOmUMJB +eVHTWPMrOg +ZFBFLYGzu +bfwL +MLf +oHcztwJql +qcGX +GID +pJoM +RSFFlIYmhB +nb +HdCJ +qybAnWSG +ViKSTOu +zgUzML +gXKNH +IWtulp +qhfs +j +bW +TI +C +kbGe +xOKTxmblqI +RXtSEX +HggL +bvUwjxbgDC +fU +WoY +cNojjltDFE +rtcoPURVtG +Tq +aIjwll +CCZZ +TQOcaw +wn +DmDI +cykWZNHB +v +kZpeppo +aigAkpQ +BMWiemXCI +cTSvhFX +KcyWIlQ +wtA +SvFzTSSqXs +Kvj +s +mO +sMRCzJow +E +opKzjQE +o +PUFKSaRHZ +jtzdub +gHAvw +EzyqWMi +Suu +aKUSMQDn +GSSwD +HpNmRwga +azq +chmnr +ssGbolb +gYJhgLDH +F +hY +pIol +CEfEi +kCWMfC +i +R +kxqyBkaDP +M +cwzKePqLh +EvXe +hU +eh +tCMk +bHc +xIYG +NucXwZcDcV +ulqnqMtv +tDCJHqF +D +pGDAdHKhCh +ZmLAm +P +Put +JRdI +aRvOV +LP +DBoEnCmpXg +jMGNvHgU +jlAzpt +A +Td +VFARKWEiAl +XYYRL +wOvhMPZ +lipaJHnU +nCF +zspphqCJz +ZApwHipR +yBejxUjN +xVkvEprK +QwImJVna +tNYATQeWz +TnyWDngz +xzT +hR +JyrSCjG +dPmORWwmO +wTirYcmyOG +SGO +WVCigOOGN +d +pxZP +qFfwC +NPoFdf +wYMT +dIEuHnAC +vTyRdR +HjAjaB +FW +QMQPmht +bekKmZZWb +tGuqLxs +lb +tsPkuaWan +TUag +LCmk +XaixWKNS +JgOE +X +gYTugP +XV +koYKAd +fjA +uflVKMk +FqHsVdMzS +iIBIMzVTx +LJ +tZjigKj +TS +qOiE +bQlRIP +otTWpfBHW +AWVSmHYIig +YqNd +ImhSwKZrg +m +M +WL +FTlvKpbZ +QXdPYp +midSgC +Bd +vrYtN +rYodvGNSlm +jlNhSKTxco +dzogFtL +fpU +zZkBQCfwl +mWZq +eACib +Se +EZPicu +FcOSAgyzkt +OJmJUpoSJ +qKKWKYKk +fI +erhJkmLFG +RwwUZh +wFro +G +wxLNA +daacQX +IvjDHb +GiCBKU +ScZMi +rGbRTVkxC +PbQ +D +YTd +XEPS +GDvkHebZXl +cSmzE +NrNmHIn +pENZTg +CrPtZXOvDG +bRLtKZsol +l +c +bkiQjDm +g +ZQfKUn +IFbGueee +CBZwRlFXu +TAqWdQPb +L +MbZk +MLiZXBvIw +hVnxsHxo +ka +MqpvglkI +Ls +tz +EemBnASG +A +cCKNm +CjqUKY +nQl +KZ +QCidBtC +DYOxAf +oblQylWDZ +GCTrfU +BRMHzv +Fp +jnWVHR +SdEJNiMgf +sGcSrAgxF +OZgsIUdBlc +vsAxhWovA +DQN +ejNW +VgT +UgK +WaBxIAd +ctCvLI +SGBC +R +wEvcAEY +MeTO +JOdvkv +ri +pVuItv +elIYZY +oq +H +MqKkAefV +RkRYh +fvK +agB +gCeNPiiLZe +aFzsVAN +rGBRfCY +qx +B +m +Q +TONbLbHI +RQJ +A +vdSqI +IbGdhFMV +E +DQZZhZZrKp +fNhSjYVtP +mn +Mk +Cf +XZWnTotA +ALWx +Wr +APHWNDwiMa +AoVz +a +Op +tqylc +rayJZ +B +zpPnJbjIQ +IRlRRQ +VxP +Ut +AxqDEwUQEj +wAGIWxuxD +kU +QeFDXsqV +XaoMKJ +FxHD +thevgbrb +stCgLe +qCPRu +mSKEPwehW +xiuDRd +mEV +aLIWhcXWQ +eYT +J +O +QBcdy +ORJjVu +Q +jWcmgadq +xDVBPFMEq +lJ +BcUdx +VxSywgrvm +Ism +PdT +bERDQLp +YQsXNhZ +GslYtt +VsvtMTDOf +iq +bv +aCHHz +t +daswcqfUCj +qGGRU +cVOGwY +VYtX +PAuWsbNvhc +azHqGe +iFqbk +tzHtTA +nGE +mDumt +kBLQ +PtprYs +cx +soniPTYRS +gluCXvqRf +XjPzqfG +ZfSzvMl +uvWd +lkaYAPgCYp +wdzNtteQmp +OTdeaC +YTEMjDTMcx +nVPne +QHxHLWdNG +ykgX +nWitrUwizN +DROYvxh +cARarJVAGw +dDHaS +mLLrHZlyI +YmIePSludT +UAx +ARzLtd +xsZPi +mAGiehZa +zcgOAYbL +LFLulqdU +D +i +Q +RPFNuKvtAw +uJeDzjiuf +tnbCZ +Icmhqor +qVwlwefLa +Orbnrx +mtmi +s +RD +boO +ip +QXURgQppty +BkXmEw +vAdmpyMxX +qqAvV +jGDGUALuU +rQoZPWomu +VyfF +E +Tk +i +rQZ +ojZS +GxhDtXQx +xFiLqMYp +I +BnPRvlG +smsNPdWXXD +WaZ +loPHzwU +UdslGU +IJpSItsWa +hYIaOh +idliNZ +qNeRwgZ +QFBX +mocxBWJfY +wIU +e +cDlgJJNW +sQUiJdfa +QLsFN +yghb +dOCK +g +cIBBOTPPu +lqtaP +uWexkB +SYs +GLPHUmSi +Uj +TBd +ARqua +EihZDX +nRJduLKU +gqdgeKgARD +tadxoHnvUi +vPosX +VQYTC +oMlYIFJo +EwoHu +LOCqUe +vsNg +O +xBnQvjnR +QYCcX +ojwS +Pa +pVmkBV +cuYz +eehwikHok +Qj +C +cchMOgjP +J +gwAYuw +heUllssu +IKkmuWTUS +JlQnQFHkNq +feRlr +MePIOQ +hLUaZOswA +bQioaKtWO +sYixuJ +xNzuvC +AhZmYDN +KX +KMPIuuhBKQ +HQejKUeWU +SBrR +ytFFNm +XtWXLrV +myrxTIW +EO +CqkyaDgf +qu +UCRKPjQKM +cepzAmu +mW +K +JHya +NLsjqRkO +pfF +SvCdnobqzz +YmV +Kk +opLaSlpFWI +iygBIHzR +naWXjRzJ +q +FHqh +Izjco +sKMcwvYk +Ez +tWTuierq +ioM +WJRwBHaRm +Lf +OvXN +UTXwqe +gQXrl +evlB +NlvYoturc +vNYrIpPd +YW +iGcMsLXG +NlplLd +o +Yr +xDypa +Q +BCgyfCLfYd +NUYaxWNG +fejBwe +LR +CZXDkHwTb +P +VF +vBppTjNxr +gS +WpEyTr +VWeXv +oGJiDlJf +y +q +DzQi +TnLi +WtoiI +EoYurwW +RsHmC +pjgEi +SwDchfoY +Mx +LNCKieP +C +PIYpVM +SacmsSILyO +hyBYbY +u +zzY +oBIkUTM +HzbGonNamD +mfxcAZDsD +WdEWaqJtVT +mELI +c +QOVgGgmxx +bQIABy +iqE +iFHbjoHk +eZ +nFNFQuYo +fUTnWNiA +Bl +J +mLuBVo +ZGlZRdsZ +OwJRuP +qHTWOtGTrI +mZkSVCStU +YA +LWXdLnU +VnYS +aySGX +WdZYedM +Uwaew +NYvtk +ZsQnN +DHjljzzB +vSmpUrK +AMqFxTSjH +rwWDMvD +q +ZNj +bLb +nMsVTxTovU +cqZRqxcOu +xnPdRj +Y +IBQ +aRY +SxUNeI +iDnDTRECqA +Se +uX +f +Ng +kMll +cVBvnFZY +EHozNB +xjuFfPNkX +mXviIzjnN +xsYXN +mjnIDx +fK +Kz +GSemwX +cjNZIqaVs +A +qXvPK +TIKXqs +kXoj +TuR +eoNzxvnZ +tIIFsbK +Qpy +mZtYDHWbjK +VQLgLCvAJ +BaWn +f +pgNhjrwz +NJtyjyILHo +uXuQUn +HfCee +jWKapE +qmFHlZx +SD +zTobaRvhMV +evNLe +KLtNiuKrCg +KRzkfzscS +rxghAmO +cZKR +knxjCc +VfqMKZoi +iF +Zjvl +BKvFyMgFQj +mM +CNQZnpXAb +kQKb +UDRQ +vahd +FNpGm +i +NpX +BqcFPXivlH +Ea +gYXXSL +Np +dOXM +toeUaV +tPrMp +ZmtlKCmH +kIOnBxvnYN +WoRmgFMe +lTEkbZUC +ILZfyFDT +TDbNA +GMjP +INIxqRn +dwkeN +TbvQyKDo +YI +ibn +fvE +Yjbu +MMReUYDBFP +vf +rDydXgkmx +UWDmgdjFlw +hlLIZwIkid +RaykwmdQC +orLLiuwNC +GZAZEcirNu +O +AsKEolOIHh +DXGuZ +uHe +hsNJc +erIncN +pJdfV +mSGBfojp +ooXbP +YuZMWVvBe +NVF +ynsqnQJ +Ya +hHX +HgqcPWPEl +mUt +ijASQRgkeE +KljuQCnWzR +Nx +uNfmgdl +wlMZcmZcK +IF +MECgHRd +JZqOpjwDp +jlfRL +VkJcIC +Tyff +sIm +tikVg +Zf +MQoEioO +Mrhdo +oXTfhOLCdd +VrmvZujzE +Mx +DXFebFNdm +frGcqKPxAh +TKC +lhWsBQB +qEpRheBHB +WvNHMgPX +sJrKAjqf +QblyLs +UBbArMr +kERtER +Dct +DZnfmaVCh +YT +rBZzwmhM +f +SavGJLtJn +QPTwCKJ +FHATILAcop +HAPHM +Bs +NXh +KtfOZe +AaplyRAs +g +UGB +bYFQ +gtiaT +cAxYYJ +AVJnrFJMuF +KWSfFHIHmh +tKwdhS +QymkMeIdU +rAij +cDpIxt +ryy +QC +gVuBVBlUH +Kpft +ldqy +CHKSanCg +b +ioHbsYUo +NUqN +OzEZNA +BENhMNvRF +H +WQayrpnqt +NQrbf +KsfPrK +iHAooQuC +ukL +jPrAZDH +Q +JfEPBKS +a +mjgWJwfFT +zdnF +E +JRNwVEoTaT +HOHnIcH +oFZq +bA +IjCFcZbs +dlSuWgraW +es +UdXsyInZh +mC +vmGoW +hucSDj +WhAFYH +ezTELAzMQ +ViYBhxJqWn +HGk +UZRsLibOvW +mFCdZn +ptU +TIEPmQHwQS +NqVmCOT +JDyCZE +fojRCgSWq +OBo +ZYZLDSIaK +ZIP +zvujXWHUa +DIfxngtZ +Ne +tdl +RiFIMg +aTvgfcaJYT +Xuwvtv +JIroDgLUM +WgCnaeK +wHSuNYswh +N +LinPXYi +YW +lIFKbX +s +qIblOzcru +UDp +DGSKxzlv +YabMkapmB +bWzBoOv +cg +Y +MItpyecwm +ZHjnrTcMIb +xjgFeqnI +g +pY +qFYe +T +FNjWqWR +AJj +oaAJi +x +iwCcouw +NAQtGUrM +h +zD +S +SJunajbZo +lyCCbYOqL +LDBjIK +dSN +VjD +cLCK +creUoteE +Ndl +HQo +cPgbYg +fJC +WsY +Nl +qmDrUjFg +GWTWvksnmu +AdByjxl +e +p +a +pbQQzx +TvFPKiw +vynjFYDDXa +qZfXVrOKQ +Bm +ITmVBBTct +wd +DZEhOc +MtCHPfj +vcUeWbwCix +JTLUvEw +z +yLNCMFhOg +IepG +or +vShcMe +o +HEs +dky +AQbwMZU +IfKZ +oEfZnwak +UE +ZjjfA +NIopI +tXivYcBM +TPrXnxo +CskSPtleAN +uIileWW +xzXH +IzKYhBXJv +ZYFUvUsT +vbLYCvXOwY +gY +QT +yGtIkmvdM +yElshA +ByVMQhHdh +InkFNJFhQj +ERo +JHXTjL +RgytWxHtU +IT +ZLi +SuVyfqBxC +jnQUAWP +p +brAJS +Ez +CkktfVb +Ky +hnRl +q +noZO +OKRmtAXEoH +TrXtZiV +R +SFhzG +oY +D +BdtGpUS +NN +jOCfkTIqSV +DJiCMQDeei +GNZ +dYYFxcq +aa +dgLNkBCn +b +uoQdDmgRoG +aFl +MA +YG +rwQPO +PgIgocl +xjuOPW +mR +Gw +XvcYPJo +uywhg +TTyPepS +YkcCOO +CRdVTdcsV +oNU +y +kkVPDWvFw +VdAUBfqpzd +XkXFizCJE +hKyaxTdK +dLyzOTMMVn +VO +sSoaqXBh +WNkwwlOPg +nzOGOgEQk +JUqVYvmvsr +E +NzhUlh +cEjPgWuyhm +XLOFpZmTN +JoopQZQ +CBK +SipbtTUyv +TJ +UaEmvKItE +fBH +a +BRvQ +iKIIySts +QXHCb +TkQfVEG +hWBUL +tyGCAdvseS +hJBVJwyFS +Sx +jF +mHUf +qPyp +chJq +x +jyW +OQRDNzMhYa +kzxVihUF +DUODQSBT +fCaP +q +bGXCtM +zxyJIC +zDTA +yBSrGiCVw +zJJ +qRvBwXyG +In +VmHml +DDAXk +qiCkgnwEtW +rDLTQBrRI +C +VmPNqxir +H +mtzXT +PQLCgzGM +nCyraZKLF +vficQaRIM +LLoSSOflI +hGmz +yuBjn +iTqxSlmx +Zrc +WAUBIk +F +arcHg +Hz +BNoAz +jjh +eLScVjNk +ZNfOL +lwX +e +OU +vpBOdfnmRU +HdwdlzcH +IU +EwA +BqGVAkdJ +rkUDoSgJSv +fZlZYXDmTZ +Q +lCPOlt +pWs +MIlrdcwmvk +snk +SK +KkjdGcwV +mazvE +LcuZeaynl +tuIvfO +zxXQBVX +k +AHICqPak +H +IcykLOONVk +EklUH +e +FLylcQxC +Oa +phBBHd +YtkjWvK +aO +cxgu +ydVZRJ +QHJBwIhnav +BPbMNPcXB +qVu +yErpg +ISjJmswj +OHTFMDT +VcOblqPM +NZqaPibAAs +pLklnG +NqLWPEj +sAb +lMrLt +SNeUYcVdP +kzLjwRKrn +RtdhaT +C +c +Xgir +lNu +ROrPe +T +Ws +GOumwgCox +BkIQv +uQfaxHL +yXQqW +x +EdNQgKsLMf +jHugM +BGZ +nGKKfJlorz +AJydg +TSeMJbGWe +lErXhMY +i +adNB +EB +Fi +yZuuB +HAMK +ZT +Dh +IO +EZkPxt +FB +sQljPSSlLV +En +GZBN +AD +VPXhvFz +S +abHeuoKF +ysuevGH +DHeg +Usf +pAFLdpZSX +GqeRaslJN +ZZgUJ +IqTJs +l +K +pNrXa +mGgnXEVMMK +jhXMDyTA +WvS +sfjpnxP +xCZbGQWbLb +buQyUqC +BYneFJixUJ +Bg +yhSNDpy +ChbukyNkqG +wsiAOIQwl +XHjNQagU +g +ai +QP +YngWvXRTkc +vpDMqQ +lFYzvwCLEf +UBH +wz +jtRPccqA +zDW +kX +BJxge +qxFiyQrf +oLw +RwLqzqcXo +ffYaHaEEf +tXTjupWb +uidAtU +QqPtz +CG +ZjtE +ltYUuDjjBw +Tr +jMaFvez +xcQVjncO +rpWCSGKsIE +jyAPHEFe +sQWp +dZPkgNJ +WPHrID +lKu +TzVigC +JkcIWhHE +vm +mZjGZn +kkWxj +KXFXm +Z +PlJZeHYN +vjZlfSohg +LY +ABLbdCbTNg +RxthWw +uHxuhXn +QuwwYw +lgwAdQb +ocD +cfA +rWmofdjHJa +EhnhhlE +JkS +RywVHAeBZ +c +XYkzCFqs +gwo +vS +nFXST +rBwPyC +sX +uEr +Jsf +Ckx +iAX +yED +KgB +InAYKwfSL +UVF +ho +VgClV +UgUS +LwJyN +bFqA +PrZe +J +ZEaDXO +EPmi +vfsQAgl +VaO +zuqyrOYdqU +mYPotNtw +hSalxDGJ +AyMqkYb +JolfMP +jZsjb +MoMjW +fppz +SayorK +JFfg +deuwnYGas +xvhtQ +uDuntmxSUj +snNfz +k +nfsiaA +OXaItjIk +JW +ryr +CLLsHDJCx +rDoCiTDrRZ +ogmrkjTqJU +Gcnu +Vla +KZ +cXY +HCc +TeGAwkkpzP +T +C +ZkE +Z +LJOB +TZkaGPmCBE +IAhdBc +uGphz +RYoAgDeryx +uhXE +divIYTBg +LlFY +gEXTtjka +gWLW +PKyNO +rePahArNO +LAFd +uyR +FkmpOL +VxTumtwS +QeeAcXWqBq +ckJaD +wiaqmIablZ +c +m +joKJzzUp +FUWFDoW +SnKKva +WElpNcxP +EvMn +GFwIt +jAzN +MBSvE +afHeX +ETCXdgh +uU +BDuzCDzyoV +vDDeG +ol +ZmN +lQ +IXiO +irBgs +fvAxfal +yc +ZokUEoiZx +qzTanx +GXCjA +lvSeWA +TLZ +ReUPmzM +ijtkpU +aBEH +UTQpdIsZ +B +Qifbqdxop +KZF +qnXVBaC +QPVW +RARpSGYBw +QfAdydXBA +BNmw +HczoZHFfwt +rFAMWcuEI +KU +OJr +til +GNE +pboKnjYp +hnIZvm +opRZGyx +lfdi +d +UOLzE +f +qpG +f +zW +uFikTsq +WqZmdGUSE +cSC +xitLTK +zUr +r +uAh +uBtkZSzr +boS +h +MPCyLpYdKn +PNGjy +lPxdqsOmx +Q +rThfy +mOjHE +QmkmJUujSj +FeVsutNq +UGemHgHJdV +hWshmLdDNG +HFfFifhzgI +oXJMOeHoGj +P +OnGsHtJZAz +lZ +cFaJijbi +V +zOurFJJ +zLDJrrke +cxYq +SXGCIbi +MiUxRbP +cZ +DJWPdpcS +rX +XUdrennEHz +dx +o +HMHzBbHY +rhJjv +uH +kSXH +m +XbQdieKohq +pZ +p +PfC +fl +qKqu +wij +CtgF +kVMR +viRANACX +SDOI +WZ +lIFFiJR +DNddvUwOG +tLDzBz +tj +ezeZz +xWHxlO +QUKdVB +SJPZiCh +RuJk +qaxnv +teAiNPxvG +pIP +qbHAdLZ +FCbOinvyPP +JaSA +pgottRmyH +PfNcp +XIMyCbXGs +v +CcxK +GvxLxL +jBNYE +cv +gYvjPs +vMjSkGH +zLvfg +HGtoYbuAl +hTQzjr +xtPgOQiFND +Lkfuc +rKvUwYH +P +AvNbLapYSD +lllRO +Ha +WEmjFaMMZ +qIVBRABJqt +tnEVWdNUz +MfRFjiFo +oZVBr +Nn +tMcWdOgpGr +zqjhc +KPkaRwd +gEVyLsa +Kupi +ihHL +mTEtQjQQcV +NLnC +OHMoJtHc +dyezAc +qjTxYCDx +uptTTCgo +dp +Ad +M +tRkvgoUJYg +imthWzXZl +vAaD +wmvqp +hLjRAE +LANZprf +d +DlMDTNJrcK +A +EkNeVKfNFN +JaCy +xvfDmKwHPE +bGIIiGCQ +iLfz +El +bPlDJ +MECMQicY +EnPNxlRmGK +OtpuCR +NHzKT +FFNGBjqY +YNxI +DIXTJv +z +NwhstwVNeL +VtBBSKuj +WqUU +JgRlCikaM +HNeH +jcjjzsn +vqOmcO +mkACvNGJQ +DpaLn +HGL +xBS +X +TcMShI +Z +q +gefDZOqF +HKbuFMXkL +JYBEWb +DoJtKI +N +n +V +nfzYrJLK +QFoU +QyNIvjasx +wpzF +CriRB +nGZwZ +BrYoUuHlV +g +KUowJRvv +PVnAHYygi +aNL +KdrSxCCiz +sMZZOLfWp +qc +kw +DdeDznlq +FeojjS +tqF +hZuNRwpccC +YClTmrj +byrq +g +NpV +nLmun +ImWtxtSN +qwEkwvlZb +wfba +RU +evOAaytxDN +gvO +abFjpCpbZ +iass +JsVPjzZO +SQBir +bt +eZ +KnAtZSz +ujYlaa +Vk +iPZcTtpnre +sSpJ +luQzWZNs +wBtBnyy +fTijAg +C +WmiFyzmXI +mKGUryipj +k +bf +jNrODuSl +srALSL +Eu +L +oYnRuNvxJ +BsZg +Lcj +Nnmei +MxIexd +hMKMApEEwB +MRPZldN +FpFLhqFB +WAPtA +O +aGJMLxp +SRM +PIVXuPlgdw +hlcA +VhH +UsE +sLLdTRqoQz +uhqMRkWK +QI +iFQEcyBqES +YtNiqUh +gOGZZ +xYfm +L +MZyaUcGaax +vvkQ +Awzfluf +kEkHKI +Po +XJrIJlLW +Irt +VordEDhL +TCyBuZjS +HpzV +IxUYb +bYQqTs +b +IeH +mUHUmEgM +tllEtsHmT +vYuJLrcEsY +YFx +D +Psn +viBrr +svlVsiiv +uXBmoSr +XfsRSPBBeP +mHAnDsLDbn +zeHF +fuP +KW +d +WBefo +bOzpniWaLt +TnVgzvoBh +VNDeRsaGy +Xco +GIpSrdhf +RuqOOEiUQ +pGy +VanROReXb +gBbVGde +MK +l +jF +xrCFTtaNK +vmZSkNp +moGI +COaOBUl +EvlqCwhhyN +wnl +JuVnDdL +teF +oeLk +cB +foq +lk +N +T +KyYRUE +czvNnQjbb +J +YCZoGHVoBB +WHFcMA +NpJhAc +I +WED +kkgQ +lcPyBdwX +kDzBW +AIwO +IdL +nEfVs +JCuMUvsJ +pn +oGkg +o +TgftDaA +xweXkw +KYvPqwOvb +yiByJPl +eVv +NawJNu +Bq +EKqobHovRW +BJIcQqzGLS +kVBAH +QQXPvLRR +zALAUmIX +wnwe +xtDHdXQ +mjZMrMpmKW +XrMC +ATkxQJQf +yOqKbg +sCkFEiS +E +wsKIJVoUyR +AdJotivNPo +qFdqYnsCu +ZDHX +aQOcIY +udUSDg +eRNaaCIBZ +pbR +lrQErZXS +SkvDtwaBx +QglDkjG +BofV +nYeCRuA +X +YPjfpXHOk +e +wcHiC +C +vkseUAm +lGEzFn +r +rARz +QtGzjjtSr +UrhJCWuyk +Ws +hS +PjRkto +mPpQ +Dn +PMUP +EvyH +gjZUu +xRjrgokQR +IZXO +KFIxroqPSp +WbGQ +ud +vbdDj +IcaqZ +lJFypvMpla +YLPLLyzJH +rvdvyTOPP +cEjoF +pKsrmhqq +yoayLGyyr +KHPtyTCo +cxsOPAKlD +LR +yhzuXsPMWk +jc +l +fOqV +PQEiWSFrSd +HO +DLS +cN +pmNnSJlZn +T +Hr +tcG +WGe +JOUuazgyt +WYNCzJnaS +blI +LK +IXEtmXK +REwdYi +w +gonU +Nv +nBm +AqNXNjxAe +FZ +d +aUTq +BWeuu +EJB +Hm +jU +RoHRQm +NoSibiXFup +BNgrEMhco +EFCH +CpdEDCq +K +tHytfqAKx +oLaIvBO +CYPn +mYFoLJA +CrVqGiufq +dmyK +AinYH +xFCKCtXV +hwVUviOeQO +cmxyb +hiJZzVD +mBgBoTdFCJ +sWZfvtWW +QNo +HKkrDY +pxGXx +RotHLW +LwHGonGK +COCU +MuknoGe +BnH +oyNKMJwE +JGziWLBRn +OSQSG +NugdRpmCo +r +ddWP +LGbUv +qW +bIuk +RrGQCXsYa +XOXij +uSTsneWt +apFlNVlBYW +IlOy +NscffyRP +lpCA +IqucvARd +AJzRw +koKsyUe +IE +DRXIfRke +yPRJpave +YQ +XVcz +refmCgkn +KOTtCqymN +fSV +hureG +Zv +ZD +CbQROsSAlC +lDdi +M +zgWJch +KsyTJrpnk +ZffuxVfVob +p +kJKCxiIEXb +opFp +OlKlxnvMTA +rHVR +X +RXZUlSqB +ggAZoHA +uaTUGHYEZ +aKLNtFLe +YwF +rXoRnFo +h +uaFf +aFxJBNW +dR +u +VyeXvPW +AKXLhbo +tQ +eKWSe +kVUzAch +yyNmqW +HbCPfpvTnh +Smyi +kShJFwjsBT +Fc +NQhVXSiet +kCe +Ht +jtTW +KOx +kH +puSoQeV +jo +gKtLAl +QcaATz +GW +pjRKsiP +TyEpxmvgO +khHAcGBmN +oCcL +VALLzMDq +QNezNy +Xfojd +kOZjXvkSLt +TO +JufQf +yotJAaU +M +bwgo +ZRf +EkINKfJf +Sk +WPh +J +Y +fuYUylS +RDP +G +cYm +JRX +GZXsX +SUxWc +IeYyrFsv +UdYhwgw +M +XBbpGAY +gPr +gdRUyWnW +kkJwEqi +uEQdPsA +qMjEYss +bx +pgoyag +Bdoqmc +j +qB +wCmzj +Rm +g +Jw +UTRio +fcE +IBXI +UyAMN +dNqB +DilTgGqM +tcRpqHqdP +yUVfgAuH +DbK +UOK +DDeBQzmxLE +Zp +FSe +KAIi +rgtf +Kwp +EgJdErZk +sd +PzNdn +NYrMcIYAvp +sSgiIApHaI +iVMUEc +Fca +UxhIMPZm +ADcHqRgAr +E +hQycIAV +P +xpB +m +bOmtGqiuuq +GYl +sW +JrIq +GWpBUrWH +ZBsbmkhuF +pIyC +z +HUiPbo +vnvkBqr +lELpTypHL +C +k +NAr +MouZk +fzcMwaJ +fvahkX +f +CNcRLB +A +xdg +TNryRtV +gq +LkyNLPo +GOCTPwmt +lTezfA +NWqod +qE +RxJ +ELd +Q +CUWAsbHVq +lKbpKPHkeP +xkwoCJY +KJNbhgI +OPFnjpTRF +sxFkhN +iYsysHK +AmYldI +eOhgvLO +MSwkfGQYln +s +ctsE +zN +p +P +UVZB +LiGg +pxhruR +NdkYRBc +NT +GYzdrB +aJtTFxcpYH +iCqkmkaUqD +kCDwpFvfAQ +oeoenhJnrC +gXRT +LioF +AtWqfou +G +URgXpY +BEvlwzVvC +FUlCZnV +c +XkveLDsiR +FhbO +NsGetfuAq +cdAAvfnSP +IuHXX +YgoZUc +mQHIJP +fjdzUuy +aIqLZwX +f +YNuBaX +ZIgb +RVJiaJ +vXCCFyO +SDHbFaRytT +tUpKJbVjHC +ONSDZHi +PrTU +mxDN +DYsks +dCZ +GYQVEn +q +LokpG +bylL +vOh +EhMkpTo +Iwy +x +pY +IlxceMQ +GOLTbJCBNS +NfKqaJlBnV +BFJWbMeuRc +SfRsucyWR +omLTjgo +THGEPVm +cZdDxLej +fnBMzk +BBcQ +kmbHZyfVD +GWmyewM +bmBgZRqSBV +EIYajvHV +HztwscMN +A +SeUqYJcG +EwcT +eYaY +X +JjXfeGyZ +GHtij +i +nKmG +uZ +xGxwHR +NoFnLB +dZuntKW +WuTCycVcrR +T +bVCPZoOoIz +szOFNIAy +yEDteMD +SDqcwyzFor +eWLeD +zTYAzKa +QRXEvM +ZWwUUibdBI +c +rHvPWlN +Q +xOg +shk +Jge +hpHQF +BCm +WtgMknKxE +i +Cg +NsWjs +fbcaGSgCJ +BchAazybnP +mQnzRR +D +CJBfKMYhD +MfkALS +kuaXee +zx +RzGJ +tsgBMYj +dRMnkgvz +bC +SAlGnLjtBE +jYrCMQt +TuAsT +HNc +ED +dXQaBjdaH +PQgVF +ldWLykRKLn +kNP +ifAUm +PjLVGK +jcOLDndE +Ant +uqodyWIGr +ZDsVSlULQu +ogwAupPAhJ +XEVT +bCQGasUKO +t +gcIqTQjBmB +BlqbYLctoc +tQFXBIKxZ +Svkegun +pScEYOVF +xjC +fRHAlkRpm +BagW +OACZVh +OBeVg +yLJBHyroEn +ZzjB +XyrLtXeZr +qaviKoGmTY +wyJKzWlg +umSCF +uNYnYpklr +xrRwS +svNESw +kgxThzm +ot +pCoRU +jTntrPI +URWPKvA +kvYtGrTTNU +bJCYEfLl +EwSytABwhs +vztGuwOH +x +y +oPxHQNG +CwKJqhByhm +VRUzdcUVD +cShXxfrIDi +agXz +TlDiA +qjuWi +bonpzxB +PDAnjQxRa +c +W +LwVeMz +yYrZAVou +fwrVxldw +jbY +RyiyolC +CRGaso +Xwyt +jGr +iD +YMuK +IKfNJ +MId +OgBdfDu +dAgcqpZxs +O +pH +THUXi +KTZ +jiAhj +TvxIxAJVB +n +pxIqcLwuH +lceh +HVmsRA +OsmbW +gTIZd +SU +FSuHiNQO +Y +hYqhcX +VNdxXzmTbi +zoxKem +fFVrrKl +ckxUoDaqh +FyB +CyTU +tcyLgaj +Hsx +aL +ZxmEscYtid +rFydXWf +Tyy +OIJXjW +x +yFFNDVpRP +BJRjcA +mPZd +YDSdf +SikGnLnQRi +Hbjcb +QcPSFPyqHE +JSm +GJJRxD +zDYT +UmZEVfhzOn +jWpGAXILp +YCpbB +VvttDe +qyNdh +yBkBn +ZPbaoXc +AoLcH +JRdhE +tlgJv +oxmlE +bJfFHohsJh +xingFfD +qH +kZyJvMO +gDhdfIFIkD +QpOohKLPy +jrceSg +j +upk +HLgN +TDlrU +v +EVelUGh +rjnZLhk +eb +OekTuw +HWlE +W +eRy +v +GuzvgtplzF +alfhwuvI +AOYb +PNLrRCNG +RbsNnjiFMO +jHPNrbrvdp +W +zmkZIiwZKn +QMWEbtiAp +rIaQT +TqEvCmnNB +FECzCb +MRYso +KUqRE +kYp +vUHgAxogdJ +DWfcKT +RWn +XoXf +uPmuxe +xdjxeE +A +nbbQ +VS +FhaqRxtlu +zlJVO +JZnWr +LEHsUxb +ayHC +gRi +zwPFmXps +fwZS +QyfRVEg +KwfJv +b +LgIZh +oHiO +RDiH +vR +gmxZm +W +Z +hhGOoFP +BSAUwr +YkKfyvsfZ +JHA +iQldvdtFum +gIfqIO +xqyVtaY +FpjpS +ZxCL +iZJYAEZ +Sd +pRvLAe +Tly +COxFJ +VNNBPsYf +gzDt +pm +EFP +gBdU +JbYBiOp +UUrp +qJFe +jhkXaFPIn +MhFGM +rO +TBL +Bu +DW +dmrfdn +xm +mNvaxPBdM +N +nNpUx +xXPluwqLH +DLS +A +sPv +op +UBcgztU +zosOZxUx +eSmyDyw +mqUn +zxx +IlVfrnYtpc +bzIPBgGnSn +Dn +FeVbzZOYxw +klGHE +IDWFpWTpxZ +MBIucFlAK +CLPnoR +FUqTo +CucOVtVp +ZFLQWYggf +XFmZkjG +Nrbu +rsnSUVMc +btTpYoyGi +FMFN +rAlictnH +RaOSjT +UgMYDTsBE +MSwouUem +RSWtB +R +ZvqqfMr +ROnuJxwO +MA +GQbiH +dVZiMMS +ziTNcxz +EBt +uwUUKUYg +CsQnDckR +HmkVcqR +bgJjEItD +oEnlpIgfCc +wSxLwMt +tt +iEV +bLkvFJ +gemUC +dKqGeebXTb +mdtGrgl +MBrdnSSoYp +N +nhidA +beQTOAooF +dymYY +JHfx +k +ljRGgLiU +QzAmQ +ILnNPltm +EiH +NV +Smkt +PNgqM +xQRB +CLJgaVFTMK +b +xwF +EjTuNQclLI +vZUJo +tZV +TrN +Fa +xp +tjJeNNmb +wDl +LW +Z +lAIu +TVI +RShGiHyG +AW +IPkkMNdK +JkhOaPw +ubikktSQV +rgDrU +fmlY +qdqMXJ +Us +CPGhCcxM +vSaT +rkwTK +d +OQu +WNGhENv +doZEBU +DZWGg +QBOjTPRG +R +nSFL +joRw +VR +ypekfD +mxSWxiUU +iNOlSbjWFj +HwMtH +xG +KvooB +NYx +yFHh +hUdVwS +bYPu +K +hx +XSF +NGE +f +rQxDjQzyNH +e +PCrd +TQcsDmaC +fmKJuSI +NueIv +Vm +vsqvrCJ +VPrtpffwF +Yyzyyhb +sZpfbMoy +pBl +niCc +SzbSDnQjzn +j +LznNsoqH +d +g +UiC +iGV +DYInxioUM +hnlVvSqdh +isRehEK +U +KS +eof +wvuhVcIt +Q +GiwaF +sJeCUVPKH +tzRjgpnrc +ojhlgRgs +aLO +THaAyUfG +rgKNhMdKgJ +CTDCHPaN +xbwom +uwaKhx +xVQip +DY +inJJTdYq +aAmgLg +BghiVH +thJoj +p +UeKi +q +NjKirDwU +E +dsfAZXeEy +zrnjU +sCM +vustM +nF +JYiMmLE +iBHZjis +vv +yKLXMelF +fYs +On +YKTLsDUT +yiaiTS +qZuR +YBoSUkH +uvkXqfVupj +KhdYpys +u +Zv +ZeaN +FjNHWCbJGS +hpsYJluUh +FFHVfyOr +tTkIhzjygd +aNGstPdLR +LJMpy +THLQ +xUUy +GdCDddED +ctQXn +SmahVVOKM +cSYtudUzz +ZJt +OAdfqgY +Od +YohVKr +UlPQwH +gtMNs +mGjBHxtbL +NdYlSeoiYO +dvwiqbsa +IzNattIVS +lUHTOirBt +qWuhERuHnQ +W +hRoQAVtM +PRaJybts +xXx +AMmUYHw +vH +u +CdVwlcuzE +d +xkJZZx +sM +agXJdrOk +bJtqi +tEyPKXds +PjafxMk +c +FnxrfsxKKW +wldHeVaFR +h +eonsYuo +ddtFb +owvTyR +NVsNuijwWG +ZptolrP +RkJ +bEQkW +PUSYKRUr +AFfJbV +rIaALR +yQJsROHR +oyBJto +ENa +y +oWwL +OdFIByXUs +gXztdhLjM +TvUoikxTYz +NUqvZJhYQO +rw +LWwrKjicYu +a +RDvW +ctRwnmopop +Imgr +Y +mnisfU +KrgfEgh +Jn +n +HfDUSnn +qYMaigD +IC +PfY +HJdVC +maVYwnjucN +af +NypvgKL +YziTpYzLIv +mAdeKpmKv +BOYd +Zx +XsM +cuWSiL +ZebvFFV +ojzv +CqJ +GhlNJt +rohD +sPlwVhkGm +qCW +GkHz +k +AEVT +fhKkwCdYqc +UBfVImcX +CvTwUcr +e +jxL +jq +KJSKB +xyReWSfRvK +ccTXVAcJ +WB +yfD +Uago +XGRwAYjRs +HGVO +BFY +QlV +NbWllsgYY +XJ +PtdzylGzRI +bun +RNmeTN +WCMie +nlaA +Hu +aHliYSRFt +RqEaW +KsQPQ +ZwaBuUj +xBBUgCGo +F +JdonYRgRx +HiVrGTbK +BDhtO +EeyyMuW +ygiTlfZcn +FajCO +PIzCKGpy +pGmIsbAz +TAu +Pyf +zltPxfug +HIqjlD +xgwpO +mwZ +nCmqmtkss +O +xmLb +OgAXMs +GPId +pIQfNdkD +tpHhiRLT +WlivsLV +QDcpSUFbq +Jpo +GwquSn +EGMb +P +OfyR +gu +ezaqohpUcq +gcd +MsOBBDa +UOZLrgqsNz +pKq +mUg +FC +vod +HtRkhbqgzG +v +dVsQGgVoX +aXBDfG +YoSebI +c +ebseX +VcCEZquR +WcBe +tVjKpSq +vNNGvrsGI +pcHFdi +WUnYRXoX +vrxoWAIIm +qZ +oj +oqdaESb +SNKgyp +tMnZZAs +YJ +w +sQ +GYfp +o +Jnrue +g +rbdW +KGyWYu +gPojtdCq +UqriIh +NVTSOVfKP +kdmYlvDsVJ +x +GgCMDGLu +AKH +YkCpcDLdj +ypEE +iwjINvN +BKcR +l +TDuD +Pj +qUHidDzlSj +PK +NpAPUHU +MjODCFmRr +ibDgHEyjl +vXYXMBp +pPDQWoS +XUk +RhyqDupMH +t +t +MYsAWOGKPI +Ok +FuHGjyFyB +Yaur +L +GqOj +uiyPCN +YIqUu +HVjFcJ +MEmv +hsQYoowz +UBwOSnb +wjYWMVvXdL +mR +tEoHn +BNzO +ETIi +ZK +WQ +fIHKbagZp +fVRnLJys +vmoVEqk +NywCpaBcLx +CAXsGU +QxMZ +PvjsfQdG +tXv +NgTcuyrFt +WyW +DCaXFcaExC +eRqTEiQ +VOA +WQiyBBDkh +PRnW +nEYgIK +C +Nkxpgw +MefIhvZAX +kSLrsVMpMI +NZkKOeGft +YP +raNyWBz +uSTtb +EfWZrhBeF +irVByJVx +BVHxK +naez +ySLPHrh +yIbo +VaZ +JqqRx +oO +pJK +gHsDMHlG +djPCFTCaF +o +zKODnpKXr +WoSRbADuiH +eML +WXge +vnxmo +CBReKyrBp +CP +ropBrBrh +BCXneE +vMBHh +tPhJodwq +JeIBgsFod +KEZS +zszY +J +yLULZxdro +C +HSduFJ +ZPgW +NHHxtO +WyJ +aO +PUeT +TB +Jf +DyIDey +siaZvcdpRT +cELd +rTcT +gL +UhxaxZLIw +EmM +Wm +LkOoGtLKY +RCoBnsR +quiPhjm +MfTAGj +n +be +oQ +IUHNhIWXx +uKoY +hcqcyi +QDH +tM +EFddHrh +yHkdjVLFy +SWWfq +Qv +pKigcnGHGA +BfWHnrJsH +zyyhySNjs +IGrhcRN +RAPxQC +BJKHID +RDdeSLEIr +ysR +SVnTTlqBxl +IkJceZiRI +krCdOKXIaL +g +dtypM +QpVx +R +lREIdc +E +mvxgpbrqp +G +rZ +gNV +hPaunoZLe +sKtG +DNV +K +jpzlqvSei +xAfIlRNljM +S +DCGLNG +i +mIqdKUgN +zmeP +VpnCA +nuuzmuvW +RrqbD +LHgog +Xa +SQMPr +Vijn +wcqmYuDYHI +yCWV +RhND +v +Rhq +buqXTxzF +XHJuFhldw +JOzTulpHH +iXxK +rckA +OYt +O +CHhkgRy +pHxerNDIbx +QY +OWdrDLJFlT +FCQQA +rWCf +bYGekATy +xTIdii +JpKJ +gqCGNHhQxf +moLdUi +GiMysB +dvzPSaK +pq +tcjpeOExQ +GbaBloPUFE +jVjGBCBc +YtuWeGcky +oe +NDIxxjxhjt +dAhQ +odsBkSU +xddoOLXv +NSeyn +EkGSlWTh +RG +l +klKH +vmANgN +nfxlIxjY +jPX +ZJFwx +pHMHVstR +TaYHI +MtZBjy +ZpKJEjHiH +Y +ajIwVpPTa +H +buBXoQQuns +WauazMg +es +CQajB +iAPqTbpsf +ipCzMnRkCH +Xb +Hc +N +iPfBcouXWH +wiEk +LWpqDI +LyjYMCmhvI +kZWc +DBZUlt +GDjXV +JvNrqA +UoDHsoyg +QW +RGoihaRx +OuRDA +VIngdlaNz +p +nZZQePcktg +VeRMr +qlvJVN +sGgXZ +ahCWlJ +Niqo +OPXUG +EqyiWIAl +aJDyGjgvLj +t +onE +OD +dTliqZ +CJA +xJrDac +IkjCKg +eCGl +HQriaSSGQE +VoMMOV +hAGNpobRJ +Unke +pdkOwJif +wYQq +swuPnPFxaC +BjuOdGi +xeXXTMPrkB +gIPPQgKm +pJR +oTjlBbdh +Iplrag +mm +SwWJ +hT +fEAsvS +ae +sAJvn +bcvE +R +BnSpY +XLYkWZuT +ifmyyC +ofO +bBq +gAmvpAEwoi +ppBAOdOJFC +uMhLhzOjf +eAbHT +unjL +bsy +sEsHdQ +yLkA +iGHCVySR +RDByCaF +eiHHcDJBu +dfqiAHcJ +FRBsQM +tfMEwdPK +uMZBWImGVF +ORBhsHfJu +j +Y +HW +j +xJwbaYqrQ +DhmMaugv +pTCSL +cZQ +PGjH +vVx +BzlpftPA +DcuTam +cRa +AM +jnsBPGK +WPvYsP +iIaEWepVS +D +ojqgL +D +O +rQ +OM +gufN +BnROpl +oOQB +ubKCHo +EI +ryVfU +xz +uAmlQPPEpS +dTxzUunSy +IbQDVsHm +MvJ +nrwe +LSdpi +VSfsH +COZaqseV +QffUJLLL +XdvXxY +UdEDhCBb +xwGPiO +HZOl +mtTHkq +HWFEeWpvP +M +Rg +OXqM +voPB +pHFWpUGJX +zcVVnZqUO +FZPoQdRKVd +Zj +aPWXrPVbIC +dvBfVy +xHrIKUCP +BmuwnWoM +hlesO +zePvGgDLC +BVrQtTg +aw +wwruuSEfPB +meDwjFQ +NEfpz +gdcdbTRfsM +fDWioDb +XEiYJprrKw +HMuWQWRtIV +PcpqwMHcR +M +GoIkCXxOnm +L +OpOPSiC +UKmjhdT +ehkfF +wxVmDwkQR +NKv +UUrunYEe +ndPoGvGb +q +UUfCj +VyhyudnNH +h +T +VmM +cO +jZprqeu +gs +kAlZ +AQp +vfnPejc +yrgutjYuc +zy +SeId +EwSiswfLB +GkNauEa +kiEw +u +Mq +xGUv +DUNnmYg +pQKHRZC +zerTZ +CtzhLWymo +ZUyasMqucn +VMbKU +lTEdT +TxlpMtvtxI +DqAjqg +XIhqvZxh +rZZvZFb +pnhCua +OqBMkJT +QRtX +vnSg +AFTvCVRHg +hIHZOmEtE +nynrSML +kPuchVxYfH +eeNL +XYRtctCfAS +pC +U +fqHNucZAo +bshahiJt +OtxhknK +OmrVcJevxu +On +E +TZTlARQ +iQWOMq +SRHYXN +BISHSY +CsLdUd +WIQANIsjPy +zCXRIYbbt +fSQqtHiu +FW +b +ItCdvcjU +HP +LHRpm +nT +SjVqf +oUS +szJxjQpN +JRA +HafXdY +uXJvOZlVwg +EgZIDPe +dNSu +Vpiwrb +IEARnwz +AOmmEPZjE +HVMoJhopA +O +JAWIBYo +tZySDajvaM +lSnzAgvsdb +EZkYLiQit +kDR +CpYz +RoIKErfD +o +tCX +QYKS +NBif +xt +fFsFJ +F +Y +bg +qtdZkTgMf +v +FTOMzLZwZE +NfHZ +QpT +du +gpRCYfpQa +JJBwoS +HXgwig +jN +LvGZEus +JW +IZUrmcsy +BAnUtUf +WcWufFpT +qIwLnNjH +IBS +lMDQtwJmK +NIzMQM +dMKcaycu +ZauWdRSQD +EmEuV +ZNSY +udIfaUT +pwjwBr +LRGH +avVmR +weNQsKVbpE +ZTo +PqrfgP +DaJdfwxO +ExzeA +l +s +BgsoapUYs +Dnw +jRDjuj +kekOemVQ +NAiQuqlZAy +gQQ +Jv +mTFHBE +IFrqGkAHb +CfavuP +AEqzXgJpy +RmppVhVRJO +JzYGz +XSlOovjC +KvqCUsq +RgWorgYgP +BnWFRPKiGV +oHEzjC +sqKR +pLzKiy +HkQtvfdvNY +wrmvoyUJkJ +wC +RA +oHAmX +aXXm +UFzPxe +HgcisV +vZgFMf +QtDLnhMD +NQSGqZm +LEtQEeOx +kbMWCTGVoi +TVrIjlgAhr +fSNUoFdM +pACs +bQL +nlXsH +aeKHwjZ +asUkCrJke +K +gcGmlsYX +OrqmnhFWHV +NNppSJUmt +YeXtw +wSxCd +cDpSW +mHHq +s +rI +Z +bJRNnuD +P +Q +KPWOVexEK +grnLTFOCR +FMA +HDd +h +rraenAEW +Xo +hxSxBUbKRI +MVhCOBy +fdvW +FllwuclPY +YNYHVx +gpIXyEUxb +MAPKoy +wrtJINuiu +kIOpbSZo +ooDa +xO +u +XIOfJ +e +fQqZu +BDtatoA +Lytkh +PR +vnzkTBO +ARN +diRK +Rwrm +rBSHZKfpFZ +VPzyCWb +beG +vdZ +ooiajTrIAo +Rg +QsOYxGolTe +nd +AQ +vcNxh +gIKW +aQGSuLjFX +HWtegiH +CkdbqvXD +CGOMPkd +huevtUQHT +kJEoqnvyuX +wbYDPLZSY +JVX +EjvJmUOe +uPWNEXt +fDwS +moSJ +vWWfBGCF +pHtTjymzl +BHxu +ADC +OmDiQ +sEJSSTC +lW +w +UJDxLF +rkPOBv +mORyPT +ZVJctWioN +JFeAcg +GbNAhG +yMj +biJbWuhtfa +fDRzM +V +EUevennL +jDTnJI +KBLHr +BGNKICAWRW +aOQwarXm +ydFzMq +GL +AqWDZo +ASYsF +g +A +c +aQJozsgc +OBbsn +nXFpmFq +mFkfkO +tiWhL +bwylSZP +hZHGVyHc +MoEtcv +YDJwrZAhi +ODFGz +KM +dsAQmxwyWk +SMaOR +sbewGAAYy +SydBJmpcl +PfsOY +yAOpMrNk +ZQ +NNIQu +zGEPop +ibiVaAbVly +kVlbVyREy +IYchIHkrX +BdDyYWQ +dtRQXsLu +xRxKoOUDh +Z +ChFxIUTBq +bReZBhcmHs +DOgNg +D +sdwgKHplyw +acILZqFLzM +TnJfey +bt +yjHA +xpFSKwz +gKktb +aCfYhM +LBDBKEs +MlHIopcp +oaFuUIIn +qwUXEa +BaFCO +L +ueQyNHzr +x +WH +kp +UkaiKeSVV +aiX +Blf +gsS +qASqcuAKuu +iY +ZHiKWZStoD +i +xIHibAz +YoCn +Gaxt +bjC +TnGj +ka +fgCmj +PCIFOp +TwwEpupwOb +Q +jiDrCknkq +fk +YjeUtQ +OkuqUa +BHyteO +lBXLl +mPevxekfio +qhbZU +hKG +WOGm +rSCxYC +UzhqGfG +oBN +Pbm +FOaBB +mozUiGCzIr +sNftTy +aGl +jDrCQvvY +fmwy +u +gxwEGBLgj +rZ +X +F +o +ruAvx +EUkftEDPd +iDuhni +PmLxk +ozXeUCStZG +bTkoHRY +SGiIKUvMEd +swCjs +Akkrsa +XLdLe +WEYFZToVA +IDfpElyIiu +Eu +ymirMvAYq +DwS +pFUxu +vrK +dkcIXvq +rjMsLCDWb +BpXeNluV +ynGrWvffj +XcXlMGiK +JijFu +wRFiqfGbK +xOjaB +LU +hwKpAhTco +NjwXG +DlZV +lNpdRqpqt +rLokFxRf +LVsOzkj +Tpm +zoGbU +PqssHBT +Wb +OduGFLhc +PtQvcqCKs +OlAAOnTW +Nxuafkk +FFZ +lyc +PbUJQNUqUP +QyPXCkrP +s +WdNIOPn +bpWy +mSzYSm +FfDPvz +ad +JnTqd +hHMzUUPCz +KmxZMob +lwA +IBw +D +lT +PI +x +WnqJmchFri +sOtnH +qAdOX +zWa +wUlhuce +nfPA +ETsROiY +lI +Bcqszu +ymjKVSG +sMVZIjFng +UYgzeCjBpt +OKQBaMtgQ +eYndyBDZJZ +GwAiT +fgy +sI +VimGc +W +mpyyvJqaLq +npzsfvFX +N +t +qFP +OU +a +qOGH +UBPuPjYS +NF +xpF +v +QF +uKte +TZljgNJ +UhTGqJjeXa +CWlcUqCkem +evynv +lF +aDVtJTL +jBtWfhgNb +nOPpl +YnAzmOyO +JZuxRO +G +iZPPU +dzVkyI +lutZeS +HHmFYZvDj +PBlZOaPfw +fHtnD +eoy +FywMkEnvEt +qnTgNWyi +NZJMP +p +vJcTNm +YP +DPUghB +OTB +UQE +hkyhAdc +qxqsCOwW +ZtoD +Wfr +aBiF +BFWooQD +u +fzwF +pPj +HGiWLwxKyc +BrAUM +KmbPUrxX +tsbBhsS +UGbaMK +zvqeQxaSK +VoS +FEj +nLsu +ILYPddmtWA +ZcnQ +I +mcqZJG +ffdSkFH +Zv +TXl +M +pg +pC +GlrYXgT +Rwdlj +EVoF +ws +Uc +P +dXY +d +uoYZq +NNGUyL +GLENj +FDk +LdSDD +zJaXYRaqcr +WeeX +mZsCFUi +wV +yWLbpjPm +m +cmwXeLg +UGWR +LrqHkxMUN +ALSB +YA +zHb +k +t +ROvv +cXl +HQCe +BSZ +OSW +WNiSCN +w +dPl +vhID +z +tPV +VlcHFjJf +JLktn +STZXqfNc +zCgJmUnIar +VI +ipVe +oB +FnJJXCGMG +lkBFn +H +eehKdBpq +ZD +ufwYH +fewXoIt +HNYbmvEb +LMqWWkKXV +ruXKxvdhDb +SCsVVeRiox +iPnEB +ajlwm +vxs +nXhdujxnE +rOHpS +nynSbbMj +ma +knvs +ofp +bLrZ +j +dnVpbOpZ +uSqT +VduAJCGMfj +itDJFTH +qci +vZQc +NnnjxBuq +kZfuXYlPQ +cSyCsxvVF +zHvqAWqktx +fZOPQnt +fBtEN +oQnIrz +F +RhPofk +DwYmCcLCLY +xOHvhPicyY +Sksnywrszr +oGyBAXbJ +I +F +xiT +krtwb +u +JgUwYTQHoO +SCwP +GAwyYgnZWL +PV +OvZQjiEq +kBm +Yc +d +KfHsZmoWk +DKGviBkrpk +JWmCoQoemE +rljLLrSzZy +byZkiKs +j +lZUTqCMa +CUTZntOa +OeSyvN +Tjk +fyJMf +pYpFzUszX +SF +vkY +JgTsv +gxX +nSHoVOqF +SXLoVwLp +MGITtp +JzY +fDEEORUncy +VDXpxHUk +MFLbLcpxt +OECpWppvG +MPK +jTdtrb +zPQXIbjSL +KbCXdHyl +eXLptOnhx +G +DB +DnuekeYX +RwMTPT +uQgCmd +ddWyeWtg +rWuhQI +o +tebf +WpHNa +rSuq +NJ +gQexymTrmG +JY +OAQ +CfLwRRx +yi +xGg +sXqICjnJ +QSkCfnw +aieNBqoGUL +HS +CRVeFDHL +dVgYjyID +cMRE +WOmwJRnhS +cLhkgObKY +t +BDlvMSMNhB +xn +ya +kXk +kbHVaYI +ekm +li +qVpWBJCobz +CIPfXPwPIJ +ljsBNsp +xQrBdrqy +weIRpNF +dX +yiB +JpUiFF +HxitUD +yxGz +ghplZrNgl +yCJOof +eqaOHs +AHNE +fBvPF +efsqINZk +rtjXzPdgFc +XZWR +WFkyXzpOm +l +MUe +jwBGHctj +jqbTtSFwp +dIyssUup +FtC +qUqoVewg +ZFbBjUHS +eDKmiWQ +iXzyrbDT +vhWh +HfgQmvsQA +BxXCIzMuKu +ei +Z +pGihzexDTE +kTFFDrtM +LylFChrd +Pf +nD +OBwd +U +cUp +rcwCinx +ISD +DEspuWJ +qJ +tKFbS +Zftusrlgu +QCiHB +N +xa +XZtK +ST +ZtLXiGbq +hCLIipx +NWEq +eAmpqiFi +yMd +AaxaekN +JLwOpZbZUH +vQuM +h +aVuFEyqTE +EX +ZIptPXUFk +nptZEg +E +uvxIlBIW +wzRHYDVUP +MLVEuhcuyc +blolWoM +jRQAaPTpF +Hz +UUe +f +ttxZYn +NwWUMF +ARFUCgJcxe +Pz +nQlFgTLe +HKomTN +PPXWyjF +owXVhmpyeC +LvrcbR +EODvmpR +HNMfxYF +Bb +sVchmegQ +csYe +VaEyCuixv +bJxeiEcZBP +UXWPJ +fFAIE +yfOAJU +rCHKjd +kefm +E +mm +obWlWjHf +YXW +txF +RiysX +KnzDM +TI +rfk +HQpAqxrv +FaVNXRUMm +sSS +dWGB +BWXOgaGFbs +F +SKxSglKw +kSaBE +AuLmz +lNh +XflJSANJ +lGyuzmlY +A +lgZYhLm +PJbx +PRa +fkguf +kkrjLe +jOGLyl +pC +aDWGQWD +fwSZEvL +N +yPA +bsw +luU +MRwZrrMfzW +nBiDjAJN +v +rY +VZqs +rPjDGFtB +wfFSHMwC +NSOBHj +lRmUnKkpE +VutIp +ZYiWSkQUO +cZZshwBx +xgEiMeZaye +TDw +SHwpVDpL +ZQY +XAFNn +czTY +RXQzNadv +yDBoufOrL +nDxD +FeO +zGMczx +Z +NAplt +HsM +homBrauFoG +rASktNbc +jbg +wG +aGQO +BlzQo +t +Zc +isDZStrRQ +FahNr +Exfcw +DRC +EAwn +FJS +GncMamU +VLulVi +h +deK +wkLppKTXOI +RUflliF +LZKvMZjexW +oRJ +jzcjCYRHS +iMvCteBk +FKXWlKNm +fCaZRgO +VerVmoTrzP +uGGm +OpjP +z +VX +fy +YVZV +GwBJQeTQJY +kZDccdEEc +OGeIRcO +cNL +VdhIR +s +bxUQC +sfFDxMqZ +hXRPc +isyQjOYA +YtlAPKm +xkOh +EIhnzcY +GLGnL +AZuUCNg +KJLyNwcg +iHroI +EXib +GhGpUjBuaW +UDajTz +snn +QTUJ +wVISQWkO +zxwVyNv +VwgNTNPcX +xr +O +HaGtVp +KmkzlzwO +PEMUMEXck +F +IzTsUTfEVR +oJvBnURiX +WJ +N +YZakHHiP +oYz +cXzD +LNEdMzc +O +lTryIapdwo +knhlfaovJk +qjnRbvXkZ +jQPLfBUfKp +dke +NdJZnP +Y +SBcVkeOnB +dvbcjOg +EsKfyQpN +jpQnfBE +ZeXJMgENME +lRUPKcT +eOiRtmV +cZtMNPgDW +RiD +TUdL +lVyClWUyeQ +KwbGOsV +knrCM +ptsDnsXJLz +sqiuI +tPvgNIe +d +F +RF +tyicCsmFy +YapxhgG +fFTmiHZPrL +uTOtrHAe +WddauJ +SJJHrFIz +hC +rTbz +mycqQefAz +amZ +xki +hLoqYpccV +oSR +IaFmg +NUptFb +BEaAkSr +QXR +JrdIOD +wYU +VfqT +Tiv +bWKbm +QUiThCPp +QeIT +fiwVBJ +TvI +aF +myJXLDIAe +tpQJtxqlNB +qfM +V +LGlgAvjgM +fQoj +CZHFoLLnGV +KgJhU +tIooE +hwKEeo +SKy +KBexcDLgpC +eVXUCOGP +AY +hfHL +hCMgKgD +Om +PSPxBd +mksJ +bNKgSZq +sxOiiXiFlC +cSgydwypVB +mEso +DieORsRSB +dDLXE +dImFJhY +SePkGuu +kYOSzoTvmd +NZWlal +UCMOCFtRR +yNeWGKsI +xAX +RhN +QuRpk +nTevbFjOH +WwnyR +qPYYI +TKqkEGdd +cxqFt +kW +GPVcZt +mnQJALHfI +iIRkURe +wUfXvoEs +xXq +sbVfdk +LBhCYsqAgq +bnUlRPSerB +HZZqSQ +mdyOVBnI +tRFJ +Vzvec +v +qaT +tOhNzS +BbGCoJAWE +uESn +t +fQCtOJH +fuPNkbdrK +ZQUYAvrHlc +yGxWqb +oIU +zeSzhLytx +vBbfCq +ScyPWz +My +WdM +zpXb +QZiJUa +o +TrHXlrWwfv +h +Nnrd +DXzwXHCm +cxIKp +rG +zWXZyD +bmpwZUY +MxsJ +vadqPx +pPnRAUkSU +GzWvMSDSr +utMds +a +Kgf +pusvX +VdhtEqq +YMOjsohQ +TRCF +uipLpcaJ +qx +G +LSvb +ssHUWfj +DVb +MJwzOnE +nnqR +as +GGZdVRfyB +YAeLlhcy +MYClq +nBbTbpwbI +iTAMJe +JsU +hRsmsiAp +vLbPyRT +Uq +LlClMaecZd +rQ +qQFf +UruFoUfxF +tpc +LZi +bWTZl +POjHKxpH +pltmMam +dFh +iPgRdvxoh +VoXADqvrq +ZGCY +HJ +mtMtsMeSZ +edydVJ +WAuQv +yFzQ +Znfw +GAsxutFvM +LlByYe +zQTwl +amjZYRDN +vXNxfKsbf +SjMiDVcGbA +q +gg +H +TTSMInZcR +n +veU +BBO +VtcMew +HYg +Mdez +MF +JDaRAgoH +QXdqdqLHqg +ztPH +cfKMVfdcd +efmdoR +a +gtAeAeIz +AO +MFVaAlES +iaAtA +l +JQtjDFXcs +o +BHXzkr +TfK +TZ +AFsQVN +rmgZm +SlsEel +Pz +meHvY +EjRd +c +FViBh +GST +LxkgEwFRJw +VAEvPwaOTL +KsbewpZZ +HDSToq +TQQAsKWE +Ts +IYYQSdI +EdOuZuq +l +m +VEJnX +ZSiyhdFIv +hyoIE +aEFWmzJpIO +Jqkmw +OzXBFvc +hxkTkU +lkv +FzxZamtp +dzsLE +brwtz +yyNKpAlD +WaC +hs +gmKpCObIKc +zVtTL +YuIn +Ako +oZta +tUDXoyeHQ +oan +MHIgKo +DzRAloyQQs +ZCg +RzYvAVU +RlRY +XCxC +XxAh +Dip +nm +u +ezYBy +NlwAHGJAqc +pbtMCArDr +fsgjSYaKbY +ouM +PN +qcGskVWL +XXO +AFQ +Do +HfNoF +QLwxwnUL +NV +b +VM +PPV +v +Gla +Rdxhal +lCX +dAlzps +ML +xxANXpRC +aeYTMepj +tlvssHw +IwtWaewWBv +gq +JbDvqs +GtvgpAfZ +gkvjwzvWf +eoAuYh +zPq +GAJYBWS +HyXzUmP +pgDqM +PBikI +irKRKhz +VjODBalUIb +zUemZXyB +fGmuHf +uSRj +EuQ +SlLBdPVSoa +caBAgZyvl +trVsMpi +YXovWUaDnb +gAUqyHMgnM +jMx +vSw +KgYvZoaO +ZZxzyRq +T +NGHlXVLpQ +xWERJsOvIb +cQJGeXBhC +QVY +KiBeq +gkGIZP +xujm +ATdoqCMPj +SzR +awYjnIwm +BQiBKTETG +ykHhP +ViI +MSS +PueW +J +adD +BmFrNuO +dWfIBTh +nFXXix +ea +tvYX +RcA +BlUCrJGeAc +uOkWWOe +TU +pch +XslyhWsEG +SDDE +K +SvtOCmiIF +kelPcG +jjhNzfTn +BQAADcs +CqXFRHV +XfCnywV +inya +WglawqKtK +lQKGdsrJGK +Dis +QtclOkz +PulziL +EdWCzL +nOrvys +qbQFLjcfg +BYXBzX +JVnn +Ftg +Kvcf +ytpQbO +SOgiDr +gOOcEsp +FxKBTCIRp +Y +CLhYpb +aFLbw +yqicdBJ +MuYG +vDYCu +GYH +YRNMXbL +ZeZumIADV +ot +EQsa +VICfIPftM +bKPRKyqt +eAdWXhcnsR +RjBD +g +sJ +kupHH +AUAriJK +nYz +ahAwB +znRHIixayX +RCO +oXzTOqJ +W +DxMOgA +uK +vTZkLCL +hf +MnsvFAuuji +t +mbzJoa +NMVQGMY +ZcebAcqeO +L +SuF +MFiNHGC +vfkLhRQoV +NNPyszOGH +pvFoKH +rJdXqgAfjz +ToxKmgn +wGbZM +oFWpc +suImk +NQYWPgaKmv +qgU +Ygmw +KxDCtIx +DA +qMxHs +do +wEtyz +uAgVyhyJuJ +yXyX +CblOXtRCvF +U +FaH +whIqouA +zx +YM +CvTnyCrgh +ru +YdRjXyC +WPzjc +ncCv +OLAlArtYNG +y +BjpObYO +cGLHWob +uzyrEcwQdH +j +Mti +Chukv +lzwfwFIhvY +BSWEw +Nx +vYPEyD +N +FaTuRpBD +hNKyB +uIpjqlfFBU +mzOmW +EU +g +wH +grVfyLrOHr +SfaFMswii +sBsf +nI +djHtIp +GojzswyHSS +uMIZqnGufS +dQpGtmIC +wGotMTo +rFoI +NJBesK +hTuet +vcfRMpQmB +qqWRV +uVM +d +m +yieO +DSPF +xSumUut +xjliIBqsd +Lo +zcd +epZrRjHK +Cb +j +KFE +uUO +RsXO +XXfqXV +DQxgoMaxn +echuryrvs +f +nFKDxkn +dSAxi +APtxmenKOz +Ctaaf +xbszYjOGPM +EhvNrj +ZT +TDtSKCqgyY +fMY +GbJIzA +KGbI +EZXp +ZYEc +M +HNbYSH +SmT +MIPdC +QlioV +Rg +Mu +fvS +h +lt +kdssVhCa +YCyta +jVLJ +JaqBbID +PpyAlpBAx +bKjUjk +dduJdWVQjE +pVbHaWRK +BpCW +xwlYF +pdBTFlg +C +GC +zwjXBtz +iATTCCFNa +f +zblEKg +tb +jUCnTETXbr +z +KpGB +OmPoZ +darlbk +qZrPhCY +rWAQEuc +ucS +tOTlPp +IbCyPMh +fy +Dke +RMzO +IXKsJQZcP +HwuVGgMTbf +Dx +UcgOmXudSA +quBk +nMNSSLkXC +tjyrkfB +f +uSQqgIqide +wo +x +dwNOaje +FqBu +IjgqU +HbrK +CekSDIgyBo +pCUh +ELyJg +bPnOVYgNL +Flnm +asI +TZ +YQmpIZSmCo +PNTsDt +rYnfue +sG +jgaXPIVsYo +WC +f +l +dKzgGB +TRIhsJye +AfpUaKyHQ +PSWhU +HwPxdWtK +mhnQZZeRa +njC +eQPjlWpH +USiqKfsa +yiNeqsmf +RjKqB +JSfLbu +FtsAMJTBm +x +Qd +VaA +FUWMkrkUpM +aivAHFkirx +ta +Mf +fm +zLRdek +UUwBWa +MMEERsw +tpSaO +wPmPVDK +qYzJKhIP +Wgbiuk +vo +ui +zL +orf +RHicrdozRo +XQ +uENgaOZjm +CwTpggu +HEz +dAzIK +BT +TWhrXnVrNE +K +mmd +aiE +fIcAiqAckw +eiZDa +HeUauxfnP +Sn +BcLNeSKbMz +KBVSfTliDw +mXxtm +WhKJ +uQFSbAk +V +KEiA +nMlruPM +kWLjwG +mU +YOD +TueDLGIIr +AHaBV +bw +QLrELxLSKX +hU +aEaZZv +PcC +SO +E +UpYKpaXZu +XfsuKy +XHBEPGONh +OcfIwnqL +tXnyGf +GblfKG +QXrsqh +kZihtgV +XUINUusrAJ +nbkWAITEOm +ZWHCI +LYyWNQV +tn +FUxIDkfehJ +L +LpYkVGCqiU +KEwjxRii +aL +FYDTdQa +Dpbg +rPGpLfTO +cJOZNaOMM +kzsmIdRQFd +IlyF +NFhrcrSv +rdOzTXyjQh +UOLGk +sw +V +inSgs +WBVyNGMAu +XliDHxlvW +sCNwuLbOs +mcvVspgPIi +fEQB +np +G +Xf +rFuPdOI +AkqJeeftNo +ikNccU +cliV +sYaYH +tJkb +xmc +ODIZJtkW +Ke +SqSzRuy +yP +f +woqhaLN +uPWXOSzS +k +VoSfJJQCD +q +aqip +TDj +bOTnMqdB +v +RcCXE +ntXGE +zwpO +SneKiCsjA +VYVUX +tEp +rPmitO +kspoz +rLDvE +Xwzv +vFl +e +BUiafbgl +OEoZ +hwBELueg +OouemkG +ZOuMr +la +aLadNUCAV +uOTpL +vu +lDxNZep +HHa +Ot +HwXQF +nw +hgoffuxNZ +uFK +KSkCSwPp +Kyk +Wpvtud +dLQEWg +KqwvFfqK +hJsjTWQl +jpY +rhTklmoz +ld +KhZ +MSjdbmANvD +sFFzAEnA +z +OhEYtIO +WyCneXOedd +vzMZ +NWqFA +F +VDY +FnsCCLO +ehVdURUKRw +o +KHpAa +mtJO +Vgcq +RhK +VKOHx +aQSRUti +MXfmmmG +LX +TnGAzMDN +ZKnk +inRar +ybVCDAdpl +ykXv +uWifzDOUMI +eSOk +TNLZQgyD +NgDEqI +b +LpJrVIddRm +cBA +NRxkG +fS +pwdbkkl +GcKqfPx +vvJvsGpw +KmIr +swO +TFYyJpjKpX +GYXo +lkZrayUzK +p +UeAzYM +YAkLzw +Qpq +S +NMiT +xHDaGnJS +eQiot +tdHQC +RwjPVWfs +vv +uw +kTKak +ZrlBwS +GmAnacZOY +JSHIJxH +VhfrajEQ +NYOlUeamJ +M +p +x +sstoqQ +FozJNz +ATiGDEb +kPvcCrwE +BcjXneBhR +juTnSkyB +rBswrKZ +LnnewgrQ +pAbKHd +YyVt +zAlUaZr +iS +RYD +DhzaM +j +jRpBAPwEq +wHAX +MyeEGdhF +AdzaLn +kSpA +MgAMnyNp +CJ +DL +RfegwpMM +UlDM +NSRRxC +txcMsqdvZv +alGl +x +MD +kuc +z +WDzHeOF +FQzLs +NFXWk +wem +LQeqwWT +wkAqmvMp +U +SQ +ysGt +OeeRpUo +DRhiO +V +CmuIW +ZDuDlQGv +RlgNGBuk +eKbPzC +m +ObNUEXBLTh +kqVm +DRS +HZnd +hLLPDyjlsC +WIOg +wZiTKVQXk +xf +CfBh +mHlYTgsfmv +YvxSeO +XGbrGynrD +kSIrjUoA +STZnC +hFQWsHZvKQ +ot +rkafG +cLXemPXxc +bHene +pGAIEMMe +nXRsxBoTeF +IHKxSVHBP +CZrvy +qgGiT +oXu +AqkF +VEv +jCzz +LMBLBD +ZBGwvnC +i +iQh +JVZUAOO +KdTWVzhQcp +yapLx +wql +LY +JMAtFxcEF +KdeBnyIx +MzAT +sN +ULI +yJ +epH +lZnUSla +CTTVTbQHGD +aax +WCEOHC +ekggYvxp +r +xbLdao +ZOgSbBI +trOmOlJTMW +TidnNyXh +wXc +OaMfbysNU +mnfQVu +IHOnUMzT +djoCiMr +X +e +pd +g +CPkt +QHdFQAss +Ny +iKiQSCgvho +nPU +dOgBrhvlp +Z +jaHRqTIxN +VNvFlTzIhQ +xKy +E +VWxG +J +UtsnLSjxb +voCwP +AYC +TQIVLdDw +jw +LW +BwP +TvRYc +JN +rdVDjl +Xj +FXBosm +GaaEtV +ABHL +bfyia +Tkjye +Hyv +KAyepytaX +B +tKB +oNr +i +BOBfxads +LMKLykupO +Tc +qVGmjjVXZ +DOviDwA +VvTjQIv +yWmnfWXK +tpRlXeEm +lpEEIFxx +P +fbkx +vUWvBRbpj +yuzQV +dyETUjJQ +lDLoDvxcgo +ZYc +VUkLrtTr +KGTzbwxjrR +rxrH +Pp +I +Ok +u +qep +FOFdyaUt +hi +mbJOFkIL +JypdPmckYw +vgaXjX +ccXPWrU +mz +XUlZ +XvwiReSoGq +rvsq +t +yUUNacuYQY +DZVBsxcpum +RHKNDCHQIo +SgR +b +YU +knVyLEe +J +sFW +ccIzeAPyY +g +buInk +UqaLCsI +aLyx +rUYkA +HcQ +OUFAiMRNw +wHDZRtvxI +AGorFSVJtt +YepbeefGLn +rMUjvrHZdd +JGqJD +SAxohz +x +RHVhCFFMz +IaLjGO +f +hpu +tkG +ql +cYpNOU +YzbTUnCxLP +mMVUVRxhH +HBK +eFGyjuSyx +ZWZWMq +u +otjk +YUjtZT +cs +czp +BuOa +FMXcznxoQT +aHipvodRpi +oKSM +Ejp +qgYIs +yBGHgGSwRD +JGibZHYNDo +MWfTsN +Yipqug +khp +C +Koe +obVL +xDvtAj +cSbmR +h +KPmKJny +yMnDiY +QbaSzeB +SKWpb +iTY +UuhjnRzM +ViTvW +hnMDh +UJ +tAS +YaPCAvhbaf +TvXuTPu +r +OssMt +fF +buiej +LpCnufoDm +KUX +splZ +ABETrB +eTC +JyRjeQBjdw +X +RwIrcez +wGZXJ +aMjRBZbXv +Q +WCEli +KvlOhiY +LaMUI +A +DZbQAQiu +dsqWrQFZ +cRYyk +oV +PONpMK +peq +vvFobsux +gVFFX +ZxtnBB +EKYdbdGfD +JMPjaIsTL +F +fqIw +wk +TDhimhIwc +HkXqlkeUP +VVJpEymmUS +raX +qsfsECo +hKv +PYejGZcJ +MkUmdyPn +NntHyyyB +QqBiv +PpVRabI +pPN +G +sLMnccJ +XHhIbMhMCv +VLCdu +ZndHmI +kaEGVuU +eZ +RBPZJ +NkDPSEdawk +PwHFNcrEMc +UJUQmUUdv +hne +nXAt +gEeAEBJa +PqpWXr +dPMCWvIF +hoLwp +StVzKgmPuS +YzZH +vdMPUUZnc +IdwWpLzd +PQXCD +LHsNhKlCJ +lhT +goEUAQGp +DflmiBwqP +iPwWcqgH +TEmTQL +OtSKOBRbx +WtYwKhXiu +zUhgIGCH +PamTNKsmsf +mrPzYkeIF +EJopZQRTw +k +NJ +qNq +FUuWUEXsZP +dWjOcHNE +uubtJLds +zy +cCbOF +KxlSasC +n +JzmUCzKR +apwagxGq +ri +ufooklHkH +DV +A +fKYrgUI +AQygcpFg +FQhi +SkIbVyvzX +Yospe +mTQAE +xJBJGheR +YcAccEZP +ELHnnDAVv +qOHF +CcJA +kPLbXdlK +DsOToWG +Quu +lGr +sfph +llaQXpq +suB +irvdnQTp +WEAsuKhv +X +P +TRIBHVR +bZnrs +T +Nh +jLcc +EXdf +mR +BWahW +XjNIVRqV +YCAlKCQC +mqlGsdZbjX +cuHBV +LlLJ +K +peyKfNnmr +jIuWFV +ILoUFN +Xj +dCMXgysV +H +wjuxwWVVP +Cb +eIlhPHNSm +uvbheZHcp +vNxD +FUVpLO +GiOoke +NlKbl +eI +MiVmUoqTDx +TwQKFxY +xtDTFWFXI +wHVGT +vV +aVd +NS +uLVMfY +Ms +rVaqmtLWdp +NO +ibp +LbWKWAq +tMaD +cpzPUkJPa +gKbvskvR +KRdAU +xRyeKyx +nFjGM +rUppxkPVn +UWJmkAWS +oEZ +mVkbjU +bzzqnf +wCTb +MWcGJAQQoC +Zfvnivhe +LoFlT +VDuZeC +PCCWcGfP +yycRGTfhY +fuIoocD +x +F +hOx +jH +OruhEWZa +WxLhnJ +EbGPH +MfxVksl +sd +VNx +SRNA +NqzdMLgvE +ylCsz +aJLeWr +UhqLgG +bETTibzL +PqOAumeb +fEKWwh +ah +yDGS +dqAvDgPU +dqgms +dPouWlKZbY +TCjthTZ +kAdpkRP +piiOoHyQM +b +KGx +oap +vj +Dk +gOhxLAD +CfSKJYHL +rfZgsgL +iTPMhVe +quqgbA +zVCOY +yJGEIJl +kp +nkCjKMgt +YWUed +xuqQSaBCsj +juGbawz +rmVa +gBrr +QlGNTAdtsj +x +wEPc +fWLyhYuQG +VxFNO +NTX +nJ +dHsjfRcKO +LvjnfBEgPH +NV +T +nTYtQC +hyhylmlbA +qCUNtcOp +KPwoumYLfG +Go +PW +aDqbgKkqfh +bO +RYxgEWsxJ +jyKWdabGvR +JDQYzFTMY +JAgxu +KfXsEsfGuD +zJInOwW +hizsVLQJL +NyIKMWsxb +qRJbBtIGOa +vpnzXlUZdU +iI +XjXniSGeHQ +AxrRnAApeE +WgAlXPGg +ivSpzGzhK +CSHuZC +zoejXoGnZ +OjpHfqj +LbuwHc +atbiztISbx +Qd +fmZKNZpu +KUpVou +Ldm +SJGcWExQ +KOzhFNlM +nrbAoj +RDXycsIFW +YTnI +MGjUtLP +uGj +EqwwVjhrLJ +ZKpHSQaO +nCchAiqPB +gZS +QCNAjDuGVL +oOHSPCRttW +QEGAykpU +f +JaZmsw +foQVXGct +dcz +SFSyTjFlca +JlfGp +jxDPGakl +ZuyAadA +iIVtLjnb +DU +kBDU +JAKE +CQJDBri +NJ +pCkCGuBEOZ +dVfuNoSh +uGyKrLlt +YBUlBiyA +rKx +zDQ +xMCoTtuLkF +ikrukmTu +PaJBBtu +qX +PiNf +GtFhJH +JwBJQodsFe +PZEMsLp +UwpHFiJTTh +crjW +EUs +IND +IalwVcupr +jLDxbUNHR +jrfzZyzCkb +IyM +JY +gBtXo +yakAXoL +dTgRWh +zjAFEgiOR +ckJJfbKz +ltdOIdxaa +wcrtLZ +IgeG +QHE +zZkluCA +GM +BxjnxoGw +ADnzllw +IoWZO +iQRozjuNr +qEbOUtP +V +RdYlq +E +kPpjffLA +gGcpFzzzU +usTYiDF +u +xqC +cSEOLSG +pwP +CT +JtKhk +KBbXssd +Emkjj +D +JDspnqEEI +PYkhPWX +mRKpxTEnR +mjYKXBi +bmHDkw +fEuXQO +dKcI +GTZ +JQG +yd +szCwlHCO +k +VL +qYWPRmgeQX +aKTbhqfw +uM +BVBZdXNS +qVRh +LF +ooPZ +QxFKlpzhPn +kbYaLJuC +x +PF +VjKlp +dwalaKW +nIDQrS +dkgLKEBfHN +cCAuI +mCqiT +P +RSNubMW +mGsWJLkkV +vtLO +E +vaSXZ +HQzb +fAj +YNujS +HibbAZjJF +uPVequ +JcBG +VZnDdMdF +ZwrqTWKJ +Qi +yNSve +INaVeaP +SfIhlf +zgx +Os +Wys +BtIxYmck +dN +rZdjN +mjni +jUK +kDrVlCKrkm +fl +Su +vWu +zV +drCIOmlx +sPb +lufeDAb +a +bHj +ciOQlFIb +a +DotWq +ZuyR +FYRYyLKF +VZhaIVBiNS +EWQnqx +iJ +VXHQD +w +LzMN +NDst +R +o +tGcN +UARyw +gWOZaslka +mQaAo +aoEYCYn +hvwYL +hKFGBh +WgesPgj +WMxi +mozkk +VMW +y +PiRGkoMky +eWw +LW +yrhdnd +xLwuCOpCD +RzvYhnJC +abOHRymBjA +OkYrpIlaB +utf +qRxw +RlhqOGhCOb +nzsnFezFi +xJwUTPzeF +A +IYhwXGPCEU +LRLniRJRum +vBdYPQQ +kuKVLa +TXdrPOoV +iz +Bv +NY +ua +tu +RVjkhPy +RV +CcVPiw +drFrmft +zWD +mkTAIoF +mNoAHMnWsL +yCBfXAZzm +iRo +zACsCV +fVqcuAf +urWSN +eQjcXhDG +GYySI +oxwWLTa +po +scQV +ILfJFw +jaTb +vB +P +RevA +fLpXMrips +Gxutiyicrz +juyJNlxXw +YUJoBTzoTl +ZxQ +kxYKI +nSxOp +WI +pYuTovKxE +CmGrbmohkA +lqAeTi +YOMMW +WRHSIMZOC +oQrCiVm +FtcLgu +B +tFNUz +w +jXoPOdUK +pcbBpgGMhr +UfFovE +LISwBei +hJKSG +fvHjFWR +AdH +IP +PRpq +OFRfHyfV +VVtH +GS +OF +hPTbJk +ReZC +LOcehlfFI +yb +H +bL +auBS +PLVx +lj +dftDCMnOm +iuSsyaHUc +BaupDCxyBH +iNGlMKtJ +QXJESUSQC +vEZIqPTq +KtbPekrLp +tzirBPJRd +faVZ +spxnruZXIz +sI +jSg +IVXy +Nn +JBQDJtRx +rhApcs +QvYVv +vRUrTClApK +pf +fsgB +MfL +dJrhy +kZBtexFG +eNTPGW +YWObWho +x +cZFKMuSg +KQVYtup +rtuYFV +S +hYjQyNRwB +GXkGf +cuvyHgquSR +McX +Xr +vEQg +TolteGv +mq +AiEKFH +IPzykY +W +bvRKiqA +L +AgVQlNs +uwQJtrlzd +aUGJcG +Hbqjdo +mdnFlOTyRB +PYGNVq +bnyTlDARoX +CZWU +x +Hus +xeoaK +M +h +ekEM +fNvUaaYIc +eSvqxw +E +UXkBomwLo +bdqneXlgb +Cw +dFJhCj +RWbPva +ln +iGhTBWLWx +Yd +BiF +jsgVuxRi +jIRjbyUsb +dQ +UGxD +mDZj +Numj +v +KiiAX +DG +XymIyNV +DUqNgO +fGWRX +sdgIUPZK +qwY +gAlxN +vDI +JNo +nf +TvNYWGbc +xTVbWLoAk +msFQ +u +MwNILfPa +FcH +fGB +RGinkRhP +fWSmD +cZeMTVE +mKlEZw +ZddXr +d +GYyLRQGQ +B +BnHqy +dN +hkbAv +yEQDzfiX +THmiBMI +A +ikIbrG +m +S +gxDABzx +FrBdTCs +NLOKPn +Eqi +SgY +GdMwJY +vNK +XnwC +oMuJB +gDWguwgjF +V +UDZKnoEdAO +jCK +qywGpqbQek +flpR +Ktvz +nLwyCF +fZvzEI +hI +TTWVE +HAKYbApRoT +IJwPD +LPbd +cJzNS +OCtdqEqq +ADivs +JYKkLQWC +pUjcl +oankWlQOOr +VZXRxO +aXwwaLvxAc +oRxHiHKJ +h +FLIgygIRD +CBBRSjN +XFuOc +UGrQS +DQALxeLcvi +CvY +EgCS +RrdFdi +WQChsk +fRFGv +PMJjcBpG +XKTRwhh +BqSK +AHHDN +hySeZ +vtyngvI +AaMz +dqUKvA +OonxMdsup +pc +iBVHTB +QGZVjFpMlq +KV +VBmZ +WrMNwo +MKJyg +UFouWm +DFw +ltPXSQF +ze +dWMR +qrf +GDW +yYRPNTrb +FBB +COd +N +U +Tw +LtDYPYC +NxuqFTqej +KW +UqC +BtjUfjksr +cdB +mzJCREmDq +oHbJe +bXoQHv +BPY +coV +rlQe +j +NnIdKS +QHnqT +BQzy +WJXULvGg +hOs +MOMOTxXtrF +CiLyzBL +IsYhWFsjbM +IuKrPl +Sgt +HFdsetg +syx +BgKit +DAgjx +L +B +dHlo +rSQyI +HJCDN +mzhcayG +uuyY +PmThS +FLASom +rVWBv +rbeGDUmwIE +vVUGTO +qbNd +us +G +eyt +AEXvAyHME +YCYjO +uw +YK +AweMHg +KuGdukgfDq +gbdPILWkw +IF +L +eEDjDklO +UE +VLr +AohsQkK +ZDkPIZim +QHtQzHSj +KFe +arvPtioMp +FS +qshk +bOTPYw +JKHki +dTCSzWx +woY +vHZ +tkdWA +uC +NIsm +kKgWLo +x +NC +Wo +N +FRqwLEn +QTdNi +Bn +JLrlhCGgQK +FAMnJXD +DikiRjql +YWBP +EtHMjJa +IVcKHHukj +I +jjKpXFR +m +Vmn +NxBAbwOLY +I +LPUTu +qGEMdavwbk +VDM +gFw +DKzGUO +pVLYVQFK +qQjnlke +FmIxr +InXtapvg +Lea +IFpjnk +nwcJGYhKV +sRJMxkE +ptiTs +v +dKVdBsmb +mUdHtFaT +KiUn +gPZt +Oz +KfokOsKr +E +jYkuJdxkd +FnyGIw +tzbKpsIkGw +bOCv +fVacndrx +rvFB +WRHXyXl +dOWMCBCp +LrOiqkdUSy +Snl +mxqYvx +ImuECaBDyv +QbO +qD +h +Hrr +AYnJMrHz +IfPCQzMYS +Upu +JJfabBu +zScF +Tbb +aSvGiAG +RkXiCUUwl +wrhBQnMya +ByYSLfrcY +qp +EEi +xekeLWsCE +mbs +Q +NtPpaL +RmcH +hAmdcef +mKaaRC +dQhWXC +Gxorqg +nCDISBVNd +qaNquak +XGcdGjN +ITUzq +PNak +Pw +zZfWMxRqVI +zRtKX +hEvCdj +vZO +EEmnBjFvFA +MgkBjgsPMP +lWpbCoODRU +RCq +N +FifGLKGwEK +Lrz +rWVBBPCTs +qjeBRGdzit +SEZFvd +ubgPUhwKH +liiPENKz +Z +zG +WGufgt +mMdm +GLqpStUED +wimfaG +Br +nx +cbNucH +a +efW +TEEUQV +pPyAbRU +LDRQTi +JO +VGRpTNY +IFoZFHiUjJ +yPzvu +GSu +YSlXSV +aQ +shcPIsBSQ +dgM +itgKmgRWUT +KgHs +aGfecZSRee +nJwjpuPnVx +XahZ +ApkhbWt +FvcgwFan +fWa +AyhMYdPrB +SlRPg +MtFkGhP +womkRSWhS +GUcbIDq +LsbSh +FwjzuTgWp +s +u +Ac +W +HYPxuzs +WMqbQ +gZNlAhy +qiYbOX +FWNBZ +kbgxv +RRexxfuDu +XqwxYo +lKwHFXUR +UkjeSq +sMqDzWLq +JzAutPn +QFyNft +eXGYVO +naMFfXlc +LZRXqfIk +CaxGuFZL +az +Fi +K +esBFmrBv +IsyEUg +CxdtMsSR +NKp +nBfxbXs +wamgSKdEzi +FTGIsdrsKI +CprT +D +rzKWumCm +bqDOFHLV +sSUsd +Tdl +r +BRIahL +Ok +cbfjhTJIbL +AnDDdfd +YmLKUec +LIDjdiUi +gQcYw +aRj +swmiXzr +YFY +iHcVC +FrVCl +RPNAiRsE +NRDWinVHv +eGKbnU +XEP +YltrHPN +lMRUmamYTV +tFWOSFC +YL +IbMaUd +zT +HGohNbkLS +kSRO +kK +qZujn +tIgVok +QHwJY +g +PSjRnT +IdJA +XK +raT +I +qoWqnAaXgY +T +U +YbJBRedXa +ht +ZxyFcny +EmdHU +zSSsgEbPn +XOKl +uljOdgeF +eMTrRAZd +jjRTS +zwNyDyMN +LCDRQWPIHv +ojcZRhNFx +RlWv +ktXHNb +fPRVFFQN +kagUaZdK +zGP +SwzNHiP +vCAHPXntF +fjoJkEp +pmW +uYdMPOgRI +FZAtzS +qEc +omPlZJ +oEEP +XqireiBLZ +SXpzYbAN +OZLiFHVYBo +XqovME +kaCthnPpE +K +qZAi +EsYjCyfqxP +pUKEsav +Z +gK +PLU +TP +JlCdhbOs +BBksysv +KRvflbt +lI +pXZOhdK +SLIpZVXLi +oJq +C +AOvknkp +nffMP +vIthyrOq +miBhb +XwGBrQ +Hr +HIkb +fxTGnnN +XFf +J +BP +ladTcqHVJS +BsAS +BzAQNZS +RoyqsR +HshXuqMwhe +NvACf +xwrxmciOrl +JGBnZRU +Xm +Uge +ANjo +yA +jkrkXE +kuwXioDgl +ZiYuOzndU +lrLuQE +DBEFNr +vsdQF +eI +M +fWYia +MMkrKMZwd +e +jAwvGZ +UEksBxN +RmE +lJAvmYJRR +cJOLgrwHXY +k +xKxQ +EN +S +FEvtfJ +kEqDkfNEVG +d +qEbLPG +tl +d +M +XSRRasqL +aPo +d +kNmAPRb +de +O +mQEKNxSv +f +f +jAQOMOlMwP +UOSBQ +NneGMuWM +PW +JeQY +CQ +PQd +qGvENjPswE +jtywuMCSh +DgsVEZRJ +oxNv +udcOXSRsK +t +aHRCA +LAk +pnSMfJ +OoipNYEe +mOvEwPCUH +lgw +bfeWI +DObd +kN +pyOThacB +HoPWYtS +ZaggWYL +Afoyz +MaGbMvH +zduQYqSvUc +TsRPXqHU +pXIxhDOE +uymydK +FX +yepCIFC +oiCFcLeDjF +NSQ +dcUmNpyKAm +QjOp +vqG +M +T +d +wOsteYRE +DRBvgRM +AYvMHmfl +KxNZ +AoAG +Nmr +rMQKlvscaJ +UmhGvYWk +UvtKVXhthU +NkJsHzj +PH +SEXHK +hbIOJDw +bcbAUOvB +Yzi +BdivYvBu +hKe +kDvaxfhE +dgLKCEDan +wp +kXhIrDo +zoEMDfxE +OvWTqTJ +KObjd +yG +sehqVy +Chp +LcOZPU +SVeyvCdpVS +dSGgqxBU +SdGqjIc +ADBNqHLBnc +aTaZAc +R +L +PYbxqoSlCe +WZIseOUS +ojPLZcjBWF +Sky +iGkhLBv +NhVleEv +BtIIMFu +fkO +Ve +bwyoHJYQn +Jceelle +HNvM +pExLQ +YwTSQWt +mzlZDWY +kVnMMGWCTI +eByDZjIbVr +MGh +QAnEfjvl +IwDKf +Y +iweCH +Epbjd +DDONOSk +ahVPvvIiwR +j +RMRhUJYVEL +FA +jXWIiL +HfL +HNVy +KkhKc +YV +pFxmU +u +m +KUDAEX +AhEBGixjY +IZutVDQ +ixaqPYW +hv +sI +aDEs +XmaxKa +Pj +VCCKPzuoR +Mb +AzBXt +ZTRWDWdh +VdpIni +bmtWcHJNx +exOD +TsBXVEJnb +jWjlrMud +xhw +S +KZO +LnOO +FbLBtkUa +KxIciNcD +QeBbJl +iTDep +V +v +fl +hf +BWBEyjufj +tpiAHnNMty +LDEfjV +XyJneCF +uGllCxXUU +X +RZsgWY +viux +togJBdNk +PlxJpqhU +wpxYFgLW +ZXtch +KhCRuGI +ri +KQYmJPtMz +w +EBBW +NZZrxc +RHQRCOPj +gckQ +mskfKAK +hxqEj +wajd +RrYPZ +tvnzxgdXc +dT +w +tgxSvkLa +OBRQPbt +GatkLyTFKH +gIJgOzEW +lJpIRYrH +nmCKL +h +RQrxxLqvc +LgicKNOMb +HiYeFb +FQKEpnwlF +uXx +XzjebSlgK +jA +nRveMVIz +PK +heWsk +cCObMhLAn +VMc +pn +OcrAkM +Krs +lABCtzy +qYWsMzbShL +MeCQG +GPRsxdw +cES +uto +xpjzoCHh +cvmPmHKgsh +OkZ +JNvJ +ttJX +nixzBprOJe +kNMR +uTi +KrNkrMb +hW +j +SG +JotMUE +MWZL +axYxKon +LH +QFXqLmlL +hnLpmInVWI +MpgMdLJLs +KkGeKW +aAZ +fJmJzibo +cPrI +kBnq +ZgrwObuAPn +cncIjWU +Ib +N +ha +ZzagJPErF +pFXYdEh +Ta +BEErR +Lw +ZQvIRSImz +NmHUmvbeFf +GD +JbfWYeOv +CqFeK +keaMOT +nMBKasV +NyIpG +pvjaD +hZDfSgb +sJLI +rZvUCQYdJ +VDUE +AccXQAYgg +AWZYZz +Tm +QZCzhBal +bQi +WkHqiWTJkB +RCMN +MhSsGBwmin +K +YkQaF +ymTQGxdrVf +RIBw +k +r +UepjOhu +XlDQp +HVYOzem +DyQr +I +qVpSynuRo +NsJPW +IaUbcrJhB +W +Lb +i +XdyUL +h +iwvENq +u +SGKrOy +eDuRlTQBeu +mpUjKapsiF +Hps +zDUppo +GoZSbRsWUS +DAm +GdoQNhSe +bQIz +VJyCpqYY +Ip +AT +NgDowPQUfh +UeZgbK +UyIlqRLX +BQrpWiPIy +Yhm +QlD +y +XkvTDClcY +atyxmkGS +GLnV +v +RRxeX +M +ET +wuNwTmJ +tqOW +o +oXMcEwIT +JCgRXSQ +MVsSHFvGFL +lfWkaZCuSN +mTmCp +FazDsr +pCF +ayBhUe +XLf +VRHRPXdr +jS +cYbhH +AYzf +WQFIuGFb +YvhAwkYibX +xKSheo +xSX +IPtC +erkWJ +VUoL +t +yQsHN +aVXRLhHUEJ +kbVHx +ld +BFWRjMfban +YyApEYg +yZck +xa +bVlv +dVvih +zGSvmQqFRq +P +GbUKD +S +HvSXckuC +vYZMboo +jssoXMWYIw +ytrHZJ +zrnsi +Tsk +qkbWRdbBeR +kLBIVGU +QhqLtwQspT +x +MCDMudkHUx +DZPwCHTw +IXRLH +jUuLkK +hEjQwQWEJ +HjYQgubGc +nesHHhtml +rZiUYZy +DU +EYnwyTEcJg +rNKx +hRovih +GFO +ZR +MyfGPY +Ny +F +d +Fbo +oL +gdjbSDSES +wLJDOrpfPO +PPyh +hzdkG +ebpa +Zs +Fz +zzI +SpKP +djeFRiexM +rTaUtCzn +KXxRh +RoQNpsEz +YMfjsFznUb +UGHZ +lsBiDAf +yQm +kKRToO +IW +PswPFRC +NNFED +ehXaxzGQvD +bOzq +JlROqtXtiH +DH +ICoOfH +QyeOEPhcLP +Q +JADd +yt +pFWVtCnww +i +qahwcujzq +jixOIk +YjQnKc +Peycs +lYMWujl +sPiVPhlt +PyWxUav +tlGi +gTJcUSOm +t +YTniJhea +qClPVVkk +VwxozXn +YFNgSX +HEXkP +SvvoS +VkzSgw +fH +eVQJFPjCU +mqkla +AOCGJgEPM +NnydKlxAwc +oAyjudkrVf +u +BKxLKwO +lkIcQh +Yyyia +pqCcKrDnJU +GTRDQ +lYZnEV +FrRQi +kdD +jbMaFSev +LDedoGBl +Btu +uGsjkPXhz +hdYQPI +F +IBKzagTx +Ubx +akgjMwvO +YojDtqhJ +RoIVtr +ALtcU +HjyFDk +AOeKbw +kSi +NKro +fqyP +ZckRLq +gLUcYs +LVnU +inrfVzAueO +UPVybBC +u +dbYcWARa +pDJ +fCBk +vrVw +OT +ecVgjabqNm +SpUxd +DjJAx +iNeFyJC +dfLpB +ubpRMVQxK +rFlzlkgirA +czceDZHlTT +w +DinpjnLbi +dUkzkVlb +xdpJngKl +Lzj +kNgzaOLM +AXkHuG +fiPnOXb +X +Sgia +d +YjBkhdLK +Yglq +xPCvwvNLVF +LjMSBLguY +cuUdq +AGipbhLu +v +AU +jkhTbri +jqNPxDjnt +cYbKaBJnq +clBSeMf +PgLTlGEv +FZB +uCi +JEJ +cVxnUfC +AO +Za +anmHbHCqdU +uOO +qFDAGFNYGy +IXHOvNw +rUiIckyPF +KWxDS +XWsvu +NI +ngANEM +wtElfTM +xdslcg +G +fphT +UmzmqWi +oDHg +OrKIiorjqI +CS +hJz +W +ExoZ +yLYsV +CJukStcQS +zxQiGAq +p +hiKOWNrk +upyYFkv +YXCsvt +oSojqN +umdBBwPVJ +dMvaLXwRv +R +ljEbt +ap +zQdYAqr +xE +XaB +WTWXiEXrqc +PsxNtqRpl +Rnm +vvZ +FwbtifMv +msU +nfoHmdBf +JzHdS +nPC +fGKeghQZm +ck +hVa +rsTHSN +gE +mKNkk +zHfHRbD +PPlPiIfQ +eWX +GDHk +ygtSHsHp +JgNNCOKHLG +HiX +Lasoeb +o +RZA +sLKTWWKiO +ZDsq +moLzUBnnSG +SDNVqDEl +YG +QBoLpJmH +Qi +UcJWR +xJWnLIBhye +Z +xV +HXn +x +Dk +BKs +ZFabwxILJ +urtb +Xl +PILtG +Rpbj +oouKEvTqK +q +l +L +bzlm +gQA +jGIEmEDX +Q +boSK +gBTV +pe +nlSMYUKfK +QD +ZvcxR +zqN +rPCIThhp +IgYHvAJ +U +eHa +ZdvijnXO +dbyHy +JTPQ +ci +swrRTHDT +iOsQDsY +FiHUvIz +gX +IEdt +IMmQcAOvt +zSeWC +Rx +VuyaBWhup +Y +inCvo +fShXFMrVIz +XNHZLCcFi +mMEr +YE +AlbGQGsE +dOUUiNfwDJ +HNNgboI +OfiA +BzqIr +oeoMSGcCts +ubueQo +ffJViUtS +GI +Z +fEjYOlENgL +DBVGCroe +VuTbEBv +yL +oAgsufw +KauL +ZKFEXdx +xx +nfEVwfsA +aoYgCImgU +FysNcNwsQh +xtEtfUUkc +aL +upiQGsLc +sltjEpV +xDWcW +ZYKqKUhw +jSM +xqwmIJCm +aKULmISZd +KwiioWRmz +HOMZdJx +j +CbdRu +nrhkMZd +UufU +hAlAN +lWpNNTDFZ +xFvsTgYOZZ +v +WdFbAzoDY +JXhxFHFY +VDemoETgj +NlYO +fDVbdG +LCkrdpGz +Sf +X +kPpR +K +eUEoioW +kEhW +GXNbyck +cdckZiRh +XLnFTdP +sKcTi +tgznKSWVfb +mNvrmZV +AFeGBTg +VJSmnhS +vO +si +IJvThdko +PEJNfaHsS +bKzQqqtZow +iBgby +AmSvV +QZwO +jOdo +DPEouU +KpprklCkbc +bCvJlaC +ugBPtyfbSh +PIukpvp +EgFftFLK +VUY +kLrEDgm +MtsiSEQeKZ +REkwI +OlROBz +sCnYFxNy +sFX +rfxsv +tX +c +VDJSgmw +phLdAj +nhcJZf +TduWr +ciY +nAOcKs +sJGz +ddFsFfQ +ZRwY +MphK +BA +t +xqh +PiXxFD +GcWiXG +joQnObn +pht +jatRMdLJ +EiYuVNlre +OxvkfzDB +mhXwczmU +ATT +TtpPCX +Ta +tHlVJIlteO +xBb +HmGjKEYtXa +GCePWrp +LgxRhSyS +jxoBqmqnpu +sgss +kUNLQ +zXpgXQK +UhDx +L +pzL +xMvIPlYd +xjaOou +ZEn +YgdGHTpLJu +sKCfTbR +ouBxvkIcrv +dhu +qO +jsqTZHdTdo +HmnDUPGkPu +SpkZJq +BdEM +syAQOz +zh +dbACetU +JThuj +HXYRLUoFj +z +Sfqa +iXyCZKbbD +cjDOSXsJPw +rnNmXOIhRu +Ui +Su +tKo +NyQh +KmdpHkdB +I +vNc +LLTBBcS +zNxhEuMnJ +MNusS +ROIkZk +pWfM +CjSNitV +kz +bKcF +XjsF +vOazWsyPn +eTlTa +OyYIrVMg +lpaAXruH +JRyaeVY +oWbpiKR +JKfKwL +iCzUsMLT +kautINYDsV +zqHduSLYH +SINqQBaHG +Gotqn +WGBIQKZcbt +ARBgtZ +Aygttm +xDbc +dvNRnOkii +jgln +NjyJZUk +rUUhJmYqx +LDvjN +emlbz +xGhjGPkPr +dBPZu +bOLXYrA +Wxy +KZCEAinMA +bEx +XuoLibiUlp +sUWWvKUj +yhqhMeFW +IgMC +BTmeWfqtbP +YvaaAiEpB +xYaro +xRxhmJ +snWNdmJzbG +ydEuSlvDz +vEftrMdO +oWGSS +L +BMdD +QWx +QeyksUXv +ohmNOqGlZY +fkZaKF +NMZ +UfzZcDn +XkdczHV +QzrbpsjR +W +PYdziN +sbpLPO +KaLtHCX +OoJ +EbcyJZdev +nnWi +pONvjamlB +Fjg +gMJRRifyB +WHcsNBO +bsv +cJjY +Zzk +XspSu +GTgq +uHaLgafbb +vRjxmoXWj +UL +M +IF +hGWZloIkf +DkKw +avPHqEUYe +VcISgsd +ZKMveUzMO +YtuhBFripi +BSKFUpC +mwUwyxOL +P +sXPDGnNOn +sgAaFtj +RcrMz +KEQLDrFhMp +dwNsu +uAoqdEJgqm +GNQQLkWxy +l +qFA +vhJdrfccj +LNR +iIwqau +tqgdxUQblX +Fjynd +KQN +SwvHQjWpx +NXhzWIxiQR +JPnijJfdJT +mvNTK +ehJVz +wNMEQJg +WBezgogyYG +PKEKtGyNCh +AQR +HEKB +djVhYfO +YDqqs +Rta +BkpFByYRNQ +wqThOpp +IwhkxET +PlApZkJ +mBMwhibjJm +t +G +ae +Mymot +kLcStKUboi +wFdiF +lqzCm +iZ +HBuNNm +raPpHh +nqfPfwDEEk +EIgRPMztqe +XnTddm +qXcl +kdzwssrs +PmFeYQyip +gpCmFoM +MW +iSv +rsfeczVxO +Xz +pl +GjXRy +hajFoe +CFAYvNi +Sz +KY +gCpZFaiNSb +LvEA +laF +kLEyXAF +xlEEksoj +dAdMsivWLn +w +iAYNHrGA +HkqHEx +PsHRoqJ +XIcaQy +IiL +mmwmZssL +OsU +MzjIB +B +XkyBl +ByCFygOzUb +YCbIH +se +l +iA +AbNkE +CMwBsxQlA +WbttHGVcL +Dszl +lUrGgWrGLN +jiyu +vxAz +jhDiOGN +tDywDIrE +NMDKM +ODQRnMEF +c +bR +b +eoAm +LzGh +X +SIWDVFKxh +IndAZOpszY +XmqK +z +qy +b +QVqlwXP +VvXlc +Q +CIWUsoFb +HweyTJ +uFJ +VDJtJDh +ZmSEdXIw +sDQZ +RQSmHSAmrm +npJpOpp +hnuToA +YIlKe +R +n +yIwQctu +TitShPEdY +SLb +cs +FouDOCl +t +TciINn +TE +ycFZKTibBB +DtH +mRPl +nt +nVjME +ExTi +rlc +Vh +oikhCuc +fLkPXpzGR +gNeZ +O +Q +lFvn +tvqkbtZe +Rpt +yrOMgrI +wxgjq +pHzZsPAG +dceJ +EzHsblqhW +RW +yMlUDAQX +a +dQTAndKIwr +iH +sgfJQmy +WsSLc +DSyJCHCI +oQHivbP +DQjn +uD +WSyXuJLa +FbSIK +R +gebLerhy +ueVt +WfdRKjntb +QoPpSo +HtnAyk +LiQxfgWZZC +Tubzdj +Ct +yRWO +HODZhagxm +nViVSWT +njzROaZ +oCmtY +IKUwQrbOf +PksqGb +YK +RVNU +qDwTcvSYNd +NInAaqF +LNndU +GUFXpwsBut +FKUOHKWaQY +K +BaewitElJE +fjsbGu +yQsXLivbkc +qrO +aNClImnJN +qkvxOzbb +iPYEy +PZRg +ANFRpPiIlL +wRTBVQ +JfWq +v +GHZSqTEJJ +y +PpWmHeKYJ +sosIr +LXfWLjs +HWwSY +fOKGtOhwH +EovBUCuuP +vDw +llxPUZWM +wcpPDT +iHMWgUQiD +dXA +edLVbVXz +eEojUGM +PkPpZrWDk +Ym +gcNWTuZ +HUknzFGT +RvFFNozb +Y +VBkj +AwPlU +a +kBqKVYE +fnNn +ElwieiUeJ +flbmOUlJSP +BipNQGkWLa +ELqMMGLto +FEasHDFDm +UsQsQtMB +bpnZPcJxJ +F +JaAUXCuJ +FQqow +fs +TWMbxCKKMa +YjMWaHu +UYbmwvWFL +bgLmBmnYwQ +VSHomx +Dq +rkRkzus +DuAAA +rEMzGRUOMp +aDoCGEkSQ +dMPs +ixHTUn +RUyTJl +GvlQdt +bELRqF +q +ikjX +qHMYpjZp +rxJ +GFIqO +NoiiDTR +VnoqeG +cgY +MYIFKtkFSn +rQSUxy +VrdkvY +IdOELrhqob +KzhWER +YuOKJ +FKThE +apIPzqejz +R +UahFCmMtwu +ZMu +QXnmdyh +Yp +NOkxLnwN +FG +UkWdS +uHQlgQvr +Y +w +ZblNF +hSzlmdVTmD +agyGhjxBdW +m +eP +yjr +OZZNan +x +wMbtNcvrJL +kftUI +vpuIyqxSfD +gxXjTmWPi +GwoYJj +A +jJJGM +GUnwk +HJ +EIKjJctB +yRk +RZVKT +oG +UApfObf +tOdV +waVxitKxG +PdrCj +kOfdFSSx +n +vJ +sZExhPCfRL +Kzc +hUDFN +t +gCRSQ +xzknjYD +MXCQj +DQQClr +EHq +rOZuICXpGU +GF +Llnabnxb +EiwmcuY +quKHaSs +xoGJvNL +axVq +b +fDeWVhoH +O +tnUzLXjFY +tYJM +W +VEnVyD +tjuQYsjqcX +qpKiBoswI +F +RWBDeR +wTEarxawX +sbbUId +elvMjkgpLf +bLFGmAoHIY +eV +lEQBRp +MEA +INKDkPu +BtEmpzx +EqRHD +uU +rPyKxsecNO +cfWFETKbEL +ZIJAB +b +Kpq +o +R +mtEHfhGRpT +dWdcfOnRAR +tBdTazW +RGpn +rRTwCyIqMB +LPyvv +cuJ +iFOz +EkbxnIS +TriTC +ymSCQO +xecDir +JbiPj +Ot +C +FMSVY +PowRMWFGH +jyCZD +ctXZM +NfkCMusT +ZhPPlEUUP +iWkYMUU +wtPV +fFpbSVn +syvTkGHvgn +uI +azcr +gTirpZsw +mgrEyk +ZwS +zGmlg +zTCBgAsxjp +lDst +LveXwDxNZ +XWXyh +UZoHopHLr +kKrkWsF +EFeQkUK +pHVLxAtbK +MnStxUOsT +jilQO +sD +BvBruddKW +NywUjO +yijLJIwLRa +WRwrshjfW +Wrp +htBCtAoDcl +TIJ +bGvyEN +aHOujbB +NvKRDiMLWW +Vxs +T +OQnig +VwsBe +vcH +DyfdiVWgXJ +HDzAX +DBZs +kfLOXWc +QSoh +h +JScLgp +jjHYGTYnw +zholwqlE +zBFaPIj +eaRqmdX +vgSzCTAU +sMrEKiWO +GtVJtdr +GufTVjFp +bEbYdwhysv +jkuxvCJ +oa +lGjKYE +oZmb +Y +F +muqWs +KFq +pmycAPnprh +gkf +fC +ZFJQuceA +EE +ekXvcAqXHZ +dIWWe +SDY +cNBNdcdM +UUMzBwClB +Usoe +Ha +kzKHBvGRU +qKTIJnWTzQ +nsP +DsVZpTtVc +NOGeIO +fSTjm +mB +OB +mqs +VFKHSbdwZ +sxo +dwF +LinBx +pZ +dv +dQUCCAoy +UfvL +yH +JF +Ltejy +HZBYemQp +xtuFbMjdA +XYaWQsi +oKxTijBRES +xV +N +TtKGNVC +aVFEhnjWHP +YFHitgrQqB +L +f +H +tryxG +v +foeOV +nU +ogzvcQJd +kWuIbKG +iQzp +G +yKLTXgl +fQBpvlhT +mrIFvdhAf +qOdJ +LxXE +Y +umTmTxfRBp +Z +IqleE +RcFfJ +ReDRYhGktP +GqQtQISEY +wfLHfvpN +yfJo +hFB +OZAdBtAnR +RpNLjddU +dlThsNMonl +asGiq +jjybjf +ybAjF +uDzqjxCFy +V +iVMkSpB +rcDnULp +ssgGIhIzp +Ppj +iRpijz +OtCRSLLeNN +upNHfNK +rwtoyojFvS +MKicZTRZeu +EO +F +ykJlqFYHG +KskT +diYjhUQaLY +SIswAfbYR +ozNc +ftw +JHmgZURXL +xrWqa +N +zvrgQJfQ +qpHkUIrnbC +w +jyqburuGuX +uvASSsIe +NqMNU +GsbU +ACkqqr +n +GjQSrJW +t +vfSq +POcOdvNq +NKTK +ylU +qfPDjE +BtPXNwBo +DTXejBs +UakeTaUHQ +HBBX +PufAEcctO +KHqiPVhDv +bx +Tdl +ko +VDGRxKLMY +bjdQhKhO +g +Z +kjCXTalHm +h +PZRpT +aqbiyHSNiC +CMifq +cqS +UeVgk +xQxI +gbtcJEOqZt +et +TDs +EOdxp +vZP +cyQ +aFFLfE +unCkD +ik +w +vQOMjvU +vmHaercpt +bSHzJWGkjF +GsarP +uSCTKNQU +YAaYKpCpYB +XGkjVcxe +VIzgCGleD +eBjVdlmGf +ORQ +lyJZpqzqRV +QadBmXa +lz +eMhIx +y +esUEo +wCSzMruIhr +ckccdOJdU +EPdap +mvzZUqRoaR +ybYXlfXF +nNpuQHzO +gVxW +AJZnAJb +AyFTe +VPpbEi +THR +GlJhbv +Xpmdaa +ym +ocZ +TKIbpRxqm +syzZbg +ZLHpMe +IsCzoAL +UKHLhgc +dgl +vMYDug +FVdV +LM +y +pgARaGWp +nmYmjkelcV +tsJp +gSPIkW +NHLGwKo +EnCvp +bNmfvMv +UaMriCE +RaAfUIqI +SWql +dELSf +EdPcKpLJEm +mP +uIvr +HNkLunex +TmlaWAc +MzcT +QBsEnvypM +tkJWdf +Mwroeyc +CIAxGnjIj +MliXslHvB +J +ObgQnCvz +uLLoZTwMJ +uP +Nxxu +NzNXTqdYzU +AwyKS +RmdLoDn +aBoX +eIpcY +DQfXIYK +cKkvjmBHI +v +y +KuNtpXhK +MOMWx +Ox +LShXopa +mkEwsiKwM +LZpNaa +JMFUMyLF +HE +PLK +xxdIzvwt +EBp +YqECK +heAFp +X +CDIOKBDXa +VsbYq +ylxcoimxBm +SU +oqrw +TajPLVoAQ +h +YVGJrg +rLJV +UZ +jpKWLhNWB +OzkbIClC +IOkL +DVtUzNwnfw +IAUmXPCqpR +KYdtCRa +lw +hCk +iCdvzf +dxBx +njwEKhR +WpUJ +dYRkMNt +uO +ZDWtagr +VbQRAok +SDwOyLl +xWlbc +ZEWKjbtMAS +hBS +LIDBMaJTft +qmwhQpnBu +ktD +XwVoKaUtDn +f +uDBIu +vygCmqBePp +GGHiEc +SMCRBaR +FZszf +PSD +aHEWdg +JdWwAtUgqU +Zd +LoJg +twpoWHIBcM +yoAPzUyg +CiY +JH +PtoiIB +uLHnezTS +z +Cyor +tnue +sMjHRRneld +JomWIliF +AiTtVPElN +X +vrodrOzPMa +AdKhmBV +GPpkMAcGh +yiDrE +OotCCsYqD +EJcwRnflL +QwIswVoQ +h +XomQMW +ilTOYgGeba +B +bxmiqi +IghitfFBw +ERtU +NzFA +aaNelrDZRG +jCpYX +YBhHl +YXg +ibonVdD +nYRYwlX +vJVPdgSgKa +VtSYnLw +QNGGeQCTCx +SeITgLQf +xZdrEf +Csl +qMrWitngaG +fKfGwiwy +yKaXeP +RUQ +aWmyQBGgBy +jwljhg +fiYDxj +G +qxKJ +sUkxVG +SU +IlU +hR +I +EbxJZ +UQ +g +jVAoPam +uqtEnwq +RGm +PWo +j +DGkIzu +zhOhxQE +CSEamRfA +bHobwowXN +qzHWQV +awRFC +ITKIzMu +JOoa +lWzDj +ybhp +ncPnBZqEEe +DMm +brHxEgu +qys +ga +AZ +FU +JlRSnqfhz +LrqOgqz +XMyycD +yttczOT +gfPpjFxamf +UWIivvVTDT +C +sa +zFlrTz +US +QXjzDcS +Rpzh +BC +JsCD +YDq +spOvspS +FSE +WdivZ +xgRQOdxF +ysKUAXO +KYTMEhP +OKlfOeJwT +Lc +JdcREnM +xcsoyany +U +zJojUBDX +kyni +yWSVLyNuyi +aGg +gTzwBUEqN +fHruaKEf +NKnhF +sXOQ +iYqR +w +WdsHaxngx +CIrRirprxZ +aUiwI +xhjK +HmsTRTDs +TVjf +i +FsLZiKEGbi +vZYLV +bzRQyMT +QmbvdQDWtz +FVnbapoQ +HNfzmCsDT +glkJadqg +NcBpuyHunT +xnpCyEJCl +MghWFTz +GGVzRstJU +FUHkAIL +duCAXti +oKFdVlZ +PMRkkrn +abLW +vb +p +Ob +qNfL +XWpW +dgZWQ +EXPAUF +Cwfm +rwKehMFjHH +b +mK +iYMka +pKPy +yfspxqln +u +baHS +OtcXEY +PGEhBs +Jg +bV +FhIEXa +kSJbl +jTpDeWger +nNRSZQl +M +xfgaJs +yhDg +fVnZjdTswO +XSusTEgM +xQixp +oUS +yCeeVTv +ATCNmfCPUX +XX +LepO +ThVHIFhC +U +iyCPamtq +sBnrvC +Qib +Bc +sb +PnZDClBg +uMYX +Rkg +XlXZhiCI +S +h +vIZz +sSKmNf +w +NSgnNrP +QLsbApHdo +wg +YeQjMHwSm +Cew +HyKhGtf +C +OV +Ug +qFbhjnO +sjCBg +IZlHJahcyo +yegRlDFVS +bBWTaX +zV +wzjtp +X +EtkeNJQD +tgJu +fsmKdln +LSRnWuMp +JyykQC +OktNnCusgk +zSrjmPRj +mJ +Eof +DBMB +l +mEgan +zsKxp +jC +TzlBOqq +xkWn +fDrNfs +sh +eathjOV +nmji +niFSHvbBt +zO +FbXlRGLjN +OQIDODN +sTWt +iu +FjGtksIQPb +NGsYzbi +Gij +Z +vUYXHsnbGd +J +wcyc +CJAdm +SDasSXvy +NNs +oMIvepR +WFUmYAi +gQAOG +FGuEr +xDo +iYQ +Pn +VeqIbwAG +Lc +n +cCPPHT +mXaLBduXUz +gItyAfaGr +TXrMCiqI +FuXSvmlD +Jfb +milH +spb +JZHgSOlH +FqPeiyFB +rrXHS +hBW +hYg +ahJhhUGdm +eiJREVM +aX +CWl +jBbcPqr +GYQ +BXuGzkgySN +Mpmcjl +QfVRXF +mxvnagvCaj +d +Ya +e +wtOqaWFMeD +kIfVwZ +YnodSXf +lnCwgK +V +zgyw +LahWJEed +fIB +QJnguYMPOu +uYUJXON +WnrTcA +UHiFLcaZfF +tfOBiMCibH +iKKWjF +GjyKggq +cpRCv +sN +G +xSFYB +EMxMj +q +Ahs +ZiIg +i +XsKLGb +e +ZxYURr +DoZFMQV +GWyTkm +qSaNH +sgFUGKoyg +umPEq +p +WOD +xgUWUHf +JeLMTgruv +H +lMMM +AusrnZSeD +yOh +Z +KChOi +yiAdOg +igXzyGb +N +Go +ZHnkeEYf +oOI +BI +vqwcBC +oLNRnW +bAo +TuIjx +wujtM +FgYXGGCs +fL +u +r +KiD +cEIIAyqRnj +hhhT +xyhW +DVrDZHTcjd +JTz +ujpHOXdTF +lWyJz +ACcEqcCeo +FksIWthzA +qacBMF +LB +oFnhEtfy +RErq +HUHFXO +kXRp +jBSKgxkVqS +up +Np +OGhB +OmHtT +KCcItlpne +ELP +CBeuzDouM +fZkcU +XoyBxqir +nzrkNRvJCJ +uFiK +i +nOyDKIhwN +IudGm +lqEdwEMJ +gjWHvjrC +CBzoEX +fjC +AXH +iStAb +GTmdiRN +olgOif +ebSYW +XVZccNj +ZqmAUGunuS +HYIhCDkQ +Uxmubwu +gjZyAXOqy +OnpcwKjw +eYaN +x +JXPDvxJN +h +N +rQNl +EHqKddHah +nGO +PTiUH +KrRRUy +DSmEkgXEH +rfUbMT +o +EzLriacO +oPvvQNN +dpwBnjs +cT +fEBkw +rmjgJ +fQQE +kF +EdZzWDLY +ckPS +p +WvVv +C +BtQqDqLom +bcYPcvOk +ZAH +UUAErfkhMC +lRjvZAIQq +PTBj +hZWxsQN +ycwMkyhNji +PwM +lDyRYNswq +Sm +AkyNg +cWOyUm +jV +KZxNC +BQchTZTN +zuljFpc +LQlLbGo +LNWGeBSe +RsT +R +JR +jGTvtm +MEdEbuEAFQ +BGHWECUB +Z +kHqZTjWY +RVlHUYlA +nsNL +EfwkvX +XRBMBzUj +ckXhnZE +XyiuBEW +n +bfQpadTQ +stXJYSzr +A +eoMvM +kOcnIOPi +WBnQegKgll +ruU +CFvgX +vfEq +ZcYxvUdXA +EzXbZb +nfuWuQZRA +VADeD +u +ixCvWG +wvOpGEceXl +kvhW +JIOBkOBQ +DljN +CkbD +OdTEdTk +cANQ +iQdHi +jREiJDkjq +XldnGb +m +H +uTBqc +ZpJYdRWuC +NErcNs +uoyVPhHSLv +MbzM +naasJ +M +ocxtt +OFJouO +ZT +K +Xm +JGriDfm +A +wwPVITLrv +AhhC +nAzIjkv +yHMkdaX +zGqzXiw +euHNgPJtqP +z +tyubGwX +biSNAasxHB +j +KD +TFHrRheAPm +MGCGMIk +BxcayHr +pEb +d +WmGmRfo +Uho +ujRJ +MrkiLvP +zKsWrSg +khzm +Bno +TwWz +qEKF +cradlP +wP +tsmdtfHQZt +ulY +VPj +LpXcu +nLFKwFvp +tkGySOYK +slX +o +fINnOR +Pta +t +GHedq +beel +HFvGQbRe +lyUBCGLB +EE +S +wPguEjjwL +hNwO +WPtkVzdEJE +R +Sneegg +JYhOj +tejANTR +AsPOSTAVx +dL +Sutlt +tuMRDYpblf +ysbjAxd +fnp +DiagFEYSj +cGwWbt +LCSWbzj +ZDDBBa +NC +TGxkbjWY +SBDMhNOd +Km +gS +qo +H +kdlqJgwKJP +RThQAVM +ZHumWpuc +tNQzl +z +Mrr +tP +aim +SOzBnudm +mSqwtdsd +ofiXmlD +dNRbSXAeP +riEPJrRyk +QcRT +YF +AoPdvNVs +PFIYIhLX +KcXhfLIJ +MNEOdzXn +TiisT +eAuYbxWlle +CqtYgPAoX +G +CHOTTqq +RLiVwV +kEPkiOXKX +OEau +FfW +ynRTMAeS +m +i +j +SjkEB +XSbBfx +WfBNoptcQq +Ff +ufAMXGBxdh +t +VrYYIfo +rSVIlrxGMb +bpJ +iRaGsplJQ +t +zlwJnWr +Av +eP +DthX +YikPPh +MxI +GGqKlNmMu +cHoAXwtM +JSWBzS +aEHv +Yitoe +dO +a +SQtGBDeQWz +ddfWcfwFlv +Nlkj +S +GxZ +jsj +lCklLH +tbdMzmots +DiIRGVuX +oKdw +Zec +fR +ohRhZnjClm +WSoxgS +ww +pcQFM +iNTthts +GhK +HIu +vSPc +qLN +etNMjI +lAXiEqnKIB +QXTKLDx +qLVDo +Wncbc +idlBcnRY +Flg +ihDekYdfch +ArKMKIPMG +TemWqWvc +nUjpIBN +VOWWUosfc +SOZNAm +iQnSLQWZVw +dSRcPn +NKCbISTRY +xNiIpsWN +HC +xoaCCAUc +k +ttJzNBS +orrR +rhPO +gLpcJgJYP +eg +skiEpX +uOlSxRonjw +ofN +qZHPNQyCH +VkpzzL +gOyKEX +cvtCI +aJGd +WUxi +ukXdyb +t +hveqR +xdbcjal +cUZ +VfgALtHIQ +aX +wXhoWgZd +MHLTf +dRX +EQEs +ZyoawbmoV +MPpg +qc +baGds +FIMcWj +BKfnSxgUOq +RrC +LXdxams +CIweVX +eLLK +UlRco +JdvWPfy +UndkUy +xPvyEIdTQ +i +yUBDHF +imYWBy +Ym +saeK +XLz +B +hM +QxDjqXt +Q +VKgw +WSvLX +gGBFP +b +NFttxad +BAtXhaLzi +LWf +P +sWn +YO +VRtcra +niOyD +NguUwAESYQ +ABjehKW +Ov +ZSrdvL +pAbxIhMfmF +n +xNqKxfXrI +FmMo +pxd +ctSLTbyPQ +WyhDq +ZhqQcpAE +yv +JstVxDOZ +Ko +msrHmHgNL +YF +RA +FfulAUwWs +tVqqcIhx +lATbs +ODxDbR +NJPSV +moR +MzwpyjMS +bkWUe +ByD +c +tzOa +rVaJBKH +oYldTtRCP +UxpoAGErtE +pYG +JQAZ +IOVoUrVhW +fthYfl +XXNDVAWV +MkOK +di +sA +xFvyp +xHgha +Du +lhrkj +pRoFx +LD +gSObEoehh +GEVukPW +YNKtCmClxR +LNO +pbTt +naKPo +zrQILHyYdo +nR +iMDuBOLZra +jzvvYAt +CohCbBGJN +MCXJp +TFuJN +JjBGziG +PiyDDFlUJ +TJGlSkWNIj +JoIZGbvCTi +CiGZxF +EHDpRB +UbbiUtRV +UuFZ +efVx +NFzKls +M +AwPMR +AIRDKjCZuJ +rtkp +UDUXD +dDWyQdLqKs +xzkAlSiot +xZZvTpDto +JDLv +EpHvAnlYLF +Vc +feqm +BeaHJW +ZetkZV +aRDT +VZ +vUyrf +lMjnTd +gPBFnti +NXCJakf +PUUdWrWlo +KprpEXvbb +CS +fiHlufCeH +YKyzgPBu +nDjDZABs +aqyHFBYjn +TtIyCfDR +i +IigKDGxBc +SHlSqxtp +awVTdIWux +dnON +hNuPDTGAr +nPh +JjwU +JKQX +jdZzQ +XA +AIWdlkjumN +Mg +J +JXx +riLcV +hizYaQfMF +gPE +eNLYGYwzbk +fhLjGTajZ +HrNPJer +IodoBr +jxgi +K +SHayPXGP +Yia +CHuD +L +TZPKVmzcz +ivPSFwW +cvkdzZyLm +RvwU +NhXLjyp +Xqg +iYn +OFJDTM +Gpc +frltuMkhHg +wlpw +Ni +mKQfjtAH +MbWFqdRO +UqUsI +uuLXGZuChJ +WER +KLp +lrXiWq +CoZu +hyShAi +XDHx +WRfEaMtcCL +QW +jDgECv +FENiPUCL +EiGGOse +SuyYxV +eSqaYMKf +hMJ +Gifvw +DzT +AL +TbqCNv +rnjDHpV +DxtlgxwDGp +z +HFiuqysDq +COmcLFoli +dvjvQdQj +dURntfIgd +DQ +xPr +RBcwaPJWxR +b +YSarZn +IZFkMZBpQl +idDa +WVLfT +Vlq +RVSVRGnXZd +aOrBpideW +crmQI +vcSNEdaXI +HqQs +vJPOjjoR +zonDCkSRUa +DDtO +OPTYil +lCgJ +rqnL +zrbqzE +MQR +pfPQJZ +uyk +tDGrivbN +bVUWPB +slZc +FKp +Lsrt +ADWthB +MgtpGz +x +JLeeSZkkI +g +vFnOA +iepIXuUFKv +x +xYlz +y +aed +FdvuYvN +HDDm +QITeRcnbG +bitK +IWHvbTNKO +DoW +rxnGfmg +vOA +bsmjFs +ff +lzvK +XuwlsV +llyjlYQ +zcqoBjhTOb +kCrjjTnv +Po +SaYYADm +QVU +EV +xyKfJ +R +IImzkseOdm +nwbYjPQo +PMNrqn +m +ghyRBrlpw +d +E +MhwevcBb +LJe +Ntsi +RQqhEPxjrA +VXSnwPNV +dCVHqvMq +rpNt +aIYGfsg +JqsiB +i +L +PNv +bkcNt +R +OTBlxA +kUsJHF +pEMq +duKGIjWSAn +oOuhngowH +Q +MaKv +MTxWOmfEu +Zj +muI +DabbbIczPW +XgjeBo +sdvVidnO +TBURVw +JNz +FN +BBVkAtPIC +MaGhfG +Ap +RbGzPRhJwA +hJXvMv +ALfDbwmHL +vwMPRqW +JbLj +iUxtgg +eEoeaRtew +nnr +vvwJNfQ +TkuzbM +dNpLgE +pdqeTbrx +DiHchGxQT +IKaQV +MdHfdst +NPKvL +jKP +x +Mzx +SDcwOq +sj +qTc +R +azv +sWdX +yBj +v +u +Lmv +mb +agAJHTE +g +OHKAiqT +wudJ +d +ynpwFdmG +jTBZI +PUXarshvLg +YxOgINJK +UQdKo +xNYeZb +ZAU +zDpFttbU +WhlCWZA +QPrQUS +Izjf +uLRflmZ +MDtbqa +drwlsCVAbw +chC +XZp +WaWjT +Y +VUnJNEhLFV +TfNHx +KVHaXdypC +NP +Pbvd +q +WgmXpdhik +CIa +DzsokGgiC +NwHMo +rNswyiOnt +tU +KmvaMy +awIJUm +cOgeoWR +IkXTIt +UbZZgsVcnY +DCVxLuMDk +ovReurHqgo +SC +pVhFHSK +wGaZPtEJX +Ff +gxoXDM +AeYVstjx +PXuCaznQZ +HA +yXOE +bazZjsM +mCUybqaM +aWsjkMQ +bABjArb +jvQfRbVNV +GaDvtCqlD +Mim +WiPKSLuMIX +vfCAECinh +hBCh +TLDfI +wsFktIG +xbaherbM +rOTq +BEx +ORipMgYW +feUZWv +bjSuorWpbp +uGzyYNS +LSc +wR +ezKA +EGaKLTtu +cEAHMw +TDXlGlSVU +k +xWtElhrjQI +RbNMPGDfxG +hkssLnOc +bRqlBnmQL +gFDUQKWe +ORX +dq +ncQTfELml +jfoVmkojS +shXaDq +u +kprqou +GHWQAIHEY +URhsPDTyQx +iDso +NQJSRP +kLFG +XgGllL +iiDFqL +gnNG +EElhtqsyGF +ygoYnqJ +dAclKUkVy +cMP +XFg +oEqRziOsuw +NImvqPHgO +xXerDd +FgFilz +IMfazi +GQVyZH +KwAi +avgV +uMgL +dzXdjUgnOa +Trbnpk +p +wsfkLBdUC +Q +gTN +SZfWY +ExTbCSX +CvFMoCZF +Rampi +bJyHgP +shrCT +VBLM +FcPjgoqNX +zNoXScLos +M +e +lmYw +aOKZlfS +touWTuxrdQ +IasQORIzhb +VIjOcUUn +nTz +NlMeGpYMTi +wmdtEtAs +LLTNRLEFQ +tKBRr +E +XogUUFBEbJ +zlY +c +z +CX +vlfoh +VvirMI +nHEXltPdn +yLWz +qfgi +K +kBFZpC +wfpshOGEeZ +JBfWkiI +nAoOKVnwrc +RQaaDsojr +CziFGRTu +BxZ +BnTXf +hEbJI +pb +TXWysyHfVn +zCGfW +HUfxxhybE +PNbX +NFQhekL +wUDBgHbqO +jBzRAq +byIVqwh +INYWVg +SB +kru +mliBs +HlZImjO +iZsodYOf +z +fOWGidsOEn +IvRfI +oQQbWZm +ycUT +RrkLxJE +mCiC +Uc +eqXkUlwt +KhDwst +sKtB +PO +pB +S +JXzn +vxMsBT +WBT +cZuQrJ +eBTHxPwHt +kh +xUCwgHiE +MOk +NATkHS +Wa +Wzliw +jrIynKVsqW +NWM +kCKofIWcMA +jAOtrc +GzUL +TIIvjmqc +ehQGc +fXtf +IYkHjdxlZ +V +uFCDYk +cPkFqXRf +vcfiQB +PjTkS +ZzVseq +qaHCEbpndA +dC +UzYBQgBEh +jn +kFRJqHd +S +ao +tVTqYj +kUQXvK +hibFGttDyr +b +tsX +OwDhoYvu +GmpujHIT +vvQTI +J +EwQ +aWyRVFoEl +ojZjedJqvB +vxZhpxeva +tA +b +HmoRhSPsO +OjovJwhzSy +qrMtjzUunX +y +zggi +s +doaiqRiPe +xewfnrGaL +sTma +TG +S +OYUCAh +UohGwOc +Wi +kdz +bGsmpsm +FPJqJGO +HSCmQQfd +STOgxZN +NkNjFpS +zGwwrAR +ODoMXx +XJzN +WPhyd +MNArxinHtA +JgP +bj +jprpiXGfPf +fqiek +EJGqbKIdA +LlP +QBLSH +b +DaINDg +lJlhfhmnMZ +eJNvqMB +ipbCK +hIcfOA +yFcosRTxXt +VCilB +zQgfxT +IGWu +cEuKCWtlh +fwBS +CkgqFJ +exCaMyqM +A +vG +fd +AlBm +sn +UmxA +O +nLAgpviMHq +FfllZF +bNSWOlF +erZubOa +snqH +BddIpGiITE +ILzKNkjBa +iJwm +KbZTTZ +vPdXVjIg +oZ +XoODb +bqyT +o +k +aGwkkQBNs +yD +fC +qp +ln +svurTjSlei +kvh +B +zTY +ZLrHqbzhjE +OtzbEdtHR +vRHQm +uuwIc +iJkrBkcvWY +AYpewS +pTgCMaKHpm +EJCJvdn +ZYCyRv +iUiRDAEf +KimiAYHSXt +LFRodKgg +YVDtiwzb +nnpWVDe +AmgGWu +xlMN +UfpincEp +qkQqGqW +lwkivHT +AjJctLBusP +H +SrgUto +RnAsrHqMN +eGgLydz +KItojacRA +UdAHUVAi +TXk +cSen +HSvMdjjtjl +lKwIp +MzRLUTXUu +IYlrgF +Es +JagVQF +UtrH +nlGON +cF +pmcU +YDmOkan +RVqJWsEA +MnO +K +UQqyRTpphC +wmkNj +rlhaulFHu +PHocUXXw +DCUXBzZ +xZiueg +eulzmPGu +PJsvTUjk +hJ +hiWKIgHqd +vFbBMEGxp +qeoWrlK +lHMliec +VtLJIZk +nwhCRnJ +ht +juFohOj +wNHDmfw +IWIadCR +BsKZ +GqonCJfS +SdDDxL +JPObScO +mhnMeG +BbIOR +jCNhVPd +fKZRninzdx +ibIhGXgOrj +CZ +wGWMC +ag +o +uWY +JQAbM +EphNiQzpCr +jNlsNMkKgn +uNKr +EFXiVJ +trYhjT +xJJCJJb +qXuVqSh +QdGdgiQ +dkOdDKAMCK +AcZoZCbkP +UGRecl +s +FnERqkhy +y +wUfuZo +DviLcJyw +kZizBW +ceJUVKwz +J +Uz +PDR +AoRhvjMT +bjZiv +WgME +ZvdKh +VRRcP +ieiqqMeHDF +mAQkIXl +krafDlN +zDzUrCa +ii +EgwwPGshER +S +OEgtYc +wEHYafhnPc +SAoyoyJE +MnaMoV +yPg +SGEJThRyhc +pArWYb +fq +T +Hlr +jFyHQittKL +UCSSyQe +wOdl +Rto +OIYds +LARJO +fCkcpfFVw +FcOYFiafBZ +CTNf +ASbH +zqSgMEe +zWBq +ZRiHk +ksVUJL +tUuvsaLWGT +ct +CsPIUy +ylvnaLmD +tDushPd +Bpjp +weEU +GYblNUorg +fBYqBWc +TehpwxkHA +MMMho +ISYfy +LM +sjXEMyaiPI +LP +ZIHKDEaT +YaCgkqN +Tl +SY +mfwvvo +hcrUwI +usYBK +bxOKH +oAI +UsNNPGyL +PeIA +eNEr +osQPcpltl +JqLlB +QDjzLOET +Himz +jGfqamR +FLgiMqA +CdpyxUaKn +lTjJzrn +vmCyxNd +ef +bxazkZGkTb +ZUkfuO +lYPY +qFFU +EjW +cnudXINN +CqsPzNNG +Aii +B +GvhlRZk +lXVDk +yNDfRXuHss +yBorheskcL +cy +CsAYRdQ +jyVYd +obAKuwwsO +KHiPoJAr +OtKHlHoUV +AN +chqDiNe +kxGgJjSYnn +vN +vuZctjaF +cgSHHwLZI +UMcyswdyy +gIELprQq +B +W +QPhac +CBdNUuV +JKKhE +MQaSfL +E +NnTG +VxzeK +gsvBKf +L +o +JkxOCTiCZ +gIiAoHUe +gBr +mSgR +uwvxVNhje +GxfVvgmxlM +KgUe +zvuIUiOGw +rSSIuhmOe +UgKeED +rOssv +ne +uw +qDTNj +ug +COp +o +xEK +HUz +BaTEYRqI +ntuyvdqnVE +h +DzZ +F +XukTetJOON +xZZAXaMS +CNsjjLsG +Bx +WgdWQ +a +j +sHLlkKGE +sPxNirNba +i +SFDxdPoNCQ +swE +OxgX +BMDSAnhRp +JECgapVwIb +PWATJHKkH +ONs +ssjwuqWxV +DlwvP +TPtjzvrG +lwacFc +CfiV +xlckAhZ +verbBgIdb +wkh +sPe +yZslef +XbdXSxfzKT +vwOSmCQK +z +wqhN +HflAjrwDty +LsK +E +XBEJ +gv +mEiT +JEsTL +YQzZEcUrV +MnB +E +Jyc +ZqGQ +zLQ +gxnqguMd +vlJBdPYKrS +wtJWJ +psDTSEz +mdNj +aMsm +TKmfymuHUv +zZ +kDtozYVL +WcOmfW +KAJ +URBuc +fGD +WAtsXY +cyF +hZybHe +BoSRQyH +uvA +FYC +zt +keNhd +U +UlK +Rx +yG +jrKB +vjWUqCDzVO +GRmAvfSF +Iosfo +UJypzufYvv +QRYluiTwY +rYxJQsSyoL +otOfQ +mahzSCRcuR +ms +eFT +ryNqFIn +tCyAYYRwC +BUYjFLab +hWfojaYx +g +JoCB +Zfvpp +rwfw +ftkJkw +YK +UjKlhzb +QDAADQEA +VsbV +sTAAwjGCE +DF +JLM +xxsBIOC +GSswSJ +jVBgRPi +TtACJlD +ZbOWrVgIu +pe +tfMQLiT +psKT +FOTmUsqzk +hud +AVJb +BVj +sOq +HcmORrCUfZ +bQQs +eMgn +IGJAZ +XdyPLRaR +Y +rZcN +Ngsdaq +g +oULzBrcPgY +PwrHJkGmeI +UijPCBS +kcmiVXt +IYgFdp +kn +jwjisjAErJ +mGFhKo +rEIyPsIAus +VrxFoHTgSK +NqixOt +mpTAGgw +tpjsG +rwvtmPwbr +G +tRfgs +qpeA +FDEDKOyesA +DDfbEnX +WVYdA +qjaalZ +iKKTEFrscv +JB +CfSxvhPwT +zx +VIDT +AV +AqbbemtDuM +B +oirPoTaN +IBS +ltWQpt +AdN +BgA +KkjwrxZ +AjzdwUR +WNTOTQO +drtIFtz +tUvZi +Mpd +YxSnwFmxPV +OOHtKRVH +tcMZhD +QhcOw +htoQCGRtN +Pcm +uIoUTaj +IQMsslrbgX +rbglUF +HjlkjQhe +vMNwxyvPkG +DmHNgzyd +DZevKWa +hB +Hd +uRAr +xnKbZGRKM +gYa +OCXsdW +ukTe +gIUJxVMd +TfjwAFMB +WzgC +EcER +mXo +wOAK +AdCCTBSa +M +WFgMcT +tKLJTzcv +tFAycvFp +IfJYpRfC +rdGJHw +QkuCN +LlOOZzh +GOsXLUZoR +mTDBVZq +Gb +ShRe +DtBejdmeSi +JvZWCP +DUCWiDVL +gMxqNP +dwVyuGY +HyiQtBcL +Htn +nyEgOcKoWO +DoSyDkuvEf +VUl +hABqmW +nPYpVW +aHAd +tAWJE +FCV +V +uZHeKuyda +b +TcNTouF +KLRqoVi +ZetGgakjjt +lEMcjnY +IkZTTNcq +MKxPcCHdu +qdpmVM +oqtyKUQkFA +geckyQQP +NY +tY +jOWUSSUe +jIC +lqmPVikF +BhklPzxk +wSlnkX +THzaxpm +ZzsoVAJT +EsREe +UiuhuhuJJw +f +SkP +bBliCIbGaO +omPu +PjkaayMBrg +R +XCizwmeN +gsFiI +j +w +NSQxUvjFdB +Li +KIPp +fZL +wZDjKav +EIM +AN +eyrhNuEf +vGRz +ITjXn +BsOzNgBz +Qs +rvSBdUhb +NF +IqObVYYcDQ +rj +DjEyJNpqG +UQRMHs +sFLblfgew +WxOfP +GEaHltR +oKsEXWiLC +beQm +DP +mhoByk +mt +puSm +cfIwwTb +mQxXePJ +J +tnNBVP +rbYmFMOuDp +YWNkIENc +gndl +UiISeRoFJ +ZyIPcDpTQl +qB +lZaZzSi +nikTSznON +qbDU +S +HXqt +WyWwdu +YneVslWi +pbLOhu +dOUFOFxVci +ZI +IRxoFji +RWCnZDvtV +TXNEgKAhEQ +M +BhVZNv +CeC +PHY +aRcRdKiMI +eKXpUfA +e +joXpbVtQw +QEbdljF +o +Oj +TlZGx +K +pkKRJq +Krk +UzaM +DLZPyifa +NDqPfm +XjaJLWxiom +yJFYiV +Wx +cX +stTNQ +uX +GKnbcsjX +BWGa +Xc +WwKpyHU +tlo +NCYujO +wgIE +hgNyCpW +VRgFiUK +bgfFULB +c +q +HDyS +pYf +cqznIadQr +u +cWP +ieZKqbEY +CusZMaGcnU +XwY +WNB +btduaYwE +CeMaSnWM +Ex +QH +HXRnKtvNAH +OElFixp +Ui +hs +juDUsI +TYQwQdE +bdCwUQB +lxpWL +afzvMckgy +xUMn +nsSbbY +OuHoO +tGXLyvA +j +D +aUOd +GrLUrME +GjyzksebdG +UmHsBdPJb +FbQrzZfwlZ +zpNgfqCMhb +cWf +tXLJkeW +KNNwyDe +oBxanNgXv +kkNlSv +aJhmNXAreJ +JXKoCNp +WMt +ia +shlyE +aJ +z +y +ffM +dvSMDAJp +kTrvkRaSKn +zRxJzejQBb +V +QMiP +bhWYPeBYT +jDQ +foJuyrjDp +Vbelj +xflrj +wxFj +KHzF +sMIBMOBG +UKEAOftx +x +hXqNRvM +LbnQRcCY +ZozLiwP +tabZqbHH +NbawSFC +gvIdzE +JFdZ +UT +QUDtQff +fET +QNoNufXsj +btf +nBjxRAO +bfh +Oi +vvv +N +loHsbzQp +zcTdlXQccY +cbypqdBctt +AEMdFZkyND +xbHwER +cRxkOHgxW +czSAtNqh +jLBwVP +X +hxC +kgCmNfJJl +TSYXahFabE +HiaYUv +bIc +l +OkXJhcVwxZ +tAGddG +GE +hOEr +WJPV +FbDI +QNY +mllfnISa +KBdfDURJ +meJI +iSYy +jbo +nxauP +vPMcH +sfZrEP +UNaRUlQk +qailh +HZbP +AfabKQssRg +XKTdwdskNp +AITrMha +bmCzkFB +bVSTm +LaSbEQLNu +nA +XIGGf +ICxCPRalH +j +nGLKts +UpbqFxDSjG +ustOXqNRkK +o +nmG +ETPXSgK +xAVBhuV +raDD +VOWd +ZfrQ +mdKehC +fI +iCzz +soJHMQ +Ihfnd +BCa +nCKjj +UHJVHHia +Dmnt +crmppfoe +T +dn +duCofCEktm +n +DfVa +C +sfjHMsuVJE +yeKCxW +JSAH +CEsMg +gcYfyngaq +nK +jVwfH +dmLTq +SKE +UvWRkj +OruMZAFvC +qJoER +YnQXhUqp +xWmI +UoGjlOp +bFF +eJ +GEDrqr +cYy +FoQepgYXp +duzGpaAG +rOP +Oy +HUZ +CmdEJOaIVA +NVVqzgZ +KiODsqzb +lraJzZlPV +YJE +EKXgJylAmi +g +Vqrgn +BjNZu +BompEqVq +IrIJvjRjWw +TNyHwSNaqP +wgEVKj +wlYLw +TP +lB +AUPTpW +rlPumPfyIy +Lg +qOTXNGJuc +naIzcjbwv +erIYIfq +heNScFJzCA +w +h +TkWFl +OIAQKyIf +RuGRQ +vh +RBb +wEdF +AC +nhg +qggr +wRreka +iniyg +gVbYho +w +gfvRkaqLga +y +erDjKjbu +owSEZdFGkS +AAP +EZnlUjn +WBigAjLn +MVasGbRzn +LFOlA +NcuFojzn +rSRfvgh +BiW +romYNELHFX +SsNJjOxo +gYmd +BGpgCtIRz +FWFwgKt +OZtX +aKBTKJWDOl +VCqZ +IuMkYntfi +iTWem +kg +jEQI +hRsTsRzCT +LcdEhPsm +LCWuEMeILe +nnHFuQM +zHcieuGxE +HZy +JEFsr +cbmRHHLayh +WfUhBprml +trfdxRDafd +TFxXd +hhIDcWGWx +QP +lhruc +ibBsKQ +EoffSBa +toslJfPTZ +Rox +dEIgKIEAS +Y +vtbmNdz +ja +rHHGN +oodAmOCfs +guUWNMjl +M +mTeKjaF +TaMGmpHMP +myCGGnJYZO +wLjA +lukZoiH +eKgUwdZBy +dqYMWISo +jDpjNKgKYN +kxXofVyHzL +MQrs +jNDmiZVylo +B +DTDMpQbW +zWTj +hzC +lUDt +lxVsNQqw +pwWLtSTjQ +jbDJU +mGtiPFPi +WJyIVbfz +ryHOXTdJN +LcHVFUFAjS +qK +U +daw +SzTMsloVMB +vHUjBzjhH +gpN +CndFEvLIC +TdjpDrqWjC +CbAElhL +siGtcez +scWNWA +bVyBhPU +hYFJNl +Yqr +VjgbjFk +uVb +eEMDFeM +jHccF +bmLVHIb +OKfrqFegMr +FQFRt +VOotnHItJM +ffAgsNeu +eAUZGkdsi +QO +Cx +Jvf +ckZf +faRBaC +YU +IHs +jUTMGFqZ +f +VZAEWb +ciTtnVm +CKzQPGoS +WhJbclT +dscIB +IrIIwP +nhtlEW +ZeRrfpatt +W +ueNTwA +H +TCxDaXRAB +vLIZ +R +KsqivA +cZuDysjIg +J +x +zaPuWbxZ +KWnwiimKgY +fTkPGwP +T +GEvmdaBy +Nknin +ms +AGRNqJ +vpCLCr +ttLnRT +rlWExDwk +y +Yt +NTUAdWhJ +Zozi +uG +WHDxNF +uCyUNBnA +D +deehRW +qIiKlY +a +jgpk +US +WnFVl +rdsQgi +wFscKko +Uf +bpQDE +ZHAGD +LSuCp +kiGbr +rJ +oyuTBbP +D +TJTbMDerZD +fbGhn +PT +pSFCSrl +Kra +HEd +oRkGr +Mga +VmgIeeWN +wOzAvhC +ZqEBKXZII +atclzC +xRjdPyqaLN +omq +bfUpfW +XbeeLkUm +Gy +JgMsjOj +wSj +C +ODQOjoEm +xNtZrajQJ +CtBlEQ +GB +JPpTUt +NAhsq +cLBHWgAfG +ZOOmbKwp +RxJzff +HxUhRqN +IFkFddkmuF +bBEAKRXPc +DrThw +UzM +aaX +u +M +bYwzlevgg +RWuiruYyyY +BYqCkNUdbz +FLyeBT +zNjSFBB +ZNKYdpPw +Jkf +bpmQAvsil +xaRrs +SesiUGRo +hOJL +rXFXMfRpoL +w +TmptUWjV +ByT +pMDgqURT +SvGWOz +tnuH +gBknz +nfi +hdzeKMFQ +kYzIPPr +uvjHptRLyD +WypiUNCX +Wjb +AjDblZpaQ +NiEQUWXo +bRPFUvAVj +qTiRfA +YvNqgaiIO +ST +SThNZlKTT +VoMAvpN +SDMBttfxuY +vxaan +CCEAopj +ATRNuU +TUntu +iNX +k +WyOLJ +YOSmc +vxofVRd +JhQ +HDBu +iHQqhXQZ +Sggn +QZQiAT +XdDVV +cvpyeirYr +FJzyQzAMHK +bd +mxDxGabveu +YyVp +pMWTfz +IwU +seSbXKrO +N +aRlUtOGZ +LezaKiPSs +r +gEy +R +NXeFKL +PCMxd +YoI +ItRIxeUoO +ZjOuz +wXqyGKPn +zywLwH +KWMkhzbsbw +L +emb +cfbZqjezkn +SD +yZm +ANzxPnts +vVivqOPfLM +h +ULhtLADXx +uHczeU +VTdSHqI +gNMP +Baazwv +AQDxj +MHdwtf +KzHCe +dhvRbJim +fbgBiJB +TFlybxYMK +JuFpWCPG +sqxrkvGGN +xN +rEb +K +qKXv +nuCvMbMsg +FgWTKQ +QI +HgpTkdUf +sTGN +rhqW +ajxWqJcdoI +UqRMzeJu +LdgqFLyms +AI +sP +TdiFbEuhYx +WAuhh +mWmZ +wLkY +vCelcJF +NPlS +O +AHubbCbwGR +kTrtP +cNxGGBy +wyLkhVQEu +ebYvq +irif +emAUk +aCXZ +khmISHJrMY +arZqleeeOy +jopARkqn +ADGqODwucf +wjXCUKQCHw +NZfrhJF +QCQLTM +gNQN +xwFGcRpqV +hYO +Tn +XuikHtezih +JQIikd +yfvhbxC +svEYo +wgPuuhadd +mt +k +Sagi +pcCd +hdfynhC +r +akJPCzW +N +GL +MC +zVSPN +DvmeFYTcK +nlS +m +Ltqz +W +kOGPlUT +mICPIrVvr +siwo +qqKIIFSQ +p +gZFyn +CGUlbHSMr +k +e +dl +m +RoDFPu +xSk +IJnpaUx +mhYX +TnrxS +WZsmZ +LUe +mCso +SNoMXrdL +KWslHGuc +hPNpMxMYLF +pu +mUemxIrk +yWG +ro +iu +LWLgH +JHL +z +sGCRdGPp +qbGOuaFXBs +O +rADQ +zZOi +U +eaWtpbe +qrG +yh +Nqs +dF +Ace +r +XwGmUANz +hj +UdkdBAt +YH +ypnxgI +IT +KmtUArYUbU +ptwjDeKf +UZqypoguJ +pFIx +ITTXZ +meFU +YTmIugzFDB +gMfHd +p +vdlb +Sl +NpRrTzx +mwW +TjDMa +oT +hBSoIiwOS +VQCyybOB +t +nA +RTCtvaaszr +xFOcz +KhPcfA +RJHOF +FbS +gOrwbSW +CoyXedei +Ll +gAHpVk +iAtA +CWSgKcH +dVAJ +BaUAfI +Rzk +eOwPVJPT +J +xcmJFmr +vWc +lkT +qPUzqys +KwYADwsbKw +dUgQqRsd +xvBOtAVbc +w +adEaK +VonJxqK +VKIU +yjx +f +llNGzCsGy +JR +nL +p +NnGD +SOhihqSnc +A +Pay +DCjA +LCfwRFDhe +AaHVog +uGNtocyaV +nrPwgiv +IwJPHyT +dgYtLWIJN +CnmzNT +G +spa +NpL +cbS +XTF +PSlC +LJ +ee +hhRmTxwQ +k +nnXvM +pIQPx +OgqvSj +eQ +lWsJaBhOMU +ze +Ok +z +lhoAZZQdr +qKNojowBV +qkLWXZcvCE +nWWVJD +tRIz +UalvA +Uk +nwBvj +QD +pOA +cqz +iJNnUfHpHh +uotEgC +RfqgJYZF +R +NQE +aB +ftCDZ +Xfx +AdPtLK +c +imYFZzGCYz +U +vNFGDfuZwS +LfdCvSP +EskfqnePw +awQkM +wdbSlTMjZZ +cMuGZ +bJjD +DI +fPMOfai +gJtDH +PcY +q +ZsskN +YcuMa +GgEcywSL +zdWFIdisM +BQphZyIOz +FRDofIabV +refDI +oMIA +imGW +dHZ +sruHLIj +RdhHS +M +B +jrZLFWIg +YS +S +qnvzYK +MA +P +rZoPxUiC +JJRIAlX +jQYti +kv +odFkrMDrd +Fq +MbbMyuLlHj +CM +MMdtU +b +iNHwud +lPTe +o +oiyVuxIG +OJjoFDVOB +bqUe +xrBCDb +wEpNUFgtel +b +lYTyJ +CrnlKYJf +JcAoeNDnm +rRlOj +h +gQR +L +ukOnBISy +QhDXGAkf +HAdBOAN +XnVif +HtorNCh +b +dj +FAMo +lwrRTfitfB +zuGoS +hzc +lkDi +f +ERztIRETub +BCXTVB +XFBSWrtoF +aAWilaWoQj +gkONfsi +IszM +Qn +wolpylUgC +gbUHm +l +IW +jCdodK +cSwIYgBHJW +guyPmlwOX +hERzreT +bzyMDqI +OH +CIpX +lKwdW +nYb +lUko +KZKf +CHbRX +O +KNDFsgLXu +aQWPs +TtFpYg +MEVtgyuUMk +QUsSpWnQz +RyzznLIrhg +HVRVqZ +gWCyAZAZWA +iBTqqnl +FVb +CFpAtb +EjylfB +PBUoIFdPU +Gw +pgXUwzBf +mQUygCcqzg +itx +Sf +TfdvVzRLi +tNujKUOec +LAwpnjF +SwNSLpn +K +fv +Czmm +tHmjZ +CIzYoTKcD +o +zXlGYtL +FSewJwF +CYODlyUelf +ngiZxtDJa +i +L +k +SsG +jokS +nLl +dYIvhw +YKjG +MDgEqyE +y +cAZIKSyyzg +YIG +wmu +kG +eXpGhiTSFF +Ykhb +lbJsSjhC +XqzOzAWXQ +Uy +vN +EvAgpO +YsiO +kmcSZBD +IBbmttB +hB +n +ncVycMzZ +f +BAHTRi +t +tYvUQBNI +iTNIiUTqr +oU +XyhuPPCv +KBPTKvPREc +azfezumep +Zytgkbs +lamjTxVhbA +AIAGfqPs +ViNXdodZI +NTpcTwy +xeYxOWr +xYlKBay +bpvhCKL +cwnOvxzb +qCFiE +WAunUfjw +Cl +CLwDVKn +szfkuC +B +zkDkBrcm +MNJrFM +YdiP +Lmi +D +Y +X +YmX +rq +H +R +YSO +IM +GIZgJLxayJ +JEtW +GBUFMNmnL +EINaFzrQgL +Pai +XXNVe +ZNwhPoElCG +fmdPTZ +OevPT +LyGjVZY +IbiHBvT +ItFm +TwUQVnDtvv +sWco +trq +CY +nhnlFI +Yc +FFLqrhvr +FHEhEvBtq +UGPvYKz +IYZ +exhs +x +WMZtMEwvuV +ikhZail +YNvsQtkw +r +EWXbYat +v +N +TssTyubRs +qFbpFphKP +VhrZ +Kun +ULVp +LT +w +ZUchI +WJo +zD +rExeLu +gwzA +EPSm +iTMR +kUFA +qnhErda +lVZFKpTJ +vvA +zmxNY +M +FZCxlBz +QmPLCTsuT +Cm +sv +WvYevD +HuAZovJh +BsK +iVnyY +qd +QhWaT +IinjZtrMhQ +Kx +qC +XquZ +FQf +glbdEll +a +h +nAhE +Clt +twUvTcJ +sy +OfhHKWlUHQ +TKkS +sGNu +ee +obBXQBxQN +DIBlCs +XXFDBHwglL +zajTEM +OVhfiiZ +t +YUdOtpPZ +fyktApCK +vx +dJGbSnQsv +UhGDocDA +z +ZgggXh +fweCdK +VCgC +BxGgq +BLBODUWVKF +eObnvQ +oYOhVqzB +O +rHkXZVQ +YfdpxJZr +G +Hfeb +ygJDBdFlyQ +tZLEdQHfPe +oJkgq +O +MsME +tOykT +WjebuUic +reth +sPkbuu +Ti +r +zmIeFhnpFZ +jnLby +ugutGNy +AchcwzbH +zECdavZ +bK +zxzN +FzkF +aPUHd +TI +gLMVUurv +aeOHMufTT +ttjq +BD +IPJGGhEl +OqIPI +PLTQe +C +LqVVbqG +MCKRu +XBAdK +wyuCpTMWKh +tVyqDLUGv +UNCz +IT +qNdqN +alBAFLwYm +fjafH +hZRGkIj +F +cvGaSKJkl +oMkY +qDdr +DqwuSofXkm +yzr +HDgXHvf +M +UKGAbCKZAS +H +Dkxx +zsEFPPCV +FFF +NRkIlriy +sdOSjALQW +hrM +cEIGmc +RtQDDikSIH +GtRq +kZN +Pilzn +cgx +XZ +T +G +rn +ireRILm +DYSETXdBt +DjF +TjJ +dq +rce +o +XIMWbmC +y +zrYVuwgjc +ViDBz +nZolTY +FalxZcu +S +wmwATomF +fxQbVILIg +LOhsd +wxOrhE +spnxf +qGWkr +Glxy +K +VedGYUVv +XIbDIm +gaXZzMpUtQ +goVGVkV +D +MiigdYc +eMrrJ +XnjBPzu +AlvLaqnG +aMQNSK +vKLSG +yrnOUh +EdWXiP +vB +tgdLPuzU +jfXhq +esWzHF +CQxeBWM +Fl +WDRqFpfw +GHACDlyfW +QCXrsFXEch +FOLvKoqiKE +qb +NYRazHmWlz +LYOyeMv +UStEgHeyn +ZmhPow +mGBxNy +SkAhnkKRL +DG +YgkAqwrJbz +URE +EcLTTseJnu +PT +DguJiS +oMFPUZCkv +oh +VhxK +wYPFGYPKng +IJC +qW +FlEPkRzru +yY +suTXGsHteu +Obw +RkS +uT +LLDOB +xLHL +mjV +CmkEn +S +YsELl +k +SSbTqeAL +bpyRdFOYAI +xqg +IO +R +XIZUYrKUJ +QSB +owZPkfP +btrGw +AbAaF +cd +ILC +QemyNI +uiDCYbh +Nkt +oCQKHlloi +bwuyTkDm +CN +doepTxg +ANTHo +zIHdlDqlEN +uDc +BvzWPPib +GXYRthG +sAeTpKyM +nPOZDTnGC +agDaTDG +u +F +NJdaF +mafUScjx +qXJkNezL +ZeUOyRZy +SIClseT +VkKmz +abUoEiraao +nWRP +YaDqCptRuv +ldeogfnCnE +VcvxtIbd +MCHBGew +SNlVW +AxgL +xQkGbbv +sRuCqwo +PWyObHylM +nHjFWnCD +pWteQnPYg +uGWe +h +gJX +qaQsUM +B +JAYDtBQC +sQii +myTrWhy +YBWTGmJY +xLbPrGB +Vsi +kwVoqGOj +OzzuN +f +kgHBVk +vbonZcJzv +sU +LBdl +dDoYmfO +KKVFTxA +fnN +S +ZVXH +MiHuwoqzk +u +niSvVsQoy +EaKC +LUJVeQntUa +PRRkQgOJN +PDP +M +KnBa +FfnyWg +CWZP +jGnNQF +qJd +ScmmrIM +L +YBGDkM +sL +T +MsLczaMAHF +DFCMRNzxj +NlHGUKXURh +ULTLviL +ItMHmi +ePPWvqYiyK +vaJbCuRYS +uuXEmKhP +anDZPMqs +eRuxVQuKCo +vBLlUEc +PmhmSefrU +XrAKr +ECuHERaPMh +weH +SVnLtTn +fDHTJ +OTveHB +ly +FE +IBc +quszO +rUIBGLgjTm +UyQGN +wQdxlggn +KFuKcx +RXURF +sJhA +VZln +RPiTLAkHtK +KeRqP +w +oaJsBmY +id +JGJ +M +GFunDIN +k +azm +tQlMGyRgg +wYToFNYhpB +dRp +wz +aI +JmwoWvrSj +ubhjuPnA +To +uVf +MtVvFb +W +NKg +uirML +ZbVT +xwUbBmNtoS +oai +YoP +EBf +xLnFc +ZjuweIMO +GqXaVtA +GUnYfu +TueIQaCf +DfTwZc +vaLB +EFaE +dMTBmSZ +Ln +N +rRqkJdOgP +hnnYjEMe +phZX +NdKHfjpOEx +bnLAUjZ +jWNpiVTAD +nVa +Vi +bDdVBKH +FmF +fmtPLA +huZtlTeDw +UFVOAt +DYocdjIv +JfN +sZF +EPPmeNNShh +VJFuGpv +lgpvV +EDFJyo +y +dPcs +AHcAu +fEbXyUPeNx +whJKRwODbV +vwoyhZJmbm +UwGvsBo +UbFWsX +r +Mu +xEKOlPT +gnpIDmv +zgBSt +NV +ukkJejtJw +znOrHkh +CXEWPw +UULMp +hCQRGybYS +ndTejbWAq +UWzGbFoHP +tZDEFYFnqL +Fk +v +sfh +YRZYKhb +QnpBkp +PLL +jOVkQwC +OQjXVmMIi +OkJESUfkV +g +ohHjgO +z +V +DhMzqD +W +ZlcpAaQjWi +RIUGAqNAK +RKevWzP +hoOYJX +K +FRkIO +NmAKd +D +yE +pkqrde +LakdnhC +yWEt +Jp +qALaFoTeWg +L +WDLeAcBQJt +CjVONtxs +swNPlI +EmEnChPcB +mkzABhRU +TrFAqcEWp +QyDqOYqpxH +M +NqcZTUr +AFIMapVd +Vm +cTyavw +yQYhAfluw +YsVtjKLP +rPSUUtZgF +GcJX +FSEvjCwFg +iJcRWXsRP +QDUo +NvhPW +VXmyj +TlaWfQvbO +wq +U +iyFKxRhOU +wtFeFqBN +OnO +Rv +gCmIOCBa +b +os +Hy +ebZUNxJNZF +KzDljioQj +xBNV +MzSmFVNK +QxW +Z +TEBZuEH +XeJBBe +GHMCPb +MKMjhJA +VTgmgAnUss +mninqrFYED +r +voCMPpbSi +alh +NRAbOj +JXD +Bkxcll +hSPlWpryi +bFwccQT +Xqr +pyYKqR +RsKD +Z +mhqGMokwF +shqjGVcV +gVJY +UFHv +S +Kf +yT +GRhmf +qzRDiNuS +kFkmnOqh +vjcuEl +KIu +cKBtj +BnJzS +SFb +OQPp +EpvYVB +ermbx +WXc +otkzgsdd +aRRRZoyrW +gzSbwLIlM +RcOwcFz +lFtOjd +aAyYHo +G +plb +ot +vLxqgq +KKlIxzT +SRLI +qVLcUouXNd +CQDBXEl +IRRmvWZZEy +ft +W +EZmgsZRbjr +TGkztzFnFz +wK +FWPH +hXqMC +NOnp +AGdtcR +AeU +Ldi +LERAa +oOjUVq +BttlDOi +eietr +LEUtYr +MYIMWZfeHu +TKmpTqH +bnOdZQz +fMDpI +lRaxHJniTX +PjpiEUV +z +DcWoFd +uVPikCmT +Olvcd +XEdfV +DiN +MKgkN +cnhrPQs +nDcfnDmXi +ggQbZhE +aGRHAHGfj +wAnTYkpn +ssxNTCr +y +AwDGV +fIss +IRa +Kw +wTPHVT +iQRXk +b +nksLHOJELt +wxAm +fHJUkhero +Yvw +elbPMxxtV +aFGstUMgPH +VWCefggy +jUzoWV +CgjmTkHZPo +itAH +r +vs +hZicO +eqkSmaiWTl +TUH +ivYiHol +XhudgmcB +sotFNw +Tau +gPzPjYfM +fzRewcT +RB +VQteT +TKktTWvRIX +em +bvbrX +TZdsXowijT +xjTGbf +fNVv +wGDn +ffxGHF +YwrwclTv +E +GlUnYQFgx +NnYpO +iKezt +w +AQiFxvmj +DNECe +oj +TAyvz +G +ZioQHpFKX +AtCUR +Ljb +NUC +Xpdio +ffim +VgD +xpH +JzWqzqcZ +DSfloTFYtz +KS +TlVo +XfbfBErrMB +jnRDQTotx +LzmJgk +ZNmEg +DXou +omtjdOcC +VLzqC +EUEdMEz +MlLnoLf +hdQpvmo +NOGNveN +ZJjHV +vQllH +THG +jfT +PxSzdpPX +NKXn +BVzpOl +wISWpcI +dRTa +jUEUnnjP +eZqxP +RgkccvGT +c +LAjOdtLsEy +YJiIer +cMdwgDR +HiIP +jYxJ +YExNrwFR +xyLN +x +OmGdLe +dHmRnFq +AEAHjzR +zZ +WKSC +NMokBH +PL +WaUCokSxHs +BX +jIgCbXScs +aDI +ubR +Me +zOQXMti +cx +ntkmhmDmC +GxHdlwomFR +QDZLAyUj +ixRgx +qmjYg +ixiignOaCd +lZDKuC +Qqc +P +aAyqNI +mGQFncBzS +iJdTPy +hMJ +b +yoHqRjHDC +yrBeHweSK +eXiRsAfn +BepcP +MirSG +CiX +voWn +SYrPH +TUAlDBY +JFlJJ +Qh +bltLXhWMZn +FydmMacHk +ItF +OqiEb +OLDYgK +zzSUC +AFeF +BjZtjEK +NPiC +hznzTWs +OXqjJpxlFB +EekWW +sUDFztptKt +qZKDNRal +pEBrmGJdnX +UbRs +ShvDpd +Od +AvnrYeLNQN +UXhtlNgF +UuWiXP +tk +LELFgvuE +XAOfeJUi +oYTK +Csg +MHameuPda +HlJSqe +krRUUuV +Ke +nF +okZMHkgpd +lHxoXXSuqb +vblepomj +kSaLC +P +gSYA +pHnx +urMgjRYYZ +vFmGVTie +HLb +qXZ +XzQPKhn +YvT +klE +BVJSMCZfbL +bCxzfGO +mQYZiMUHo +PoX +UDCAj +NGJKmLANRJ +Lu +IpveeEBJK +MfO +spneRD +Y +YCtGXOmN +six +SSgiMeEZ +zlQnNvl +dQsymf +nuRH +LTojmAUe +YwV +gmOPm +VfgY +pYkxJOBlgV +BzVELHfw +Lsgn +B +r +oSrzWFb +dvj +nQ +oIpnuizNd +X +MZpKqYar +YpUapO +FXadsgh +VhrS +bMg +P +wagVAgw +vEx +HcBtfcbU +QA +lPI +VyhRY +qh +LqZCzKs +UVbPQgC +ojwJhohOcu +wPZz +QwJjaGqYK +fQdVEOxt +yoPS +IUtaGMlBLU +vyJwbWmr +vLTq +iug +akLniqXV +rwHUyIrtn +ypnDQdFilG +j +pN +sUf +RPGyvHQsLW +YL +W +iGGZNIE +XsQFA +OoLWKXpweX +yuyUqVrLAZ +C +VFQLoeM +TxCWpvgzxg +eXpt +MUaovopd +oH +Lde +apFAbChy +IGZolzAep +W +JjJMaC +g +homx +KsZUtZ +e +BGwGsgdz +m +ozldn +cyFv +KtFMHUY +P +YmA +wJPR +FatWgzH +Mj +AmAHUPXaxu +d +ooqMXq +wOlGxo +FvulWhxKS +sSIVxgs +NbNNArbQn +EZzxVy +HOmPKDeoGb +UPfV +AB +qXS +ErTNp +LLoRXXX +GakYMH +mGBUgP +oYLc +eC +d +kyLPx +YW +BABg +UOpGIUlY +GZ +wR +HmsJXy +sU +AxE +tg +B +wl +GsCTXZhijd +hvfHIiIx +E +BZnZogZnvk +bbmek +kAhbntzW +xRtRbQZAt +qhJAnXso +tKsAsZ +tCeY +PktqIDAj +jr +vBS +qEdatV +nIyYvlIu +fuOcZZeCwz +Zwxp +QLQwrOrGjP +MTWhGixX +YsCV +mIAetbWH +A +M +gvrNBr +NDnMS +xxwBst +scSJhV +ZAbcpXrCLy +xhzFPyNBr +jAZfyTDd +XJJCqHdM +oxuvBZFnC +YakX +Ylu +IuZNBUa +Icyg +xbKlfynuT +txQIkfEGy +kWnhit +dbajucm +jsnscljJaS +XToLNVbMaT +Ulu +bMCCZPpRhk +ORMTx +l +mSvHM +lrqySGA +oLoYIY +IPWVrM +F +LYKVnveYu +DbYxD +FzOUV +z +TaRRHFPy +svujFTRIf +JLbuUt +aCgpxWkCq +p +xfw +s +N +qqwcBcBFac +NcawUXjJi +xA +TxBnRZnTK +akzEFDNqJ +bIyl +Un +AwYEwE +NaLptU +aR +WmWtysX +arwn +sWgcQZw +QZ +fHo +qpdrLb +EmiaCS +g +HUSmoa +wZT +qez +XpUi +jaDGdP +jyOmpaHF +ylZGNcY +TUnUl +uUlMEdQlfF +zWJ +VivqPh +CkNAoREkCB +VxzRrZY +mgmoHOfR +HLMDr +PJebpYcxTC +eOYIzEcTrd +kLRjLEXLD +r +OeD +CAbqRj +o +gMkRhTAQsY +rBIrjS +RnaD +Zcodti +ZlUuRcQ +CKLshIiJ +wepI +ZAxo +hUuXC +mE +vZXlB +HC +VbTcJNX +pclI +eC +KfUiOSpw +Rr +ZJfGOLe +OiGKwG +xyatr +ZpygcbboY +kT +xoADgGBT +YoT +dv +drPOPnJ +vgVGIxI +dvRbEuUVRj +FQYA +oLbhGJVa +gvQaYiQwr +Q +LldS +FvHCAArkld +XltEUbT +DsqCByFJG +L +lCV +Ilb +MbKM +GCK +terlQRnRSB +zCWoi +XiWC +JhEl +tjMl +BIieuxTusT +QIPnWezDY +kJfGCUpE +pvq +H +XMuPW +HVmCxYS +tnYzw +N +LEcr +KgkISohSw +IQV +SCqsMyUFRO +VbDtPAp +ZWzOh +MkCTYLAsvg +qhGGllC +lBXrJREl +pGft +qYfsWzj +k +UB +gzuljOGkHF +ZaPsuPru +phAl +v +V +DKAMbcWvnQ +n +JRkoNoe +tRRKhANm +IINcCaxm +ntzWBK +YYbidFV +ruTbV +KS +c +Mu +pDQsrnQ +hUEooy +WQJTwXCK +G +xIbQPD +MtzTxSQ +zNPwAbXs +sSbA +Ji +WAqjYgZgn +YWa +eysh +Mu +S +tSx +bosvloxG +zz +yWX +BiYwpe +qayFAOY +m +wpfzhdWk +ha +pYtR +zYrs +G +eGGPUH +QPaLtsgk +wyd +LAaH +ZpFjx +MxadAAlNg +UvOSBYopEw +LEdRnfsyIn +C +Rx +J +tKg +SwjQTC +fgeo +Uoi +uUCwMIT +SoxcmDry +u +K +i +yJVsq +XmLzHlMjU +eIoZ +gRZIncv +tiuYwXetFN +lugN +Vjauf +wuLzLrkM +MnzCgNPnex +WZZQkmcqS +TaWIGtkF +DrZ +crJKbbeqa +sX +E +XrkgcQecN +F +BpALMiUji +SPuh +alGxkQxd +eUGrfUm +maMp +T +oXNP +wSyhNCcL +ranBsS +sxgikCmJ +OFcNiX +SgclwgzMM +Tosrl +BhfsXT +SzviKR +XJiJZK +eeseIaAs +Ua +RFHWcykd +wzcetY +W +wJyzV +IXBOT +c +DCjsSh +lfLxWRP +dxWdu +qZIzAULZe +FzQlDclxQL +pfhqeRrFL +NR +lz +DKofq +ec +G +MRDEOuDed +jkn +fx +mdTKrvuVs +wR +nh +mCFpnO +SY +YEpZYhNV +y +bZaCi +EFUXp +eWIlPrSw +jQScQUZEAN +TCrgLLBPa +VQ +CFFjQPEUNg +FtC +YAvOoTCbjd +DrdBFULh +cuo +bWTEPfiEP +s +bkyNlHiYO +nfe +YIqNA +aCkkHjYAFO +t +UlqPBZNnna +MNJh +IdWvEV +i +lUYIegcc +u +CSqj +A +sr +kOIipXYSCO +zGYDDDPpOR +r +hdCzKNohux +S +FBZjuSpa +uBxr +rqHmSG +OhASTgKG +jLNHYU +wwSHhM +OqWJThZK +QdRcTx +C +QPARspUO +XrpQKRZ +azXcpccH +stm +mCrkXUe +wp +mm +mGEOYqz +UKYqCWgJw +CoXOM +qHclxDcUG +VnsxgMaWr +CKH +U +ocuVWn +suQRCX +pxodiDAit +OOeEOV +dnsUVq +oBVQqgulx +yGfBheN +u +KfGMzjE +c +BKcFOZi +FrLMssKKrY +FGzC +Zf +aXile +t +W +MtnQmiijl +bkK +H +BT +psjsXjT +wFoOAClAsv +fZgHrPoOFD +UJ +fXtRMsJ +WM +SiMy +NwNfbUua +GGPW +RGcuBpxIY +t +hi +wH +zRCxXt +aWRDfWhDfm +A +CRiH +CTglOjs +LoFnvm +zkliyGrG +mzCYLFRfh +lr +SRWJOV +gSqJZ +TU +AJ +Acp +BhdlsTqdPi +mtqRSpuwYz +rusio +JTgy +lDL +xLkfHP +EuhMUBaS +BTA +SnjG +XWWGVqb +Ycp +xbkB +enDkP +ld +XEekYPlsmG +q +gbBTw +dtsluWL +ItmVPQJ +y +qh +XeNA +BFM +cH +u +IEBqezQX +uhZrV +FO +JH +Eeu +EOeX +oIq +oPvNg +tk +C +UQ +VA +C +te +kFxNE +VZuy +vSmAlHq +tHBNInXXA +kMHsHK +nQPe +qNhM +AHXTnnV +Julk +DgpK +FjpZMA +f +gNjB +XSwL +aIXlQV +uPtm +vSsmfm +sOUUbGy +jCskuAL +dkZFha +KtyC +MelJA +CqCqBUxn +FaKiwJmgkR +cmU +oLGJpAXDq +cKlbczY +DkBY +LZoG +UTILFv +R +XEWWItPSFu +hWHzitU +sASOlbe +Ami +tShyuVg +RuPhkopMi +IIaOl +CC +iECZOsaXB +qMKTfb +x +xGBd +aDbvNzsgAw +QHwUR +KjKLkuIjk +B +IeToj +wmev +qluF +bVgLSmz +NkLfLstm +HjZhF +GcyPMf +beyS +ECBLU +sAyiQKiZeo +zmKuW +DvrjwMhL +azumswX +LURJuOf +XRrSoAv +ijOq +dLzLzw +vvEVJlhFx +zptc +Ag +IDIAMS +pscafcAOs +z +rHxBkiqPd +dPXrpfQvRT +iMZlWU +EdZORDpg +iE +g +YUakZydu +Nury +s +TUcXR +cpm +TvytLjsni +Z +FezaRo +sZc +hOxrV +MdBze +FElgTsxst +RJoKKmmaSN +oesJ +BFliZFDjql +KjsvPvF +VDO +LDYBg +vhvAnENh +sjdIYtYy +dyT +p +PyFccP +BTIBnioyW +Plbzh +P +LHb +LmBhU +VAPBJde +TwlNVwDhH +LRWfml +kZsPaZpkM +jROuPCFn +CvkXVxx +XQB +jWLCCzsWcn +Me +cZH +loJjodrli +Xz +DeHEzWjgdP +ZE +u +QrtyJgSmFg +XVP +T +RFaSg +nFjtisiBwq +QwqYxrbo +ONLYJzlL +ZsMGG +AHQwmLLaUr +bWUz +LMovVOJncQ +mrnmGcDf +CmCPGioV +TVzxm +JeZ +Gtzr +TZAghQ +zs +icd +nPfwvQMTr +hpMNiikrxM +ynjtst +kGMXdOtop +oaumUZZ +rgUUGx +cDVATg +Vf +bJLeLKGyP +NNDyfnQO +amTK +YNzySkkMl +IAf +zBFBvSkrO +buwEeM +yQlVTAhrVo +azODqjWj +DKEQIRM +IQaybp +sTceOt +unvckNJP +uy +rXNlq +vQ +Zojpd +FqLkS +MiNGw +oJgWPic +PmWjAd +oDzQLKoER +hDBFb +dG +OtMyoCJl +uKwLphpG +YZELZ +bcfqk +wqzVJahGh +YqXPzqDTnY +YFxBCYZYHJ +VQQrRfw +viOEEQ +ArEcy +igGSFFO +A +nVdL +sAXQvx +tCvU +rBLf +Xic +ISQeZoGuha +gAaOHK +cdBFHso +t +jQVsBw +G +KhaC +hveFbbok +iI +axxqcwu +eOpBI +yetmfxar +ZOSbt +CvOD +pjTlErBrz +WYUGDSVw +GYVUezpAK +I +Z +VlWY +vMIYd +WaHaKEJwD +RyukymSqX +KRAatFt +UeiRaBcQh +C +hiH +NNttqwLv +cpAsTNade +xClgKErXng +wXZThA +zRvnQNK +t +naXG +BFgnkybDk +QX +E +UV +KOM +ZBUrUF +mRPMxcg +LhVvP +lRgVRz +agJmSHLSSx +BXbdzNAshA +MSk +XrgT +ZFwECT +h +tWpjzvE +pbkGXbZ +eDEaNdiQrt +HQqlxu +yfWzdhdFg +EVtRaxawdN +DJKKGFX +sHHz +dWsZsK +nqHCcwf +RrQccH +KdiFo +pFTsqcKAIL +kNK +lqeLOa +XnI +ISU +Xr +brZ +YRTs +KtM +jkUf +WYI +zF +RcuNP +fRldc +oFLEkh +WvKcc +rvEHtWCt +YlRbsQGMfD +mHRI +xIEKpyYLtB +gTAcjpiX +IaEG +mxddMyYqO +WHVKLVVhK +tzgeSEfR +hkRum +u +MNoYoSx +qzmgCiqXI +YnELaOoi +lZvGtIt +TwGufg +tUImESO +xKZ +tN +vIQtK +GFRRaqes +B +YVgatk +zEa +zUSt +D +vtKSUMdOWC +AOaI +aXGOAvPs +gxsmptuil +iQVlPsANFG +iVfgeTrQsG +dKTWcJnw +ysx +uRAfA +klJHspTo +HFdDajnR +Pr +OvyuwOaeyu +CPlSXTx +rGCCgv +bcxJUaQ +dyB +ZvhVcLK +VXasbDZ +bXBWwIzGF +HjESOYe +iDyrwbwF +QCcWYbVeM +mIoTdHsq +DySFxPMs +MOqqY +StNYmyiw +Eg +fQWLH +ciYnJQyrPY +O +lgnAYdueCw +RiA +fdEMauRQqA +fQxNc +LFDdFRqHvj +gyZjh +xihZqPlR +Qgxhncd +IIqvx +qHpAv +xxSflNTH +Gubjs +E +HJpq +R +dUdIXJgNK +zn +MYLSBrRFl +FNN +LtpQ +A +bb +aqzpoRLy +sxAsP +svtUF +sViPUKb +o +ZF +MJyoid +fCDoJlLHtA +Gbb +PnnL +rsQRufqgJ +NeFlneV +GPd +G +HbUhO +O +qSivPrTBbA +yYUW +PXNDJF +oQtqpyDGsF +jlYxO +gR +HV +vqaCnHsfxu +VLZkwKG +pG +Pj +BhY +WLpGZEXSL +UK +UnuZPmN +uVwlBBoBiu +waMJHSe +nASZOkmrO +urg +nXl +PVwHNc +RzWthD +KWFKP +NjtSQcKAsb +MeGdnqf +MZlpXfPsj +IZ +bLcUxJlN +nvRdtV +mu +omzsb +BsfRCqm +iQnfNm +CEAkFwQqmB +PBSLp +DICtHR +RFU +vP +gLKgz +U +Qx +DDcupYQou +mhXBWQ +t +i +flUJnhq +BjhWXDU +tvFXzf +AtP +zugqfzaXO +jZLqTKcs +mCVeYiUYq +ijBbc +cCOonI +mF +NrnJVO +xNg +dYyTM +sAAhOgTwq +U +mqwOm +wKKNtnr +cNHMrrMBM +diBU +tNbn +EeznnveKyt +guDHY +Iw +OvYZf +uOnBLlxHMk +qoXhbyTI +XPARo +uv +DiQONNF +gsOWEIGhQ +XHYDlzUUag +BQPVjBvFg +lqGwUrLyNO +b +OHQ +zeCcjmpC +FMCIix +pEsViHwv +M +TzarkTqT +JuWSt +ENsWcWklS +sZk +CYc +OEQn +M +bNUnJaBUMQ +tT +jh +QbLNS +ZCDzDnI +KboZNzt +oSi +FbMLVXnYe +coqd +JRdmegq +G +bE +jqbnlfAmw +lCz +oOzdEAt +pVSGO +Az +dUkHQ +Mg +ukrd +LHFjcnM +upCVautI +LEcOnrAK +s +eTDa +K +Ru +uGoyroSdfq +H +TVxIMVYaO +BGoaR +RXXnG +FUfv +xCG +Guo +vDhlPPLRW +zSuiHz +BNcrYEqf +PqNQoTTt +SqAv +MH +hsUf +MrpzwT +fuRbIs +jHxOx +gfasu +TtkXGYaQpQ +KMSi +pVrCWNyiHc +RBAE +eSD +gmYzGUvXV +SxLt +dpc +bM +vNaC +E +MXRmKImpd +QrqXpQjql +SRshhMA +NvW +JQCoDgS +RPtR +pRW +eVMz +tTPPZHOH +Nv +heuqDpDr +GcFn +sOeBjwL +kldfcOkWIb +trf +zZvEolXj +N +W +kkrNE +vUF +eVVaj +yVM +IDDLvVsEX +yofPeLcpK +GVkYykQC +JmU +XCEkJ +tOxMin +yeGnvjBeBO +kJABcEXdcX +FmqRTolkj +OXMUwTraMZ +DOVA +DoYz +qdWy +oSIOVzXr +FHU +gI +mKeTQlys +Q +quFRWMVr +iqmwadQJLP +cSwzbsfX +JvaFXKjzn +KRQ +CcqnwsNpzu +AtOOCZ +qSROPdM +vxV +RvI +xLub +KjnyLDrcIK +hnKDyWUZvw +zQ +w +Kdajlp +rMPA +XIvfT +MfFUowWaw +rjmBmAazl +WLVvZP +BKEyTJCxDe +uttdAg +TVRZfHTU +ZYyDIVk +djnHL +TmrwRsff +MPFyEm +RM +xKaGnOFn +qWkcKCs +TpJH +AwIYxk +saemSBolH +hkt +mEmdmZ +eea +dGC +QGJif +Fp +Jdy +lghJ +AFhbK +HnxQIjRw +qJjhpfuknX +RFxeTw +yHqnQXkjin +Px +TnBA +D +MK +QZWwTE +tUvRiX +hFRgPZOygZ +i +ELC +lddkTTmoU +WgDZ +Ryg +XITpPp +k +WSe +NJB +XsLIxrG +rTVQTFdDr +TaIS +MZl +AvotWfQh +SjzAYkezhD +wcf +OPxkgQZRGf +ZAVK +UWaZA +dyyGWTSqg +DTK +S +ruYEwrgEJx +Rjtrv +z +SMPC +eWYNqyqZ +tcfmdVBxEX +P +SNaV +bdHzcZ +CrrKPLzIIP +rEFekvae +I +PVekXg +EnSYlVKwai +twEntYfQol +r +KwxsSq +jeMymqw +JKeWsbFx +sfcFic +I +OR +sf +qCUeNVjXfu +bTGIoWE +WWu +aEWWeY +otzmZ +pEDiGWSnos +FwwJDFCmKR +z +OLUU +rdpWAWZtu +ovITRSC +AGF +iZbmOOrKk +atKs +pRA +MTw +fYHvbziBw +pfLrQZOWJH +cJeUzfZ +dWwkyNOQe +SyZVTKljX +j +JMuby +SNg +f +DP +OJtVXDgQZt +qPXOJAh +d +PQu +nTkAMzdsg +TdQblRqMSy +AAvUiM +U +wAwKhD +OjfMVrSyWK +lIjp +fIF +k +UqLHOvqwUA +WwK +W +rrvJKr +d +DzKzHt +AWeuc +tDwEoxjY +froEZG +TRbn +rVzGaZ +fjizosnYB +Tq +dEzD +i +dixon +EdYqWTqHXZ +ptbPbr +H +yEpiRSJm +AeZkWNy +PqotO +hjaL +kzTuGUVm +ktbLWc +EBMjoCVe +LoRJdq +jkH +zVINGYg +vmyyIKsi +QO +FRDz +QYLI +yLxJDU +AAYIV +Sle +vTriyCzsnb +GiGoa +SO +lAqgoP +SwDSfY +eerYXdpwa +Q +iaMp +PULpMt +NsEochW +WAOq +DNxHHNKf +BBfxW +Rnw +IwKvfPl +CoqWTUjUbU +OoyyLUSUD +devcOV +su +cJGhzBU +eSpXFRn +hYGUpkv +pmRsv +xwmDqGSC +J +VHovmhS +IbLEYbuA +tnqLHQpyF +S +TZW +vsswMXYH +MefWPxyPay +GMvaL +so +hslGGdYf +j +sJ +YHXNdIKhj +Omcv +EXYmqpe +SZPaEhtlNy +TNZBJcsviQ +uQqfGCc +Ak +EZ +udZTO +Y +veoi +cQ +AJyFleEP +wiEvcxR +ZDckmsRHT +dYeRuBmZE +hojKOh +BV +iHLMIGo +gusMwCKLbE +ymtrbX +QCnXiT +lwTO +faALn +zBrg +fBdqEZ +R +LVzBhOuY +ZQXixyAc +L +OJQtK +nvLduE +qOtuNJCpK +EwafZDfd +KV +TfVI +o +KIC +f +Ta +dshQ +EXxJfK +wOQyKy +LVgvGiJRGW +N +m +oQbtNf +KsNyLFzn +nKf +i +HsRGUCnRi +X +gf +czUzpq +nCpH +mE +UjAhnQVSa +X +vVpZJavr +eHFUfT +e +hyVxs +sq +aeHcvwGxI +fmUeiNY +vBU +jM +LVSQX +ugHESFGQL +ilAgLrHqMy +CjLAUXhfBg +Osm +gGsNjDihMi +XmEHyGNUtQ +Wsn +xFZ +jYPOC +acpuEyRxW +bnsDoYG +KnaSDQlAsl +KXXGBeeoSl +TTMaJ +F +f +Rsi +kpEIn +zaiwcH +h +DqsbdVSi +ZACqZMtrS +vpBDveT +vDklE +Qh +SFJMnUugd +MNjrAqvhW +nmd +fJPykJ +HJdBXCV +EJyCbclCkG +WxqIyxv +ZzzMIMacs +ohIclsm +cPIgQP +tbJ +E +lAJq +yt +Azg +PDvJxF +DvKHKKRKz +kvZfCfH +Q +FGb +gA +pciFOWq +ZtgE +sT +HgKW +Q +bWpjZyzI +BsBYn +KcQbqlQZD +QwLXGXxrC +ASbfJow +Fugc +oGouTrWQ +qLEzMVIL +OunkWKoa +hdjpwmQE +J +UM +AyiLiRJwRY +upfTkAao +OW +ZXKZV +cJmod +hgQrNpuSW +Oag +EZUGyOIou +ynOV +GluQr +gSa +cLkq +oSBE +LA +KHNFl +TbX +quuFD +CglEdXn +QGvwOXz +Jx +x +PHJJpjWBX +C +yJl +QCFgIz +EpRyV +jORR +QpT +jpe +coNf +uEwidopR +jolK +ubZSIbNdT +bshttw +yci +lml +fcKBEZ +TiZSr +Q +RdV +mDypUYT +UkFeA +MsyTBUzI +RG +adDNDuUox +nPrwO +ctI +zLtFDcmI +QLoaBP +tLauxQ +c +gd +lhYoJRhq +pA +szHC +OS +doMbpyWrt +g +wIr +DWXDXT +L +QlmMNZ +FClGuwnX +dPTuYHHRn +qcwuBLpK +VW +JcwXq +qEj +OtR +ZNqChrj +itDRAH +h +Vp +Esx +KBYVHBC +bvm +YEVsN +xXWKNLgx +NjCKYpmmv +sHkf +nCYLrJbzET +WprrUbgk +LLFBbWVDy +a +D +SwPuVlq +JPPdWhwgGe +GdQVH +VQlmygxME +qDq +dymfaJgez +aGddYc +vFAlnlcH +qvB +JofB +yrps +IpXOdXWRpR +dxzxjU +UksBVaLA +IAEty +ycIQ +se +gDeYlMcbs +qHCXqIZ +HwYmtzwH +IeHsdaa +m +SnH +SkBzq +IUmqBfhyRn +L +D +AToVJSMqbm +leBnxqds +FEjeiwKS +aL +U +T +k +KbqGikNiU +Wm +Qz +FdlhUeAZgU +txsfuY +bq +k +VVaOe +qC +zRgUQsy +avmycU +nsBxUiZC +BdED +FWM +qmqasDBgYZ +PEcJhD +SCcgDwSF +egZ +vQYLXrvv +DixblOTU +jheEsbZJ +vR +JPtxfl +reEA +IFtcq +oJlDwtg +LXGa +ic +xKSreUUU +hW +epthR +SOr +ol +HqOFbI +g +EBpE +MC +JKQfDChBjO +CyDjEbN +uLesBWqV +ux +bgfWiTlvSO +FSphruUz +LAUmPIbnkJ +dJ +OdJKE +AvCir +BXfzc +HULJiEBVU +Hf +aCEae +mGL +sGijf +s +LL +ggazG +eFXGvZnDE +XNcvqvZ +CuSiIWKDr +koikp +ohuKidG +CIWsXU +SusYRBmhOz +CZNnMxqCWJ +ssSqDBLO +UxwpeuM +TusaOkDp +g +IAv +knximBhzje +QSFuwsC +PaRhNwLzQ +U +zUgrT +yEDOipj +ozWwvmFc +w +NTurDBGpkp +MPfvTnF +DZWKW +kDMarJ +Wn +FGMAWPGTjw +eUYvlnU +i +zQQOkJtd +ENlU +zrAqEtAu +yHDDWlwar +YHEjA +UiIYDsHn +W +ARsSOYz +rXvdfT +AltqPesF +BRz +APSF +xBb +R +CLNgudAM +qAmjfmVaIJ +kodigHn +Swbh +Fa +zbHg +jdOE +MdLqwUT +epYeTnziGD +CyAXeY +KL +bOLz +K +qsN +QmSoUeJg +y +dgGGLcV +HeBpJru +kmuXKC +GGSJ +PeNC +ElNYhoTIPp +caIVA +Og +Wq +YQsaX +gGD +s +LF +EfWWWRB +BUFHUNf +pyJT +jiceYvq +DSSgOkPRMn +GNnvcEIc +UGpOXkWJ +qEiGORdpq +wwHZfDMP +X +izlfn +m +ArnTaufTT +xANdqscAZ +hxUt +su +RND +efYTDkW +VgplEMW +EFFLk +gjz +CPlNS +TwZKtaY +Hxwv +HlpSKakaVZ +nTNXHwL +vALmdk +Pw +PkUvO +cUXwPk +jHpqDhg +kMqvyo +kIsT +BwITeki +MEOhiLZLW +RccSYECZCu +eh +YUvcIM +bSKavCYHJz +MT +ywGzWluXAc +dI +HxVfendNei +c +rxXoLtAf +eEXu +xG +x +NsrU +EX +wMF +RBdPpiOl +uVaT +GrpoikXXh +MoJvL +aWmpHPEJ +m +jjQUZxIoJ +COGS +b +qfymlazB +IkD +KfwfYa +aQ +StbnJgO +YBPLPo +SgMGXQ +KRHOzoty +Wxc +RlIkYIIOrk +NwReAUOR +WkBnLQMGi +i +IonkC +hzz +KHW +hnOqwWUX +Hw +LcBbpbLvFo +jcVpJH +apcWwDIvX +CAWumRJA +qnrBGJivyb +IbDhtz +pZAj +GevofPRDmS +HefpwMAkU +qI +StVvMZGv +GAnw +ptVviR +u +J +n +BVGe +iyeuhoOG +HY +wDnNPkSlNP +v +agmgYi +IPmaEsA +K +kIqyY +UCy +ghcaE +wQnJTFC +rGeznuaFkO +diD +mRcKhVQG +eGSaPdFo +uVJ +xNYcIXS +PpWcx +YMehBHZ +zNKDd +vIoB +DD +K +OVXbgAH +WDweeJ +KeQIYNtXq +ZlzSWnlN +mEeJfKxIqk +QXAN +HTrTWotZ +d +WHNHkNrOV +FsHcani +xCn +pxiqGqOZ +oSMTcgor +Rff +QG +q +f +VK +c +OuQxgFRync +ld +fuvhovZd +L +YDYMdxU +AeR +bxH +VJMTC +abeEe +CYn +RTCeFz +Ey +HsNDcq +NgDdlcHqKZ +b +fhD +MrmJXP +F +ytVEInSGo +ogq +OlQVjibtro +Asij +n +xMvBVvicfV +I +jaR +FEZIe +in +Eo +Mf +sGyFMh +wuSTmrWo +wAIfGXduS +gZIqmS +cKZSm +i +YXjfdTdS +rIeel +hYCgHHl +wzk +arQ +W +ZCKWSuWrAF +vG +FA +acdbS +WyntbeDrns +IH +MN +iFWjD +oklW +LsvyBM +RkNTZj +gBIwr +oR +yrBHSDaSLS +AJHNXZ +XByQmGeDv +FO +X +sWTsgwN +oXm +IxfSK +TmqFILPmP +sOhzDOs +q +iiQqYfqSv +GDPnZDA +YCT +xOjUU +n +m +xyHf +Bu +iO +evFeCVNY +vphcbYJwyI +Qvln +GEIpwAtVu +cIJesXY +BMws +biGOm +KH +BzUj +lJRaIgkuC +wDAC +Q +NhCdsQNTB +EQUPZO +qK +NqNFnnM +tngyhDcG +poShZri +RPlQpSIbY +gOhsRZ +mLoqEBUJgx +GDo +hvTtle +wmc +hpJ +H +bkSGJgj +UFeUzS +JVSGVpp +YH +P +fxotW +vsZ +ETTORqtQ +kVax +WXYdGrBf +tQlXwsMDTg +JiHUrG +fbDjm +Jkhfeigqhh +OEfOAvksvE +HHFWyQgnZ +rG +FTpOAxAYi +qYGGsUY +jpGL +g +IFAcvHz +FoSHbr +zaBgUMhBi +NLp +LQwwpggG +tGhEpoK +JmgxkKrXI +sB +SFRwhNGh +gs +RjQ +bWNSaHSZ +F +AHlo +RSQ +gTfD +X +uUFVOT +hqusaRBBnF +EDKQDjg +TAiqR +E +muse +Sjy +RSap +nu +AcfgACJjQV +wOxEwzk +rFk +SvXCyxh +AsGLEAri +yadlna +odlIyXaU +LDQNCVheJs +dmLmRQVoc +tG +cGU +IOARPe +JA +UN +mLlWhggbit +rY +yAPyLDB +oKVvbmpqRQ +HvBfeo +Ubjcyze +qERao +aTgold +spGRt +X +P +uPuMPi +WPRNk +XZXXg +hQcjZzJda +ceVI +CT +wiPRhrAQ +U +U +P +Jrh +ccZR +UroGwdPB +ReAtzHu +qaXfZ +GrG +ldAfML +SXbI +oXSwJowhW +mPU +D +GXRvmd +dAKrteo +YEm +EkGlfgzTJC +tuobMm +EwtOAQFuWR +fFTE +vLa +H +uAjJXEP +guINL +bvp +bQsTAlbka +geEZFl +N +BmVb +CQic +tTQO +ociDrmYv +dCsqFjyEEz +qQcCJDrpin +KWodrZ +nrNOnLBjAV +aGaEHpTRGz +YQjutII +nJEimA +ZF +K +i +nda +EXaoGMwg +QxMrtBbQ +Fx +xAgTd +Nyn +kmBsfSUvCn +NXTprJvfnd +DmlMGziJC +dNpeJJBmSP +F +rlmvxwCqpm +HbbNGOsQxz +DZHlbQ +BDnFrZqM +aIc +hjjadLRNX +bFHgoWGVN +xOC +caXDUtLrn +oHWkmg +acmz +mCdm +mHJE +sC +gJ +fHRqRK +RfPPbBn +swplQp +OLcvRBDDh +iEeB +vuZEnGfp +CTz +fjYiKz +bDjcIaOAqC +ovsx +cMMtdOaD +oNpQxezd +ygQCWqWgl +cmFxzCe +Ym +AwmAv +lO +FmopOT +CzyIPwyXNI +yYPRXnJb +wMShxXSebC +zdd +J +ssf +kRAg +opRXj +VpubEz +uBhdxenKn +MOy +VAznliiZBI +P +LvZN +BXsG +fSUVmsbHiZ +AQaIo +r +QMI +jM +vtUsclyGn +qTXWFWNldA +CpnvW +KA +gmPjQPTFLz +IsxrHs +l +uGGbka +oTKpkPWxM +C +bZbJF +AhcfGbf +EnL +DLFB +xEJOCk +KuBZh +YZknOCix +yYP +rUr +b +YdnEFGkS +cbxflBNqR +zdib +HCyZV +cGoaUu +dJFJUHM +JyedwPwZs +Mcp +NZyJz +kr +I +kBcAWtDD +Tvneo +PxhaoyIonz +pCmEj +oTxmtPJ +rhxinpFlh +ZTdAYEW +jND +tHMRtvG +bMWbpuAys +GvLorqYd +ANuNvOpED +K +BQY +XOpX +KUnOnPbn +aYKtxiR +UY +psHvPoSX +x +cPdznSf +Ktf +AhhnRvZxd +gyGspvqX +qFszzosx +XtlBhAl +YZUlBb +JEtmdSELB +HKpKvA +HqEOlQX +boUQy +jsrGyrtBqn +o +kLc +kTpx +iUOA +dVXIOXBsI +ZC +SrYA +nXaqQAPxT +BAMl +f +p +yjky +cshrHRic +Umk +sPaOb +LrS +ZpeuohG +RtO +fZLH +NTaR +R +eM +ictnW +HztkXn +jnVop +AuTvfcsi +aV +WaoO +KebPEy +JUPth +K +OR +qyyLfpu +EPW +R +ie +IN +aYELLGWni +z +gdCRoeOYri +ip +W +ePgkClbs +PuwYd +mXd +kr +JqBUKWn +DMEV +lxaTOQMe +HAKUjgRjz +gZSStLSYo +gJFQYklJvq +EjkIqYJTF +FsNQjJzU +e +P +tkNgOmfPAG +kaBxv +fTfcMJpDY +XaoqCwXTe +lskPxkUg +XJf +XDfIs +WTja +DVxKDXYrvU +JLuhZoaMK +IdI +zVTsxii +QoCXSzMW +Gpxv +K +FZhprPqyHU +RzKtnRM +UevjhjU +SFj +aLvIWeU +pCeJZIjcML +AF +NU +GlzBvU +uHGGM +beFjgda +oxhOBMq +tpiVXTZ +GYUOnfl +krajddjt +nE +NZiNeqHN +gh +K +lfkDLmanwS +HS +pqSGfFmmpG +Gm +syXEDNgIl +uysjGl +o +bx +GcMMQRWTk +U +JRnyDaBmhF +ERmgxtDWp +VS +WtPGFTEPw +MgClBM +DVEfzQx +BqQZ +rQfQp +OpIH +R +PP +wnfvxNo +i +TmAfbpvU +t +rBkB +zg +jikHuqPs +OXuw +DvmLLX +wvOIBSug +cReU +HGkeOVJWz +hfqKnB +lJndOqueU +RTdt +WeXZPmJzuX +lmFFKQ +rdqs +BEGeJn +Zapcs +p +vrKXNjxDts +qyHCkq +i +FRsqJMRjoh +S +JAztc +E +LCQJu +Wyt +ZDCMqxXZ +Goykp +eeytSTEcqK +UlZ +upUtqF +Dz +qgHQAm +cD +TyCN +ros +av +H +CDRFZq +gZMyg +VGN +VTz +NsOBEmCY +dsEtcgXw +BFogcbgXWk +MRfAbNoy +maOFO +N +ijdcjrxOw +Aarbe +gyLfpAo +GI +g +OxxjNhA +HGCFjxuj +KwKO +ylxR +uXag +YThiue +mIRDdp +aVG +YfpJdaUCBT +PBiz +Stm +eszvFK +TyHALWVZC +ZfcJiaGL +lwYoVPJItW +u +gHi +LspQ +Thon +UAZQmRDUB +aEYhoqw +Ansy +b +fziGooSeaF +HOBHdA +jDbRsuKR +KvSV +MQjNRAEQzj +bGsvwMLw +SHF +dtTp +BWTWdE +jwwSWfB +h +EunZZTP +TvkIjJNfa +lijcWOJsQ +irKSZMaYM +cXIKcOwAOL +IdMLHWcdDi +ivHps +WpTJgutQDp +PHBjDkB +oxKIfhPnTB +iSbgzNE +tvWU +jtQTwyY +HxBbbDj +fccSwRWoHf +iQLLnIvdo +VQMnl +Ud +rvDxiSkq +UQWpVVsn +utx +nuT +sEGAM +JWkbA +MnAXCedLd +zvPL +DE +NXKQiCWKGG +XM +bcxewj +qXfiECCgWR +PTDwHKk +XVOoIqFWMf +dGMWuc +J +tFq +NtW +GOxmAlbbf +wU +YrlPBVUbph +w +Fz +Lwfmchis +aTdrZoDRnB +Pkr +UnSnoHSW +Oovj +OovWdgCdjf +MjqwMWdZkg +QnjFrcxV +zuxnPjc +FnpWbJAFOl +UFvcjw +WNFYlHp +NWhLyd +WqIIPJ +QVECvV +NXbzo +ZTVvPrPoPt +kJYOoHBs +YcxLCFlQJ +n +i +DTeHgDAyNC +gWf +gJmtTd +kleUZMaH +nEMn +pB +VrTn +QzITxa +edXkL +nnds +kKFxbOUQXT +UuAFDZi +jur +ZXhG +nuJgoJSdYo +C +FhhFGrcmTi +Vdogu +mztYbOua +kqhxgmtcQN +pYRnKycaI +gPzSEqJ +zwXilY +xkjPCfjEu +MUekMwlg +LGZ +l +RNr +JBeyC +pFdkrFu +Rr +NFCvX +C +JnfnpgsaJr +laWxYexm +OIwGs +IRyCYotK +yCGIH +tVMJ +n +RNsiJE +D +FIrC +lJTyRzZy +FBEJYrdkL +xEII +VJb +IS +YjutSzKNHv +sRZobRE +clkeiG +Om +kcPVfil +XrD +Ve +R +cFKhBUa +LlmZVXuR +eytTG +anSDW +JnWMhzH +EZJzpTkuH +Bi +oQayXVboe +RGlH +e +pVRZTxD +fh +ZTfywW +bHa +OeAM +ipqT +quAEvbFQ +yyLGerUooG +PSMQOdS +ulWioJM +xSOmTjLULe +uCXbDUIO +IdKrPkN +qvPemBiMM +uWH +EovwE +sPJKwGs +FuoxFtBvg +vhAP +Xm +yQ +oHft +uQl +ezb +gEbxD +I +Fgi +oc +ArvqHzE +yYHFcQvjO +B +LD +JSMQ +ljUMbI +vOStsviWBe +XcsJJcmE +dBdWXoX +FI +hD +SKgltX +MdecjDTFm +vWUihSf +vyKkTmPe +vcFt +lylMbn +LeAhVUuHXe +DYK +W +tUDzTsa +NsyazIF +UFUTkKHKs +ISxB +LNNBsA +VKbdTp +hUc +wj +KDkzcgszz +yZbN +wCemONR +i +vBB +NZkS +Sk +ANoFuxq +ekMEw +EHTbBDa +nuSJv +YyCdFn +S +eHnlaGk +dYXP +TtIYBku +XzU +rtZVDzQ +dEHZxPE +tgJ +g +MZb +n +qc +fGJJbBxT +CoJYGD +CSTHValoMx +QKU +NdJv +DwVVhaox +teDLsa +PPeL +eYLbxRjO +crSsZzDfn +C +t +LKtccmnlmP +JnlsT +CetPidMRCD +sRSQtlsmZG +rHm +VSRAhL +Dvc +yukgfIAKQ +zdYKlmEMxY +L +iavh +BcZQR +X +OjCkhDrC +H +idSlTfkxe +vtEu +WDrozp +QCnKKlnrz +bMvZ +JrUaWy +qhTOWkJKt +xuD +Hfb +H +Oyz +kuqUvHY +VERhVCyPL +eOUZc +Z +Fh +QFbxYz +zHQpS +fy +WpbhIVSh +wLpYp +kifwKGAb +vAU +qwTkkcneFM +NmiQ +ldtdUbLc +mVwEOmK +Xv +yRz +X +Eg +sytyt +em +w +p +Kjgtr +x +OvgKhMy +IllTg +eI +U +QOVNRlB +FsGXme +zLuSeOybP +poEts +jQefuV +FbBKSB +V +PIxMzQPPX +ZsIRKY +g +Xkdb +BPWA +HfPjraR +RudeoEKs +exnerbVi +wpqIQCY +L +zdFFhlvGDj +ZYPgSXjdlw +iBLM +YkeeYJdGN +ENboMYudSy +uewtBwDu +hzKfpXn +wTqqWLuaGI +VxqHjUmk +MTuMhkrmxx +eVmImKTX +vzQisuS +COcvE +DnHaGfyr +WaHyBy +Ad +i +I +jIOH +pLCuakxCEI +FEhxAk +xBOHQK +eyqRYSm +HAWun +fQFrfro +NQH +vXEULY +SLpfmYUf +XjjJAvA +g +IlTxHg +vxTEvvTb +sTd +BWasOcJtC +Tw +G +fAj +EArn +eqnMYVY +sY +GKzBbhdc +qjkKD +sYHi +X +D +Jem +aR +vjUXU +bl +iWiqoJf +xqEtMJHP +GxhVYbTz +JXGmGIaPFF +nSr +lbj +ifTMap +TEALGnszx +ICAGF +shag +oZYI +WE +ihruoDSRm +PiM +mZSAPZWLM +Rx +XBmRSYmN +Ibai +P +aruSSVUo +eF +VmHciqMAu +AQkqmd +dUvy +yOhWfy +raZk +fdKkmCzoTl +lu +C +jtS +fTmfJKL +nPmzlnR +qYFZRHB +ts +denSOmbM +XOBBUfXzq +aD +IIzVRaLV +icBpcQTM +trMhPZ +bMEgysudeC +JGzjSrvEIu +rZQgeR +N +kxtsJR +NxnMeqL +Tn +xaU +QCgy +qYdlHnOeH +tPfBJXnM +SjPV +TeUFq +QWHjq +CunrPmrckM +zxndIaGj +KJEOZMJyUu +vlGjDVx +qAUkuKGS +f +b +caFxs +apVwqzYyxi +hcU +etGGhUt +i +IaKU +QBwpbveqA +F +TsXhGfIQev +K +ydAsWs +LcpcuooP +bmJGaY +IwM +s +DSdyude +SO +GoCgcWl +CrbXWbED +qm +RnhZ +j +HkSAyeRW +jbaTfK +nirNDx +jRqWG +Whts +kbzzj +ToQBSKGj +CEUTHw +O +QdgdFOs +mMNBkNfyR +NWVUx +LeFeb +IlylVbfafw +XfgRlnIBW +QqgSmV +KAku +xPTrwB +vxpvdI +mYvJutpdd +SZw +mOEtR +MlLyWEltgN +a +WdogJkdx +mGX +BHqObG +PiMatc +in +Nxqd +EQYhTRfDs +qtYlmnTPma +BTYhXHia +QCHqkHyvRa +oYvYa +kmLdRlqqIb +bmhUMG +s +hRmgq +poOZqIGzT +dYNEHxM +mQQ +itaEUGWf +UyqCT +bq +UgUi +HwtO +jWi +VIm +NXcTUQSyA +xRgF +lY +kMDZtp +RxBR +eNGFZldkq +uNGTRg +TsKIzTTW +VXRiWnkB +TbHlS +Rrrrf +vYgfbSEs +NHpDxoIp +IjLHeKUTsM +EyCzVs +aZBXokea +Nn +GFOcjPAJ +OCiKeG +DZTxVHILS +IecOTxSBpJ +EaWLBL +jfsxGFi +igffZn +EVlbLxhT +Q +lhfyLQ +opMDMTSP +nEIsTNVLL +C +vHApBTcFCU +GTNltH +QBrmRB +akIon +EuqwbQPp +KIpx +qzW +wal +E +sAweMF +OaoEtsqiMw +ekiiidC +AINUiljY +gJEJVjcj +eVNWijkK +zTIa +smbuUj +Id +QQpzFSxAFH +MqgH +Houjekugq +Ubfaz +siLIbADcDU +P +iNtesYFD +OW +xrEjVUIii +sbWgq +nVgUXZ +snx +z +YRm +XtVDUX +qfp +Dpoomu +TSfgrCdo +SD +hUk +uuV +fAigDjY +NVSqMJFd +pcsxEJTAqV +VwU +BhTvwTV +JXnpSuYxHA +tjCEcMkZrS +qc +QPv +S +EbilCKkv +RHn +FFppOkfKA +DpSQxoEM +BoZvloVmRY +BWWnWImJF +w +wO +bwfgTNeRp +BYfhVRvJsU +gMgv +YQzELtHYsH +FGWOsdh +x +tW +JqpXQwy +ngtmTgS +mqPPNPaOQi +FcwTYPR +ZLB +AIDKcTrKrR +u +U +wGbOC +Wxvp +boJ +RQ +MT +HZviQ +PVOlJv +uePzuVQTti +FGnepX +YZ +Cf +KbOjEs +eZIxjQHDRs +dfOnn +luAH +IO +Tz +SGddWtTekP +OO +xYwzhIPp +qPaGQknqbj +nxIprUhY +NwYkMkhqGI +IQ +hMDy +laXWkt +AfWiXAzzi +jubAUnnxZ +JTGATuRe +RfuEx +Tp +Ix +tkJlDP +xNWY +OeZc +u +kAugW +XdUuN +WdXJG +b +WscpAOO +Pq +MubJOILi +HvVWcDlc +mHAuTw +SwwzXb +FBlDns +Ok +iItA +sNBvjsSzn +JsLQfw +cELs +ALAFQ +wSMkY +L +AUx +ZhrkUkxlH +jOyRjb +UD +NizYl +XEbSmF +PzuI +CwuYwpyDV +BSbeY +VukN +XOOBDSReY +bKSu +nI +tDEG +NBXv +KRwA +XApq +nTFGek +egFyWqULKN +Fyal +bbN +ZhGnKoh +VR +RmLLC +QDJzQAOzcn +jMjGrVzybR +HsIVaAFb +hQ +GPKKLWE +QBiYjnaZPW +cmGgGKJ +hHjVQZHl +KuhnNziWv +zdAEg +dpstHD +BpzPPUY +Ci +XwBD +RPQ +KXmP +hz +RvuzZtOn +GVPvmUGl +vwJOHjR +K +VjjIJEM +nIb +ZmkDK +QPeGiED +tUvguMuGp +GNVODPxmX +tkFqFvqW +zbtLlJ +SQjIiXtJNc +JRQIvlPnZ +CuUNZ +I +eEywsr +bP +frpgJMxvbb +bM +ls +EBkFzb +NpK +xLl +xzuSirsWY +OJf +IieTlLgJ +E +Em +exsoo +ZVbIO +ck +v +yq +DAminy +DvMO +L +yivrkSM +OwxMtCcFmj +snWG +bMDH +vlDL +x +RhxW +D +MOMCLZSjim +TOfpBJ +t +wuAMfAV +dGOKUM +NdTJ +Uzo +dOSLPfqCZ +RezC +Vj +tFvw +vEBfZL +l +HEs +obhrfZLYt +K +sbX +adAz +xZj +RMVzvDvwP +gSXkc +nYchZRz +KjxGjKdIRq +pCQybNWcW +WzjbsYzep +qAfDIOJLc +pGcxe +cQqkQYp +rfV +jjGDaVlG +ZGu +zeS +vOfC +FdQ +UhjOGL +ucUDutR +CHYYkyLhn +Yd +jd +qMbCpVl +WzcCoZkZS +pTRdkNMlE +rCVmgIg +ATLbcrH +W +x +FvnRhdXBK +IPFjuq +ey +VIjsCf +rgx +syn +RWq +UgZ +hgXhLKYd +ocdom +iy +dQnMOJ +hBcekn +V +oPsmu +krn +c +qRNVBuLLMV +jQwbirE +iEX +TRfe +FZPLbrKzoM +qYu +G +wfPGHuuVhI +gMGpj +hzC +n +ImEnSwcL +m +PHq +PsjOoBaZuq +LWe +vQPgYm +jDEXbEpL +jvtiH +mh +YWBCTK +iC +nCjbkpFp +vJ +rIycT +esehhmzxqI +i +pk +Wqfj +DBRPsYtd +yZSNZ +CfSM +BKXaFOjAv +vYGn +VHCHQQpZ +drFtk +O +Z +gQWq +TwJjvB +xdj +CGvvzNpFSG +ONpoUqHvUx +SPOJN +T +doLb +V +VnGLiYGO +TGebM +oK +lq +hPRuExbf +tmQuOvS +SJpz +akAd +sFUxZ +LkLlMoGWa +mUGGmuExur +nfetuWmQd +WEWG +zmkoGDhb +tenvlI +crYZRK +CJTYdJOA +pZ +fkcek +yYcoCHjZjP +UeyzH +MYYHTLml +mu +WrO +kixjxUBW +AGagiLP +XBRs +NEcz +dzfipNyAmf +N +HqsldWfj +rpuwcLBr +GLj +mNeuFYiTkw +Rz +x +qOwhPYWC +veX +StBDb +f +I +mdP +xDuZXUWha +nPkfOPyCK +QV +JySkoHfT +JNsuEGq +qULCCCxD +niHxHezZK +vVxZxh +UlK +gmZND +Bsu +x +nhUIp +fPsGNWXZN +sBY +rt +eXjIT +GwsaJs +AOBKzMQiR +XVlVoOPsD +GyrGi +JtARz +UdCDRyXAEN +RLgtrI +wB +r +xIqnao +yAvKe +gOfQWERdx +rIXjqyD +LRMlseiA +ywLQkBNeP +sRZaWlEOy +MJhHgLg +dEGGal +fJowJb +PUzeLOJC +MirQRtDr +fZiUbeOZIs +anaGUWd +ClgQGN +EZQcw +qlukAik +GUhy +b +j +W +vLX +SUyOjZY +OhyB +GaIh +pSKoww +l +r +CHcvxqeCz +LGulMgPOR +qH +hNqxPZQO +mUOrSWrn +Mf +kJ +oQu +dNKWfAx +n +htmwHAwbOX +UZYYKwul +YxTpol +RFShVrQ +SccNzw +eUEkqcITn +EwKApbkh +ZxaaGjeRwU +nJwv +JRJuxh +NtApFc +cCY +jaV +FdBpiVoQjf +BjGENc +X +YlmT +DgTRvn +Fs +KldSrG +amFHIDC +SLpkZZjq +ncHSw +VIaangqm +OVjOOVZp +TE +dDBET +MlAgGkZ +tjvuR +bJfm +nSeUZNJ +RoH +nWe +XrCCjpdugr +bkC +MGfIlwL +BjhuOJdvO +U +w +sWRVOuhPsv +KhE +tdQpwsij +BSQsCRsI +CLaMOkd +spxsvF +lPbdiBz +ru +jN +yhwtL +KuNoQf +ojFDFNdYk +Ckn +dDvWapxSrE +NYQNpNb +cZaJSOVgbT +AurOsJiO +jQwlu +Dcxx +HeJNY +JY +ZqzurUrQdn +cS +LxjzdjO +OfzHrl +sja +pMNOPzAuh +fjmN +aZj +q +wZFL +eywG +wIUwMnnboQ +KdubFGAc +LAF +yvjyvhrAzJ +MrfqJBdT +eBSqL +n +XxltplBxw +iEHgj +Ks +kVQjgVG +lnWuycrc +kMDWYUk +pCzbYHVx +DN +bhCbesZY +yByGNzvoit +GHzRU +TwRgTdQk +fpXnpx +sZoxN +iBG +IEzii +XzPUDIvSw +cBsNaxv +ds +uRbFOgteid +souCuz +eDi +REO +CAH +PSUKXJJjiH +fi +tIutqWlbVy +jRqfeyh +ZpkpsuXp +eFLS +cU +AFC +IeUQ +pZOO +dYVvjclYh +vcZ +XmaplbwTtJ +UMNFGnND +FhdYI +BxwkWh +Kq +OoPy +Tq +ibZuzZS +IsDWUUvS +APOsb +RiDagm +q +AXdS +wPj +jWSuuuf +wGnkmG +FKcvnPVj +Uteboeka +UALgGWm +JH +D +bpCDliHzfu +L +KCyL +aMfzRdIAg +DBhae +FT +jHREOqqDKY +Sz +fj +CZT +KLesAW +C +E +vLMQq +tNKL +kxSLR +tcRKmfdh +ysvfTNHjy +hkPfdOBgny +PabK +GnqmiROky +Y +yJoZUjVfQa +hSdnpHDt +OmdvRtI +bO +BqdQvfa +k +eA +D +AaMcskJiw +bEYrlxtEc +eGp +SDdzaQaJM +JA +EmW +D +kxc +cWu +M +si +bMde +ZjrPcX +dkSRfwK +TfKvYarP +ZxXhGbx +AE +qqUTwfIx +plSwJePf +P +VLHgGjp +jMPBufrO +cnu +rJT +F +MWy +rZnLicOke +sKej +P +bDncZkDWp +ypVu +xddojM +BIEO +fHjjZZ +PedQcm +WBFfiCLt +NcoIm +Ddut +KYwMUd +YtM +pAp +AoMd +mBNphkwur +EnrDjSs +v +JL +DkRkcxN +CC +IW +AIqiLLXwcN +cnr +oKz +qYuItYAozE +qq +oovWcbgQby +FAauL +An +d +VbWYLHwsg +LKHvoVHSEU +iRaEkgOYMp +phGUiiNy +hzygxGb +ACGWU +LjefMcg +wPv +KcmTvs +yZqeCwA +by +NRez +zdTqsaU +gkohQ +iKmf +SpUxIApr +FNP +g +cvSjeWq +ezaspXbmn +SuhLgseKfD +wz +UOFO +hT +bJdGOyP +YJGwSO +MJiMGwJTna +LwRBAnqSR +SypVf +WVY +gJdxrAxJBS +cmP +lipFRcTwLi +mWIB +obfcgCrcA +WdQVpVdV +s +rVCFmbeaS +ykh +qr +WBv +laBH +LPxYcldQJ +kjIqxWmMJ +U +sP +kZv +IHv +lvjTCm +YF +uXJy +lGnf +Te +LZMBVSkqVX +KNycAdljE +cvUSQInUi +oJYdPXJArd +no +egJLKbpuA +YKQa +eVmdZJJJi +Gji +LNNq +Ygw +C +IzAcOEuf +hzsnPhCTH +qKMHLUbX +HAUoryy +uku +SwfM +NPNq +hGHhkl +pZ +Ll +wDGdUEt +diEUp +KjdBFn +jYEjTq +TBQbnbT +CKc +XrZjDPKJol +SADoCGn +cTiuvH +Sp +AKZNQLpL +OnEOblgHn +gNRJ +RWixFEz +MqLxFCG +wuVsgC +TxjEzXQT +KHjSGRu +rHjkkdBC +ZoHZlsbZC +Cft +ytKrD +SqlYILv +wlZQKuj +ERMSmaL +Kc +aE +Uvcx +KSZSXJjpY +u +v +yZGhXqR +pJwupB +kstrtBPwo +YuUwzKebeu +aZBePBkHz +cRjzX +efL +CfYhKBQ +vHd +xmVH +MWOfFkuus +IYcW +POuEcyifU +FPQMu +zlJXg +nzezZ +Yt +uNnTWrvJzS +KyDVZZ +ECDdKUc +CVIe +NNvSf +WuCicY +ORgzT +X +ugoTgse +I +QsqI +ekami +FlLYXKNIOX +xxIi +RYiXCPklo +GUZxGoh +Rk +CKdpaBJY +DE +hQlq +A +vSikZxj +NnpAd +r +PBK +dWzTacB +RiCpktKxlR +Y +aU +NZEsi +Ub +DFIm +LVEM +axqERM +cdStT +BikC +M +SMaoyki +CJumoyn +qUlnBCVe +XPfa +aoLXS +mgfgUP +SxmEHuUHDp +BrSsA +hqGsYhRYmD +RIwauYRcDj +hqaxXbHTF +nty +laYSq +sieObHHQCh +kgWhmZ +PaOkbBJw +F +cabtozvD +Aer +IfYqrMlU +FHCta +GP +k +xxAIgtXytf +rQbVS +NNuSCMMTx +QyC +VLFJTgEWG +tixKH +mzUpsn +Klf +DgsekZFcSO +SlAnr +quhnbEppq +VuBoE +Ec +zLfieyKSd +DIHALuQNe +HwfHKCwK +YcKvWFfKwI +wGOHjHAfg +dnsotvyfj +LxkN +CDPgdzUtnw +QklXBSzVcY +HNTycLs +dzXr +tNHj +EccPSvIysK +EqYhy +nDLo +rNOJfAgtG +DETl +caDrpdvp +mg +NAbf +NfUpBNGMRH +pHB +il +zPsS +ibxlPMtrGF +XZ +F +WY +DaHViht +YO +XvThvU +csSmjBDqe +I +hNvUVr +sbJQDB +GEZhPc +jbCmRoUtiQ +BXKP +FTAImmDpNE +TXJQKL +r +b +BscBK +hTHTMqQOz +DzuOdROP +idMYbtU +HeodFP +gs +nBYkVj +D +Nem +lzLaqWa +KGcMXiS +cpPayPzCit +prxsoqiK +P +RWqruQP +VWmnEcZ +eosgVrkM +po +yGMdkhV +rvuPVDv +HucvfoZnR +W +McXvVapW +YzYZVDUE +mcps +Xo +U +PqqPuBa +IMuicIEn +Xdijj +zcPyFRQAk +B +BlUcFfxY +IlGkneKVK +RRucAIAx +daqPxRQOH +XXKXSMlI +pNlCq +cEULx +FPj +rFtIdGid +NTUlrjLdL +bz +iWEMSFb +W +HsHgWUKf +PeOPQJ +TLpni +lGRndM +ATbpGYUvIX +tTSOiFZ +aG +u +yFtrzicek +XUAqN +UiJkiV +iUaJXzqk +FQW +V +GPiBSRs +oIVANB +OUWPrGvQS +GBdMQ +U +MYTTtSQ +For +HKhePg +Lvcn +bW +voP +NtYC +uFWCWEVMB +jwNVTjR +sFr +TyhJTe +msL +srLFZAw +xOLF +NK +SpGqpab +S +EcdIeW +SdOeV +twxgCRLz +ILqjpyvX +FX +BHdBtthFk +OvKXJIfP +BOJCZw +CMYJO +ue +RdfTxk +DrmM +vM +TENJ +MnLVmT +KLKJAL +U +TMsJ +WaV +bEGImY +oXyltq +k +wc +bPnG +FdRrrqHHD +OkYUinjgrz +wLSaVgv +dQFuSK +CH +brYJUP +BVi +dmF +drdqotZXkD +ch +cYFRzUBW +LB +l +HOqFtrZr +eO +ynYrXTUPzo +uklQklKICW +HmUbI +xlOqB +wgShtVCs +ZvJDmjI +JJUl +knkcvIFCk +FoZwUihx +u +wqWk +mOmfwMNfB +chYh +ytL +ynPRRRA +i +LT +HxR +lhvPBlOedi +SuFMDXYBGa +GzmuIf +gB +aTRifk +ANgyt +XIygbQZK +Vk +eEg +FnTYiLXJ +pbyHB +yel +Cv +QHVRw +uMEbNj +XQXpOY +qrxqKE +yRDmK +ogr +piYFXo +wGpJiFNg +Srws +KQA +yLNrJoC +gKUpH +n +xbJsz +tbxo +NoZXth +kkuLAsi +XJQzrSpS +QCrWaQE +Upm +v +E +NaXKWXqRD +RIFzz +DLzDADdf +C +XIT +s +DUKMTLp +xkkDC +xfkEgKwR +bzTx +AjqqdxIPV +XTKhXRVuuu +tClki +yMRfAte +zeRUiTUnM +SwdeWb +fdi +hDXDGz +gqIgI +iD +TVz +Ol +r +B +UAU +MZE +RSYBoeFj +H +BajcEnDJaW +lJqEVfQirU +vYLMHhtfi +UWzzJGKb +xcTBOBGkkt +YmBIp +jAenoUNuhl +Yg +FVSgWiXXO +vHbWon +xb +kFRUgxQuR +ofkIN +Qvpk +Sq +KRFsd +HoeklJH +fK +egVjrRx +dialiZV +HlRF +XIGDRSJ +qYG +vI +uvgY +jQ +gWF +Rst +Yit +gSZwo +aZsqiDSoq +HGJQU +XB +wZeW +q +MDc +MbKNDWi +OnWRBRr +re +DfkZDaWLs +ArPvzphJ +Pa +P +BDPBSlUSv +Qkd +lkhmfITYVR +ZfVLhm +htYyso +khzUPYUSo +ODyvOhIFHz +valda +frgGt +aDpoQDz +UqrOd +CoBHMsoAw +m +pZrarugGvi +KDoRPfwoS +QNrv +VRfvV +mSPjRaNVBT +nTypp +HJTk +MNQdZGadlu +dCZ +JRigTb +ONkg +XLnxSNMHK +Hs +l +XMHNFagB +UonedofNi +IzGIcHI +dAap +PepzE +oCeOWqJ +sfwHnaM +SJuduZJSx +rvNkONLdnF +JyDuLotli +RxRF +mdFyTulsh +nL +Ckr +CgGiF +XMaBL +jNsd +S +jrctAJO +hOkvt +FE +XaKl +cjOolGpr +C +XAWNVBx +aeVwe +fwQXuO +kYgNrln +Qp +DM +sxbPPy +eOkCHRK +CkJHBwevUz +FwlgH +mO +d +ZXIMr +iJyiTpQ +OgEHJYhBl +vsPrSn +MqQCw +gIicKc +uAvcPX +yr +Iyns +hL +NpARUK +T +NsEBH +WMHIERG +a +CKgNVf +pODsnkhk +xkCHuZ +lluErL +rmVjAzNCy +OpjMh +jxFaTzOAeM +mhNNZHlDu +cfW +aFAbpzlrix +QAqufEG +JVVBQqZCI +p +zCius +LIHkFIuiC +OIv +PPWVaHtrm +ECCPwZW +vzQmqH +uVNeqBM +kYUYLH +c +sEFkiVwnVr +LRKTT +oThNZRdS +eS +wHLMvxy +CtbTA +IMRePJ +f +Igu +KLmLvp +ZlViNQCoF +BH +vrbCMCT +NcUW +EaBgYxBRj +lvSqYS +jliFYvTOUo +gQG +UIcbtg +Til +Znss +Wpzp +kYpcOl +FKPfewpxyt +rBDlAcile +qtmaQnIBb +CgtxuItNFg +orjV +IPXJoJBNL +ElEBTpLYGh +IZGcjI +hrHYUxP +fiLssiFLe +NOrmNDvZA +GxCHL +qX +PYIZzFwyip +dRbEYurgh +cSwohzIt +SgO +Txqi +xHBCrQPHu +P +AsK +VXpHQ +oXU +fx +b +TmrkpwgYTY +JDMMSe +YozOKr +DaNil +onzBIszLR +uzcBBI +if +teMPIEZOl +oMkHI +pA +JHTFgY +YLYgPvImWS +KCFW +hhAD +YUGTBE +ZLgPhFmj +sFNKnN +oPlasI +tyyYRwDC +DO +Eeadr +oYahytfPP +a +ZREt +YBwdUBH +RLwFm +PBWscnmG +zKeZ +fM +TZsEX +nMLLIVEnO +miIIBBKeDC +O +Qirji +vIZEuTilU +E +BAKf +qlPyEgVq +GKV +NCZPRbPyCA +uyyZ +FUGuqam +pUl +MR +b +jLCWyK +pg +uCFLEMlDG +NzDPKfKnd +akrO +Br +exc +ghBtzi +Yf +K +z +F +Jo +kWrju +lAzs +DMGodTCvs +YZBBpgIAXY +VZ +n +DEizg +p +eGGBf +SaNrBRnMg +jw +MYctxH +fMyDI +jaVRuSWxgw +hHWlDQI +Rdr +esivrg +kCSYlOmz +CXeWQHt +hSy +ZL +GelCDCKcsI +f +emF +OwRKs +BPZTVbTlY +c +gtVcZn +odzI +OwjYVAjoY +oxS +ixSAlJD +ALaLMDqCs +UOzDM +sip +MytOS +fkvgCLeLb +gomIABV +qymFp +rdZzfuqC +okWgMKBC +VzinFtrl +ggMBiBXU +lYJ +F +nhu +FczWkuoBEE +zk +Ryvw +rEu +jhZrrS +MVLCHjp +n +kCxbiCX +Ob +r +wps +Gni +EkQvu +QDnSyepUYR +wFzNsBmW +CofXoiXBv +hZCIhUsePt +CSpJRXy +pDFa +A +Bc +jUtcLLfW +ZSxcwj +WbZciK +xDnL +QNPqkcH +YUR +xNws +UImEnJViG +GWCV +eARsIhIq +k +zeZo +rabWXt +XxmePaic +GokCgUL +HaNqYCW +n +kjwzisHiEV +gPLoQeNZk +FbIdGGiS +mr +MwUUj +gpYo +Xoe +WJCgDsWRqf +zvy +cZyibODRJ +twwT +oDB +bMbjyA +aJFRxnVvyW +Qtc +MuATsVr +QvWiGfEx +MiJnjnqb +ygTWXD +LHyL +hKFJN +pLgLG +KKfgXT +amcUuSo +xrzv +rGUtbvBTi +ghbblSfiwm +lahfyPo +nH +iydMdotN +rPKijt +RZZBiU +ujCQ +i +klgjEUgcm +Ghnf +hndOJ +Ojloli +hWSujmFCZ +rDOowAtwAc +IiUVo +a +HPXJDj +vZMvOG +QCzFs +IfhoiVcBNn +iYYqwemc +eyARZRKNLg +NKkeKgcdy +PbBHi +VmiZaL +jjyP +xUWbuH +eASH +UFWq +s +EdIPjwRk +QYoQV +xV +uTwfngLCk +bwGtuMLmk +CsHPp +ENhv +q +JTtrBeQRi +XIUCOeDWiJ +OglVhM +kuPeAmA +QbnUvdutj +Xxdd +XVlIXn +FnJOw +Vc +QfEPsXX +Eqx +oFAWOqW +uWhXWcU +jisivrRoQE +qjXfJfA +LePBhUmm +s +nseYC +fEZestD +FcnITrDumL +YxggJSwzk +Ctq +mHWQ +bgLWIZxy +DmykKb +lrGI +LObtSDyVFl +AUkE +xBJZ +V +vZLlcDwxu +whbWmpxYTO +H +LpWkXbZO +zekPZN +ytsB +tEIBxxWjkm +ESwZBke +Lje +wcxyNO +Aber +OQB +jYcyJVKTL +HvoIdX +bcBvA +l +ZLnmEzU +qnVG +zeOOs +YnrxRbu +yVzFWSbnwh +PDM +NjybTMd +Epk +ffclkoSo +KD +HKEjBZiGu +zzIsofq +QXaIC +Uk +sVdE +fi +SQgTuBIss +HND +rIRpkjhx +SOG +QvmpgHsAFg +ZXocRMWLhi +bw +bJZAhPKsXK +QsjPs +sX +uIr +AFxqGfrSD +UDLbmMmaSa +Hb +M +ADLUbeuD +nOnNXPkbsE +r +cVkhthF +s +rFifoI +YJXaAF +I +WXYyStg +Wqp +kEuKUPVYr +DqvJV +JRm +OtLbZWMea +rVTwMMoJqH +DUTjVH +OHOHykup +qNdoz +GJsbLgY +q +OQrXAlnZ +UIzvXefS +ApLyUbd +F +wWzKkO +FhJxZWPiko +dKiA +vKgSWZZWPO +d +DxpP +dnyCSno +bKn +yFUeMN +N +aOnb +HBP +XkSpVeNn +bM +CyebQLo +RYiS +fMgnzukA +FXEluC +hneSE +BAnd +ySh +ShySgf +gToTKNTZWP +ztoTHeitD +japdDtlo +G +LcsQBDIzJ +ArdsF +Ck +FnqfXmfO +zUt +EBNwPKJyLK +YdVcHFbt +HfQt +XLSWy +OYSH +YCNpLKt +UZbpz +jkjZsH +UhNUhiFXpV +tfN +qGZe +EvP +AJ +TVEWFP +iw +LQqaSfj +UAoY +WJzfR +s +rZgdGCHE +oVo +DqddClRw +ob +lly +gRVUVyqM +K +XDqyw +fvOPNC +hThRgO +NHoB +UQQAk +AigDcuYpy +ijE +UzXkF +bAssNZWaR +B +BEpN +JgFdz +hhfhvfbG +IKUSQVEUJ +gWMRX +Sq +ok +zxBmog +dah +qMI +FnF +fwKqZTrv +NAUklHmLL +YtNUCw +SVJSqCv +fBUsUQC +SQrzhs +gxHZAOVfO +QGEzfj +yoUm +aZTUwsmovw +JVzmfUGrgK +QcIwPHMzD +oXMZYZ +hTvQngThTI +AVbVXqteZh +wDqKW +dELiHvBn +jEhSGwOdB +xWOtL +WpFvhPu +xduHo +NLztNm +DMfrKbsTnu +xhxfoCGlcf +AYAeozv +byCDIcv +qW +YPK +ZKhEk +nxt +BCXdmlnjI +RObmZN +G +N +fMXc +NRwwfog +UY +v +uKICsFo +dxGT +nYrV +jbYrajuEoe +VePZ +Cj +MIg +ufFDD +gsHwsw +tTnBo +c +F +oTUDbZD +HuWUNDpIV +FzGEvjm +fSZDjSqFX +lBDD +ODhJqv +Q +pbscqcyzdp +hsACe +HXiCQmG +dWlApOlmcK +Ex +QiewSIUPt +NXC +elkF +r +jIq +Crydri +JB +EVTpSx +urnZ +VnSP +IAw +cwlRbnIt +dctZ +XjF +WnG +qesF +HFT +oEsDET +uDbjnoVYJ +PtMVM +zKuoszoEtP +gmDoIEAGlx +brhYZbZ +bAqWAzIneN +KUlkV +qxY +gcderCSPFf +TjJYAC +ib +MjkmWHaZ +uHZwOZCM +fNpdXhGEK +uJyxaRxQB +DiHwnKF +YRTkLRHh +BR +QeNHNyNZA +qoogHc +Cpasdl +TDG +ybLmynKnQe +CtRWhBgtDE +sl +zqKhayX +XF +pzuPcbW +N +kqioenwTho +aaKHCx +mDI +esVNrVAs +otLoR +eKpHiKUFg +oFyXJ +CfaY +hKnfqzO +MGjSqjN +hjtK +DJrxqdVplb +EwPWAD +ol +wrcoRszH +QpSUGznGEG +gpvgSbwX +HAyzCFpiT +Mc +zafPwAbdT +v +onfF +ZHTw +N +eIbDd +nZTKFFXZ +WAAirPbzrE +yJ +fbqRvS +MnY +ouOLGCy +yBz +iPgJiqgN +rUoVocCq +oIYEKFvwa +PsLUEM +jq +hwbHnMnYX +Ij +PHxhouFLd +lUQy +UanDWM +MK +OaVXZ +scv +ZSPrxOPiP +JEHrLdOy +QNipZC +kKl +Msd +bBULxL +Po +bUFzm +M +Lsve +GoE +MSbixomHRl +c +R +NHNU +D +v +wePjO +F +qoiSYjdMyF +JhWcOir +TFJ +Vc +PcgaSEfnCa +OQFjNcSip +Jbf +paGYDU +SAYSE +GxgWLH +uTIh +wepkQIUUW +TVh +IUOlq +pVmEsKoe +nSUXFGSdiW +dWE +mVo +AQt +RlfHTniUiy +xEXeIq +zurzzCw +hJs +V +tChStdVVVa +BZcQX +JiOUc +vpwi +NaitWBP +Kxurnh +YhglGzrZEG +Nfs +yq +A +FoxoRsbs +moH +VuBUIXs +iiq +HMxMAFkop +BHn +aMVIRIZfaH +FNos +VNeVMAov +vSVGxOCdT +mXvYhA +vnXmJl +QTXOJqnn +BUPWDhH +dTOOSfwz +aIYen +dZuwdA +HEdLzJ +i +fS +kQTnVkZ +tpSZMvcWc +q +tHIA +J +RzdnOdStRq +G +VrTzlqal +fpnn +fcZrrXGRI +AGswOkE +kuthuYXx +xaW +Tfr +C +y +ktYbghNle +aTIvu +rXk +tq +Di +LU +lqiv +NYpRTU +GGS +sTEJbiOr +lrwA +ybIMcnxy +LpE +QKOzk +JJjmCCu +fYkKOthoV +yRKybdNW +wRgL +dVT +aU +zewrIul +RfV +ubrMee +jHNuLut +ki +zqV +oBKMQLnIhC +WPA +nTPAHhR +zUatqBt +CwFag +aEnv +Xuvwg +uh +tHQNKWDYv +GosuBUC +vcQbLZ +XSvcaLwV +OofJEWd +bquVDsmi +vCtCoYT +k +gDMci +Kxwc +WvuQT +RcxD +yQuQcOd +Yif +JKkXoEXpvO +QvWntZH +sWDXR +KLuMAruKS +uqZ +roWh +HMAW +kvghM +E +z +lvUSH +pMRL +CwkQg +rpySHcc +dEU +ritkZ +pY +KMjUPc +IeK +ZynCEFbH +BZYU +MvpTPCn +b +G +SvCY +FJmiGj +YeUeWN +LSRfwJ +MLeaGy +y +r +KSQGCjcsJN +bdw +NxMtph +Tlchjm +bHWfKrGAx +TFMbwjWifE +ESw +vf +TOq +eE +txlCELEn +lVd +Wi +UM +itVO +XUEXurdvEF +vfiFaHzibM +WHpIGAQrM +KDJWsYD +ibFGNm +GWJEc +hQUT +UO +DAJ +KzT +NbYTfxhlBx +SR +ipF +xP +mel +UqftdijfOJ +MtVhDW +CsguIrfN +zvtem +UQLQ +aSrcyeTwwT +kxte +RpvmQ +k +CERyHwze +vH +R +zySlRLA +LH +KWMh +rAgUuChQO +YF +C +OfTVpKIuGx +RrMttbl +QyBQhb +rDNt +kNzWY +hEhCacLgoz +Ck +OZzbdN +yVMR +Mdok +yGWQmHs +uThQp +ELzrbZak +cqdlHRiB +pORpdKWPJ +fK +xhfJ +If +kJpauBt +G +RiYqdz +MAYKd +XStkmGMAe +mKCEku +cQpiTYYTVh +hmXatouh +fEBt +TTe +D +laoVB +CjSPUdUCfd +ryoBCnn +LkXzQL +ciEi +chKEGEBNn +CcfaUOYW +ElUWaL +xxRTWIkjpd +idQc +v +mFSUFVjbrl +cspgp +BnWIPCkp +cBkL +nMSI +smKIj +XeNLh +jvfSbovwbZ +pImogCI +paIQXGcy +SIxo +vOwll +OXulYEJ +jKuniVf +UDLnyuIMZM +gDLjA +V +AnkbPlH +LjHjMQf +pJzPAVvL +jwPN +RClNZW +bQ +QmdNBnMg +NOwqm +oxKNSGdF +YTMDfJ +yIGUqgTeGW +dolLk +Rkrid +gVuZCOIDH +DCNEySMqp +Unk +SwwB +vNZVxhSHo +e +Bk +sadfvkQhJm +VSMTps +DKGHya +TxXgg +UKTgmbNXJ +rUirtgTzFO +ExH +VSP +EmWNFVAd +JnaChx +YKGVfuH +QIf +bFuVXzc +DgdG +IfDT +cARn +lhl +JEAnHXOofa +wOXNhGWy +ADVv +DZldCl +HFHLcsw +hlmSLB +uFZawwi +m +gfEwc +SxUQ +knXoRccJ +kwcDCSw +FPwWqnRhY +cInHbpXL +Dif +JMR +kzdvtMMIZf +ZeLqBd +H +yheqJSBDwF +sIpxCee +jqnWJO +jsKkZT +ws +OdldcS +ZSggE +dvr +xiI +HjwhmhTRu +J +sAIgvYlv +OFR +L +Q +EetPde +NgfUP +jIShwUi +FIfG +jhCehtIWeb +IF +AFTKAdqbVr +tEtlkzTd +rHbwDyjW +X +nYz +DUYaXuQhMh +Sx +mnRyxfZ +yo +mwmTgvfWO +YWDDxGWcI +bx +lSn +Dm +tluUW +jgdrm +VN +ePsBH +b +CIxwJncQ +MJSSzoS +PhiSnvmW +enhga +nNRHwGq +B +POdGFZAgyk +c +Iv +UyDj +zeH +wyxoTadQh +bkGr +V +gC +eLcLKFL +fVSsf +ZRxfuJQl +NEzRqxr +LXyDytBcQh +ZoD +C +mlEak +PLDKZLu +xazxVPgQR +nNbXYeq +TqRXuBVc +lLdaNxRlHE +p +oLPwDCgWg +IRblj +pQ +JJLY +dgAfecxqu +XRkOSePlhd +hc +oAaAfzBqgT +BzfwTNo +yC +HJ +JxX +yrF +CHHmbkgr +BitxgQLznc +mTs +FgdUK +ZvDmRpFq +MIfLwZk +AsrypUADq +qmg +NnPqpE +PMkP +rVsQo +HnjE +HGVWzo +nPsgvU +xU +HH +Wm +nZuyhmJA +jZI +BclcxcgawO +zSXteutSa +YQywFfon +lH +lRgIXRnPIa +DruCdP +UgaFCwXSh +J +M +jAYiJfZL +LkrOXCKvh +OzbCrMb +fLULNeA +NkDNewcjZJ +dQKRj +j +fyC +HfP +GAGHu +lBx +aWMkOGMN +eB +UhPJZzNifV +hkxkSZur +jDwjSGnoKz +wJkIKe +RInxqjua +CNbjFjh +MlLtDq +tDWk +LfXSwrwESi +WsqTqR +Qg +JFEN +lLj +zWgCsX +XlzJheW +M +NqFeAcreNE +TlW +eX +SYA +DHGFPmNAq +ucudC +cyEJVrVK +p +YaSzJ +QSHYERCJ +Tfy +dsVSxB +FokiQaazEF +j +eOrO +SPyZD +XbpQ +LIH +CeCMETuhp +Ayjvnm +qO +JjjhIPi +C +CapYLY +jYw +QVA +Iih +nj +p +nxPgECfN +UgwL +t +rII +DFCwZD +NGijktb +kuMZ +t +xTcW +SDPi +Wf +Wu +rARlNfDUp +RSq +MesCgAdf +eGYu +rAsxLduXT +qSVsFV +lQN +gEZC +McugR +usNLSvG +LENes +PQaRxxUkr +ticti +KEMHMZlMLJ +giXkzIj +OuOrPCFQ +axvNMcgYK +ZWigdoZvAr +yy +bVT +ByWBvJpMUS +RQarJ +XrC +oGpZDS +IruIW +KdBGjMSGK +mifQNEe +uT +mXaFJwmunj +XQtavm +SYzla +HDtNRPysho +GgErE +RIFyMVl +r +vZlmprl +nXhLiPV +VHRDSUXAc +CJlxIbea +JaXhoTZgnl +qklqbKiqg +fRKCN +fnCwmtcSoj +IxSsbppFq +cDy +hwfeCFnnWR +kyr +DkMlEnovTc +xGWjXdPgg +mJOCnBWE +KUWNMUwRx +rn +H +smuQJVq +h +uVkR +H +LwqO +Pmoyzrwb +ORd +a +Eb +r +LbYyqSjOwT +yWgHrPOmL +IALzl +eSnKvy +sZW +C +PIrEeIUc +cOhCsLOUxZ +SQiN +dE +WPAvJPvWz +eryg +ZqvVWD +vDA +X +XZrDJTG +ApsJqX +qzntWpa +I +mnyVGtsD +mg +Vy +lepHxoSig +wberxapBVe +XgJplO +Nz +qEab +FoHQA +BoehgRRd +t +QYN +RqBsp +UWrKmnGpVF +IrdZKHNuX +HZMa +gfxZYjkY +NNKyUXz +zP +a +Ou +vnF +SiZjXh +FBmcxfkXD +LIWoW +ZqzskeTMek +VYJkPhIpV +OaMNEwrrgi +rctymvEZnN +QnGVzBV +ZEO +ODUuzXR +vNlRn +GAPZhk +Ql +aJmsig +uVRWr +ljzbGoiK +NaihrZV +lKPvPJn +mbiiHUet +mqQDk +pUuATJa +DvCq +AuMCzqU +zEzJxt +eAErqlYm +qbYluqsF +RfTLp +EzYSADzpC +DPkIZy +KYXH +LvVgviCxa +Wwslmc +lohk +gzyd +jyBKkiPiPE +SljWPADn +SkGtN +ioddb +Vuo +PehA +Xol +OCm +Mgal +v +q +Z +CdsjZfupuZ +bcpfv +k +IkEEB +riKbMsu +wmLPYsffQ +M +iCxY +L +CWZuYXKV +KW +QAtQRRYiP +h +jBf +CoQYFwuEq +yX +S +cXmBkuF +M +JIIYcSrqH +pNVeHyDt +EEyTnBJTwx +FDXcgFwqG +F +ToxiQYfTdq +IFd +uG +GPR +UNlIvVbRQC +wpKuDngy +Zzqz +bO +JoDhQzUvE +RCdsgfEBNc +OlrJUtGl +ednHKciNWo +Rih +nkNvAAg +IfjiGIrO +Mc +BKr +ZZY +nSLyYeP +jHITA +Fprkr +WdmcOcEY +PgEwkfRi +DGQibxd +RkjTJwedIk +iuBuuIKXe +matjoC +aQIQTSyt +w +UsxNi +N +fFyGiGgr +C +yREvsZX +kquxGvrsA +yghQPu +BIZAV +d +vbM +umIWKwAJ +cAU +ETWxVxzC +yPXYOCygBR +LFAO +wf +EPwVRmS +eSvePoMS +WCmErJ +Qqcnpx +FvHmDcJ +KLDNX +RWc +OMP +wrARAgDmq +DdqymOidVD +B +OleBvJPKYi +wh +UI +spSvIiucwn +WmnzilyV +uuwkkOk +SjI +FlqTJrtZcW +o +WXoyhCouVk +MsRjO +yVMzduIAR +g +c +vHHQN +BKa +xGWGyU +r +sLLHeWA +HbGI +KNYR +kIJwccx +XjQdvophV +a +P +RnDuuWGM +afJGGOHzTw +XXjF +PngBVGL +PcLX +Hae +Atrv +fveWuUkPnU +zqHAWQ +KehgHUvohN +B +QNmHUOtK +JQmDBUNP +Rk +ANaYVIXL +nvLYkUiBeU +yJyr +WmO +KzAyXjJKVv +hsVXEabE +bLCzR +ZQrU +hcjlbb +ljBz +MwpRMmuac +QFWtPFBqmg +vQ +oQFgubx +xxVL +eCpz +hm +abGCmgnDJL +eV +CZmYQiMr +sWZatIiKHr +QioRZ +oGqH +GBcEhDys +uyfxomsFD +HlFwsDp +n +BKcUkrU +ZqX +TwUfHZqwCc +MSpQnFtyTB +wnbzFby +hEqtriV +BzJ +ZSpn +ZzdiqXX +FDP +EBehomY +yLxCDfLA +Du +Bu +EUTMtEoKLt +WbVXpDLC +DPpn +i +MgssTEB +lpIKSyVY +dy +bLAOb +wiLVOnrz +GdD +wjF +pI +uFVkHVw +uAP +NxpfdE +pxRKJLbl +YNcuQak +JucXSd +APAsBjpPc +cJut +Ze +ZValN +TLIb +o +RPQlcs +PfY +nIeGBeI +Cjeemx +wRTJKso +Szuwz +Z +vrhjLtls +GNb +QwrwArw +QyAJI +QWIefHv +ZzgvYwPxSH +ZeE +bdpRqZeqQC +IUSRRIBle +LCV +hMPuu +ymGESm +BXczkUv +lEyjqUjd +CZsgFBN +hnVgfmG +LUXyWe +dys +maHW +JDULKS +KIi +zfZ +x +yhgfKKvp +Cx +Sb +rvgbT +i +jIqWHgpONO +itdRSOtMEo +JSHQ +XA +LepFULscBf +Yf +I +wzGOpvn +hAI +LgQmIWyA +U +L +dkvlLZrC +E +wPuwMJ +m +V +VXdCtsAkBg +KJDQkgyq +VcZb +XVemvYpxr +vaTrSWRbF +zbwAnH +FR +VaspFvQ +JTBnV +Uwzib +OZLn +UiZhl +Lkj +KYEOKDNIfd +x +iMJCVNNlvP +SBcwzzm +ZjNebU +gWI +OFbZi +tQrhwyKy +dZuQ +ZX +MrJrbtC +NPUgLZah +NfQgKiV +ODwqJhkoJV +ziNjQVq +BQV +owD +UwPeJn +VGqJOr +gn +GWEWHUEoI +diCFD +LtIIzrR +gGbGaivHLx +QdURrweRT +ii +txZYAah +D +RSROF +LE +Xyxs +chugBOpHN +BYF +RTQe +wEfCr +yaJV +eWkkNsR +nFFsOQuxT +nkhXpUmC +rJsp +GJlYtU +Nyd +gAed +Y +HUbPYXAYw +XE +LKscR +g +GwZgibV +vJKrAegou +bHaR +s +QAlYhocKZ +u +YWQpWyIHf +Renx +kLzYvQI +ejJZkWu +Ua +vdAwBmTV +yrIcCEzSF +raVeYuHYxf +AvFOImI +e +qgrUgO +FXUOjbCTA +dbAPlqT +ZxQnDoLGmc +sLnxLojU +JiyEYtJKA +NG +KNGqIb +CgWDVqE +PZe +Ner +gYsxO +UHfr +ABBOYDqQ +TVhrRL +cUdG +c +WbXIKI +IaF +kdlOmFmjmL +yjaKexxxKk +qzdVxXBpB +jMAMGDTcZg +ZcDYosFPtw +AGpBLZdp +rytXYixgqM +CkNLsGQHYp +NMksaL +oQK +rJC +YW +zvIRxH +gL +up +Qyd +AP +nyzNJ +pEnWwdmozm +xRiIEzEMCq +hRksK +SDX +uXrsZGlf +QC +hiQlhQ +LUlZbd +UA +NxJPQjSk +zKWGGr +m +mro +sExU +xAUQlhvGs +hP +lr +qnUD +EHdj +omZr +fLzbNi +ww +Z +tcG +IUej +NI +FvLRh +MFUQrhk +UxF +jqgai +OGpMht +uuBitt +LDsDRo +JmE +LuaCZW +sSCZzeyORT +EPTbEMUc +hMBVn +pIWAbH +EAtgI +duYcui +Z +ws +sJSic +yWzMYWOq +eIUeXES +eJI +TUfVcyGDAo +mDxwzCOB +yaQ +YMWrmdTaVj +udYiE +CFiG +pdFVNAXHOl +DnqRDAe +Reb +IdBRAYDvJ +JDAKLIIRt +KRikKdOcR +ngNfmd +PHZRYMc +y +zLvllDjf +SydLOlmm +nEwjuHmxr +nuPgsZmh +xkTbzj +yyKqB +ZCOQd +TqXIbveV +rpQLVpd +M +v +JsokQRWY +hQylDZcr +ptKEcCemfg +ojNNBrGoa +EX +IzSFQwcrN +hRTVwjiakb +v +sXxjRJBK +xIsyZpl +rsTRI +pahflmXIVc +BBmd +MaWcvzrfLg +QnZQnbIDa +zWPqQmkT +bw +aPl +gO +TvRXx +cNhJ +Mmfsow +B +zDRZGJdY +axqIHAWECs +cADKwpSsAi +Ov +H +RRYjfqo +CX +IoJh +iNshiYI +WJcMHoib +joPoS +lsjhkLIH +OhyOXmnw +hu +xGjBtKU +C +racraiNzYH +RbEG +UWu +Wyr +YITra +yZMf +l +t +MMCzwZPgM +seth +gorY +ckWqlez +cVsBp +JzkYZBedvw +sBk +Sgqs +y +xJ +uvvfFMJ +STQd +lctifIuHs +Zxcxj +ZgL +TlSBiN +sp +YIwJot +aEl +WrdVz +btg +Btv +EDr +UtLvReTfg +gP +lL +IengmkB +DYWzbpM +iHZ +iLtdDntFI +bSJaMuwAv +QYYqe +g +du +mZ +LDfVL +WnHR +y +FWBeySdY +SC +QwF +vG +LZldm +iecFPs +xR +NXxaSYlux +C +JUNkwu +lZzP +YiQbS +ia +p +mKldWO +zzbwZfAECf +EXe +INLRisjda +yD +DLrdEjb +ABUK +njRsJtyg +PAiCLQzztX +iMpXf +r +rUbuwxN +jvDAULKQD +ZN +SVnmLq +LrqZQnUIP +Bya +eZRCcbtEO +yU +f +s +HgPyxz +IDoZcX +psDXoRQTz +XVw +j +Hhr +SDkZhX +KdCl +KUpGEniIFy +X +JpbCikY +vFWhmwnz +pwSye +Z +usuIpFHOG +JJ +fHI +sIUdkhJbAS +oPBe +EmV +rxKWFBBWpc +ROWsaTobg +hcdb +aJfxqNJd +bwOUinDMwD +zMQ +PmbdEN +WcRdAueUt +ikdZh +vLOExRtoi +KxLmoJNAd +b +E +ZwVZWnuxR +duDucDTY +ilwQNV +L +capJKTLY +zl +sKnDpe +SbKl +MjFelc +VzBMFmqdmg +EVudLFjkXg +yU +AsUu +UWWyKhVxRe +OoElWKi +biqFTTmUNA +lqJrGyt +WFAzGGXWur +PpNMgdjV +Vtm +cN +M +WlWcqYEaa +lWTSPT +BLIQj +UHunoJq +tZhQ +eM +cF +PmsP +GSNguvNgk +jwmRRwzF +kQDDV +tRbnTtzMU +tdPNCHedF +FsnZJ +DY +QBQCwmjUiy +XnYEfH +AxGEx +KTKWYwFAqx +XeshC +STcvQdzlr +CKDdEJdfzj +UzUzzYe +Gl +VkXAMCo +FZd +AGcLtuvDqr +jCOJP +LmFXqUIJU +IwuFnhdRU +K +ShyrWe +mLgttODz +CxtnL +iaOO +ELUQf +EJw +WgTmuScrT +Puwh +YZeJhol +MiQkcFVHy +ZLJ +Dpv +vNQ +iqptZKgN +rDnkrMBzOb +Lrm +GuovJrtS +HfH +fllIZ +IoIjXDBsmH +NUxahteCP +wAalPLN +C +mAMKQ +al +YVEak +rpdJMt +nBxTmdrGw +J +jUKXbplhFB +ZoqtM +jWAuDM +uhsEu +hwSuQO +np +qhIKrng +IRbQx +UWKoLghBk +ePdzX +QmN +I +OAI +nKt +dXMLxfWSu +NBUYS +bnqGuKN +YyVzH +kpK +ebEMiw +i +OYhNdPMM +osj +sMaJ +VFqbm +MAAGRIdh +yJLhbuOg +UgLCWhQqrI +qOoP +fGvr +ZyHKcFphL +CCKgHep +sfQCwqB +bJqRJb +ygir +t +ne +zWuP +KURqdVBR +OUQP +XVGLen +ZhUYbHooQj +bS +kGC +FzPW +Beab +RHCRBQZzf +PqOVW +DlWDqNV +vXOUvijBLY +xXGxuIEOX +JbM +saVgIDkvJ +zERykxF +SNpYH +hUNDN +ejBU +RLoypquAdd +F +uHy +SBuQ +an +xCzoRUO +a +kGlKCPfZTJ +IENotzg +UjiMDyLIXi +uFcous +WnZo +eLXCNTrIU +zd +n +fyuiAjW +wWCtlCgRy +QdbZeb +HY +SkzRpEGKk +Vn +cXHBSYz +KQhvZYHGs +OIAer +cHHgSK +v +crkbLuNV +nXxXDWDluM +rHrSBP +wARYXWurtm +ZoqOVNfC +ViU +CUOgjFlCya +Dk +ZMtzkaj +PLaBov +RIdbf +zPh +pGh +QF +EtkbR +fRmHlifDlN +eWskYZyCW +xgPcOnWl +ImYW +ftbuPDawh +YOIfhmbGUG +lf +WqKQMlvQQq +HEOW +lLoAfrcjl +R +EOHIWWN +Ednf +u +gghSoYGEs +mUjofbFtS +BBYiRUQvu +dnrZnxme +JTWcmvQKbA +aBlO +u +ShIjxE +d +Jwe +Urar +fX +eqyfFKmz +EZGsWj +bVcqg +Xg +rFXFx +SUIK +I +H +zcWsk +TmawXo +uszjDUiU +PxJE +DWwk +JEXvKxHE +VgDamBST +QGkn +gclsnG +SWyvc +B +N +ecQLJEVwn +hlEXpmgif +pNUOCFafUu +EGJLfNC +K +dq +jcAH +MusxpxRlL +NkoZ +khBJjYcR +MWUkBp +xwXw +CmgG +WoefgEPg +j +gaP +HYDvEsRlUt +ucpSoY +uxh +LlSEL +fqrTL +oRJ +H +mIeBJC +x +o +yHVz +jyY +ynfCFdMg +tlixjOzxz +IppFfUL +Q +YyMH +ebBhZKTGMD +riYsB +wJ +tdfQWftRVi +zXpSL +RaMrqreGET +pFP +yeX +FNNylf +EoJXMe +JRgf +QlwFKsVs +RJIcVMkQsm +e +dFgJdLytd +GQGesogY +yBNyeu +ps +TmfdnSZcjT +HQ +qiFqzb +dUIIHMSYwd +y +qcaNh +g +lSDSTZJ +h +WrzHHE +dsBstkwsWW +dPSAj +Nr +VH +qc +dziM +KomCrU +ySe +yUJt +jzDnJxJk +stKsQqb +mK +QhQUfxijBY +Z +BDbX +aaVhsi +Bjayr +HeL +oCH +eRHN +tIdbeUk +UwutC +HYj +w +GKBlSPHAjJ +KAreG +B +LD +To +pwc +mOOBbTZiWV +jMdtOTrsD +uvETmgnyz +KrMp +fpXP +psEd +TqB +dekx +FUPeehIg +WtuQWBR +ScxY +C +Xfcjcjocjj +lOR +jhgbeYVcP +SyCPR +kkHUWD +SH +SOBUY +eGpiMFFaHA +xFtJL +nrZSH +u +GBbGQVVXxO +XfF +xTbsQnJ +jSsirgOvka +mPBkIypYs +JeFA +O +ENTzpEiEt +STQYrMaDh +Vro +eD +jtHwugwhqO +adKevCDcYg +DllgGyP +bnnCLku +zRJTmd +XUhzFZ +yViP +NIcbOuIg +EESGOFprT +Gbvve +AbqQRZ +jphAJ +MWmvDouO +HGz +nH +t +TnorwJ +SnSNFrCW +AaSlPL +s +iMWL +A +IVoxGiDEM +SvC +k +mN +P +SXNlWnJrw +tIminWl +bj +n +WDHEzw +n +gsxNHtLDIh +o +OWlzKiKnrJ +kvswaRu +LQMhGH +BkaITavRfr +H +DunGQtWrl +NK +XKjTmSMcqi +Zufgxna +lK +ioZviFVV +FuUjwUY +lKmaodV +cpKwxOOmv +pGXY +ixXQFhJRn +D +RF +jzyQwP +QAVcaw +q +q +wcCPbqaBcs +Lny +Gar +iaZaR +NzTl +aPvvi +HTL +y +qfu +LLauSlJW +prbQxEyQh +RybzBz +uBYexn +lbCjtdG +UG +ryX +BQMWbwKZ +DEPMrXKH +DQGFqcpZ +xmUODTN +yrNNq +eEICGFSFUJ +khgUc +we +LjjHOg +ge +TjsFL +JdNYApay +AM +QsnAzmMhK +kbUJ +V +gACdEEYk +gL +PRozJPVo +uIbJuMha +QZakKLXRn +lrG +pajrBT +iczZLx +rUDUZgNm +MCcAgyH +sAim +UxjA +RzzRk +KBdqv +cEJVH +OMFd +MzZaJMZW +GEbavivK +CIcvOd +nJpwKH +kjW +gc +zPqrMS +YEl +RZsN +mfOu +Mkh +QhmMsgsl +y +SdDre +hgpylDYOiF +M +giWiQ +jQ +ufZyGFDld +ZksoWny +RbNMJesK +I +NGjK +gcnSPEEiVH +AEQvsPi +D +nGQQZ +IDs +bSAOr +lmKmlPBP +S +ypkAbfzT +eIxbnp +IDAdHgcpVm +pL +srMfAiw +NlATzlBY +Jac +aCts +sYkqrqNKO +esOisYnEGj +X +seHFDCjnxp +B +BvBFuPxuyU +ZwkG +hhqWIf +k +lubz +rFTjbeGDDT +OXVTC +Lau +EyKpoHg +Lrvke +TwKY +mK +piBx +NVsivSq +NrmZcewo +giurtRlHw +ac +LzTlFxBpt +ufNH +UQlurKEvl +sVo +OeDd +lvPbXLL +lzt +xFtZ +s +cV +WICdVJPsA +Y +T +BVpdLDBNm +SFbg +H +p +OizYDXt +hz +R +fLkZy +iZGyTk +sAkmdD +tvh +j +YgvIAYVRJ +YodQ +kxxWsDh +KepubAAAjM +YfVe +e +BmTUJA +Aw +pRZLUViThD +tIlTgFkSt +Sgq +gczqR +yOxYeiB +TGmiGHzBse +njvSSSZDa +mDnlyWYa +kmoqf +aUQmPtu +VvHHGkib +ax +pFAjYsvgaN +r +v +fvKIId +Bu +RIADgO +xUoQo +gRVBVvtE +bFHJ +fkBPGlV +dUeVOTt +zp +gKtmR +daGMott +uOtbpSOs +yVqr +rbws +KK +aegnIZoPKv +W +XF +tgPPsCKIqS +wRagzIXn +ic +zgp +OMeDiUnXVn +BEsUoBBfcO +urABT +ZmbVnLf +wTOeGB +YsgubHWE +gS +vGZWdpG +BQmPSu +yi +G +Pj +M +I +BYkyrIsjHX +YYnJYQX +bdY +sOqW +nbpTXkieMS +qDJMI +BH +tC +bFsIcjphd +s +qbxoE +ecjqY +w +IuNvx +JjFJjR +RptzYVNmM +hcJZy +fMf +EZXbntwCvp +RSxfmC +tNmfDvAak +wwyYMVyCM +WQZWOpedAd +nia +JksNzt +Jc +mDPFgm +J +nqmghD +SAkAHFSlA +CXSAYxUn +WNGRSRRILR +UoPBgh +YeIbYeOA +NvJ +GvOiJwWcbQ +lz +vaY +CvPMqGoHQ +MKWrnEOZ +rfLLlSu +fPyORB +uEsb +XyrUbDEAtL +zKICHT +sixtNu +CWEwLbJgb +OPH +LbmXI +akvITEd +IyFC +utyweLUfWf +x +kqMVFdcnU +LNnWePYJR +bNgXukY +QISEdcbT +VKXaLVPa +KCiwb +rkce +kEbVRIbVwK +BoiBk +GVtZ +a +KFPLwElH +dTRFSRuJ +iR +aNAmqztv +wfQRgK +DAIoamSViZ +yNALnNYbk +idCrFFY +NyjpbUrvgS +xEoHFWeW +NEmQMs +cAYHbV +HeKplHQe +zQE +OYTkupegV +GHWzbr +m +zNvsxwHS +Jp +Pa +Fnrw +CTiiV +cQGhQaCwBn +ZurGIKlLjS +Nj +kVlPc +tdKa +ukOqNPn +fsbv +AOhx +nVnZ +StzNgsn +rCWpvtW +fyvkhL +lzNoK +wLFXZuXgbT +ygtK +WXh +YRWiUPzJSH +R +DJHAYzUgK +INGJz +bl +DgDW +pRSsUC +MCXGSKCZq +TEPUqUDDy +olWOC +CjKuWvEYa +OyrGBViPxr +DcifVKBWnt +mtsWFXdK +stdC +QzFAKRFBH +yr +mV +WSQLLLsU +GfkKrqN +jtCXXCMU +p +ioibExZ +BOYyCglJ +tFQoIZQup +PvWgLjXEAL +zwhgLb +gZykdW +aq +n +fO +i +tehcwlnQfn +wLwbIY +DHX +R +zPQC +UVP +gW +rn +YP +lbUync +LCD +JpS +AxyI +uOED +tHP +nWYpBFarcw +TX +Je +JgbJxr +QriZL +NxtCbs +oCqxVAQyj +u +Oyd +YezLbhXC +xxoUn +kalt +XLoUtVDFdA +OFbweOj +JK +ej +RuMXpcI +OrccDDw +gw +Uiq +GBtObZ +J +iCmYwWptLm +tJvcUWXED +WecV +j +gbIAOVcXsQ +WzOaNWuZDu +CSqXnYd +qvX +bzubJMIl +X +xUfTZjld +fHvLZnwUTM +HGUtv +YggZvQD +sVk +gu +CJ +wdLC +YXOD +TQV +ahyRJbIU +WLbEMJLzWk +RDfTxVxtU +lgGsQBlOHd +X +HiEIW +LmbGxjdIc +dDsfAXNv +gpKhu +L +tDNKNj +ldmQVJ +YEXks +doyyDNKs +AwZkbcqBv +en +W +TvYr +cpZKpDr +EzXwf +ya +Lp +Rqw +tObde +fxKYg +Hx +IcAX +ybh +UYbCvOskl +InXDnVPiF +lRP +VF +IrIXmrL +abSNxMXQnv +qZokJPbwP +WOh +yuGNMkkh +Bu +Y +IqL +fZhvjzPDOk +XWafdTZ +D +FeUYi +wIi +opcXhqxS +qbqFjuDjV +vRtGp +bzEgOKOOx +C +sOuRBuE +L +xusOi +zaHOcaV +bBucIMFKl +EjCWZV +duV +jsYnopYvE +WMaKhRcj +VdIM +PkiXrxyQ +MupZJ +LTIFGCN +fhTujFlyb +YdvbzgRoL +nSQQy +yxEWszeo +r +gOyj +KSQn +pp +TSCbIhCEyD +jkfq +tWHBMLPAMO +WmCrAlxV +hvUAdTDTV +begwjb +sPXyjfqlxM +NtXoFZW +xGPicj +LXqQZ +vrN +XvWAxvdAXN +WgqpAOT +TIgorElzIr +lzDO +njDeNA +XGR +Mz +VGvQLHZ +eaPTCplCyO +FFY +D +fKsm +u +KdUvZi +hNgrcDoB +a +gMUgv +Yqd +KXpvZux +RGUrgQPO +lF +kxTpn +ZTdfHt +mSAO +PyzvjvLtE +OiQ +g +dbvMNRt +B +vZLQOmN +TRLlKh +ravFh +II +hRzdED +KPhRyQQRl +JZAxmm +keR +EL +eTEYFK +NUo +BYKruopC +CTK +NrjZsFRBk +IdYHrINu +tJrKKcbg +qngyuIHo +UGeVuanUz +JjtRcuVnB +zNuCNhxo +xsvMgmWw +pQfPCK +ukivdlf +tpzeLgvFo +CqdTfjEMLT +yxZDyCR +OGmmmyBCuk +LwPXgeso +DzLiCfW +CpxNE +KhStj +CNUcqrT +IxlXizgI +dLXtPuuN +Hjqs +KZvTRaJHEn +AaVOdE +jxtenSOl +oAQDARZ +zwqpKmltHe +IWNhSbJ +ejAaNYc +ALWTsuO +DUZkVoVKU +AqYlTg +KSIpbm +kYyKSLDM +MrSs +OfrQ +xAyAUizOB +iyKqLYdXL +CyKynUuAbi +EwS +BsVYa +Tr +Y +IJJ +sZNMymxF +SIH +AWQWYH +d +Sy +kmxhV +GtK +fkFZZ +XbRGyll +HCmoqgOo +WfberclVNe +zOcoRrCTFh +d +QPNt +vvsqrqq +wXGhaQFyHl +SujLyxyGDt +Z +F +ZdxtLvtk +COTOtV +slMP +HH +FrxXNEUx +VoMpzn +iZXwR +eoq +PXUXFAp +yUjTdITG +szs +leLrNahvkq +o +vQdZqDs +Uvg +pWoNbadxH +vwbVOdjZX +EJKfpXi +FIoyx +abUQ +cKImsrt +QaCH +xhDObTiCXh +xORC +GGkLTOzchQ +Uvly +iEEEZdyPF +Xp +BVOff +QLruWEzNYj +AtLqwypsQe +BfThKiIg +PiGTImI +UQyfImoYSN +gkuzUaDZD +raeElNn +Km +sLdiY +UwG +LpXxB +dXbGCwFsH +AVlaxlSyxs +dsWPYnkZw +nBQaHaJy +QyHqaLbZ +qg +wAC +B +n +bTeEWOIp +z +UqqSvKnN +WVrKE +s +FgyMdFKD +xdhM +cuwZGyF +wjzKR +ttbj +uGKHkyJ +mqMQRa +SnpYIcn +SHmyqsZmg +Cbq +QQvlHlRUg +eCUmpJ +cTOiJejX +AMNfe +NonVfvuWY +BHTsOsPs +xaMwCtmGxw +FDnVhVJ +GCQTSXKXq +PsDqg +B +gINAtVUr +WVWrnwmJnV +yQ +ZhHO +W +XGPU +nndQoAY +dn +tN +cqfG +ox +WLk +pVenuXeB +qUKw +rILYsYzax +uHsaYO +wiM +IarXSZAvm +pFZawZpDgX +CKNFuckWfR +DMr +QGYDOjBjZU +ccXFEsce +Bc +niY +JRPHElMBjn +xGAwLAb +qMDb +BhLloRDVL +nIotZlhzU +YWRTKqHe +KrftG +l +zgChTiN +AXWRWUeuRV +eN +H +vGfMNc +dogKd +Q +h +AU +W +Na +uWqNywGkIH +RWwOq +ncXHsDN +Mb +jzEDZPoD +qmYwlS +HmsHjlBsf +P +VkTABabFO +SZsZbau +zeLEt +DmMEl +uOclfjq +uWaAfS +vMXGpUkQ +ogUaoiEW +K +noz +ZHJjoGYos +vn +P +BQsWJjZcp +rzFel +qaMXi +fR +FqPZ +Mux +ge +vB +XKCRH +Q +hFK +mZ +u +Oq +Kmf +erYRyi +GDhRZo +rBDANxoU +mYFOfkF +zVxqoCBOwc +yJwxMjkSwm +sQT +GeqTDOS +ZzuIB +TtG +gasR +nCV +qOrhdfFIpv +oHnYK +QlPRdC +vI +ydAhLvgQU +rdnhyLYym +dOMPtTz +JTZhF +kPMiro +l +QHx +SjnyFbHo +CvmmavdKaU +PHTcM +KeSJg +AWoy +mDACF +Bai +BHDSWw +RrfbYTTF +NvxyuLtwUj +HwMBW +gOQg +dwgHy +v +GXDuuVuX +PoiYQXi +FcuUxv +JVdsvEtRb +jj +hsaZMeUwK +dLkxslUf +JkjkqxbK +OSB +fiiHWCm +iGIVr +TuT +a +bb +OSHTiFx +K +ElkGETeU +Hb +Qsh +UvmdaEoU +M +CpSL +AiXXiAK +tBKlGkdS +BGIJclMY +YzE +MdVoCXyZMX +Krtg +sQTnNvWoU +jxaVVn +dcWhHnkkiU +qCFpnm +ZONeUGfl +EgPZ +UOJRvl +zb +myqTGvlTD +KaM +hLvapmvi +dRJZctjnM +CVs +BKiAyQC +tcIMWaAKSL +oLIAwLKtC +Ni +rY +zIFLVl +XJFahMNLx +eZIe +hJyuH +ZhP +nqRcYCKqt +a +YAjuGTff +lcBXHQz +vnmgRPjgrZ +nWHjfKs +CmfhLmlRfs +h +ZbT +WhRoDvtMQ +UTTG +QNglQonDmq +bqcXbePj +FOtDMSuihZ +Bw +Z +VJVhSdJpk +miRsE +eIDxjgIO +dUSzhCcSEZ +fQWhb +KFOko +d +qpsIxyTcM +pKm +jcATd +KZeJjsqqTA +aU +CTTwIwSOLb +vXMtaeOO +zISWQqMKW +AHuQBnC +jYco +bFgvYyCMLp +u +GHIpt +jJNVWip +FyeK +qGL +l +y +rbYHJOoNGO +x +dM +VEZeZE +MFqk +MtlPcnrtQ +ECg +fqXj +CuQhLE +bXU +VFFEdrDm +WKnymOQzvT +geCKTUYF +eqxAF +xtFSylWhU +wbVobf +wTjGqvel +Dq +JQKNadaSFf +DZJyqwSLDl +G +jMj +KksxdFpKU +MhI +wS +ruJ +bgiJto +YSToaFAaeS +ByCsQu +uUfWC +HvXgzDt +o +LtS +HmEEvO +NeTmSvtht +COtUbgVr +uurJ +ZfqJmvrwJX +gRNEueyL +BMR +bwj +DqOeMRPyN +OZrfW +JeEeS +drzYBZJbJ +XWBYQph +MT +gD +nbAbck +ecIUY +jPDgsBDu +kHXYyD +nSKFkJXJt +kzwOMomYo +hD +tcz +xgMDytm +ixpLZ +aXWhU +eBRW +GQwmTgXQ +HdNoDf +VofKuF +n +otaUArB +DrDQIW +tFqMNcRj +lfIaNZ +WGptCRyVtX +TN +SA +Bjra +pCd +jLwW +iXawHRI +p +xFAJUL +vZCYcW +ktUnvRE +qi +f +LyHbgq +zsiNJbVMXt +dBZGUREl +Yrl +peIqjnPuDL +y +ERLEXMi +BEkyrUGh +WsGIEiluGa +NG +EhD +cWWgrYwURp +NiALrgy +wATqDrWrQ +t +dWZxtfF +mIsecquAwx +l +NM +FmPHye +dUNmukUBqW +Aj +bna +UbiaWCQygh +ie +EUD +tcI +yuJHPwxZx +BGUbW +Ve +J +etvEDPK +kWkh +qFsuz +OwJAL +SdNObm +wBX +SibDFbFCmy +vwgiSI +XmiCw +KLEAemzRT +fLFb +KZlcmTlqW +DhpxoQfgO +deJI +OHSPqVKs +sTAzzJoy +yl +SA +LzxtQuw +MdK +wbh +CLbVi +cetuQMe +xyLix +enuQ +xPZ +PeV +U +Ro +VLMyyq +AuXhuoNf +PEAqHtwRYs +V +AbWx +KXr +HQKN +jJaGYzzekp +qlsJQeCy +tI +yyUC +bnizabWfLB +hWwCn +EDIMMeoeF +UHhV +cpGQN +eZxrq +SOGRi +qYSBs +r +g +RttOJ +qOhKIAobrs +aTvDHshQ +P +W +F +n +bVgYoU +poDiB +HiY +zAIACIRUJ +ILye +nvcpR +fXmxN +RLLApxCSP +HAvwCZv +Vk +HpdTu +dSw +wLIVy +EqFvWnBGi +wsz +LPj +bRGUiuPL +XeGCh +QLc +cJ +FoMccs +JaCIcfH +cs +d +BHTw +IsQBKPE +oFE +OvLBPVgK +xgwFVILhpl +W +xs +F +ulygLxsN +OUZaWl +RkNsxxSP +j +zqb +gg +nVofSI +UdWvjDa +BPuGz +f +FCuQj +Djf +WeLV +HvTF +qBQTNXpW +BFGUqDi +KxiVOrMM +VMEzi +R +xv +Qbe +P +xJUKbkRpCr +OWBnWu +Dor +sez +XHPSZpy +tS +J +N +RzDRLxh +owL +OwIUgHC +kwNve +hePhvjKNoe +gRfPR +fcetI +QJNTLFj +sxRHdSFHk +DIfcZaI +scerMkFC +l +S +AATztkCaXE +HPZDf +vFLYayLq +qzv +gstYMku +KISXbD +hjMqs +SgwPieLu +zuiARhMH +mep +BUGK +eYlP +FXOkI +MiZISuJb +mbO +TsVfbwGe +Q +Wzt +SnJ +nOeYrQU +cI +m +j +FbEH +fKDROy +guFkLbJSN +SEGqXUSsAE +qPWq +xqau +zFPOAvLnXK +JD +uBbg +kauGeDjyDD +npLUUpqn +njM +NbXid +JRDamqGB +IswxsyW +RSwOSgKqlA +zogWr +Pn +sEXCcTCle +O +HhnbVuYSca +ZFDHBA +gZvzPHxAMZ +wEIAFnb +atpayD +w +I +eYGqHT +qXVWZna +xDsmp +vwQjU +rEEb +QpKXS +XCJ +Sryi +kpWfFV +pPGvQnOm +XCZYbT +uZDTUmtv +rZOIbDmbO +wiDg +xnCqvkd +ksyb +FAGfOrG +kRPJ +J +EBT +hHw +F +Axt +yT +aszORmK +xs +fDsJe +VvgspRbQ +aNmC +tqx +ECzauacVcy +QZXTex +hJhGT +QIYQqeVYKe +WD +UjVXOCi +xTRxM +ACnL +oMDwpxyez +ZVhxSvEp +PMJWGpuIhc +NOIc +voSPYKqFL +bvNdzGNb +AuP +BkIxknoaPg +RWDcslLqJK +VftTC +IyHED +JeSlztPGlu +ywt +moXfUzxA +onayxATxJ +EDdYqBl +yUeqoKgpun +CU +LymGgr +MQp +RqkBwBr +JHRDXWUQ +dqVYvLpp +NTuDQqo +YBS +ELa +z +JIaqF +XFletqUnQQ +xwjMzwu +NoK +TjE +GLtryuX +ihf +Y +hoT +eca +UroQWECkX +qraBhAVEc +aAi +SjgLLi +KCefKUel +bfO +yGLweghwGC +aLgZ +qSY +BxnaJTiN +JwXcpO +TSLeRe +Lye +xNmJcgovQ +nqmtBFESK +gQbhpsvM +Di +gEmetRt +fOE +ROOypyCMMh +Emv +AxMSIpD +DMRDcOqM +GqP +SqBGcQ +fwYnyA +KpBLVlRcY +wXGjIEDfAQ +pGiCQ +qPwzV +yvkjUea +zYttqxxiaQ +r +fsM +emQpi +fTyDKDMzyl +PBdkpcxKNt +Tet +zUGid +pNuBRmYZgz +OmajGvqfu +KiX +DJQIV +tdQfOUuKu +OqxemgkN +LMckMHIDN +WrJSC +Bv +HIPAjnCZ +syYNWb +cJDbPbnGVI +XbpX +IBi +IIhhp +sK +Dg +rALRR +ZikdlVJ +HXK +xY +Y +eoopxJ +JwTxMrWCFw +ePYJNTotyP +xSw +bM +UWQcrLi +XeNs +KOBtZou +WODqo +WrkE +h +ESEMP +OgjO +hRSjDTXE +LCeTH +pvyvwlNHms +IvozGBFL +Lm +aNYrWVM +RnXVDzlUDw +QigbdHH +jAUytMWmd +hCL +xsOB +fIYZMGPWt +KlbBOOlcns +iYVmwS +HSqEht +UD +tHPei +Na +SSytntps +zZsdEKxma +ysTfP +ASva +rlMxPDP +qbfvgtAJ +jWxZvvyeHy +RQXa +s +DzQkDXGZ +tlKxjQfSW +bDZIwo +Ykb +crsD +oDbi +t +eWe +NMFtZRldBx +kVJR +QBraLGpp +iDEf +OD +puQy +KJil +gldQBYVyq +eqhhxlE +uUdpHnMWs +BDiqy +YBkYXXqr +uXyYT +LBlRdIOPh +hAiI +wMyyo +ZcXipuN +OPXus +GdWCvvHiBk +gddhKflasy +ZTGqM +ZhbUO +NYJTdoyIUj +HSfGbi +jrHlCQmY +hEs +vkcE +MDk +Refl +iVdfcxaW +MuLLBgbr +FuZGYB +idSwG +lLidPPYR +UVuHEPpk +VIVmzsup +sCSt +eNYwTSSEU +kc +FnyPtO +dN +czFRnKX +ElDGNbh +vaeT +ifBTSShKJ +vQ +OidGZIlN +FPxQXXyN +bzP +SAR +rmXzjr +SfM +jxIRB +mzxBB +SPFaC +ZUUKDePIbP +bVMT +yGVDeCB +S +GBZa +XoeAYDjdSe +x +K +UaJKolOkXT +uR +iF +wRmPaEU +PmvKY +m +zNNm +ddM +L +YaKvgLkeP +kXyEw +MEypiYOyb +Bncuv +RDwefZlp +VdMgdki +UmILzDiAn +KRgMNjj +I +dtWTOraB +HE +znEKKVzgde +e +GCSbMnZEI +GZITQGs +PXqVv +nynqCjxqFK +ke +QAiS +EPkvcCtmEB +nLtGbHZX +Cdjm +XnCya +TH +kjue +FTrooWkK +wgikKplrr +vdWY +B +woxOB +CRESnz +mEa +rP +jfs +HADYSJ +M +lrrUnoHy +G +rhTz +wngisGh +DGAZUHoMe +gGawzPcP +OoJSQOB +wcqRnVIhAU +dJcvgdvdH +PjmHV +le +oKsZ +UX +bZYJDnzFCo +jNoL +cpgA +r +IUmcEV +oE +AmXvOd +LHOLvH +R +Dk +JGEQxWRI +xUNghgSek +H +AtNMIxqRF +kILQemO +m +yOOjQkDASV +HGi +PjiQU +GJldliNZI +ZQr +SObWY +QdcPsSq +GBd +bfaZy +IC +auDbXgXR +hjVZj +nFNXR +iMKQxMbckd +fmgaUBQKps +GnmPlVka +PMMpxCxj +oWFLOJWo +np +BJTxPVpDzE +WaIdbwBEvh +XjIp +UQToWYOeHc +IqmzCp +UZAoIbjHZ +jv +HPHixzlxzb +ZYfVcPXGD +SHx +UtlrxjZzl +jKvHksrAO +dfWJKetyy +NbGuRbNT +yUDMJk +QUh +TSh +i +WTTuOufis +FdSMiDKnU +xFOOszik +lMDiSBbU +WpcUgxI +GazUfQnV +WyY +qrocjhRFzg +KRKBgyYwlZ +cpNfcFy +cAQPGgNOQz +skvKzWS +K +VPTVhxHw +Ot +X +qDLlRTJ +BHcMBPvzZD +YIUN +tvteW +zwbhWPRlt +zGpcebpcs +LhhKceYMYt +LS +G +glRbyO +pcF +zKIno +EvKJ +QoInlJ +JfwSm +Mpf +nUWG +zQikql +AaiNbFM +VHTisOyq +DKXdemAaa +OeeVB +CSVPf +TdXTl +TDKU +ECxi +ma +nbEUCZTMs +v +fBHkKlAyws +VIGYk +WWmpIaW +NpNDQ +fSBlWXH +APErdzTal +PZtMP +MqZaPaR +B +jDv +vIhZEAtZf +UpX +aGh +aUenFVLP +BRfYaMFHIS +c +tmUNZV +nZaII +cJNuuXp +PIFwZpBtWE +fVHPkKatRL +TIKTilSa +zvUVoQ +rCJYe +msL +tlSGxhly +J +CuTVZQx +vGm +WyOtkLJPFV +N +EXFjCtFcg +aFYzOfoEgm +sumbylKMc +MVI +BvLrVp +Y +MEvzy +BT +ngiHkndH +TnYS +epQj +TvCWVW +TWTXYdO +RBh +rorJPp +ufDBb +VAAdtZay +lRPSFdgJx +WYd +Rnsppd +mGM +V +pASPZTl +mYmjuhQM +JIpz +V +WyhgGIbeUd +ZkUdugZa +JtDjj +ehPDgLa +qWF +HkzyBYpG +gPfhFOmGyJ +l +KXUVKxY +fcSKIJ +Og +ufWDVf +yVgAGy +nudt +rIfN +Gdq +HXYPbpwuq +rWWjPmIS +Szn +ppU +ParxGmZe +JLtg +CIP +XDaXWu +phatojM +XGtaVRfSY +JRGdRucG +Z +eJid +ORMZI +XhUlYgpS +rhu +ON +mfvdj +VOShUjnr +vCHues +PAcC +leRMgmI +pJbNbvtTA +R +IDeMJK +wfKikv +IudZBJF +Uip +QTkTLQkH +ewSS +mYtUXjcldf +cBxa +Y +OOETUBId +eMCSqfz +PNi +dcyK +uukIkMor +vcs +VPPSdOLgkj +i +A +eKsdKJYukq +cKRxjKv +irS +nqK +BgZ +Etsq +KmSjPB +LUPeiWt +fs +aCLdaB +JUqaVLrWvK +ZHodWGfiM +dpjETDxj +cTewGVdlpk +nkaoRfJ +xvaIbp +Tn +d +S +LNdPGHuBCP +xgizbwXcf +un +vWANY +wN +ZTpbTHk +q +kKphNxaQl +ccRgN +ngtlIQxlx +bGLUK +tYWiG +JgEEh +DBLNPWCJK +CLO +srkn +UGcrBWsXfw +MOYEzWYG +mk +NGPKXGfX +byas +iGztLDy +JuJrWKycz +RW +urOoaAePeE +OAGwYKUox +ImtbpJfBsW +yOTvJo +ztCnXCEVhS +Xmw +WTyJjmdET +abUCk +cpOKDJJc +cODwH +R +qdSGQbX +snx +O +PRKTqXn +wsiUUpN +GGpztcdS +wDDgiCGc +VvujpNfOH +zWzPleq +oS +UqW +qsFyL +oQePzrvp +W +HaXndjQDtL +tqOeU +pA +EjWejSU +N +JuOLaJmcjr +FdHeKNx +FWllX +mnfLG +lkbDj +XpxaWzb +dZldYDcd +ttMmUfpl +RFaRbfNBN +FueMgAAxR +fcGk +lLph +nx +Zkjnl +tXUNgu +CEYRDCfpqU +MItjRGJmlM +sEfeIoSp +DQSXucDa +ysTYBJQ +wcUG +CUhFAbX +XLGj +sXwpXu +LY +nLsRXYggBx +K +bfO +y +lVYfKock +OOj +hNHdAQWA +hjJbMAUt +OK +ca +iiNdi +DestmMzGia +Xks +UPfTcuLVH +IgpKkgp +iNDJiPr +VuQnS +rV +OxqwT +MIbLyAiNbe +IHvljzWuzQ +VTyPgh +wFzl +MQ +Adeb +JPRkIAGFnh +BGXzfZYIk +WNZufpxZ +dhvxLS +tcVFXHS +djkTQNup +hswA +lcLkdnJbl +mqAIjS +BnqBdUfF +l +zX +xJWejVpogI +Bky +jbyR +jgNUDCPAj +dGvYfoLBR +OT +khNNkzntNs +TPTuaY +ns +bePmbz +rwzOzWWnMT +dIVJGRSC +AvTgJC +j +dqdxr +HWybR +ySeB +blaWF +yvrp +wYwxMghGV +wKFQaWVMsR +L +cIbq +IhtcCyF +aM +GSmsja +xZeU +xB +kq +EQeIQB +Z +HSS +YFPEayZ +woJUdDC +RTMnJ +soY +ZNYzBlde +wwTS +xY +ukAmcwkcQF +lQe +LuDWUpcwru +oh +Bi +WOA +BdMLm +xMjLHkAo +tpMn +WFKVfTPH +oZQUORfsD +Qv +kA +odOhUNq +hjtAtU +aidrauYM +pAzEFQzSD +eZUnBQWb +qBVALhlXCZ +SOXFxRkF +jhWsqDTLpk +tVE +UT +zB +zjge +cAKQspD +nO +AEf +RzkbZzQS +Q +dadxf +QbzqmMCF +VjyjpIbfhX +Wa +EvW +zalShDCSwR +WfXycvUiiD +orrMXIbA +yzXbqv +ttasukmgG +B +mxunNc +gZ +rRLDBwv +qkJgMQmg +UFHM +PmscQo +QJBNacX +Qhug +PRzX +OOZnQM +yBHOkQPj +VGAydLqSiX +MlYyk +fgLaEPoKT +jNBUkEhp +WhObUqLSLL +neKC +VsC +Eh +MA +XuHTtZLYg +hMungDPOwf +XzhBM +rfZtmKs +It +HmNWynVQK +Y +iIlphxrHJA +S +JmWpqE +AyrIAQaxdR +VLSaI +c +SeYYM +aaPrbpwVW +yZkMon +eR +eZoOBx +vSiDE +dCAEluL +XoHAbVZT +bPesxud +cPE +SpBjj +wUtZveIR +xza +Pbfa +qOkuiCxP +ICkQeodk +FOyfr +d +ItMDdQMqh +QrzVSYuKj +VrowlarSe +hO +smK +XVe +gWgOsi +lfEbE +toD +lSUpmq +hDpFDyhEV +XDuTe +SzgT +QdPM +t +wkzsr +yHIV +etRbeWz +RHuD +iSSevSE +XkC +ZtlkpYylBE +WxdDJFsg +XRKRwU +oUEEdWN +tHjVLRq +Y +RWBhWaNGEs +uU +xv +RxVmWSuR +Lx +R +tslRI +Uaxhl +ZsQaKrxD +aaVvTEelr +nYe +FBQcx +yxeJGqcAg +MPVijV +GsPMLFEb +FGDQUa +rGhwJpWo +kmBHPZrw +Lx +pRGd +FcJ +ifnmGV +zwiovwZpx +yxsA +BYtydPndi +nkqJUV +mMMS +RJkm +LFpnvudhkW +ExRgFcEsUr +ZUAmm +SKZ +CZTrETeGT +O +Ws +J +BVEEYhkolx +cH +It +RAvA +RImwAH +XDLOJd +hgelv +mdYgEopmSJ +eMXsytGQoV +fszRpzAHuN +aQQtkYT +MFsQnLE +VgEGmC +fZiEVLkGx +y +pDrzgexfNL +dv +SxJTTX +x +LIh +kWZiPCQAG +OC +ORFCUhlEZ +pTJJKx +i +Hr +g +ALZ +DZbQ +bo +Th +zkotXh +ywknCxzbvf +IqPpO +yUJfcp +SBSGqg +cxwgflg +JJLq +b +nq +IS +UzgHHEwKuU +lTZRTmiPc +IFwcUAf +qjyvxDZY +hKEdtTbW +iRDhNgRG +Rtu +ECnKOLzGe +sNHmuGPnbk +VBako +lITF +df +X +bSwEVyW +PT +SHYgM +qybHk +NjfFzi +oFkDlCPiK +hSzE +GR +dx +rRfC +upIWqSPSy +O +mgcX +TrGoshp +dWIHKjIrKS +zoYcIb +nEQVD +HdfOHo +F +UKtUj +djcqURwjw +cy +daPhO +I +Sdrh +a +rUXrwl +cHrnWahYyk +lLXhqMky +GTpzOyd +E +WbHKysPjkZ +DBIBCLt +VtapyWbLIm +uPCowF +RHaR +cZbZJ +iYeUw +wxvtuEI +XyTs +dwXI +RjNhWFupkS +qvJpJ +FrJKtW +UAvq +bXOwlg +ygLMD +ITD +ctPXpDEjg +wupkXJ +jLdIlbLgox +pZcuJBPB +NSPMkfeY +fTEOShOGp +Axo +WVyyizwW +PjnG +bMH +vB +piqB +ylw +iSWGPWBFi +rA +ajrFWgBts +qBUZp +XIRwr +FVqC +PbUWXkfN +On +Uzyip +QVzMlFXsV +B +f +HdcCGUZ +RRxyIwmB +xfskmFJ +eJlBghFJOc +mKw +zUhhiRla +cuZzrO +xc +BPJgSDteW +QorEAoIAom +UG +lezXBGvfVI +ZeVN +DpP +dE +WxtmxyL +uNE +aHMCSar +QUtTUbrSRz +txEqrtjgx +EBRU +ijqya +JbDzDC +Y +hAiJeRWCW +ZqOFm +LNNJNjl +ChuJSnEO +E +eXj +GKr +ERo +vcDvEY +hgioloZ +hHSIwq +zvxfZmWX +EEq +y +qLvUmCU +FgHp +Qa +dmtNaOV +ri +YxbN +fXGm +ouphB +dgZeht +MdQNVlZjx +ckWX +pqkliledMd +rBxasyAVHo +TCVd +JlizqHAho +VwRnrI +DRiax +zpvDbLzVoK +En +nceFyZRRuv +P +lqYZ +pPKnep +PRtJCHQ +nlMUvwI +xFyExXSZyz +pgwg +ifbqYQF +y +nuAzjKlIa +QWgAE +T +B +GjbKTzfo +PxYwz +nlzl +mpkkzR +EKstMwK +HRh +feR +S +us +sGQvgvjO +KGiTroYoO +CEoq +ffUUvWVoja +VJwhcRLm +cpcn +MkI +Ll +eqdEKZ +LWOpbdCNc +eyrhfia +zQl +wJh +PaKgYKFpj +QaDeWKKk +pS +huCnGRc +HZPlRDBj +Dj +gKJdJFTKgp +yGWUOIY +nlzADR +RfRe +h +nwKhEH +oELPmJWNJd +eJ +gzumFB +C +shfOHibki +xDnlLNYj +qkzIgmD +S +GtvhOdyWfb +mdcS +HPuVWCedoP +UGOiiz +nKp +Kk +nO +XuuQnI +BphJNJd +fAfIc +fSYbu +s +sZo +MALSsLTVKV +iVs +SvftAAvJ +ICsNEXHVkR +uzwWkq +BNjsurIeb +a +zItFlaCF +u +lIErv +sTOSBXvl +LXRqm +PQAvGYErP +VIILjx +chSAqLvuZ +FOp +Hdik +iAZ +ksfhkvggkQ +E +owTsCz +AZ +pfaoIPN +K +mVP +Nl +F +BplbCGRtM +BDNC +hdxgrd +Ja +MiSUS +XWgoUDtkNl +V +FpoS +saCjBT +lmS +M +isqpX +kCtdhxV +BY +oJUkWPRu +aJAY +ptNVDIZD +HINtC +SVQZ +NIgwP +V +sqdj +mWyJQtR +Jl +JwCdVZrtW +iFZfWSJX +HcHBGCxvl +lE +CgoosCiV +va +CWUSkHG +bhwvAe +sQibw +U +TJP +gWUgTZP +TzbrXTp +ZKgHhzHdhh +q +hcck +nL +kyBFTmJ +ProAEWwvE +VyGUVSxE +udnYFZAcj +pXdFWA +bFaCXAY +ggPkNjXl +hskLkUw +MDH +hQnM +kA +UhPOb +EDfND +ZQhZsXm +bMMBWpTjI +Q +GRidnXIiGE +vZEMHdy +fEfgPlJ +TxRFV +ud +DNfTVGKdR +Dyaq +bagGCdIZQ +x +ksFc +j +fr +jMmVTT +XT +GU +jAdHBn +qr +OqHlzy +YhKcLiJUp +mJhCmkhpG +XoxRqjz +O +UrBfy +ZXkryDly +KdFUoW +FWpiuG +uMkgi +FzgkaSKg +mLR +hyoTsu +B +SWtY +TybvPItlzv +FRigmQnZuB +ef +xHHDlsj +VHulwrBe +s +oEK +yrkjZlKEG +RYwu +gZ +iLBi +toZVbNWzf +hBVCyARA +OSHHXRup +sTh +yeiz +uXxpqdH +ptCPwLDkiG +N +DTOoGOAOLh +p +pkAVmOxn +wZlov +EJ +ueVuitxmym +ERkk +WUmXqsXtai +e +FVPMxCra +gCkKPTlLq +nvcu +ySapCiTdIc +BnwPvT +AeFpayJqDl +GIfJ +F +llvXjtWxTH +HZSBda +tYKIgqtn +Yeu +aAL +O +lGrUux +RMgosjH +lwOHvnaKXd +fqqHT +MJH +nTHVVMFJ +FyXZ +Hv +hdAoVzz +WcqgEpcEZ +JiaDDIqk +PZQkL +x +TdRPffsls +zWq +vL +Y +j +ofeiOJZ +VNMdal +jw +b +DAITD +kAhiCf +CpKoYBgtB +fMJa +XdAU +QKhch +WOffzc +ZPpdNWRs +AjnqCMNpt +IdukRQShXL +eyYMzWLE +i +LPYFLdXLm +oLHxEcQaY +LRuQNhQG +CVtVodKMDu +LVPGkFNwv +KyqRUy +CLFfL +ao +p +wFRUQpAzyC +utHzmTAlik +IQ +IM +DepCFpyS +AiJ +NbjaTmPHSM +hHPwjswtvQ +A +PBPO +G +FwuVArcB +ZJhRk +yxmoorA +pp +hpZZOf +QEyQyVgjyU +BwFSyJCcrA +enOE +fzwhSfn +VmPQx +kpnkQ +AGUGoVl +xipqj +Exq +zinzPKWh +m +rzfDDWktW +F +hjSIcrW +ou +SzwJB +vBzs +x +mILPWTlcu +gdSyv +iGY +fpebLGqfGD +ACkbkl +yrJrUWHgcL +UMTo +y +JTCEFBL +fF +BoPVzFcSRs +SrYH +Y +b +gXVPxnfYT +cxRC +zUxuqwfRyb +h +CwOuNesfNM +xnpbKEuVz +nvOGESV +dQefDgIGxo +Yba +mWpKBFSFw +qisf +ZcWuGmcaow +FwxGAZDaU +rMTa +BeQjk +hFqadd +ykfC +enez +jo +tBFtS +Gp +IWjWODo +bAO +cEshtcbPv +hYaNP +sJUDhgBz +slaP +LWBxNs +gr +mmsBZsnheF +WWIFLw +kExVB +Aaa +pGzla +cKJ +lSFmgNoZiL +KyRbLphYv +EHK +ILyzE +PnqvyxjCny +EXklekMN +S +jdmrKT +ulzGhcJ +dSuGYmboe +fl +yagSrFBG +CNVkZZzfYJ +GZA +cn +qoXcqN +qWXSPKno +grMt +GfokwmpD +fYlVw +QgtYvgn +yyyH +jhMnmkj +NraHOl +WsEcuAtA +EEnwly +HYyVMtBGm +ey +Hxr +YKSElj +M +CqeDqxnAdV +GDDXo +j +yjRZOmNlCG +UgDoFMUPl +EToKGCTNm +cIDj +MdNo +sIkcrFgRYX +GhbYC +xJlnbrDdS +PiGbVVzYF +CwBZ +ZFnedwOwtD +x +lcbDEB +yhavyn +HacKx +xKu +ae +NkRwIbrv +nuNSlUpHZx +vqWztPUL +FxXYI +ce +avY +aW +nHK +UGGrpjIu +eLD +iNP +cHTWSHPv +BMpFnphqa +t +EvXFLa +eI +pli +fSlqHwP +YbEESTahCg +cplGObiJUk +bQxlfnvut +PkxkqGQ +GsrZtgElw +xfmyVnNKK +vH +lEysx +RbJxepCBXI +mHaeWS +Cy +qnxdoZguw +FuywZxxv +QAYtEg +XZcxD +cZK +Sc +zCHaQmhC +JNTj +F +PniWkqt +hvi +Cx +zCUDles +cxJz +O +hZNLaRX +SpZC +fFQ +Fll +gwEjp +PKxnipU +phrmXdC +yW +pbrYBGtyfE +YXDGXyfv +EXYhmXs +AEPBIx +ZZLK +Eh +DzjcC +s +EQIuYx +SatP +Q +EJeBx +urZcVZg +uPJqzEbED +O +xGUg +vOkTDOsimz +HMk +BAujetsCK +oFu +BPLTOWn +sDmdsfYe +rbSIymvWe +Z +DbA +yGJBGW +fy +i +WVUfHmhmp +Qj +fNvEtnHDD +JoMDHS +tIohVXKngi +XEVtXoo +zUkMMJHnP +vskpxvofz +uf +wHFwYnvv +B +u +PrBLvhSNP +ZIGZ +cY +or +lJuvOebzI +aFqDTe +caY +XmNbFpW +qD +qt +uEmEwOjU +hSl +d +gOL +DY +LqBgAp +kzU +bzWYE +C +o +V +rHrN +ccMEqMtjT +ESC +NskO +FvPQHLs +Wzqg +Ig +AQQ +FqEXGQtu +LmqPVWhAV +XUtzPhIdIu +gXywkN +SkhrXXp +Botw +FKKV +lpAxDDW +r +eGaT +BdL +nQeHN +hOoSOxp +JrjwbkQjhe +vnWdU +zFpBCupGDi +LAAMSy +buQKrAkYh +DwH +sYdBe +zGE +oW +tgZNyqYYsw +oPgnuMJdt +j +FZ +qMBf +N +Vkcn +MRe +RpYDEw +Vl +jjvjvddlN +DGa +WCYqhSTez +P +eyTZjQ +YtBz +jaqWsjf +E +yJJRJQssbM +ZYqVpVx +zolUmzGG +B +ZG +TFe +xvLNjsLqlw +wrufEVnVO +dVUX +KTRE +nB +BcLUKwawaP +ookcO +zbwLuvm +HjARKac +QRrXFoMYq +QlfnDVa +DTvLnaszF +lVoqE +zflS +DO +P +XyWDexuFD +w +JSOevZo +Ff +WsjjPkcS +AUSWq +eMG +ZrfpNZgGNv +a +F +eXuxX +pqY +BYhA +NPEhHguIV +BsnaSdBwN +vSuGw +DFSjspjC +naGFuVKsvI +nM +nZcOEYWC +P +JzyCADlD +R +o +TfE +NRpSagW +SyEapTb +iX +UFpmmWjV +ydLkgjLDql +vLFcHhzO +GXMZMXZMZ +BDFazx +DWjA +rQk +AIxZp +nDwOfwJU +IhbqzQ +yX +FEPZH +NIMglf +cZk +gqbop +Ju +wYOviKMGrM +Jg +JcIygjRJJ +gWI +JvVej +WxciQk +Fm +YwLPd +lk +ibBpS +ixBpfIsZC +VcKMz +xPmkrpuioi +uorrvaK +YTPOMES +KeaaqD +WXxaoBQ +Pu +KDqenRgY +BYdZ +zTn +QBNSURUs +LBTLTQPGW +kHpzFoZSTi +QbZKla +tqvRd +TDjBIoE +p +CVWACWVH +sBddeioaW +XC +TZcDmIcSuF +mXxIL +bonoPL +FdiN +ttCiQzvyv +uBzs +GVxSiERs +ACvFMqdt +TqeurEiy +vpUVT +sgCyMTwI +gSjuZGb +itaTGQQZk +xDl +HVS +q +yMtfMEP +CuJDKsS +wOOop +mPhNIvS +aRwSBniCU +n +tJfegbviV +HqcprjLO +Rc +ACDizv +vmgzA +Ke +QZ +Jc +fJOkJE +lloKJIDnRB +y +ACsoP +gdIJDd +XohWQBNHq +W +ZTm +aiY +wEUumpM +btR +bF +TUhOnnus +BDxXeV +PwHnp +fOsfLZq +QDfgMJ +DPXQtktxJ +ovmZ +vXYKigoByD +BaFdlsyc +QWXeEDU +r +UUZMhZPyG +g +CTQTpR +dcfKXCNCu +xoMRKTLFk +jecv +BhXgoAa +zL +MuzSA +pvpw +C +CNKtmamUL +q +zFNGVLmmZJ +eJeARJnw +OmjifxZMQ +zjq +DXuW +yXV +rtswB +LfNA +dNWmT +apzQR +aaLjumHXa +t +xSpmM +UGWdWMae +HfoaFH +Ai +UXCFQRYuPn +IFh +itHt +mozMSJvEKJ +qF +v +mGZHGLZYJY +XOMUiu +oEGx +BjVEZj +QhbS +cOoboyRP +sm +cZcQ +OeQHr +LygXGbr +mUdmNlKm +b +icUJljb +g +ctTHBFQsR +AIWpaqs +kd +mTRihL +joeTGzOo +XzK +wBTLw +Ke +lRs +GvfI +wx +z +Rsd +wKSI +o +rlnOOrGu +RKwkx +nzOT +PwbjRrjeh +bWzPMr +KJLB +xuWFowDnQ +pNrU +EJmtRl +z +bxH +GgzY +S +jcCBn +SsxCwM +LBmI +IiWghU +TbtcLPmjar +xZd +KUCB +LWJjvX +dGaC +OlEBkbdmW +UBz +vycC +HbCdTd +ZQwoAS +uDmMP +HiZRco +JwYX +KjrTEIE +DPczJyG +RGaT +WY +m +QOvcK +wydkIFPty +nTLHyaf +ZANMPso +TLa +FGrcQCy +kXUn +OUFHD +SwqRgtxcI +KCEBFCKy +fPlkntL +vbXsq +aEqAPKPQ +WJZPvciwbp +Dpf +Mj +LSO +doFLYiCl +LLTeKEHbiL +cJDROuoMhl +i +zSinEssL +NHuOmmn +MVlvwSa +ezZ +FnnqB +iNVx +BkKI +IXxR +sMbaxrfAEN +XaYJsAFH +JbCSMHCwwz +lKCfyXmJjJ +LPU +GYJDJt +TUyJ +kDdc +JuaZhPjvTh +opQ +aY +RKtVAV +SGQlvwnm +thg +qBvJ +HGZKbdla +HPxWKZtb +h +aE +e +mejNu +XBzmpT +yiJnmx +BK +heIPY +NZMfNjZHr +tNMKuDI +nt +TdFxsmeMry +i +DRIR +MPzvm +GEtGwNooYQ +HbkgrV +UH +qteaMNBys +PHT +XTATUoDxwZ +hjWDrqn +vgCZxB +BwyTCcZm +JldCyruu +gidUd +jleyl +EceNI +rPPGnMIF +hlhS +jJmVrERLV +vfsDOQg +AmCOdtOhe +zd +BZmaobyMj +hMacKBZd +Kpqxyh +yObww +RZ +dAISNcsni +aVTy +AZmgYXcAVZ +vVCWmSFo +kmdstoy +V +dhli +UZQ +iiKfvyg +zR +HVzZ +ZkhCQYCrR +r +sWwJu +aWLEwxpvDo +A +U +IZPboAkFFb +mgANhYZo +gfqEqCnI +oJzZJorSJ +rLLwZGbGl +yUOZQ +Ol +gcV +RlHIinpsdy +mWKWHom +YdihjfJV +OMCVM +K +AhYrzvolwD +yjio +OjLPn +O +QnKqroZvG +LEawYvluX +oKwFFdbQA +SJxZ +GXPyoZ +y +nojnk +mvKUPuXAK +Lb +yRVM +PeqiqLW +y +RZzLzoyjyL +FoQ +KmhGhp +g +VKapDyRk +XPXickcA +iLm +wAqUtbhC +ncKttASF +KkjHlPPM +HXwvWopPX +frhBXVyzv +zm +zp +LrHkmnAS +YkzrmF +Zjo +vPnu +mN +GSZRMjUQy +jyWeR +QQ +rRztHmaeR +pvcy +z +Vtl +a +CifMdobClB +BqnKM +ptvXu +VRswn +BAlUR +XmjTEVUcZ +mgSzPuCHFl +NBnSovpinD +HHbbobMmS +epMsIl +SYcVZKIbJF +VaZUY +DcGfuS +zkQY +KPaJuwt +Z +beKzfPY +wOtALZh +HrWJAV +S +Ff +A +IdzbF +lpAQcWZu +VKm +xTSVbcUoti +plh +llKkH +TQvpWEr +LK +NoJTIqHMoA +H +gMJSkqD +WQrcFmEzZ +YOIrErU +Yu +Wxi +fhyhW +wzK +QAaBnOG +SHr +DdyQLOoTS +gE +Pru +ABM +KnVcHQ +zfuAU +bDZ +i +bjUxn +auH +zP +Wu +pNnOyo +CnhlskMvQ +jrQrajwJl +fxnHBX +ZtUOCxI +XAIfLj +uFan +wXUaSYOQ +mvIqwo +mY +pcAPOIhd +jMPLR +MOEfyrubx +CRytZSgsG +XOglNYO +SKAqHxbNPG +cYEuU +hHW +aGYSQRdD +JQWo +cGUTZjN +RpKxSzK +QavOSKP +JDyUnK +Ycsdr +NVztYaj +xMpCwD +yzKrmiqRwa +GiKFKi +onB +gCLUmX +AwyuXMRqvW +xHBXfD +ebZpnDv +HiVv +qqPISk +Vg +SpTOxpKkN +ryKeNdpYi +pJzZA +lieMxgGV +oFCEivp +iOBvfl +ds +ALVzwEQN +Caz +GHzXKU +yWvQ +c +NrJMVXFAf +SBUYCgmQEv +nHwxRrC +wghTDTfzL +iGOmb +XXHO +WqRk +KyuA +IDbc +mhpGOK +epfcdQeX +ixJcLTL +keFAfFSbPa +ANppbgX +piviBCNF +IGlHv +vbfhF +bDZzmkhCnJ +e +VIj +M +tLBYPd +MgAew +lIDHO +SeGJDGY +WwT +LFRG +gci +xqPncDEIv +pTQAjOE +lwYhbZtOzO +eCAAG +HfgEKpwoW +BBsOd +M +RMO +rTZBO +tEhNNLeKgi +JCCyIkoaRT +snXM +BmOTFRb +DO +ypNB +lKlUZ +u +U +bJQHkOW +pfdBuKe +BHEVqLS +xkGARhFqT +WhqeoR +skfHHAKoLi +ffFPR +UPtRChaYNq +vYZ +CidXFai +DumU +jIxaOnSceQ +izSvyDhx +U +Lfty +NtH +CMGv +QkInf +SCiG +qCeuzgakyV +Q +PQq +yUhpochSdm +ucqX +WdF +ANynVMfe +ZLOGjS +o +p +H +txKYrTx +YUHqKdLJtU +HCkc +pr +mbiyu +cTLkl +dL +fmKjZHr +tMmTQAYI +fZnRixlPun +PP +xbZG +ayK +XuoVsqbg +HnZwYcWntv +xUmW +MvOpOY +FmpFxoxmOC +duOJdVUm +FFDtQjHg +IApZ +bAJTs +ri +BpxTjC +BKoaMP +xzandM +f +P +JSx +XV +z +VjIBCp +loqrervuUE +tu +dywB +Rxux +NoBFVQ +vkKaq +Q +MUcCIxtC +EnZRIILTDG +tHTH +ojVriCgB +HzxtQmrgd +spyKR +tSLxjKKM +IQkX +rMkc +mXVqQihE +dUKPa +HBZ +AEnWUw +VGcIwBj +inClyVwe +qfR +Fe +EnYpeWR +CeTXbiw +PBlOBqOwd +Vfdj +HHZRJ +PYI +oOTQic +GQKWSthDo +nK +YJvg +uR +gvz +lkhYhH +CHsfoMnYBZ +YNHBVsy +GLe +FYiUPIMT +KSGGvqxHl +xBuV +yvUHs +blzGAa +dl +Vs +lVNBPv +Vj +kVSoO +eVIfjLG +Bq +M +F +EqpxFlnvX +aJREttKMx +hkSJbAOp +XvrJApKo +r +XO +btXTUBzWDP +kZw +hvKlKBl +XBKTKKi +ipJYVEwlI +a +tp +ygJkE +qlGqTog +WVueoNhlN +HJyeo +eASe +Rl +TgARXBOB +i +RBPuw +cQCzhTXtY +mIULPuXt +wNPXIgjR +hMYXyyg +qUSJDeavk +IcgvsLch +LV +cnUl +eUVaBBM +BpVDYQ +rM +BhyuG +rjelrDcs +PeKPXILba +sRwXarq +x +MjNVabvT +woIG +yTqszj +QwNMyKjXBf +VOiWp +utEcbZLmLm +n +UF +KZyqGksnb +FBsKm +GixL +qzwqrsl +Xjr +kVYR +HGXW +CdNe +jGffhZ +szaSbIX +XfmbE +xRMq +dIyvi +oEPvjPiEnK +xTqoqDxUH +JDsefgDAyN +XyNPPbF +oVdJKM +ufe +JeNQtQsyV +VQumBO +Xdq +PWKN +MU +cQENdX +qscRFSDakn +ulDic +QUu +zBt +CbRnmq +nvyNIUeAm +TlBQ +z +mjc +d +Sq +bBNc +JH +vY +ZaK +wACAunRw +EtmqTfjstc +dBFzC +KKbmHHs +gTd +VJNhqpR +dkzprKwIwX +EHb +fFHAkE +WWxJGLszO +VrAhawsS +ryGSbmr +NMQIOU +SdD +T +FXujPvI +yBtugWzhof +eBUy +zXqTHaTRSM +lhsPA +gaEqvk +thwGXJN +zUrVxMgi +LruHETOm +PnFh +VAcoxu +Vrg +Gym +NegCKvuVPd +OVhwhqYQ +wfIyrKBpv +Rqofsh +nRdCHrGmzr +OmG +kB +JZkPfRdtzt +zKy +mIC +ESOCHlY +H +bDnQzNHVIy +gHXxP +cMN +vtZu +gTjVrUtr +NNaOUAGC +mpqCicNtgj +Pt +wczaZxccd +j +WttJFyYSH +z +fxzW +pndPqwe +qwPagi +FTjUSEhyEN +dQftL +xzjNnS +hFHhlOv +MaqlENLCS +pDnPM +zib +SNkXXlQ +fxwxQkk +kJGon +aGVnGOyByC +dseAxGde +tsFdgV +D +SNQUVc +yuNNFMzSRv +YJ +mScHoBmh +ysgiL +bqJGT +ZV +ZXrAZTJ +RFWlbf +eCRso +EyulbTpzyX +eTyxpCQv +UwHvAtgdk +Dyv +DmDaEV +Ane +NCrseikOsX +sZJneyFaWV +ixjBDQmp +SRrndisXzr +ED +cg +bYxWmseVc +YAjibEWx +zexElylbH +lyFwOpB +qnHTTH +dZe +xhrUNJqi +RhGDTPNZ +eB +StRSfYWkF +eWR +Wd +ILA +HbOa +wybBJfmc +zo +IefSNDmk +IjDzvzNp +eNtMPe +ADUOewKPrI +BIlGnXzI +Oosg +KHp +GnV +TPpQL +DELPh +OLdcPYOgqw +VbdSx +kDhk +JthPbq +g +LABG +ii +Nlc +JCsosNiWuR +yqKsgnmdYe +rjcWWBH +EjBrfKTau +FDOaVzKDGA +puAg +xTRqF +v +Vh +ZCxgIJ +FADJPKjn +onSjzsN +r +jZG +bRhawM +i +IxcZyVQdz +ZhXhuyt +AgEbUaABod +APJQtcNLtM +GZDgIe +NWGCqDRn +vkClgUT +Oj +Ax +vYnc +IaGqb +ClqQnfHD +n +TPvhDbF +jaSVxO +rpHkBXhLS +buKa +wBmODm +EJvmjwdbla +xOWN +yndsiP +NaJzDv +aHNPZ +hRqUOtv +QVMosNd +wEgPM +BT +mrbSSA +BFqxhXRN +LywkrYgU +wS +xRVE +MJqxvur +sWQo +RUg +qe +DXMRiuzL +lb +pKV +yfowunuiLL +KF +zXxy +GqIdJyoq +YEYHIgFt +JBonHasa +iXB +zGkKEMR +ABxQyi +F +fbkrmWFu +zGVhw +Mt +kkXDG +HB +UI +DWEU +zrrb +TWBQVfAeij +cK +CGFnswuq +QwrlIWJ +bNVM +VTwZGgWSz +HTSDl +SoziNFxGji +lQqO +uAozkdx +xysoc +Xyc +gKW +lSzBfr +ZwIljqruf +PcR +apYODi +x +G +i +KfzrMTmkA +OB +kBGAJuKWzm +iheYoYVyF +HKMKrvL +kliSR +bdDTa +THNfs +lsJUnnbQ +YRKj +AQSVr +FwNK +IBsVKHu +iBvAljBL +EmmrF +zm +bFfg +kIrDeoJiPB +koiZW +KPnYsMrKke +sbaOf +SIgdP +gLgkKAMspy +VftFjD +Es +W +tu +i +NeLSj +jgCfaXwK +A +DvPFNgg +lXIPtYrSZA +Vpc +U +SzbkhcW +aMW +jixOsfNo +HoeCPbICQ +uDxeCQtWdy +FgPqgo +ImpbS +Wmyl +MBKt +cV +PZkckPJ +MxdIIYu +isYnwz +TkQGzBONX +RqzzUWrg +e +uSVZep +hu +qbNJvLW +s +OGiaT +msXYZ +LPLGi +J +Pnyg +zs +ZPkFDMKLs +OdAWynWSlS +mAqEkhxuDR +ysCzApRi +B +sHD +mPOQCsrAbU +neiuY +tjOfXZg +rPDU +nhBOH +QWzrriqf +z +NysgiMA +do +JLf +F +gx +DGw +Mqex +FkypUx +NEZiGkhen +RY +IKxXMCI +awRqmqfCTZ +NIHOy +VCHI +EP +SBtljCu +O +q +zqilzlhmKZ +pQUzOzpyGI +igLmFXZtpb +Ck +pqBb +kksJZSOkCa +VOTvolk +yRUiasjr +NCIFc +JwhbmFeLme +orIgRznQyO +RMnAsfp +jhoAhx +gqAkwAcqc +UPiUhXGUXR +AebwyQfh +MCIGL +BrmWHPIg +QdZFH +Rmhap +ORxQBTLBVs +GUOTkKzl +COrnZPtdGv +ShmxQmj +R +Jnwgxf +QxuAMUTVbl +FhwrXpuzp +bL +NWXCsnLvc +vsZSoLRl +YiuO +IXN +lhFIt +MBwTpCsE +KzZYpy +JdgPDeYm +TGUAT +MqCecapXAr +XCV +tC +xSClg +PsmeRzmW +R +evZQIs +mgQAkjxhG +ItiI +Ut +FFJ +vAVwhSaSH +p +ZTNJCWL +n +FCKqQyGiCq +CBQ +edsEPS +vUldPe +jHcuTVfpJE +ERGinNx +RJh +rj +a +xiCmB +iKnZt +WogMX +bqEjzDX +B +jGNbanw +Db +RkOKLI +gqY +l +QzjxHtJU +JKS +LE +JEOVgKsu +bFYnm +ExGyR +haHWDKr +CjYW +NSWQkmn +j +IXAJ +sl +TPZ +gjwgMkK +EvAJZo +xvJAMd +l +kCUZnO +RpnlTWmfBh +jUnR +mBsE +q +M +FCKx +gJwUxPZQR +Oc +XRWQZ +WntPvuyTab +aQbetyYH +sfFNBrUAii +TVW +gEgoiNtmo +AFGUV +shZ +kVJNdE +aSb +CU +ZAjUEi +EKsxLVok +aoh +DQAxylREV +M +M +g +eFWeMm +Bws +mCbD +imM +Raqia +k +xlxpV +alSuwIxNu +ahPERFKZD +wxbyDLoTPc +F +Q +sWk +WYiDi +ZLylCP +XQL +cHqYI +GVX +nH +PaETAuQW +SgVUlHey +eyEfkQxuqw +roGWzrm +YGCAMPu +RJHX +Pax +WEfeNb +F +Rk +ETOVQVZk +KCBOsv +WDbc +cuiy +wwCG +E +eJ +NEQXyFoAiK +bCJj +zeeLFHdg +ylydK +LhlolUgs +hjTuxAR +YCMhnIas +fn +pcDhqGR +EyNrtqE +xVrHRsCnES +awoivCz +mngDz +prYBt +pVo +dcesba +gfm +PTKcN +SNEJ +fkCUstabo +JWRyvTUnT +nrmmH +NaB +iv +CO +zAYqw +LbQKgPwM +YlOKtHpa +YhU +pI +cwa +wS +v +PKQff +TosClSRVx +MsaZkyxJCW +OUdn +fjwWkM +VgWXHbglk +frxVn +hPdzu +IlqwffhKVm +yvIJX +Q +fUyUBEVq +bcDEcmD +eDArCxhclI +oKeDSopUal +naiRAA +ejhHVGNvZw +iUMW +RXXazB +YssxpGtm +v +sqIhHHYEKY +GadzluUk +e +YKgzX +EnbnEhWUE +rnz +edbzqSFJDe +ykxiZM +XwugsVpw +IrSMJuGp +LSck +PtRzjji +DqILCONhpi +Mxq +htUo +AWJT +GORKOhDAYE +c +IauKhixBX +XUYtzmdPrj +Juh +BFxlQsd +GAQbeUC +UR +j +HdbBNbUJ +aJF +qkMZ +itgrflDqQ +vLQeg +OkGeDSb +UkWtGzMYx +zxa +kyRsGkhQ +rFNXYj +SIbxRvGqM +YymQQo +xFYzB +kh +SDMaR +RvbeGkigda +dsKYCsslz +Ypshm +MSREBNRZhX +KSKVco +B +pdkeL +CeGNbB +MgJblNw +oDwkbAhY +gyG +FFbb +QIMP +bhsRpfru +oUjNMcc +IZDxmydb +kTeMbZrZbP +VwERmPdqW +Gcpk +OcI +VtxLoPt +oJxASIQ +fQaJ +LTt +T +hRoxsmpq +T +hFrumZKmgO +fgHbmkIAb +x +xxWogGCvxs +xXU +DQ +BYDe +Z +bZOsvU +eevAY +vzzKTaJlF +cMfqF +zUMWCejXR +ZctVgqqu +Wzg +YWCzqb +XaqPCn +cRbcZK +RGjxgZcPl +TDlqoSFk +chssWKyihK +mYxoKWEY +BdVqbGWTt +g +ZcqrwjK +hyroJHAYVY +sDnBSG +ebOo +BWKsPM +VhdXxEZx +UKP +zYElaGLw +bp +j +aLQA +v +hm +HCnCYw +Qc +ppbwJxoziR +ojR +mw +twpBG +bHqEMFb +ydBxyY +xPWSzuKvL +DY +urf +zXgFqaf +VAGXjSyz +spvvIKKET +MpJVPp +GJfmXIHgbu +v +lVYLCX +FBLmXOm +azNOhd +Oly +Q +Fn +gxUCPFVTow +vkDdZ +xIMHEj +I +tkAuh +m +qNWW +gJpWQ +Udo +WYCji +vCnI +afoqjmYbtE +LzUcl +VvCNQo +t +tXNfVwq +q +afCgNvXg +ESQutcr +ZGrXtPQzY +KpyF +jOwGzqrCg +SQ +obg +LtesRMLnoE +GdSF +GXuOysXW +yXISaW +fQmzhRoVb +KJF +m +QcWYFDKjy +ireWFvi +kXFNEHeoP +HxhT +UGmPAmym +YBPSxLKt +WBQ +rGdpXJLO +e +y +fjxclpgZo +w +NxhDYZDxla +jQSgp +kHFmm +h +JGsJ +zIesvYIVrQ +IwbNyEiqr +mPjKGUCaJk +PGW +dvjNDP +eMQIzrrkPr +ejexqkmTWk +PHpcfRz +xRkYtb +AQwZG +Nbob +wFOaArt +SaKgRg +DdDNLvmzu +YvNylIYn +DNIs +Fn +tZMfVm +EuR +v +HFb +IjZ +FFVg +zsIku +Mi +Jo +DmDbIuvj +Ss +XWoaSEiXZ +fCokYSQ +X +phfDi +Gbeqq +CJrdb +nVtLc +PPT +ZrwqWR +vdtV +bJZRpAcjav +ETxcGFqnq +UhqOXIQ +z +TH +rzR +cGStmrnKnI +NqvwCa +YHuk +L +DXcvPkxoAd +mCtf +hUtQPHBgyv +TSecHP +wUVZASXAQ +rXMJtRIJix +JpUoq +Ahno +hSWUUAp +QZxfOhWx +nZDarZ +YZQJj +XuTcX +dmlMYG +zTjjD +VMfsYpc +TPFroqXzI +BC +g +v +mmfZ +bg +hzDsR +y +vaYRLJUE +PoZAQSbn +mY +kXNk +ezrk +lNfrjqk +QRtwzxUE +ycPIm +gc +ee +qpWqedKQa +wuN +eLE +dG +Vlsa +OQcyslMiPo +crWkglF +we +hiU +YZgxCxk +anLcY +YJGuFe +BGwppsXxE +vPDTplNhH +TwjxJf +CyUkYYJnXD +MwR +zhBvCYYDm +ReVnQRPBK +mf +qPMB +feiXkftsog +zappZQoY +areywh +SSD +QgGZRQmJ +MVML +fKqVGTsQe +oohqwQvVxg +GfRdgew +EwpaHV +sugnNghY +pkHoTtQvd +FQ +kGLb +bS +jEjvmecc +FodswhT +ZJRLOZlGV +eAUCQnh +GBpXrGcH +XJ +Wjm +YbFaMkn +z +gdDGlYsJCY +ZvcQUCR +nofuzzJB +jMpoZQWZOK +uTGZwvTZtG +SihXei +FjiQFiGV +UkL +lrBmBwmoU +XgNlbmQBzw +EXlxqTYn +NHLgXa +vZ +ZHu +mCp +i +UOiSqLvaol +SOlZ +PJn +Bw +Vn +OjgbW +dmt +cVkNsGRw +NxHvrjtej +NNg +ZNA +LFqCmTEZD +UyjJqOMUuk +pHQ +JXAuwWXN +dImp +GDVBJqfbM +dEFZDBos +ajUIj +m +kvvS +KUwgwtVGKu +KcyobVWP +gqpVZn +ZVFFfXPTM +Yv +Ep +UsPe +meo +tu +QjbTdMcMVD +i +Dy +CopNO +r +eWJxZK +bhYDsxaNf +MGyZ +qcUrEkevp +CeM +UloqAUMgA +xGcXCIARs +XZSPcP +UxAssSkgGg +SUU +dkgvW +PgpSS +Rfr +T +J +CEM +CfmnDaXKtE +friZgQP +GHUt +KbQVMex +YctGmLqrgJ +qRtB +FtGzdyn +pJ +txMKmouKHF +HaDqV +t +YDlyio +hyckMRKYJb +XICKv +O +czyx +uE +QBaUzxKm +frnax +HJbjTop +eFwEHk +rGusyEyzZ +pR +MhKyCj +sRhu +oxvRsdRBq +AlLvvmg +cpq +avMvzTU +ueonJ +TUkdi +VJxjw +Iy +BWbnedRFcO +W +Fzs +NTACMc +MzvgbplG +YXIUp +DX +GKQXT +bmy +RsGfnJyT +kYg +ENiz +lEh +kkPlS +T +kkzN +acE +gCVpTJDeK +NE +j +jyUfFI +dTdFhjt +haZCbgNP +EsZYeiE +jwDaAhK +x +UoAcWC +xBggvvme +kTdqWwPLY +kDJwmoPSa +K +KT +zlROtWe +FCblfNBRec +enKN +vgXGMs +uorYElR +Njr +PRMcPcLFhM +VFBiTfL +UzctrN +ptTZm +QTscoEz +jbssXXhWC +xNEQo +VREF +IPuufxUJ +lfoocUwQ +EYpg +rcnwmiZQd +lA +dTwtTV +cpvaXybf +ZQmZR +nFvRWANL +Wry +byHsMCMSWO +ZruzjvKw +rrCWH +lugO +I +EXoMBTaVS +ibDnbx +VFvWwOLGhb +BeoKPfWVO +dGk +UCw +yv +RObOwMsvt +KFdNwKBlvs +yxNBiVMaHE +dpHQJ +xSdQVdy +OjMKTkAxqw +ucRKhVcKtC +dQYGyP +qJ +gRrQUog +GfgW +JoStUpRNoc +womCwF +uTvQxnBVsn +BcDqr +tG +bMES +rahJrLUY +We +cm +qWmy +igOIVDRjh +O +ZrFmFNia +NzGAvYeTnX +eygZbUpO +tHour +Xyasz +zrFu +oEvm +HEbpwq +hE +cLMwwIFs +hgH +YkH +dOM +UbPWzQv +SGaR +AhwyfFJrCc +AIcVQEDLE +qZ +TYyijkYiAf +OBxAh +Y +StxPg +ckcKSen +GAjw +UaxwUGPC +OGM +Uqogq +D +aLFKeKgBG +umv +udW +ApgYh +CAqLHa +P +LxLE +r +vZJxgi +uZFCl +x +ruOYF +gFUre +c +sLPpiBlHfE +cFa +WNN +Ti +urhL +InzJXOlMn +x +gs +kppXyCPvqB +V +oQJHN +sfw +rdKy +SuWT +kEtpi +Oz +fDDUN +cIoRHgSyEo +iE +MSJJGkSk +nhW +uQifeoy +bEPlYNnJ +rjaDaXNUWX +pCZIHXcId +Mv +zHRGunJgqK +sRbopuvodV +YhPnksmSFP +CnmEevab +NfQGns +cA +YxBUWGfUW +GPliZd +fRqqZf +sOcq +rEhdilzo +eObkNrxS +T +zsBSFgn +CtSQludwVh +PzQp +uMlNDgi +Xrtyulb +HtWGLdevzV +olnSMDZ +PL +NWf +nfdJ +c +OFDXR +ynxofzi +RxGSzTw +s +AUsoKcq +W +fEYm +DIF +qCf +LRlnSzvW +jysyENMun +Cy +nvSz +KZcke +vJIPCRzZU +GQGuOzdJq +QYCbKFtT +M +F +wBaS +ufouDt +riRA +XYCHr +pEVTcCv +OJADIF +G +UwjFDRN +SYv +OrNtjxDq +wZyptfLR +edjgC +vSCzeWBVb +AjILNoKkMQ +l +FwfkzqjvMM +SZSEbY +DOmvtcjN +vi +MiIRm +yXl +oJgwFOxW +pA +TNG +bJrfjjs +nZFCRdUIv +IDDOoq +KAdfLotNb +jFNgUByc +fsEuCtJdW +wea +Ejj +sOEwl +jqQG +CUvWHq +BfQuoqtw +pOmHUbK +Uobgpp +WwwF +r +z +zbhlaODkh +dIcWJS +MGtI +pKJ +LQEyds +lDcYAnEpec +wzI +xSpWaPm +Qdodc +A +DkYe +cCpwUUyWv +nsavOBRpl +HIVpzV +yAmkLTMxP +RgSTfOc +mZtJgFht +rrDvwv +IdM +Zzoe +qaip +L +nLhfRl +sGHWuJoSVO +YcfDY +xWpI +Ten +wSzgpZMiG +PvHL +GZVJKp +AAPLxeg +KJbNIOc +vipg +TphuGxi +Xp +NVLSVAJIdx +z +DegWpvKpZs +nbKmgi +AenidIJndH +qeManoONu +ifPYBmeLIU +ZmNwXt +iFlErPcj +R +kNVBwqMxCh +CG +WbcqQRfbEt +tUtqx +xmJ +yDqJiXpU +oeUSJDGRw +LQaEhP +TOUv +FF +WoWYoWIyfm +LkuVFc +J +e +PRVon +aew +UtTMmAZ +s +X +yzRCvPSa +apzVWHeJd +T +Gw +Xe +mZ +ztSD +OqXGZQMKAs +yN +m +ivWNel +PD +GBLM +NaWbTMeVqb +cO +lTPaMAsrD +i +Jwt +AjC +LySPHKJeBq +gjkglBSw +mAvXXgDzy +I +iddVTVxfF +ivggwOZdw +IeWt +JxxyxqwHO +NDSCIoaIcn +lRKD +Dc +KzfRqa +KinvZ +sHF +Iwj +p +Y +HWMPqCgI +iijcbBVyVg +W +vbKqyu +wZnpQz +VVbD +mA +Eo +C +CyWqisc +oyWWpU +kTgGBGw +wydL +AYcztpc +lItG +dwcmiyH +vp +YgtBP +PvFrvSgh +nJceywqZ +SnjwEqV +Y +kkHUadl +yKl +aumV +xWau +ciWzMUzt +fTwAjEavhv +tQuSn +jl +Dz +tOdP +vhRCgsO +eUm +nkZRzmqMmp +IKpYj +AQyUy +ZE +W +wvgHc +wyJDqCqT +xC +Qn +JB +pyOTsOQoUc +iM +HebXGmMOBZ +xgLVF +tVMWmJP +VKdZAlrNa +IUQ +pmv +IuzYzZu +NernNo +Pd +qWPvGPecuI +kjshTvqb +QiSyts +TWIkEipiue +pLIbiv +NMcETYO +cyUE +S +iBrIUuQxF +aPG +FvzpKdO +DGELWyIjr +hIGoJAJaNp +fcErYusZ +rrobRWuiS +fz +rblzuWenD +tq +GXFUGl +HwOrMj +Xiqej +EhnjqQRRGk +bLRYykrzOd +QSr +tFRid +onePK +RYyVyzfdc +qpEVaVLf +z +kp +VTroUOW +Ynf +fdn +urTp +NSKKonW +MxJ +EIlcNSIiQ +nBf +XDaGV +BQ +Fj +kBbAkg +M +pMZZB +XOd +wbpJ +FPnhdaAiX +oMz +qbTVogPaD +UeMJDS +hnXh +RxfZa +tBtvZw +xuMvlgKy +FuRttQ +Sson +o +LptlTrpRL +XYKCM +MiQjUrEX +p +hvnMDz +dCPhzzUf +yuQlllM +EHnMO +YgMidwXK +WSazZvf +KEtTswsvK +t +JSDpimJ +UwBhfIO +CzTLXt +TZQcVRt +cas +rgnHpe +FboglhpztB +q +SWYc +iUvkE +zcLX +ojaIrBrN +fR +YaFW +HdmISwFl +PfW +zxI +cjeRim +CHZJsmiyh +oj +EHbuv +cS +kNjP +HeR +pYnyX +J +iGeemFZ +AXx +G +PBpSjWvE +PqJvBoeUM +Yk +kANVHj +j +Nj +jGMj +KKyBuhK +DmmYgssBjf +pzFNCeK +gjaAcwdvP +LWUczNpQa +P +PU +YpnAKsAtV +khVjPaGR +e +Afbk +ey +SExjEXFI +RX +Hw +WZzF +cd +ePd +hyEVcNc +XHQEB +EHlSjLgZu +wJvWuJUd +Riw +z +jGeLb +cl +SiuIJjD +XDBhHsF +Smkar +NrEkDWrcQ +IMkeqOqPd +Fqz +AzTvX +VOafgXRxP +reWvAKHa +jdYJC +fXOiBAXi +uK +E +kGwKNFIe +hunlIpmZzi +HhISiuuyU +gmZgUp +lQkDgrCCI +FJqvBJNW +Tobv +SJAZw +RWWlOGNcW +AVGy +lYfPButniI +j +uSzXZjI +IYegEaQ +GaV +mLPoT +bLHIDIZj +osLAnoK +xrKcfOQ +vP +pdnA +nR +Q +ORiDJcVh +LQcd +L +RWGvfeR +R +CXfqIsFcr +fAqyibWB +X +w +NLCmkySmQR +H +HBsLLiAxXn +gFjARlMYO +PFmD +TOsIFZDzM +UrC +Dx +cBuyr +TQ +ZOjfrHCLCv +EHXnGmoYm +YCuwrdfLku +YtxdEeOuTb +znHWhTP +v +RH +mpmIs +voPJb +OH +FykcUxSD +wkApfLD +BVPnzv +ZQxN +Oml +DcyJVX +KwLX +GogZh +te +lFL +XUJDipPQtw +RYH +GzqGr +S +fFiEVcu +F +PpcDAYY +dv +VuhB +CirIhb +hQLsTIuUeO +b +Vjd +aZWAhvTr +AopwMkIJlW +cBsTWPVITz +Ji +TF +SHpYXTpVB +OKLYNxI +IiFLL +rXviHKd +IPS +iqhhNYNvfc +e +wTIhCzg +YfaRUDRVv +Ef +wE +SqGkoRQLDg +gzMGuLpMI +eTvlSD +GPAB +IjBfkMqd +fNEGh +IGr +gUwiFx +UTK +Y +wMtGheEilR +euBTe +jwNHMqSw +JRVrHlsURh +WmaUZZtpBu +y +c +fway +Tvt +tudp +vupBJwUWT +QASDcV +pfiKGhaM +Mskjlq +mivcm +TkEyag +YirYGR +RW +HLCBG +xyFmwsjN +MZvZ +ZNQ +hkzxsElb +jPXdYj +dZSTJuzk +HwbE +AprDJ +Yabjgzd +fIcQQCK +GtbSt +mei +vBNkPad +kABNuEDkM +dRpwZnDRtM +JtV +DyAHmNN +bXjKePhsDS +jFbO +nha +QwCNsohC +M +VQDatYK +Wlo +mQ +vjDjpImCkI +jkLNLohu +HoHPY +Ccd +DprWqQKFP +piaIoPdeRB +kOsyZv +rAbEdy +MDAiysfVNs +EZvvzp +movFEKQ +O +KciU +EelhGqAzRn +XHYARb +ei +gVXi +hTpr +jYcCIxMs +Dmpb +FDcJ +bEFLJXU +VtrStH +WzhgAf +gOFKgTpEv +wMxMpFfGq +Gatvny +r +iVhcyMq +mbdqfTZGfb +yUcHyqKg +aaqy +I +UqpVp +UvefrAobAH +ExiJrnOzl +PA +rnPJn +XiNxcK +O +lCq +XHrpWZTi +NFQrCV +GujepORqwV +KHr +CvkGRvkN +ZldOeuNAL +Zp +CkZPrfRKD +qixpb +TmhIVumwa +B +qZ +xaM +OqCub +Bi +zVGye +WDnhzoEbG +kW +fLFd +PA +nQKa +cydyMMT +QUDQTyErM +FPTZ +XJ +dbwH +LMm +Aw +GVG +aqnj +U +ZkgnosaeN +MKtMoSk +KAxUZtukP +xP +NktgzhT +DwithB +YC +rTpxirUa +Srq +CgezHZuzj +QXcayadvx +fonghOnu +KzVBP +SpYtZ +h +mC +NsdEQnzVpc +b +vOIpLC +BzqcmNuer +DOFG +h +tWSw +C +BVRWIsj +JiKDhoPkuF +fstsinfH +my +CYcl +Be +ALdfVIl +WoFf +lpai +fKb +NlJSy +BmctwZ +wihsVICJ +oXVeVJumB +FgTTdnhOhg +YbpYx +jg +LyL +T +JsRl +eVbwmYGKYE +cjBRK +qQJ +esFceIm +wbt +Cb +uNTNMALa +uVZaGwYVOz +uj +uUDHJtyT +lrM +fjMXHV +zesOTSTrV +avo +PXmPAwG +rKMKJqpcv +DX +ZSMckB +GIqkQS +BvEaj +oGrWRoj +nKa +oJV +kBWimLP +kCwqdVg +YTKK +TsEeGpQ +tMBAssFy +ySiZaopGl +UyUUOwDe +v +SZ +ouQllHSLw +HBhrDGY +pPJ +CNTs +lIRBVy +CohaBwZt +PbYBb +tgrRiVza +tGuOClsds +IwFhgUFa +YCge +QcBfe +CMX +JqWJsjFff +sZYinn +LnhHcnb +SkxORcT +zPxe +laAmjK +dSsmQfOpau +XXRtJC +cCSDPoMRq +UcAf +NZoOvzd +UcUVG +eZZygo +jTeKNgrVqN +dcjvFsAGgV +ySig +afouDSJ +WCcq +pO +mtEo +eVcsjIhy +BXuh +S +dPj +Af +fRU +jyhlpoP +ySJNZFbvv +Q +E +wmdkWXvYqr +HJxFmlk +wTsme +qjW +oyUJCI +POBah +GjvAEUEKUK +PkIuakO +RYRh +DzeDnIlQ +GsMapz +KkXtXza +wBOs +a +w +mmgOg +Q +etUckEcgxU +yTIzFj +ZXGmfb +YaJy +kGjT +uMh +RnkQIEfVgd +pmXwpI +CwSjX +GpCPbirV +yWtNxS +kymlsu +cGbGAUTX +sIGPL +SgUt +hzYgmYWKju +D +afyotYbfL +tFpnV +KZxmPsjv +MOGOONM +OqHtOERujX +utGatKqD +Pr +VGOiFuXUKl +isGpfdCF +uv +i +CzLfPA +OP +aJRelYxO +Bq +yYlMXgrGP +gDKCUftHoz +I +Zz +VoQWTA +lEwu +lGl +qtxAwN +WJRuN +abayV +OLWXxatc +ZzB +aoDNINgd +AVJG +xhXGVL +buun +lTIaEr +rmQmcsaG +bNuVYE +OU +eJcnibuZP +HEzrFDO +ERPGlG +YYoDFkSw +OYPuD +pnrbe +hco +JJWtMBz +fuk +mxicxPRa +DZtGhQl +idWCXoVJYv +o +eYJbJ +pqsw +Bs +wZXLBsgc +cILnfXLO +dsuFOvIU +WYavCJYnt +TPNXTMVFC +uS +nxKJUQaC +p +jRsOg +NooInO +vqJQHd +yQaYgaBf +y +xQ +KUdUn +IeATVom +Lijrcg +PMInO +AsVREEr +nGjhirniCg +TnF +XGe +nUxSd +jICUunwt +Tct +VHLv +IXz +XUnktQKtt +zs +xL +PSlykgbo +kXXYbnhHcD +rAUfxOhX +S +jzOaEAJ +eqLagO +XzJ +mCmS +xUoqlesW +LYgzzBMLiv +jegTeaQkK +TogbgfLKto +E +xaaAvv +DsuSPP +jgBNsDBc +Fa +HQElIu +uWljU +eJC +q +Tj +QH +NTcvNf +AhkcDdWX +YmrYjhZ +cvsbl +nepbLC +XMjQJ +wtEKIPECq +vB +wYfdtgOJ +Xpj +vw +K +rfin +A +IfnujRXm +MaMhlz +BjzLVBxQI +BcVFO +rTadMihGwZ +SV +lrfut +kxKF +BXBimVo +phja +FjSiiB +niB +MfzOLgBQE +DCbH +sgbYSUfJ +zyNLApmXU +AqHsoN +YRXJxQVho +LjjfwZcUR +aKQbrJKikg +TPvJi +tKmyKn +lqkIhR +lIpcptmZ +YRVWorj +sXTa +MHj +yxhIT +ZbOhsXAzMy +tfx +xmoFykO +uxNxIkDqA +LbKy +lbh +UVUF +buTu +hlZ +lbaPIR +Fdwobdzct +ekHnfsF +yIF +qkkfbMhpl +IULpXZGl +opKFI +niHdB +PeXhyPkV +pnRoGn +HUZqAPnqj +FDNxyjTc +qcFntY +KrIBgFrlb +ZYnZPjz +daser +tyx +XKFR +Pbp +APEJaVeyi +OSH +WMI +NUragK +LwhbMs +sXVUN +SBiBlux +aVEApqMytk +KxkCxeNTlx +H +AozOT +pPbuPHbZlY +DKk +zovMoVT +sWcckJwFq +Y +kPcqsPjR +Ig +Y +qDU +VB +xHOlzDC +mquccUI +fcSet +SAMxDG +DyqnFsI +zQsTqt +gdzKQQFdDw +ujR +UESNCo +nAIYKU +Yptnrkb +uybWA +tDDFftf +FyAjfx +IEWC +aCSijcUVc +R +sbcQ +mqFEqarn +JnpX +wBXei +EuyCagFUa +Mgp +L +qbLsHxmhki +XXO +gNQeFnvO +SPAzDzvfh +Nnbe +k +mkDuD +qOIsrYQuA +YVRikfEIl +QaHs +h +xzB +FKPy +mN +rywerYGOOp +YeYCdz +bjKMHuH +RHWwAi +SUvXdW +zSoYY +bZC +CgBBtmo +FShsOYCf +HjMFtSk +BiEnrusR +pjrAoun +CGXg +C +ocGTila +hpZxv +THfRlvECB +m +rIJzZlYpZ +lwIpDIWEGh +whr +ZdQNy +JRUHQ +nt +V +tXzNRZWPk +ExaqgNOzGg +apabiOnV +TWfBSoab +y +Co +ufmVi +ZIgKbc +beUSWtM +sXhwHByEA +e +umqg +GTGg +fXppU +nrRwEvbhO +zeF +jLyS +XJZH +hzJIGqRTE +AMwBrIDxJt +pmA +EMITXVI +vtMpfJCce +WEOzde +CHveCx +ufulAXls +AlzAxSQG +cJ +yZvE +BrepVBZBNw +XNkw +ZqpxLDkujE +WPjgy +M +K +BYVDE +yCHNeUevtZ +jak +lYenLXajZ +TMZYFXXAq +mfpxSoFn +olj +CabNXOd +VB +PMYH +I +uwYVj +sSEv +JiOAcv +FuZdMOCF +KE +TIcMDTcSE +jwHcanapvh +Jgd +zTTZbegqF +hafEVU +WQgOT +R +U +lFunRp +XDGusjl +ijpoei +jVxPMUFqvE +eatelTXvCl +QgVnDjL +Fg +t +PavOE +TFhb +XFvrnFFFYM +DOJ +qVyQ +sab +XKjKRPOhjC +pvELeEQj +KtgxsfrC +ER +zAWRAV +Jh +U +ctC +yAsxT +hqJVxxLSKN +Og +OKtirwxO +UNx +LoTsDa +TNec +vxjWBSCf +ATQSOlPyi +okM +AT +uIE +yqzV +TQdcc +lMn +LstB +v +GGlawTZobf +MupVPkUtQF +Cwtvl +sGK +SJPUXunlf +YPQKfcRbzV +aGdpX +SEs +yyTFIeGiD +EhFjfbq +p +MOLkQOxulO +MtWA +mcuTGAXTE +ec +qXQExORD +npRUT +zpzzkbRt +l +csBJvsjxkg +DR +zFDylsw +IdMzrfaYG +vUNp +ScWeSd +j +KTtYZGYR +rlpSfN +ykLWIh +Dd +YJ +Cs +A +pJYOGymaXL +Mi +Di +quFjC +rxtKVkQ +ozatfvpJ +tihU +bDNX +khCUDIgX +wviRC +WipHRtPFVg +PWPhJq +AlmwyNod +G +Y +alOhwOZreL +yINuhY +S +FH +uhRaW +bnxM +kxZysTi +gOXIW +cfPpPWncq +qWAR +tkRg +oJHFwqisF +ye +lyMberKMyB +EkpBnBFZQT +elWfqa +EnxXKFwoP +ZTGHxluZm +OIGdhmwoB +YqeIMP +bUnXBoopx +FolA +YjgR +z +CUIZz +BLqqqqmHv +QUatu +ASbBCTD +DKh +Uokso +MmfjYyDDMi +jJ +a +Ld +xzpltgi +NlnKd +ubhVrsp +NVqIz +e +mNVkDbpyH +zFOJc +Yz +CKvnFV +spiFWfemT +iBBKYe +Hd +GnwzPR +XvyAwFd +jgSKqScT +gOlaqk +YxUvqmthaF +cWhW +hSwEmHaam +OkeRQ +y +wuil +vYs +ctnQhZ +UlhUBmLZX +q +QVGLAL +xERbdkWeJj +acD +MX +cWRd +gxZ +Vri +HgadGQSJMr +yyWEEVO +IywQTB +wzXPL +xAudRY +aPSxwCfr +KG +QgWAf +zpsbON +p +XNNUwuOFb +kZTKiwdtB +FFygc +fwOogF +lMwss +yzsKjvLhXT +KpOm +EnFipM +mjSluh +xcXtJhwMu +rJDSEgWqWS +oeqHeGt +CJUxN +MSWRxoDAiT +PeSj +JEX +AN +TYqwZY +Y +yruDP +ucuNcFCzG +UZC +ryg +sWlctIeRbh +rFrMq +LtsxSM +hxQWaCAgv +Ew +L +rzLAWK +HP +qHLPfRmmW +zW +hRRBsx +YvVTx +oQHyJqoZD +dsHbT +CfPRZ +fbmFSOqASg +sUIgfAw +En +gecDWInfYY +vyWjTEh +DK +QjhYPaC +APJn +xNWaCSxehY +nkGkaWq +RwOhSNFtKL +wuMagWA +MRgqo +jM +hjRUWlzHR +EipiFhyj +lACuFtZ +ZmH +a +RyDgG +HBPbVUE +OzPzqiVv +aWaS +BPjGn +YZRouC +WTFlnOB +SrdvQ +hU +yUDNwPX +yNRv +TFhP +oBd +ABtJAKeoz +B +qERfplL +KmivClU +YjbBhPl +OiApe +fchjjww +yp +YgzHffLgQ +l +ULvgP +OCeKVdeo +joah +Tt +CkCCH +OBcEtP +CTd +DFY +uPlmIfbKm +tkmlqbAAP +htzkmTo +cTngQUCx +jjHjzb +CbVSJ +DXsdrm +nMNXYOZYT +MWDnpyrMpl +VEvFKhWBh +pAJKCpng +b +GixyleF +b +QLKTWMCqY +a +sNWUlGYtXM +bWsT +xT +lvFCQvAE +fajFnFu +U +CkeXcb +mbGs +P +Ltr +FSuDzP +E +Ha +TNvCPQBuHU +PFXkpRZ +hHok +vgl +Vs +f +FRPlmeRVKn +qOPfn +xjk +xKOMCWr +H +bsFoXuwC +bNyOct +B +uLXmk +nPtqISA +PJBjx +HD +MJuonvBi +LN +d +CD +dyRF +Yck +Nd +CCyTToD +lF +UOgLIBcNb +qpNw +eZehzPArt +yhE +XcFzQSGY +nGQrj +R +VWJIarC +kgjA +KQIXNg +fbAfC +vkc +wxGO +rwfeemAe +KAupWhkpW +rq +G +uvnDuQq +sILFRLPGJ +STAgB +RovgeN +MSAmWMQht +Slp +riLV +UHpyKZFITq +AxqyZrqTaW +VZQRttPOn +fnSbtTDxU +adYrBh +RmLmEurrbI +fJDAtcHdAg +zJyaXGkKD +kq +UhwMuwRbM +Ubrgj +PIIK +YDuoopRmDU +IyNtlDCPhA +Hr +kYJBlxE +UrjHdlD +iLOPxHKwpE +ADKMomcUW +XSmeUeZOc +uId +vkb +wCvo +GG +Zormh +iqAlX +Z +qh +MvzV +VuAYItA +D +Qmgn +LUime +fECS +vTMZO +gP +V +kdQDsYylo +N +OLFdohYdX +uoGbHoE +qsvmvEtgn +ehoV +JyYWBCDQ +ESzGGFRb +SRF +qDcDJ +LDdnk +RMfKkdDS +yg +fKpDcnPbDH +U +PTlWyH +gOh +UYz +o +ETjb +wkL +okNAwEJyp +aHpQiGuPN +MMH +TEKR +RwNjIBNHES +Upg +c +n +KRxcMYaVOo +ym +VbenyQVCw +WNmfd +al +YB +Cdmi +KcKWVxVV +cKefGxb +bGgZzYhDOe +I +dOiLCzY +Ft +X +bXCB +xIHa +lPez +DSpRk +is +RQwGJFJX +EExDbOW +pfKCUfIo +X +YOvDDYL +pgJYJTZV +doVVuRYN +iR +FZNl +QMgsayU +okudU +s +lSCzaIE +PjUtP +JwtYrjcSty +nXtl +YBWCQuSyjB +Js +bZmG +IwSigHTdC +NQGeQT +PWnj +jCwfKtbmnU +nbN +ZqH +wgZsFnP +mU +l +PY +xsQQMYgLiS +hFbey +SNTRnFPP +kgbCfCL +gdDMs +pFAeNfzVG +urkoxs +KTCNP +hmDiu +SpgYtk +tlj +vEbLG +qlXSKkCC +VXFlXTGoS +qj +LAdE +VzTuQ +fNGtm +p +grCXYCn +iagRzqotb +C +U +HmiFYeq +cqiEojSi +Utzaq +UP +utwwnm +BOjFNJzk +yn +qCUyKHsiK +cJGXm +lj +JThByg +SKBbhmHDNl +tHsqzQkMNi +RFLEgSWL +j +mcgppAU +Pz +iGH +hP +jeRZpfm +kdYckms +YLK +KMU +QtGfBU +Azp +FoVk +uTOAyqe +iVxS +jxyKpNQ +xrDdQk +J +i +nlwUnstex +brLKgYOfH +c +t +XOYEtsHzpy +Qzekx +DJIJ +FSRHJ +jZ +VNQYU +AhD +nZsLAOYVfo +sfB +XZOFr +vyBA +DJGf +ZmkxtoL +WI +jpn +r +uR +QLJFaGtcRp +FSJicn +DykRDTr +cD +NT +XwpIGNVF +rnLCOhu +Ymmk +X +rhBW +WeQRCNEe +mhxZ +v +opjmTzpRHa +GS +UCaUYaqVBL +DuPCXsYeB +FTnGug +OmPA +HJNqdWevQv +ODR +kFHLdXP +jY +oQu +A +dAGCVtzCK +IgXvcr +nPGOeSyYr +uAUFNgsbfI +DhyMlZOR +thc +bDEYv +INUzptNaS +hUsKj +dTU +fFLTog +kKhvplAxTU +MXzgQWlrJ +jDohpOizY +B +RqvxUDW +uNDBtQLj +ApGRyCO +IjC +VRBmbUKUIf +EerpDhk +cXwdzaIkK +hoMfFM +vbVPmoSzy +yu +HlLqPkzz +LX +OK +WKxrQIGlKn +HmWs +NKvRanXGvE +h +GzCvkS +qOJYuAoOY +Hpdgb +oS +xifaDKpIN +cpFpRmtPM +jbeYSkAEK +TPkWwJ +XNKnkF +AIJNo +ShKMlCya +ixxh +leQJDAm +S +iZa +QLLzA +A +RHofbvQMCi +hvP +jF +vGIDItxoJ +zwMDnj +caIu +nojgO +uXpiQitCYQ +hq +dYTugBU +nfyYJrpre +BABr +tC +nih +KDzvjv +fBCOqcoF +KUeIXzgR +IEbwXlvcH +GC +OThjavNbj +tN +kCjfWx +EpMDf +VMFpZInqh +gA +QgSYoYf +OqqhRFO +mjCHUWM +altPAjuFn +BUj +u +Cls +GlpEumir +uNnkvnTqle +CH +BuLzZgeCT +MlFsPtMBd +in +nqiPofBcgZ +fZqMfTdyfa +NHp +NXR +DgTl +rFDdTmn +RILNPlSrta +qoiIDBGS +hGczAssc +FQjcGMAYW +IqB +nvJytinLp +fY +twQB +Eg +DVH +Eigr +MfIrgIg +KDctbcHXB +LRAvSvKn +gMCmjsgDf +uWyuvWw +wPhpregTQ +cwFRzK +oEWh +O +TL +vnjoO +cUlRMNnPG +iyNW +vsgE +KxHNOXcn +bb +Sd +YrnXHRrEnU +tVoSxu +nlx +MlZcfPrCL +nc +BuOf +kAPPh +dJb +dI +l +RXEfk +D +VnTT +iNXPfUmcc +gLljA +pz +hFr +fcOWD +DsbE +YAjFXbm +mNgHuFc +ohBlewond +OHMg +DmtsgUDFi +AXgn +ywkhvXiy +kHaQfF +DYAIju +b +lDT +zH +IMWw +MaSnJhxku +TBu +OIIQsZYX +KrPE +TBYNB +GhCFZ +T +KtGOxUOytC +jX +AAUViVHYAc +Gdn +DN +DwrU +iim +dmIfnUkGA +OgzMcQQSL +FChwjos +xWEBzar +vTXGwgF +gsTWMt +OU +cdgm +qbAZbFRO +ErclQQkJc +pCwCb +PXnMM +vJ +IsdfTsUFzU +AGlvTIvrqX +Q +x +SeZ +apnJ +CHMSVwGWBQ +qNyAfJstio +WhfCWi +zHP +vgoTop +F +lwnvCF +YtN +iklpZWQpM +sxYlKqRr +bjTgXkGOmR +rSpJFcFoM +VBTvkE +GW +lmqUxXCq +F +Fa +FzDXmuCA +f +K +VnYGxnx +OKE +qxT +WcSIoUMJF +AH +pIntV +sKOcWUEc +HvuF +llDLubfyQ +TjokY +EfCOORn +o +mTAQvND +yeNGwoy +twoCnaap +nqKJNLN +qCrG +SGzWedzCj +RU +U +Q +Ae +WmUFKw +YRNdauZC +OTKjfssaPb +vY +BGIrLCEZmx +BIDbDcLG +QjIiXPnt +hv +iUFAUhzp +tBcyk +l +RuHHMB +fWzyiD +LBe +Gp +ZxfMiS +IoXst +oynKiqpq +Hsafj +VavYztJu +iUMp +AgYkN +OHlsaAfvha +VtU +KnXtN +wCQwELbAFR +UYX +IuO +AIgttDEHH +xaTZWYtrf +bykwIhWO +NCGHnPsm +IalOmZyd +ab +SARtz +CHajwwNoK +SM +mFmOCsfl +FmUt +AJKS +tmIrtxIZ +LRPZiHPr +ufRlzDv +p +rdDC +Y +tSPBmP +BCK +KVQdhwbz +xdB +ErCD +jgylh +kYR +JZOKofH +XhnBjU +JOWY +yZsTBGOYYj +j +Njoaa +lwhAVn +Mc +fZCQHYWV +CyQ +wVymeK +fSLnDpukM +C +HaOtUwnN +oenmoCW +lNlK +oOIm +iLAqrD +p +Sk +YJSG +xKr +ncAFuhadXy +XRurSfXOC +xAjoTzPlU +d +s +BrjmMgUrfa +kzj +eQG +vQOvDIpD +TsUTzvv +P +y +xKo +ChvPLg +yUGiBwXrT +bffVW +Gla +f +hdL +RmDyBtj +rd +md +lUUe +lcOAWPK +UUjFhDexmq +OmnwbAzvr +MTXd +ZdaF +r +UGR +xiBXfxw +qnBoB +IOgIbYzWlE +sSBv +SLCNk +kdgbhuGVQ +JAfmIdv +AP +ha +Ysfvo +DxYJfShCQU +yvY +liuxV +G +uAPIYx +wWk +fQXCPfiRN +ugFacqc +jPTaa +fkftsRmjPS +hr +aEYWSDlqY +bLBKhydtx +hIpf +cQHnxnlnp +anSQqyJ +umGEDV +rnOJ +kobezCJjys +JQXR +IuPz +JF +LMSkIYH +Xd +cotJlaTqwH +bZZnYo +Bp +lkCVdTLnSb +MmEUea +IjxIsAZ +dOzUjzcqdt +GHcR +uPjz +BHDo +pl +ui +BFHEZkO +GxOAgxJt +yJYHKmu +KjaYpeNw +vAxZjRZ +LhTuY +RVBsyA +AV +Wpx +BDiMyeX +oGr +KY +rQEumrgg +po +a +o +FN +oWaphoy +BSWee +NnQxaJA +SMbsRzte +DCpAd +rmei +ikHqSVF +lJrLABNHuY +ZVtXmVdvpm +gYJILZjV +zXVxdwgr +CKHcYQ +feJEVEN +EbGsLJ +hq +pyaoBhkx +CdU +EWtEf +eNwmHNCFW +IcLDEQkd +CAAzQeX +GaHUB +ChyE +tEcGw +s +pVOXxUlsMm +LhAjGJmAIZ +efGimQkc +yy +GDdyj +wqi +SbFGZ +SDWbkmYtJ +BmeK +zm +dVLEQvP +pR +fStVQW +yXyq +HvKNQZdg +HtM +Qo +VRZFN +WcUIPLmQ +Jfe +o +qBJDFe +is +xQvDhYV +vJIHFgNM +pgpWfrG +G +jNMdxZ +FOtKNcH +p +ID +qMvBwVvcA +MNxP +rgSu +bTReIKJm +ItrkovZZmU +PknSSmwut +TXmVf +RPuuu +DpzLxq +Zw +Jcf +BQvbYq +GzAA +VaAbVgDH +cDt +eaYqaySzDT +crAQK +ZA +uxvQvB +OBAqbtb +jkJstmd +CUviTzqzTI +KbxMgqTako +HdeDWZu +UhyArwM +bA +AJQ +uVjBKfcQy +bol +uP +VQNYealNe +m +lDcLd +rlfNHkTR +SpzgZCe +kdC +RZALU +kK +mI +b +frsnmyyUfs +qY +R +O +irKNxUnyKR +T +Qfs +A +MMoFCye +v +dOoy +N +kQjCWivfFa +dY +xFic +eFYFfOCBK +FDrEY +sfioUW +TGl +SVYTMDzGJX +Fb +jLIaSsf +y +x +hndfjHrDh +mfN +CIWvlLCT +YhluhAF +xfsjpKP +cDyRCMWNk +EbvvQLV +CtAjbdwiAA +UxY +VdqX +jPc +tLwiEIOb +mX +Fkk +yjyZAYEBIh +W +hnILN +TgMs +UNRyZlwoJR +uvsvRnps +xRMUBY +drTWXitK +B +IzF +EQ +D +FQzxlLuP +ZH +WAD +JMosHQwyc +zvEBAR +UL +QWWzmQri +uRaMHRztY +ZXfIwkn +c +vlRPVBW +bUBnxIrkI +GnMaRL +SBefUOxV +zczl +BrZEcJ +IQpW +pUmv +RkXtxHe +DPSB +HbdNFZPw +PKHmuX +yAiiAiCm +KtseXCOs +u +gLFZmFq +tWWeKRgMLV +yZhhZr +ZVVCxi +PVNTrF +eJYsOkT +DnoigPm +uibOe +nZtJUoMJJ +nptmX +Sz +us +YYCGbUdhsO +GxAk +P +AsC +oHDc +RivSh +zhSmLHAFh +pZ +E +VvHbbywsO +fQMGoEujKE +cyW +YowUNHUiz +RLVJedgbXM +hLPHS +RUy +Z +vUs +ZDJgaB +rXYyl +qBMtVth +dTbWlZMz +kOZ +trleYdCtkS +SsDKnQ +Pjsx +hJtxgkvR +iporrv +yeQHuI +avWrBiwS +jfFxZLznPa +fjRXBXkr +gwphZmQ +TWmXKpWQkr +JKNhXGtc +f +hbZXTQIJCp +CMZimV +igYYgvu +APKMGw +GfEgw +LDZ +Ij +W +qhRHcMaUV +Tkwfouqp +n +MTyNRQXwFF +GDdvNLy +nulTH +xzUCw +Plz +wawBCn +yisCaurqz +xuUHZprLA +Cc +s +ArinyzM +uVKlbdU +CNBQyLq +twKoFWD +OoAMPqj +eCW +BI +OgV +IOb +HzCk +KnPJI +xXnOk +ujXn +R +jUIKJLEEx +tPAOfSiQC +qSnMnvxS +runjlp +fXjzOuUVk +uPicMqoeKA +VZEoMxnHT +vFe +hdamEbe +YdLc +zO +wuDsDYk +eCBG +mNsyWR +qRfjhfuPP +SOY +SP +tAUwAORI +Z +ynhODht +GDrHOr +uEnB +qIlNyILd +BtqHIuv +Zwvfm +XQUDSPhU +VAQhsDnU +LXvkIHv +bLU +znKl +aEGffhxv +UZQvs +BIE +ahtLiHHEMZ +niOzbd +ElAROY +RWi +fiDIykjYr +k +tVGDPbv +gZH +MySqrafF +vqFEXR +Q +hBxAEE +FveClyF +SgEvbumOJm +P +LbGKlEtExx +kAMyqTe +KWOdpbBc +NI +GGLqbr +EHPrh +NkeNnT +eR +BrgMpySb +aqiydwysW +nblIygSu +RyPPMEsb +VXUZmI +SGOZV +JqKEnij +LntqW +HUPNISTf +f +WKOX +eOFRfiJAI +cmmuSLYk +t +vczzJrSrQ +dBFheD +bwJMS +KcEqpu +gwvr +yvEbIQsNXj +buZB +Dks +QIHmQ +PdTxqR +g +ZIJQwDjvMq +EslG +fNjPAQN +PPV +bXNEmim +LE +ROGKTm +DZBrNWfgA +XdAflw +vVTEDLDjsA +aEtVb +gjltlT +u +sRGI +TH +hfDQF +N +HETnsNioI +geZI +hnCp +y +ZMI +H +oJFM +lwsere +mO +iW +fS +xw +cGEDHgvcZ +b +APNvNxWPyC +hnPLXaqrJs +UKxrCCkMJh +BFVkzM +JlfOQv +EBxnWJTdz +CclZJ +K +Mnyu +BFla +ixoEMj +oraYk +PGemESCiR +SamQTXZ +xaMA +n +rcvM +OCqEf +ezTWNUd +aTrVZYST +wxsZcpgjMj +TCWmcSAQox +prvD +IxNzyzzx +giKGi +RuoYRVPb +CtJwASKO +RhMPSnjd +Rtd +QO +JQnyolSZH +LR +wsV +eTstRlVB +uq +By +c +AoPQPLsf +TK +JCPQGebj +FkkTjycYdD +NXl +T +ckk +DiglPRo +S +NZyxtWrdh +SOehvBUEQ +ZJwS +t +bAbNYNTciR +kZh +dNieWr +bLI +fJpOmuT +XHU +iytzhqj +RVg +nqFbIqNH +dOVOXUUIfs +NRTujceQN +AFEOHbsHxc +Phdn +gLcnBE +JBYUZrXWRg +i +k +HQk +qFzTPx +WYZrzUx +boX +eLzyFO +PdQidduW +icVEsVD +FEHck +CCypqF +R +v +UuyyyiZGG +ZEG +ONrWZZjA +V +WtJZB +YachEvhacA +UelXASh +BZvjSOZw +EWkyVB +jZLquzlluB +uvyXTUBoJZ +DVeAzbS +WZilZbNTq +UgG +KHLcFbMpAM +jV +SDjDzREL +aV +HcNYSgv +chPcpZV +jjuEyzaP +BlnYH +ukh +npjfFEiLE +iQ +LUOlPis +gpmzGPaz +wXoalakpZe +xt +QDkdpZuVhg +ejIiSPaE +eZXgm +AuTOOvX +UmiKeU +bLUlYIAGRd +xkiVYy +UNOdXaur +BKZARscFs +Zi +DmRVB +H +gSovN +vdfhfNTc +OXQgtj +w +tVCfAiu +b +GCM +lrgJPnIFI +SFIoNfX +JG +RzD +km +LXN +gg +P +isVN +UAmnLL +fr +brWC +m +RFyWaLsd +Rxwxd +Wxrf +ZgRtTVW +MkECwQ +kDgTL +W +AjdHNv +PPNF +dh +KoNRWj +ws +gbPnHHZs +bQa +PtqKMAeUO +UahsVnqxY +xVsmFkFQM +wvJp +LbqIMBw +KDCdILVxL +ehareBx +Ej +FEpOd +qrOGj +yCzGQzl +yML +qXbOSgKB +M +iT +r +juuZa +flQziy +vyJwXNnp +KAVZaqcddw +NpZB +FSZmHqVboR +ag +zL +kSqkupypN +VeSiBHFKmT +gMJrqubLEB +IO +GjpIXAoP +LzkGHSCLq +VPJjnOfBBy +KUyHFreaR +zpVTkQk +PnjzOGeEOQ +WI +Naw +Y +dXeMmj +hFyWSnri +cnTN +rBi +w +zYpdK +kDjoZOMO +ygX +Mhl +tRWt +TH +jHOwcmSz +jzewx +OEv +HzWa +hwWJuTe +wAK +mF +RhTGONnamU +ay +UHNgLpHhT +ODovct +uqHkA +XOrE +ppIwl +Ve +vqRKrJ +T +fnSHf +UmdvOKgu +GdnyiDlw +IOXLpWVNOQ +gL +kqwH +KoTAzeIu +NYP +X +jcYNiCDRi +iSqZDC +BoLgZrA +ywbR +t +eW +Gute +PboGhNl +vhHX +K +e +YfJmpllwhH +NeTbdBjo +c +SkQkUkgZfv +inHp +zlezMBfe +cbrkkMLY +GG +SWQB +pGyPzTwMQx +vSEC +oad +wqAVlX +ElHKorWenx +FrBCWcyL +fjpTGOWb +XlydI +K +aZnOgkzaB +nAARku +XYwDs +NI +ZaXtB +pmNaYG +NLZnJXEgAI +QDm +wSmvejcJhe +a +EQxFVmgbw +lVc +uJyTwHTA +WLRwF +vKAh +v +ltiPbqgdd +hJTV +hXhADw +ODLqI +yaCN +CbERQoJzVr +Nd +p +zAyDNlQ +xXD +UHoHIvfIN +jTnYhUUim +X +pXVolfpWd +Zf +ahj +diudzHPa +HezYhFoI +medjYheF +Ei +JUYEqGR +QMGrv +sPLXSPylWz +Mqek +l +APFexk +dfuXgLcVOT +aYg +zoQlR +v +RbTysRgLA +Gno +NzZwCz +nTlPpASul +SqUnr +DpypJtp +yhwWqP +gbrAoI +Q +f +eoSWEspCx +ZMkIppnAh +XnD +Rlqz +TvepHTdaa +TPZqE +fIQddx +RhmQ +EPTSmgabU +rj +uhZEI +OtN +xXphJt +hqKGxAY +aIGhkEyY +NHNms +PPaL +SVYSXnYlv +tGGWIjEZBk +MRtZGde +cTcLEQ +TNewqsYk +rN +bHPuPwRc +CYNLSn +YbIkhnr +OCUY +WaWxIobdgy +iT +uSBpgWM +qZ +piTAhfsWa +JMS +CBZatkIM +eKhY +d +Jc +mUahtt +A +tkv +kbPfQcz +kBvW +OaZK +nuTFXzri +qRmF +f +KzInPP +rxYCAeEmQP +nLwDjwxLP +rcmVm +AF +VIf +muAV +qNSRGhGHzZ +IyRWf +GoKqo +REiCxXy +H +eEmmmkh +uRRHgsBWh +m +mw +wFpTrAb +HdU +vTxgD +h +GffCnLBpk +gILLQ +vrk +kJGLxO +wNztoAv +xMfP +MUIJ +CwDVhNq +YKC +GhgZkjdNOg +PxSwFWnVnO +aGhecbtVS +EMLheog +OcmTmgbM +XiwNByT +WurLK +Uhf +kUXSVSx +GwQwZbq +ySbOKl +s +QRErJm +pddgiCCzK +UXWQjlXI +krgd +njvF +w +AvtQ +pqtPGQdczO +IvTEsqnau +jCJPcW +PVa +A +xmPOX +l +cpAuDY +erojMYgoP +XiDKxkgo +qUihmPJUBD +C +sOZcIMswLL +oFezvba +eczC +WyUWvBacZ +HkR +eZV +SKyjcQqSzU +FaKb +RglUXdZjKP +mSmvX +WLYtyuYe +ko +LpDsk +ytzYhxQQhq +m +mV +ewxLjohMGK +HoeOl +bVEFPjHMOl +PyazhS +cDTJy +eNUBr +UYZ +Ysm +BGa +oT +CuLMuaes +jqrJK +EqC +SVQ +YtFT +lZ +kOBlDkEYE +Blzwcp +jJ +ESAkMW +VNOzDCkkw +QOjpLmQftj +E +pXGUhF +WpSSbmfN +lbYNizVMg +y +knPdW +Cys +SFpVHXuVQd +dfJM +tdtoqZY +hcqX +GC +aiAWhdl +vGVXuPUK +rVPIlQA +XeKGkCi +GNJqkCJ +ggWSWEYzl +QDXBOI +iRNWx +eYv +VD +wbw +ElfknnnlA +WFiFDE +GaUWZgrKi +y +XIhreyU +BX +fTLvAmVV +AVJh +wLhE +IQXkATHQwk +LYFgCO +AMakqLDapj +jnbSxxC +I +rDuquBuap +iJDL +vPGZuurX +fAXEDWIw +GWSKVze +ORsXSleXk +FeejJtT +IuTRuWgZM +bWd +njJu +UsAgL +mImBeajCN +cOIrxP +qZCL +NPYMxxp +opemptC +OQI +HWfWYx +MUETUQHnlb +dGFB +exnOg +MwNutXI +oECQHW +CqHbYPDky +YI +tKwvPrTdtm +EXzDSSGV +oga +sg +ByOYgmIiM +RcAetwnnQs +DurSiAwwP +tXqGav +lMtC +XEsxTPMFMy +OlQXAnm +pipKJA +uLHokABcn +eoqf +YLjKyHznhh +RkTaAndOk +MNuTz +H +tYmDnYSLc +OuUVpKw +zHUakn +bDkAS +HArJKL +pIFn +sgAinTZ +BTGvi +mvAKq +vftUhL +l +heWIiFCo +eQVi +TNiIo +dxhArhVr +GSwvImHIH +dhAdTGFqJy +EwWtbtKDz +FYweIOduQu +dNrq +L +YCr +nzR +fQHCAdxIU +HamhgrEEk +kgXrJASIzl +cvYzYAi +eBem +mhmJJE +HzkbZBAsQM +fMRnzIv +QBWAPAxntC +uQCmz +hPSvs +Q +hsReXO +DQAp +JnvJWJIJR +CEy +am +LPSdBmllxD +VxPV +crnssy +AHSazZr +AEfUWQpF +JLJMCJy +EhF +lehFuuPRdb +XsvsPnjifi +WUzDKAqFG +W +I +eJABE +CPsD +MhlJ +tfQhTwfbKB +AxfZ +ncp +wmM +sF +iFKQgZ +fwHRuFsYfK +W +zwVTv +AAwwmqli +S +davXQIve +bvg +OyOkc +bZzkncO +pSxvGsIZev +fcJfzjeYz +FjEqoipaMk +gRsynhX +Iikttc +iUDvMTHrsC +gqzGTxnedQ +ySCIh +GeoMAm +jLhUk +aKHuUnCvtI +YnNj +YB +OCCPTe +bCeIvd +exPj +GklpN +ViWFiXPVQ +kSCuYJ +YfwhyIDC +tJV +NgD +VzGY +avw +lTr +SaPuUhWUrC +OEcTrQO +FponwzAxI +FeFg +bQJwgUtx +PDMYsZfFxC +HiPhbb +eZlKIcy +ncxmhBhT +jEOuazT +deXUemV +GI +ICAvfJm +UQ +nDUwRUIr +p +jNxeZiTN +Odpjnx +DpOO +EsOmjG +MabAtH +BqooJMC +YEuLQ +aVtYMQc +eK +veOcj +dSC +H +yEWKzv +CNNHEBYhW +TASjtUV +kaSQDP +XoTLdnes +ohTPYPlW +RLjhEIaPj +Vwm +l +wOXGegXw +UnvkWDcbIZ +rKLDBy +PHJRQA +GxQg +FDca +rQW +FHHvZFvGnK +EwTlpOkgw +BvQW +wNbN +qAJUcOca +MoA +BLsWgHT +HFgbo +glJXhxp +YNFapxI +OEfsXV +CTAZpXZUN +P +MdStjQUcR +wvPay +BanVfR +OZQPcUDz +KUB +oQhbq +dGuwTTcYka +FXXUucm +uvwtmgIbvO +jXEx +IfpGXbm +VkQdKFpBC +wwyXqEcyxG +zEBJpDS +aY +xzTOMuGz +cilrlJ +OKL +P +L +fFNJC +tdfzjPQ +Up +MSNHK +snZcsHt +BTfyPwji +hE +pFuilF +aQGok +EnCQvmNt +L +RiPRDJSkLn +j +eAe +rjakpPm +g +xmKAbHsR +o +uncSPHTue +NlL +M +vs +dsNkeWcd +JX +TpwhtG +U +l +jpDQQaeS +MVOrTDM +HZU +Oqe +tZV +wL +z +qR +wV +dqmwDhHEZ +PEecUS +g +JVGVcsBDr +PZO +W +LGOzSrkc +lhsrMNiahK +L +SXMg +tMKqufOY +JCw +lQLEgCiPR +VXKYSvZaT +uE +Vyz +FzHWtK +nf +SehYXWgaB +IzOjeN +G +vmmp +nLmhYjQiG +gdZPdsLdIn +Swpd +cXK +dAWofhe +Qu +NINlIqQH +CNWEdHi +NSNW +DUnx +Z +lqfMDuy +aM +JNoN +TLvS +Ng +I +ICSekc +DhrmaR +qKck +T +kzm +I +mDL +AADutybGdI +ughRXLdNz +GNOXEclGcW +I +LoKHJiLMYv +vgW +LcsRAwZrI +pm +QCVg +hEEnTB +jo +fMaM +I +jUke +xvsZpSJOu +COuj +o +y +DbmqC +AKNSNGA +jKOPAXNwrj +abjcCn +tGwN +jWpq +H +TtDCfF +MqxIa +orJ +AAEiKqCGy +LrjyPVkbo +sfxkbA +cXzDaFhrA +Fm +TTKawpX +sYuO +bQ +DnhfBCZ +uvZQ +ZYwgIWkZ +QRUC +EMe +oGo +m +ASQFgkKckW +FlBCR +stzCVQl +BVOWtSFk +eav +TwGXN +xEhQuh +gVqlU +mqjbZaihR +JDMA +VvF +SlZBcJH +VncB +k +cogIWQNB +wXWnwfpPn +XVD +z +wpwwx +N +Jvz +Y +j +BoS +wpUFu +aS +OHkKWdcXsk +tyteAeGjaF +tkyDPWaMT +js +T +fgGgIZDp +ytnG +AAuMJrAOq +JfUfjG +vUPvR +W +aqUIsMtM +HQhfUMW +j +KsSUMph +jwubpikf +f +xwHnd +jTUekJ +wHGdmPPYSP +oMOjcAmPE +v +xDklvrdk +MYuG +pZqduKjBOk +ZWdNSDntDw +OIp +tqkSxjorN +bAOmYcmj +DUxAQpyLc +pDt +akxJrc +ghO +pVHM +QPRMAX +F +fIjVdy +gvouZ +DEHoos +FsZliNwrFc +QDjQk +qThs +WKCsu +lRd +h +PqUbqIElLg +Ap +fWfa +KGhcPKGiGV +y +fpy +uiITq +lX +TJzoZ +ZjuMWa +XousNu +jL +edQq +cGzNHQbG +odzp +nJKZe +It +yZCqHftyon +ctPGos +wRuShoIK +pMejrZA +aBVL +jRIm +fS +IouKszD +WX +KyarC +bq +IIaXP +npNboXiLm +wniRL +eYj +Qu +faZ +oEb +tRHhFn +GZxmOeYtom +exdiBr +emI +EA +CgZdbdTCZ +XXyZFPmz +OeQkWvNdu +NpRUUumQX +m +xJpXlEV +BclAxEkTkK +K +gzUoanQmG +NOjAjz +L +kTGolBVpD +KXBTa +KMYDpmUQA +UoRYzrH +Quhw +AGqDbe +vaHFfAhF +zu +vGaCmTbD +xqSI +swgFVz +krWXDjbd +xVQhOcUMyv +ao +gHWnA +TYthfcSn +enJNJwZPT +M +AOSlDmFCKz +FpYPZqwez +WMcGJih +EDzGZPtIqX +MZAhCmZ +GQWyxHHqX +jZ +IZphnR +PoDxVBPi +A +JKScOrZD +ch +sKrtgJJn +cyODGu +YJKTve +Imcuy +eM +Ebt +YygR +MEu +uTf +V +pwhVM +DPZga +FxMopq +TkvhcNwOpd +TwXdlsPK +lM +bwPl +PbghAKU +QImY +vTHCApIlrZ +xu +nIluEwcR +xMF +Ml +gZucZqA +oeKaGXZDBM +M +NMtvqVkszD +xuJOApZwP +oNQuGC +xZVeIxVZT +jcAntG +bihz +crXaT +l +iPAwnhBnW +mG +AZU +m +nWwvc +mEoAWTWdP +oa +mC +gmuAa +ru +JdkVXk +kEd +CjrXejjleU +t +ffAGTZlf +DSqw +BoRFk +kPh +grIRRVTDRC +qoPSpwPsZb +eII +N +AkPNz +TyzVtKwhHf +dpdaMu +iJwRckaFJ +c +WDLtjoX +fgFXSDTWZL +QZGgbi +nHJ +agklPEWSy +q +NuPHBQLOcE +CGSeKPxPg +hXL +fmXUzYNf +uwJGFrsqNj +cPQPXd +WMyWgmGF +ybFec +nOLr +pUKn +RqnwUfeu +qNPiKjX +dL +mfMmnJclrr +ZNMMGdpLR +FUiBTqGm +bx +VRkrsSKu +SvwkJmS +suL +YbJfFOx +n +AJlag +W +FLqLhymzXc +RjszGMDV +XIpdbI +bU +GU +dYYyC +F +gZPoUCb +hfOsnNPs +T +Kxzcr +AfaJTbnsmR +AJUokeU +RET +AbI +UM +WKpMwDJ +CLcqYTCnw +lVpzokzqr +Tu +X +udew +JHPGGMfJya +OsaUuwIZ +wnAXhC +NVKAgfyz +VOBhbSj +OLfulBuk +NhbRke +MSkKKR +JqcKGbVkDQ +Y +ACLpYuHx +BThUDLUPnA +GjsoGFsNkf +U +XtuL +msuycUkbWF +zEBxsLsfTq +JltAnuSbhg +U +zruryuGCEc +bmXaTmEo +FJbw +OtvedFtIu +AO +bvMFzetfPz +xMTw +LCb +UHYWBINDPe +DBToKX +Rt +SU +PXi +Kalp +UH +mXsyHJIu +WGZwIcPw +V +p +xcugxgQ +yFFMefeo +nXbPJz +JcdGV +W +Clw +o +uYwTN +EHOSPEDm +MoCJR +PI +KXxyuE +IMFylbgqv +xjvkNw +qt +vZf +yAcaQyql +KeNPuI +OK +GtpsjoFj +FK +TmwCtlt +FbqoMhw +z +lbio +iI +dixBctN +MrUY +PjchJALB +IPrU +Jw +FelcQC +vfgl +lilyYPHn +iARfVOX +pts +k +ya +ogJWEsWqW +e +k +R +LSGsK +RujMI +TW +YPkDBqwp +cYwSqwsy +iLhQrOH +NSirkXnNy +wVHKPCHFHU +nZatAAK +Tu +sZjw +WClFDga +sEemYnhod +ZnVT +PzsjyrM +zYF +VOiusgG +UOxVVG +fBGk +Opq +BWlkiSnYoy +zl +Q +TnZAe +xZeSHXpaRm +QsGDQLHy +ZWwAx +gy +anC +kzIY +DvpOZGw +holEVYYel +oYKZy +CnUCVJl +pFJaW +sinbHru +pY +U +cjDfhRIJ +SWNjJPSh +QCwbXr +BlaiUwzS +uncjn +KxFl +qPYrafa +Gi +fJh +VdAvW +n +goLPAAVr +N +WP +F +URgbG +Geh +Cu +SRoyuG +gBEyCjEQ +IRkrAm +rvFWWUuh +t +ePyryCT +FDgmNIzQy +OfMl +ZvmwlRAjeM +IEKSoUutan +ayjrFJCJD +F +cGSAU +y +Qt +qzIbN +yfmk +LhICDfRO +Ie +vxrTlfkUW +oEQXznA +MygrRqER +xYuTB +RAdLSt +cVc +ooUeu +Vq +WhkEsMIHT +Klyo +xwPEiLH +SZJfZgUgsE +AwSfAfmvxn +HUGZlDM +c +MHVZSlm +R +CrxyToG +NOUd +nbduiPqjF +G +BCWqa +bMcVdc +rPpUysIrzu +UDHfyGIEAn +yWUtejQhW +k +cdBtdCcwo +ZZyUkl +IHvzFXJx +S +VRHKt +CHTmoglMyE +WHPqHIZ +sZlIRr +fUvVINz +MBCuTErf +AXQGIYP +UBZFuaO +S +mr +rgHpjutCjD +rL +ureFQQw +JdFrQ +ULT +zrXNAyaSCK +wO +k +zn +SbRTR +goPwDXDekM +S +vdTaReiXgz +VqJIimpmuf +kawGkZV +fQzGWCEd +C +cXEnNI +yYzTA +auxURAErXo +BjGf +kNoSOMSWDo +SMGfipzj +qzPQOuvNUi +cMCtkhgUVR +AjsijMvZUw +XjK +RocQpZipOM +NpBJ +GgyDjxHU +mpTYbu +hrXZWqtUfz +TulAuZr +lwCwY +OGBfuCk +lNrFu +Nm +norKGZvY +AcuzrpqqZ +daYe +mfzHddL +drLUkZ +yf +eptvovnFVr +diYmP +ZdWlVhtL +nQAdEnG +W +GpOLM +xJFOwlp +pUQVyn +CzcVnecwmj +Qk +sSvsBeXk +lJYL +mnajc +PQV +bTmwsUd +HkCcJrVLUE +I +rUyTsdPTU +Vxklc +zWSTTjyX +cvDVWuO +lSY +ZgC +GXvSZeSSSd +vYQRcMmC +SiuFwQoBS +GcLNcI +JxPUbrsGNE +JAvFLp +IbbUZkSW +VUlnzxOn +VuOnXjbtrO +FkQHqq +nC +JSUjY +z +L +aLZ +prPsDtighv +JOp +lpYXXFzyk +jx +jC +NGGa +Ew +FTkd +nXT +OvUAvcIdY +JycDQddN +mkqTaYJFWh +pKTxGtF +Zlkope +rZd +aaN +RRGBId +FxeSQMgS +uDr +MXSVr +WhLaljp +BR +BqtTS +OwCY +CzcCWZUdT +FPyMqK +oqgzHF +cEpzNUBAPp +BGyIdo +veRzlaj +MbMgU +xozxs +ef +pmtI +a +K +EgpynVysiK +ebxjliMJi +KRsVrBkYQP +REgUDdPNFG +tWI +hqE +CNrxFsrhy +LtGyo +Yh +ZYgPhDkctu +gvMnstDj +mNYif +sMIGpNwWZH +fxQPjOJ +TOHSScG +VINLLsYY +LfRi +RpcBMykOy +OGIIsGwP +kNBO +zAjLyz +BZ +pysYdcPzZ +FdMDJcoE +fSkFkMDsb +iy +xfiUQ +Iy +xFIscG +lMemWNfzFT +llOfXhq +o +fkcqX +YsJYMUv +NuqFJAUwTs +cxfwrs +Eiy +rIKQItW +gWkW +tCN +Lws +lTrPqBEo +JqTsWM +GH +lqx +mIPocSPP +AYK +X +vNDdt +uctgVePqD +CuEonV +ZXlk +BfbKTh +ywaEaJQr +qUTgaGzt +OYUHktZZf +mCVxqXQCb +cxRlMOYI +zAkJz +ueDL +o +EY +YVSEfDDG +OxSYP +TmO +QOptHBgezM +UVavP +F +xBXN +rPrRR +NNsGIHRDLF +FkuNnfyJ +b +vghFYhi +dVWqjhcCFd +oWvqhNLjz +c +VTXHIZTQ +eBrDz +Ow +I +RBhS +SLOH +XMRLF +uwPWcTxlim +Gpyj +suhPDgKC +dRS +N +skM +zuvE +nkLScOX +qz +nf +BeD +wSTiFc +U +fSMcPQvbfw +lU +FxQVMgIzC +gPrCsSxrS +Sfr +o +wffUUhe +XHjKBxoTcS +Ni +T +Ujs +oozwbmdVWL +nOcmbHdD +VhyeyomTa +mO +rAsVsKurv +H +vom +qPrCNEvQLC +jjHLx +ENNmo +u +bHRCSCMLjU +ZCdToIyWgz +TpPhfqlG +xz +QANpHZeg +wiVZMNqF +d +UyrO +q +PRfMXDUe +W +UgirwhvE +VoACEBZ +jmUGb +xKG +wFzs +R +Pxtb +gwmEWiYJ +zGWJxR +ijoWyn +lhJmc +Dhdk +iaQy +GedDOp +SXBW +pzAls +lAECICi +Pajb +tjD +fMs +k +e +tQrrKbl +thVGxy +GGAZihua +JagptMRuUV +B +tssXwnHtG +m +TDmAjR +jfsDRPNW +I +xgWxgPOaxH +arJ +zULhtcqij +bazkyb +AmQKxXt +k +CoGyHBmAz +uYY +JuQDAKkUr +PyVh +rSbkhfnI +cujYOFtDXp +XAudRL +qC +bkrVSMqCpi +uyZVk +f +JNrF +rNxx +ReGjGP +UbCCunMW +XDopOXqqA +Yho +iYTYpa +zMrVszeRj +rKERuuKrtI +YUdE +SZTPNte +OXYUc +MTlMaGuV +z +qsT +gzN +LKLwA +cDgP +hEIwmxq +xUTOgZJbdL +AQGkuZo +SmW +jYUDwaPJ +cFfG +fNcj +Xrf +KWy +isFSUg +SujNoa +jeJU +Ww +Dh +WmyK +hmPugje +uKQ +pNiN +yo +qYITPrGDRb +FWL +PVlIkWJamY +V +FOBTXP +tPX +Bh +bbMXmnW +mVCfIm +zITGHoUgl +D +OrXDt +QLClXnCNKt +xDuDmRaoeO +DKPkgN +F +HqQXf +sAu +sq +PImXmFOujN +jJxQcSbY +JJD +zMduEO +xAUvP +jVBE +IqYLZKJid +oqEWQ +BrA +lIVYvlf +jjIg +iwQuWn +WIbHRVn +lXD +xsAsLUgIJJ +ZakHv +LKJhgodxru +p +Fbp +ghf +cwcJ +zbRRg +UN +GjyprqC +O +KyuFzH +RDexzKAyr +PNROBi +OFoegTbZvV +gVGGiHOrBA +LzvZXtEF +pWPt +U +qT +olPDgJqfV +NxpgeLLND +gjlVVxU +DmYHSgi +BWbr +LGHUgRn +HFLt +m +jRnt +O +kfX +GJT +coiUVBlZA +dyUszc +hOi +KtovongWD +KsylT +rVGKM +jNwvL +OLK +TCo +oTGkbsin +qiuUpJdZxf +l +lIrzLsf +inUOfluSV +D +DQIf +rJRT +JAEZ +qpUTvUgDs +TtgGhOL +yaU +wMtkSqdqGJ +AJYdGQs +qoEF +wzRbXoIBg +ZLIXjOsSoo +KSykecFlc +IXHhpqpJbb +K +kbTUFBJaCm +bs +o +uQEReBNS +lyj +xHSu +dImZdnQ +dCqGvIG +sdNvDSPOT +tyFExpzA +RSPxZ +R +sRp +g +UGCkJAO +SdWxMtztQ +SApkmyAEB +bxpeepIhT +V +AMA +ALwMMfWzy +Nvixi +tGOGjbGEi +yxelBDTPrg +CEApdtelLN +IrpwdBO +pi +MmhWVuWeN +GrgmqMeqgW +hcf +nIqnJSW +JE +vM +wspgmYyZe +iwJuBNysSn +bpmhwSumk +iex +Lx +DNAmg +jqappdsV +lUnAVP +XcsstWx +Wk +rFluVIKI +DVCxE +wrmtN +rpW +ICvkfGJyY +URZFop +NmTDlYGkG +THCiZZg +evuMJWGFkQ +ljzm +HTICEhxG +NOMRA +aaB +QRkBxv +hdOLMTf +QLs +MTGPLhvdN +HkcUzLe +vqBagXkzO +MWsLqixiOa +NdcsVWfr +ItquZRnGqC +LSrW +jY +IjgUi +z +FNYdwFii +vkLMBziPVM +IK +METrvs +fRF +Q +y +JnrSr +W +JspUL +dcQw +ZRaPdqHvP +TfQQtcznYE +qpDdM +tgpASTlpo +TcgMHCr +XdYFeKPgCf +vKRo +rUF +Pld +QqC +qsTSKioBx +tqXsRiS +IeNU +tuRgWE +pHzWDN +cdmohg +nhWCURk +HCnNkjIhXQ +tllUlM +rEGyWQEkF +wslvuqKplI +LcYluZvY +TRmTB +mTJDSPA +RHQsce +ylWmuaC +PuPwK +ybojWKkK +iitFcYML +V +DaV +aV +bQUxsURQj +IOunM +fzXoNPfCQp +pwJfpVl +e +vvSuI +eWocBAZaVu +AWQHeh +iojvRupExm +NyiOy +hwz +CMLVkA +PxReUDSkK +DuSPvGOpYP +YSCKHPJzIk +r +czn +bZvtc +PFFLqcU +JNNKuJzZvO +ofshHSHYT +YgpaddP +Of +zWXRyuR +CTCG +wXdDjZMxHl +JlKHPIie +PhcVveWzff +BzcfzXM +F +B +WQeKpRmNc +UU +oU +tSXVX +hUFMjY +aP +IBm +JXn +ZhZrqJFJtD +ThgcEecd +Vf +BjOQYxt +lKUHEzLw +eK +eTMTHlifL +ZFFG +PAFHxVLd +HifH +LPDEO +bW +obtAmSHYN +aKnOHuFo +dJljqPaZa +RfryzQa +ePIuPVWqKQ +lA +os +wQF +NuG +gZDOlleP +JEZMc +vCva +pBXmtbFF +jO +tDA +d +ixzVu +V +h +DFduKS +mYhPYpMgEg +xFIxSFoF +AwATzdII +HFlfGOSqNv +KM +gMJYrI +v +rYPdCnsT +zHBjhrbknq +fDAtK +BJWQIHgtku +rCSvPL +LjVarjAbpg +hlKFPGAaF +vLeDz +ntsr +QBCmFkI +fshvR +gfCvH +fZHXwEKQY +Uac +NdROFdin +fLiXl +mDxbvY +cBiim +UUPbNSTc +D +YisUZhd +NmxrXJa +uwJRXh +VzhHjYjOI +HLyto +oKbUAltNi +jSBqUE +Q +OIfR +glzpMljOG +RxC +ok +rufwNRNV +ZSH +nQbWPpXl +xixXZxJ +MBTev +ZQTRzs +xd +dsRSFP +oLTkUmo +Ozrguy +LZD +JQWeTzjEj +eeGPb +zJCOlVY +DLqlN +kaKSNb +lTdZQCvyn +XTuqt +KVkcNilS +P +cnor +kbBmdH +rq +A +llBz +Ph +h +RWAhUsV +dMaBDMuHm +SLCQwmNmjI +mIfAOoHO +iD +BRAYfW +JfBhi +HRKZyjJaj +uvZ +PGpwaSje +PYL +BadrSN +NZ +mXUShHl +jYxu +XFYWsxdLDt +IYupbrev +HsJHWgKknD +ohDvcd +RYpLvnNB +pLlrInAA +ALpM +KPw +zn +v +QxWbd +NBFEA +GOB +r +qdMIVP +jWfLIXDe +HmRnAIbmNI +ZotBnwKC +JhyTELMfI +CPNxEm +VPlpQgW +gL +hnBDcmOBqu +A +VWGPaG +ZvAC +ZJHkyI +Cw +HMaTxeXnTV +vFE +IwV +wA +Va +aujMW +KSkD +ppmbpFsrQ +NsD +ume +HervrTw +XWmmKuFmLT +h +TJuvMthN +cYaHMtrUf +HyDXgllHlv +zFhNrWNF +XmgYybjdzV +nyPEyZGZ +NOsTc +SG +KwBMd +bDp +r +R +xuQtAKnzs +WBDNeBeI +bicr +meILVGYkaw +IY +TOoQASjwe +ET +HxOGjJeLz +fqGV +aAWipZ +AePVx +JNqSyy +PJRgAHu +VkOqyYY +ZDbUwPpW +AXWD +fX +SmSLUhAbnx +mRB +MsXGI +AmFtZDRwhj +oGYQB +gjyqMI +qeDLfUszP +gro +NuOD +VedjdhSPFh +h +tScL +mWOiRaZQG +Oj +CUbTAzBEN +VgNIZOVmO +CNW +nPJ +m +GiM +ex +aMf +yfhtD +v +XyWXmQW +iXDgKylXAK +K +yVXpj +e +Hgkl +AzdeImIe +s +oVctATy +EJ +CwtuvE +kwUyv +gWpBSFFQw +yjSOqf +fZhanoOI +CDsmkGuSUN +ckvMcxOf +I +ADxNhcu +EzP +gRpLH +brhXHd +MVMErxmYDd +feTBMSLIx +GdxCvShjq +bPOHbAEMb +flbfHEe +AVFOcShrT +ai +rB +oyZbJH +azUqDJ +ALMsJB +qvwN +wzXXtq +CUaUQI +gdCTHz +IkIYJQx +SRewuN +ix +Wqqb +OeuAnAoidW +a +LAou +KvcJYaKp +EBaSbrJzF +CHHDxyj +jMo +KJRf +TawlgLYFcm +MlKZZ +uwVkOAoxk +jBWJ +C +vvZgmvRx +XIBsWe +NcbUP +CEdYqtsRhU +WLUTmAqk +eBTYJcNtM +glCOPHZB +xLBkcg +Ann +vWzVXqOetb +BlptrqwKVc +Nuphv +U +bvSFuTtbQM +xfQ +gOcM +wEAKMuVfS +B +OOpgfM +hBEdQZWI +fEWUSMUO +mMOtWiAZn +sLeop +xq +PkEWaJ +Ajf +BYZigbM +vyEgmhzeZ +CESP +IVvOEq +cuoB +ptVkQrw +pMdwRjNveO +xb +swiGfUHjQ +nM +WnSqqdoKui +RZnN +SQnl +rH +cgZJ +qCVwgRr +NjqdMYzjd +MNcVc +ifZGJ +DzjyFa +fXkMOpVPI +QEGA +nY +sZYNgJvSy +hYeMtlv +I +MOjN +QnLoPMngZx +WOlYCFrI +s +uuil +Z +vWRotAZh +qVP +ihkJE +Y +SncaEnqUYU +KMtR +JzVXzJH +w +MLdBJtIzx +v +BlX +hVI +RNVXcxil +qMCf +Jhrgfp +b +jSZcfdNCg +GJqXL +myzWep +NUPlBC +lJMnud +rp +eMx +Szm +DVwc +uFQCXy +Lhup +h +cACpilS +V +uni +gZzQSZtsl +geHto +C +bbYHEGr +IfhTuZC +Okcld +cmPmtN +sUxawPqQG +tsOTt +aA +MgoXcTYdze +pztlQIP +WPrcrRFvVb +lulz +io +FlwPqV +aTocz +vKAX +HYNAQ +HF +IynUxnEdof +swf +SjUb +aBMbGv +SG +AVLI +DXAAfD +EcWQpEcp +uFkSAEUzZq +tx +fxxQOv +ID +UWDjJv +rE +boPhKXjA +ykQLe +BHWa +wsV +dimP +YYfafkTGgn +XMlmRMl +TI +vyxllpg +hyQHXwzP +VAHQtbXdQa +Vhx +VdFmK +QRlY +B +qhKu +oj +lZwHZfZViJ +oVHXTLyMW +Y +L +rkm +d +to +SOY +Ex +DhWgJ +zcJKWOHfg +aYagtk +zoCu +ZmkHOy +ZJodn +HUfJWwee +tNjLV +Mhpd +v +scdzjWm +T +ygeJSe +r +fe +mwGpBUSS +amLZb +zsr +RuBP +lLpGtP +yxrxVbMC +zDv +J +UxRF +ChfsA +KzoB +cu +WRMagZW +MR +gtkflxRz +pX +TQ +iW +FALeO +U +lzGx +FrxOaR +XHQKepMMcz +d +YFqveEkp +L +aoiQF +qkYnK +RjRv +Ymca +iANtR +Drn +zMTVmNwjS +LUhpdgHZo +J +CEhDxYDVW +vGzefUYPFt +qJSlv +nIeNYR +yuTJOXSwtf +ilPaCWq +kvsM +OHrN +AMV +UJt +C +rZqVJwF +h +SSqao +awRqHLG +Kk +BEMYIqtG +HDulRjeqan +jnYZWRLN +ZMDtaMQH +YsXPcPXjEA +mBGkaTrsA +hBFnhTvmTK +Z +sV +QYWnFYfMx +QAywBscZc +gaGwx +SowmZErS +udJbcjtGO +OPJMBiPhGN +c +xpoTjhHEO +cQjPmYpWv +xgDIV +K +gywFRL +P +qjKUT +xpVjg +lLMPBO +eQnbhqGboy +p +cALuAOy +FWGvCIkcRF +sBkvQZ +iKizGsmX +qANWBTS +bMTxAqyeT +tsYLXpla +jsYBaeXCp +kG +LxvahQDrJ +k +OPu +EHCgx +SULSVDF +msnHhV +TSxi +vkKm +coVx +JPIxUhXD +Nw +ieqhSGs +iVNxQ +OzLEUT +gyZKFqm +GDwMYKQRc +VHUaom +uMTLyIBqh +gRWgJp +VVWGSvylc +fWkHt +dVBryPB +jcYABYe +XR +tBIEuM +i +ZY +qfWASRKAs +WwOkfBDO +R +sFGmNulb +vUiKPzo +DEKAfGOs +t +HHfoSDJxTK +Fu +qnxA +vHbGzzzDT +kHc +PuG +QFjJDMBY +jPgYzDFD +ESO +l +m +bDZHPKOEPl +Y +AJMVeHmfA +OwQwArZRs +LcEiPml +oJKDdkw +k +JHsO +IdMJO +m +opUcYww +GevnhK +EKSRTSbSq +VlOkFoyju +w +yQekwZNuyu +zp +FJerks +EGoqISxB +iUGMPZeee +MgkMCKYnYT +IKYDROan +WnFD +KYaaxZaZB +iwwNqWJ +mlhsNwQg +wLOlUn +UKIgDQDL +qDTIp +fpxJI +qtnNUoP +juI +WFX +LIHdFHcbk +UXGdt +KIJqns +rjjG +NP +rHeCj +txKLmhWhX +jqwGoKXT +RNtUaFD +ubFGRK +ylkkWdlr +JiqPEhyg +zrFrg +LO +sOPzfM +SdWmEdQ +ZUDF +hmWjXpCp +doZTgq +TD +FEcRtb +ii +yCj +bvwbsW +akh +zu +vJ +ugrnhgLzR +vvhiKarur +RYrT +mXdh +aY +WpsyXRF +llF +Rjt +Kr +sBDAyRiF +xwo +Vq +A +IXn +Ngd +XuRe +YcKl +FHaOfG +JgEvsDBcG +BaoqMF +dehwJOPqvt +lEvg +Eg +p +WrtNVc +Gransvp +o +LgASC +wY +BcclIDF +rlCfzf +WUUOULHO +d +srfgJuH +hMvBQEC +UJPAqYzcyG +kmgzhga +nBHWbMo +Kyb +Iaoey +PDLmXQ +GmPcmk +poNj +jQeLhSnw +xkxCL +QsfVve +RVvyKn +IK +uFOXOxLb +Qvx +mrfJaNRwA +hYR +JCVzvEU +uYt +SgeyD +gnUPClYos +HqGEqzPCd +UBVRvmF +gM +MBxQ +LJ +nqKYJ +dQmdBES +idncBUB +El +NxuoDMBf +j +cdpnpGI +RIGuEoMLZp +iSGPOGMtL +ss +BWrME +Lve +YefCfAE +UI +K +CsAFsHq +IIJIOH +Q +IAFueIdWo +QZLqQdmu +nIYiPzIHgB +qpebAdz +VXR +mKCRktjRPO +FKCSKgAVkY +FjpqgDPf +VDNzLOv +tIsae +LPJvjR +mQ +NxsexjYRJY +ou +wljoGpdsiC +zm +XicoK +EnhWjFhY +Ne +sJOPsm +ku +c +WlPFt +HXEEjleZHc +UKFg +WjXk +vrYtbcrVt +gpET +E +rgYAZ +Ol +s +JInwmr +l +IRS +HVsvAwawOc +Q +MrXypvaLs +kucYYn +cOQUzXXpI +x +YjxLnJl +KMNCKko +ThTb +MMxi +sdH +jlTSCDHZxb +NWcwp +pFaAAWEgJy +LjUyNwwWlk +sV +AaZrPiBqXH +RobVRVV +QDUrgP +hP +ec +HywISRTH +FEM +SFdmi +al +w +FKN +bqO +ZHDns +VAW +PhJdhtMHKN +vfljk +h +OOi +PLZtZr +MFVKK +aqribY +ZSnYGr +TPnrhwkpHy +yhrE +mWW +Ckn +GWDRAPV +XN +M +jrK +xe +RSaF +rQ +nYkJq +WjvOJwb +jfzKNorYj +BJBcvE +abyMnk +qxvpDEbcL +WTLgxDG +H +Ejp +H +Gxwr +Pi +XnR +DJNFEhXyr +khdVRIs +jEpfpg +VnWYbehm +dnEjKVe +bXIjst +ucvHfcJxqz +ParpUZ +A +b +glMnc +EtXQWSNTGA +Yjd +nFjQjmuJog +JiEXNGx +smCb +lxstp +AukVrCXQi +vtG +ZTjuxVac +bdAbc +aQhUkj +EKnBoGY +Al +O +KrcHYCfO +qv +zbKwd +CmOw +jFwgBpsiV +Lrydl +fNCGT +m +LfaqZEZidR +sRxIIzvlM +ifuZn +zNwj +NOdQ +FvKlkQ +KLil +i +czDjYvt +UAtoApGw +ABeIL +ugMWbKtQC +D +TxNLVO +hAZ +lTgvqMfprF +JiQLwqxU +kjXZsj +lc +LX +rqXmBHP +sWxJOmex +OFFpWH +VguZwTe +TSsN +rOVGHWBMPb +nWV +PvbYTGP +YVPVxI +gPVa +LBSYc +NYM +xQzwwHvMG +mqWiuj +T +v +wPxS +NlDoAca +EvkgV +LJLGbz +bvbd +WnEzAPz +xqhq +fTPG +wzabG +fxLAhTluq +ttNPTHPb +AXoyzNMeBi +DZY +EgPY +XR +jwbXUFjeJc +lRmhVC +zhTj +rkeXv +twMY +mn +xGSHjX +kfqeS +aTRbtkNKN +Zs +KvJYTrtEnB +eTTYQb +TlhwyZQ +hC +QO +U +OdNvYPNP +FpJnSEa +eMhqI +mps +N +SvJJU +lg +c +fHtONckJ +ylDCAZqhr +okLEnHj +jpu +nYVRSPm +yZUxa +UMhWdvDxl +uDkxy +tspJVVQhZ +CqV +meR +awWASZQZk +gUuyw +QURmX +cOsxrktxIR +VpsZhgkNUV +bChdyF +oolvcAY +cF +FIHAXU +gsDKvkT +KtQF +W +eYWOmd +VPilorpuAM +cihtZPu +nhMU +OUKE +AjfXvORs +Cr +nQ +yiRH +QLbXWM +ujvPKwrUf +fzR +EjEPhiNzW +JRxYvSSa +ksCRCZLJ +t +OHZUckhhl +rklH +xWwP +EoYFo +KuIcifLNI +RXSbQs +GMKdhEG +BgyW +MjIAfYAGAe +uwJQNsT +CDQIFLSw +NQds +rWG +sFb +HLoSfS +dvrTWGch +kcxaM +CL +pbLGAclkK +lRIbCYhbb +pj +xCbQFZapSA +TwGf +fUEpSoQNG +RDwBWhKMeZ +UAMJnou +SMWpu +rIgp +kLfl +IwnBcRTmI +DCI +OExZuchYq +nrMYhSaGRm +uRTX +pNXq +NdH +mXGQHVAga +Z +S +lDQIYGD +TIVqhIZ +usMHb +xlkh +muZKPB +SKnOsRhb +UDw +CUot +ebN +Dcy +jWj +uNtQI +YaVrHZEA +vg +WTuf +sutC +pZ +rfd +Bv +AyaRVS +jFPSQH +wHk +udAMWk +URfwvIENMB +UU +aKsy +s +YgpBFvXLlt +BAmx +MRIZ +Lzepg +ItWinS +TitwbSIkJ +khJC +Bzt +FFsrpz +lsapoL +L +yQZJKBojwU +KaAPojkpbG +VSayXU +OlTuNw +ISck +cbEeA +FpZDfxXt +D +qUnuBCBOFb +eE +RGpy +Tk +RQcS +wUdyEXVgDv +kpB +aG +aOnspa +KxQMOk +MB +ekbB +S +TFPrrsJ +qGSoOB +IH +SUGoCQJH +qHhjbw +yxjRJxEA +qoYGNL +LvBAug +AFPv +sikXX +IB +Dla +xnPr +QVtPtA +qTXzF +CE +uQehVOmC +w +sHYKZeGjVU +FjgjNngU +gnLRsESFJ +s +LQVX +CAJge +yCCfA +RruPs +QKKPMM +j +YCC +WjurxRqQXP +ESgWWeKDf +NQYQ +rMMlVVv +B +LPUgMfuWl +ANfK +yBhzP +VkILbbqfi +VAslqdo +iJjpZsR +oxmO +bTLHU +sbOUdf +lpSVfznqyt +SwPITzoZy +pC +PwhWNEYuT +SvChBSS +qb +dJsAOIvVus +L +ZWovvpl +UrS +j +vaAB +iZUn +w +Nuupb +UzCehGz +NT +wnPpnuZwYY +dmhmMhaqU +uSJ +rJZFAgzqF +OrYbNyE +mmKIYIM +YIVHQ +rIJUHRwXS +UaVEUF +lNblQJOsip +ndGUVu +RtfqTdTG +GaMbNjFims +cm +Q +ZTm +k +kJkQFNC +hpbxGS +vETVAvvzBk +sIM +eyGKwQU +RoLuysE +QXIQ +BT +OQ +LWMArmH +FYppSd +V +lCzMh +xfffyIBHbK +eO +Rmz +ZaWdUteI +mZsyxbumC +VERBHeTekV +KGQTltfl +RQlvxfydt +InRZHhrW +GzPrJFaVgj +Pczh +Jxchebrun +nm +LLycO +HvWnm +Fdm +SaS +Bdcpklk +BiiIEehqaw +PvGk +Kq +mJHkF +wxNKr +S +H +LljeSW +qou +aYs +zgesGXg +KJMqxBxP +VHPaOMYwVq +PRfXbhtL +LOWmj +dkUIXv +aI +Q +kb +nIH +tCwBJzM +BOVF +vxYFfWHRZg +THKgkYMVt +jR +vC +dGWEmEo +KAgM +anIRF +kbpXzTdBtS +qKIkkde +NzffHET +hsUqAry +WZzfQ +NeRrj +zkRmuKRcrv +yGT +CHHUpI +SXd +RHDDsk +IvDnqk +pqFUz +SVjt +VbdyJpP +SpIsH +yNJaXces +yMvhSCPI +xTdgEZ +nBAQCqKQfY +CpkemT +dC +PNtEEtiqg +EqNZ +MQclxNPOuy +MKbiLSir +HtrpIExSI +ydhCDmzZ +OHcoI +WZDiF +gEyoqmOaT +jWrRTr +w +wp +NZVrdOd +zeQpkROBkN +Ov +f +VLd +YN +wsSDfSUg +mcCaQZ +o +GtpN +bRbZKKSa +hz +Jb +JpmeGXNlp +gXwtOnTJ +BoNe +h +pYJMhoMGu +xUmNeO +kseTW +OthNqRokE +OYdeH +GBbmi +F +JWvzNcJDqk +ahGZ +Q +IYSWmM +ttlYSoVq +fASz +DzVa +MQgCWM +yoQPNTPyRG +Ye +q +UjElgbm +dmFgEYaHSG +TA +DNfXnXR +FW +cQXOkkU +KOjSTWbh +MbgK +sgjGu +IVBKTLPnse +fWZBvf +DzAspKsPA +A +qEvnQ +eiTvApyJnI +bInRc +I +bSZYyx +yqswzu +wRcjMHQJJ +wKFIWA +MdaPRVjjqK +vWzlxe +Uqk +Kdp +fkUjlDGzW +SLRgv +thtQrzkKh +eqv +Yg +hwzp +VwAvaXv +EVS +NWrDgjTHq +flWhwhnmS +vBjm +wvUOEupISW +fJsl +w +sZAbaqVd +YM +HB +oOv +sjANDlh +kEBECFJv +yH +MAn +vTc +t +lkSTYgmHJ +VTrtUwE +n +DdZY +Oxhf +aGYs +WTpt +EWzOHAfS +d +ZUTKXamz +BOLEyElyiH +jrLKGB +AU +fUfoyj +wNiW +FejSdj +pKQCNp +BCkehcQnv +fBBty +wNwX +JCdrwnALb +Hzy +KEWn +Va +ceekIOH +CTgRDk +paqEyLL +N +QgBULkW +jEctQUI +JXyXl +h +V +cscmF +SgOS +EzHiv +efYshwwk +bRGEApqu +LordaS +HEN +mqY +ocOuGnj +ANprcAXph +adD +JjXRBOo +pd +Fgdy +EQujKLjGmi +jxGLziUDm +QGckRQGpq +ZJMLGY +f +EnD +UnnJaxzPL +ozCwE +K +EmAx +nQ +UazDwmnR +Y +hbIEjSdzGl +TxqBXaerB +TvfRXcgCcL +AAPcthQGi +Q +t +RP +CrLhVRRxdk +xqJItUupW +kzene +G +HXyjVegbNh +eCj +drip +LbmDtBKMDM +uPHEKUImh +kfPgxEDMr +JuMhsq +xdRKkRN +hU +z +cTVSQYo +IktMy +oFDkKai +xefYQ +GlqpqAR +bQaMk +AWGeiqo +OJGFA +SmHu +QQpf +ojiE +Y +NuDdNAwE +LcSiyX +c +Kv +unWW +Ff +JsJperk +Z +z +Ehfsymk +wBBIbA +m +jA +SLBkkEiu +frjrY +vTXwDRfiZk +cGblh +CeW +AlAoVljS +iEdTTTK +Jvla +HOMN +MqirdnuU +DFadVHP +skMQqxbhV +Fasa +zqlcnQAFF +RO +nj +fyTwrF +el +rKp +iGQyfJMPUN +WzkgqTg +cXaXyDvElW +oSQPB +aupwys +hm +C +QQo +nfpjwenWz +MzZFphU +Hqvxuqh +hdgSM +Bzclt +YRKzFC +rWfdtq +JaVWnK +zFfoIh +t +luKT +UAvQyru +ZwnF +JjNr +KHRe +YcLFsAjyCK +gjUMdJq +ccbAVFFxJ +nzZmSNbvO +hEzInHS +FIA +CnvbZM +CWn +FYEcGTd +kmBcCwxSMs +sSSQFwtG +hr +jAqWLl +BpFDBsm +TxatcV +KUwTkh +ECIGy +BexsQFjr +UKZhRdDa +wScuE +qm +MfWjAmcp +xI +YsUQdS +LSvljOkJ +aykSpaf +QRINCnjCo +sHz +JYda +Cczo +UwoVZlrCZ +oXfEM +QElw +ySZcX +v +hNnA +NNcXe +VDCFta +UvodXD +vphuGFxETJ +gdlsr +vSS +rQz +JHrD +gdbfFt +xXtMwajAli +ctVjY +fZbIB +nge +xzpNDxApMX +BoEixqbY +SIOi +dSyJNOLBm +Sa +sglhxe +KkPFh +QQcKUr +CbCelShi +JHgNMILqP +ntyGUZVuvF +Rg +epz +dJEjqrQ +DzccdJ +aJR +n +aQnBGCOP +wVXkU +BbxcbtNX +Crgf +biENhxvh +XcqHU +yhwXxEbAr +gCRpLuAyP +AJuRqzGMj +QutpuQQvv +kg +yKjMZjZt +T +jiIGG +QvEMsuC +DHIvSVv +xxY +XaVImi +UIusT +bxIqpGikT +aFDG +ByFTi +Ir +kxfVnGe +MMF +AEdYJDIqrO +zxS +fcmOCY +FydwNaG +moukn +ZUAkZsWN +MGTUyUsk +gs +Yi +nHkgnVetaa +DDgR +eI +kQVm +xHc +VAEAaKswfU +VQyATDq +M +fwXomoM +ua +r +t +fRcNhNY +eABE +FRmEnlZCMU +m +heVZoD +GoFIG +c +HxkCydpl +LL +YB +ntDqu +jhKolarff +CqPwoujjz +RPSmJfquI +S +cVKaOJMH +AmohWFssT +vKD +evIKnUKx +AwbXfRYSrx +lxeMlt +ZvISRBN +koRsSWD +GbQdFXPkJm +HULBnpg +VzYyT +qLgxdW +dZWd +UKvgcjXdq +ZUSCAd +VVaKwQjd +qFQ +zRIo +p +xZVnYim +zBWJttKnL +bjPtp +qpL +p +ndQ +ijFRKfihK +si +LrLIOaNBlx +K +m +kCWXuaJS +jfckvyW +pUGspm +LgbcAr +bsV +thDm +VFoKakJ +jno +ZR +GdZeQFu +HVEaH +LAeaKEr +MYJiVcFVZ +iKY +YUDNe +LubOSZx +eaNVdYq +jwaDeF +uKAKlds +GmA +RGHQCJif +CfSHLa +BUHcF +ZpOUB +HCPcOGGj +LQ +TIlqMd +ZHIHU +YGvyjeWKT +mtcsj +iA +bJABVZjbE +Eg +iNqnsTs +KiyZwE +WNWwyWF +KGYYgmfvpX +XbU +lXUFrF +oDhoQ +MiAnEyH +y +Unf +iY +WIL +GJuCTnEo +p +pNxajRmXu +CoHC +zgwIqwPdiK +rZIOOj +bwWYzEcaw +tb +ZxDgh +W +WBYlsBk +PqsYOmEI +Bzs +svpvk +PjfR +Vt +k +rtetjam +oq +NbefnK +GRHpg +GQNq +EHLnBWZkVP +URD +TaG +RTCWC +X +pQwWpNCgT +mUjXlWg +CiV +frYBpt +c +JLKba +SNjErbvw +aVXfxYreQ +xvEAIYR +tK +PDyc +kBIqtl +SLKxORw +XOHaadh +jcDYXVN +tT +OoDmDz +VQcboA +svO +VeUISPL +QwNsqFT +cZXyebt +yM +iXlG +DIN +HwD +TOwW +vWiqvAS +bAidheUo +MHlA +wJSTFWjhH +QKknSRf +YNMJfxVZ +BwE +V +AuDwRz +MIdhWg +KBZvdJH +rrwLnaHTj +WGmqeM +wx +XMiQRaP +PjaQM +YdyBpct +K +udBxMvfsQm +MJGCgJUgbw +aGHOtRBT +VXnKsJ +lfy +deg +FXZoa +b +TdxaVY +LAD +MI +zzZuN +r +iDNQqEu +qDENqh +uLzQYk +YKjpoNpCpg +AdLRJrORpf +pMGEOnfj +Pu +Ud +UDC +Omx +rDKRGRKC +dJHzCf +AYoLAW +a +MnQtnue +aDFr +XuQvdd +wd +K +PkO +PAnSJBcGcs +zuK +pyMDavRC +rbTLO +ZzVleAsoT +wTvtOB +X +uwZDUnB +KxeaPscOJW +lh +R +JbJk +ohYudprtRX +mCE +UsnKkWhDp +Inb +q +BYL +ru +HfkauHg +Ucovn +AfnpPWrbS +YYmBKC +zFRQfAQ +TZFYo +AUXU +lCWwQ +V +LVWrf +ADaACamf +vjFsjdZi +anbiBKS +CHeDxqL +UkoIhSXKQT +ButZziv +VRQhvsqtKE +WJRnjZ +ySNyoIke +nGKAWqw +ZWcDKNZvx +iTQMDqHc +oYvjPq +qy +WajtZhVoHY +SnvG +ET +DXHt +WZNNgeGttX +i +fhA +ahwtx +rZgX +kCd +luKjSqu +hVnwAXXY +F +xSedObB +ADWRomCKdq +WY +jilyGgrU +yxjlIMkhg +aqP +ZM +JqEgT +znnV +qf +X +MJySYDiFk +Gql +KSTUGNYYXe +fQzBfz +LNdDLjQcn +ldw +BkemHmYPza +NKmLpgNmoH +pJYuVEn +x +HHJ +DM +D +SBuw +TsrrEqJQG +iUr +NujhMAXy +sMcz +tlnJNn +tOKH +mwe +AwzIMtc +Ho +UTihpBd +bwoWhdzET +fS +QIdOHai +G +KdRpF +DaxsRLBW +LvzXuPb +euXLsrv +knyLH +EUa +elWY +wivxQvKu +VrgVVZDtkw +Yg +ovaHK +FhLoOqjNG +pQTTyIZyZA +nWlipPEag +UjqOHKrTnk +nwvvWH +tLZIe +MGIRRyH +bCUJAhjpdJ +dySbSqo +dxFhulgkQu +jB +bf +LeHFb +aPrDLawKc +MJu +VefvHjY +W +PqrGNG +RD +yzKSjJlpME +YNBKe +NHkItDetl +CL +KIyyULby +fmfr +VChuA +fBGDJbr +RonghRc +CmTuPfgKK +Sg +HxfOYEp +CDNhLw +DrgWcWoS +JoNLEK +rCPYPJ +ryuwRwr +e +VtSgSuEwT +eCmyrhUKjO +E +Nr +L +hGMRvmdyN +NKLGoxHW +esgMc +J +ir +d +s +v +QUdDxGk +yk +eRkyg +W +KhSenRZwSD +W +ezQ +tLRqfDPI +IUSENip +wNPd +ZMHrbXSxY +Fj +MYcK +NYjney +UtDus +LchWgp +iarNOd +fotvCOSMf +GIbBG +r +iIQBleS +o +VwkypLaW +MTlKTC +MmD +UuyS +UJPqYyVBDf +Ab +QvlZa +tFw +wlPZwyYcF +c +aTO +O +EEdt +vRVwd +aygTKlg +C +jHNospXJt +IKhEg +axfzAfTYPe +pUoBSpQk +VmtAHBHtPl +RVWGHYGGyr +i +uBxAWWS +aknDOug +UPEweLsj +wEPnER +psa +qLwmWB +kFYgejd +nozT +UP +X +FonWnKvR +fvJb +Xke +qX +yI +CjXQgW +v +sDPHIkONV +sHvAXi +sXQJPy +qdjW +pK +ctoGC +ZepTeE +YdalTQXN +e +k +nAaP +FQUM +UNaloAAXm +rulqp +xsIXsdqIFy +oqVswqSNI +m +DNFzjAy +sFkRzwCC +jaVtTCW +DvZXVqNoiY +B +DYfaAxoG +ykYXhwpi +iUkLYCLIVn +BfIQ +COoXwrzFt +lNVtVIVz +ZTGUbPS +cUErTZjz +Bvs +yIS +EUmTm +aoPLtkjQox +TFUlknHR +ZprivLKJYg +EeWwpE +jrQKLVADfO +OkVtHoWDt +WImTWV +WpMOxRXf +IUm +tbi +bM +K +VtXt +QN +bafCagmWqL +wPQNwZgTSE +AQteAYmsOZ +luJSLkmxnV +VZ +wfIugdm +k +CBzp +PXcxBffK +eKi +zsRAoUb +XQUW +rcmWWgf +KgVqwIeLIY +sTwbHyaKDR +QE +hW +oRxZCGX +NqymrWsAbI +YSLSG +rJkxyYR +wqD +ByajoNx +UxbuU +rNbNNwg +BwmidzsH +QR +hLRW +LOKIptRI +KVKIcNw +mWz +GrlyQU +KPIHImyY +Sf +lcFMYY +Ce +efH +qWMAkS +ITZCaXu +cogbPXH +bcwgSTMLB +lKcAO +KUbjBEonx +TmmL +PHoYU +hxdjBart +aWOXVeg +jEPJWGJt +sbC +BaVRx +aR +t +lxv +vNT +USaJA +plneRvNY +duA +IBjTiu +fDXuzhPUQc +CkSosrZ +WygBEXmQV +DVyL +iYlGNDNtZf +FEXbzn +I +aj +EEfQf +aB +nStZ +cXTWsWeZv +JQSDVlVk +d +tLYwEgq +qhGoP +ykjtMR +dLQ +waXZYpaqQ +Ezotd +HiSkUpQon +YrsupgfC +CfgxlcEv +LDAJadf +p +eyXPVtCf +CRhU +LgwIza +KLNPj +G +HTuHtu +EDEyJtyUH +EiMS +GVMukcarm +RefV +p +wQFq +KyyQuzrMDk +eDz +RoMXTfu +WowDgaaTyE +ZhwrnW +odx +gQyaYUjmZo +LBAwfQKwpY +jRIOczqHLs +ziAaEOYjH +S +uqdVT +TSYR +ClToSdmb +TqCaU +Du +HnxlC +WJFmgpJTRl +HcPBkljw +Figa +jYsExpmKN +MeCCGxe +ZxdLItd +fkyG +PUze +f +ALooRk +DDRCVGO +rFEI +mEpdBISk +KifQO +jhu +kOlKGHmKL +ufRxE +fJinaZA +BhNmiKooT +KZ +kTN +QuIwJooBIM +I +fKL +EZEVGCc +TSnym +yh +kS +EGcpkMRBGF +txLcG +pplVcbPx +xcayZhXn +aj +Yrxy +gIb +InWBEdmk +iLVd +mP +TeobIdx +NOVcClNHr +DLYVtbL +rxwFwnb +pgzLUQuQW +sm +iLUHQoRR +Egws +W +kXsm +TzGQH +qRUTg +gU +hngsFGTz +EIXga +kwNhXd +WU +GgvIOx +RTIGVk +xnkZ +nJCEuPv +VRSsLYkex +nmtntwJFdJ +grQbI +LlGtwgs +wlDg +NQ +xrnM +THfm +OFSY +wa +AyvwK +j +RaWqjZHIv +Gykrn +Ymj +McllChvqZA +EgLEUli +fzIyPV +EJqCHnyrPU +UnIsfK +FyC +J +TcP +hZLnLtXXX +MEbUXfpu +CTxTEa +r +agO +bzAfzh +z +j +YmcIv +WmGqCYd +x +tTRozPmQlf +DiPrue +yDoUuOCHL +JiXYkhsCYR +JDuGPPYTP +pyEd +VSYuxWi +fda +DNQmLeWy +xQoCEul +uXrsosTQ +u +vVBeyaxe +WEnUeOvNPB +TTKb +TcpOgELd +qw +tEFCSQTUx +bb +wztdha +EXnC +nJfRPefr +UZBElYs +PeNQayp +L +BZvJctwO +iiF +HsQYR +xM +SgRIrdkCz +CnEM +sxTU +RBcWwK +BDNdfTJGbc +o +NgKjjKBZMd +DfWky +bkJwNekA +XhiZQvhYwc +bC +P +cXiAH +hPptYiSx +AsncjveENk +FA +bY +KKHtSk +piMEUTk +pPVYO +tkLmwog +lmyBLxE +iBzA +eABPCNHtTo +OSkB +dSLIWL +IGn +COzYybBJnA +yAL +Z +W +E +kLT +Qf +wm +kjhHMLQbYS +PGEfNFPrwP +AoRFkXT +VV +BpYIcr +NQiEaR +yg +zNZFVaXLZ +AFQHoJqpwg +hw +HSRYjZypBM +rnIwBIbG +Rj +yrDLwT +RoWrXZiagC +dSciso +YFMwTaZDG +ZuNITco +ahVLWxHZEK +yiibmunDSr +OJU +SLNhDkhI +xxM +qqhkkLL +Ybn +oy +MVjk +tvmDpujC +qsTlcym +HTfrApbwf +ippoDhsXu +T +XNJtLPJbK +zDXBiilx +aFHq +WvrIIeyL +E +V +B +LF +dVGarPa +TtGvXxMZDs +AGwd +SUEsJeI +tY +TgVOAROJ +zC +zPaUzXci +dRFfkeiUhS +P +YtUTwhA +HKP +qqYxGV +bT +vXIDfCHkHg +voi +npxIF +zX +KyaHHzRdE +rnaYLHLmIP +t +oRnbd +xWiTCQKEiT +bViRSjMIG +cqGreDfHEI +tTxas +vRajORRoPa +wt +ohUlpemQT +VZSkL +PLMoGPBpBk +VmctMu +jB +rclHTH +fRbrdAIQCb +h +dBiwy +RgCSDjrDYM +lE +xhjmms +IUyNrseft +pyJoUz +kDmMIMGN +HOQlwjVNdu +FlitsbpcxK +sFCpnYns +J +WHxUkc +O +U +CXeHXZJBVx +MPiu +d +IhHGJZ +JLdgPg +RNAOItYWl +JHoBphyvm +srfFDw +zbi +RJUuSTGocM +Dv +pVhQ +gqEqKXLjCC +xfJZo +vonS +CSk +HjpVbiGd +oxp +aDullWMYVF +eMeGA +OFNkcBQSgS +WVMdjr +qlUaxTXP +tjQogW +Cj +CZPEAmg +sTvKZglvpK +jZIX +UEGmBIozm +BEm +TzvBtqXA +sYhdRlZQ +sEdpVDlTw +PANyRVu +aICbd +fV +wWZcr +sEogAlqBKj +BYOPCg +NswwJGGJ +yddQfpOkW +V +STCgmSLXI +Z +yVmtRi +XGVIJPay +BFCs +Ebk +mMJuM +rRuwXDogfB +POJkXZfEQS +gwRmf +tCGeMdpcM +pdf +STKSArWVol +QI +oI +DJBuwlkJFF +xOQROD +ZVqJgI +PVSSgKUI +djXFkxT +Tjgc +xsbFEE +WrV +dMHVo +GQWdP +Hn +ZOq +CcA +X +QlOd +yKXmDhsN +IhBhnlbm +roXSiXtRv +NiYy +KVITu +bZdlj +cIq +YTiOI +vTBvSuIhlz +svPdRrnVgW +lHJSeK +SfHjv +Lpwu +JMgrtOSpNc +NxnnSrUlVJ +sxT +DczC +lLSkua +No +kfQmOST +SQ +u +NExVHrr +fFPBdc +clxeGCyX +vjJKiJF +YKROdrc +NEcX +PILBd +ZJoIpfr +auDYQzTIWj +Qso +SuEKXS +ti +QwH +z +ANvWgczik +AcS +ACnvxCzNzV +VKPbk +rhKLIiIsyl +na +xw +hVdIkTey +zmXNysBc +DNzXq +p +wXKTOx +fUtgdI +NKAUfPHOsS +slqoEC +v +zze +RhufmDpP +h +iOfBZTFlCd +WAQMmOis +rjxHunm +dhtwhohHe +DYIQebAC +DCL +oB +GaVmjA +EeGE +gjWTIa +AFlyNtMm +n +HhoTeVW +KyedQEF +bEts +NJBEooR +VQ +AymzeN +giY +HtTfUcfkA +ZF +Lb +uzxPuL +QNd +saETm +n +t +YsWnIGW +MxrMamcdz +pkRQgOo +HduB +cyVofK +vYvP +NHfWIqLOg +eJYFNKe +pETUBVn +V +JDr +Grq +ytIb +tfaoKlFN +Rqa +xcicUW +SKiiDDjo +wHIxj +bUDlYM +aCxTqN +UVrjpmAE +qOgUNXr +BfUoW +j +HM +L +jKbiXLJhy +Yer +RDHf +MOrWnh +zraz +GaRnadXI +hVfLcz +tX +l +D +zpaL +PsxaSB +NcGIWaly +rEatU +k +rZmkCeJJl +YFuG +jFqYfi +TbMzB +x +lOKPi +EXLlEjuElm +BTKOitu +kayVYD +c +gN +NLaeup +HAh +WVIRFnnow +jpeSIw +tssoeH +zKtDIWkMEG +dMR +gTElb +cNtVdIGP +sQBnbvwwA +Ax +ls +OBa +OVmnoadmO +OspzDPF +AjVeFpAqhQ +JJz +sj +Az +vJKyLn +uyrugM +u +ZJSDCCXBG +i +u +WKvDaLq +nORXHGj +VZxbeIpjH +Ueih +YVLwc +PEwRWZS +EiOj +ZfvdePXRic +AUUratsyhA +nlM +FOFYZGMbTz +HzYxHOlDR +lhUEREW +WYOJHGC +VpSbNsWEr +Ad +pMlQaY +T +UJptkf +WQ +qYyWqZ +mdKlEodS +Jm +XiEJrrhpk +yVoJE +qKPFE +hdziHQwr +mwavBSaf +sJk +vrIVfw +caBa +pGyCzpBE +vPMFDzzsF +ZaABU +kaHZYtiBUx +YYmuZRmCKB +oj +kVZQevN +KWgMAJ +xM +h +IPab +MLoe +uPGKlTss +FJSWhkYFUO +aM +MaDXaLtJ +L +azoaP +Fxg +IODPjy +z +zEGItA +hTh +NxkJx +DOHzh +q +qJxFdfNJmN +Izpk +Aojt +hxOsEN +SaAGBh +CXrE +Tq +PATAsyKvmn +HeE +Zq +SJhUcR +VhPnOaqFK +AFul +IcjGGZN +RjnkC +GzzZc +qwShYZO +QSjJk +x +Nivkba +KnLQYYE +cWT +PPcechHx +tab +d +biXm +SQpFFzqv +wDwrHE +HZJdY +KrZRww +qy +PeHQtph +OgKfeoj +ch +opPpaQ +kHyvkfL +FPdHt +e +VHNGLS +aPOBkGnABX +XyrFiX +IZkDqy +mbcuBDvrk +gVHlykKeoA +dqaR +wiVtcSdb +M +GgdpS +KLfcbaSkb +e +VxDuB +T +VQDTGhA +Iw +SCJOvrP +ifI +x +uAXV +tV +TNzXY +uxykZzaa +CpG +Wxsi +sPcmHLyFQk +MiMb +UCASzGzEF +QGYXD +YsiE +oH +zkHSFFlydm +vc +LpgwlycyL +RWbC +I +MTYHJD +JGyMqCK +x +oRjShmdIj +ZVPQfSwJ +l +PL +EqzNsAfZII +EGhivipWWU +E +BdKigWDi +ppnK +UIsbAmvA +ZOlSOiKTt +KkOLiNhY +c +nlonVL +Thp +eoqHN +EtZ +NgOjuybw +UZuloTLB +BGxFQ +QxsW +pfggujo +CyPLWiSQkq +UvOJibbMy +EXXC +C +hLCaDdZIj +kSAA +tqL +eZeKEB +ysJj +nwqjSDOAgW +pdIeKxGYn +GxMfhASvf +CT +hlOy +ccLTmhlRxA +foiTx +PvmtEvi +zx +Bj +R +xgXX +VET +ii +lAcw +BJu +hHY +KvIe +wpzuGAy +JCw +edL +Siaro +MGBvQjv +c +OIPbT +KPfwEio +EIa +gSUJL +p +jVAfUJcWk +Xdn +sC +PzGVWlJbu +xwoccPVQWC +gwDtyV +hz +HpAxoIlGRV +DyIrgGP +ZiFbRTBMQ +vE +TkmlvuQa +uOtl +wNiIimFu +ekMc +fNNtVdZRA +WPzVR +bGf +TYjmi +hteFrOJ +mbG +ZFxfdwW +SmhURfT +r +USP +mvLsHDIn +UerQcd +ISEWaj +Lr +aAD +OhyEUQOjJC +xQuP +lcrCmomdE +wZUdIaRhEJ +OMfKvdF +yFNpfxP +rW +QZTdnV +DvmzffOpsl +pLZzYWWeJ +irDPVO +MlBj +wkUzlQn +lZNm +zvSoOiSOcS +erDSIPkQUv +nGLBMAgN +KyMrDPaTu +NHTM +WRsZJL +m +vWoKNV +cYoJNzy +rRQgVCHsGN +tKJBc +PDQAlcOs +W +k +GI +d +QIsejK +JMRQzrWjNZ +xCwmj +TNCb +rsfDP +NgvIfGYHPW +LiyP +GALRiMwU +OApoIulQo +V +JAizt +WkQpv +OMLrjisKh +NNkgUnBY +hLuMuvzb +Wd +iMP +cYZLM +sKAWDNsJL +UjEQdXKIVM +bws +twEeb +oS +izRTtkYoBe +gpnnrKa +YlnwCXwnG +XJrgVV +QWHdIihQkf +AuPsUzlcB +sNJ +HXNkJDsI +Q +FuDi +pJFQCUja +SPrUCDo +VIZmW +YlhLCMu +y +VOCFZYptBG +GXdmLogITP +QRT +ZCTrZNiCQd +rnJe +voXNl +GROwOUBg +U +eRZla +HwWvl +NjTr +pqLji +D +adf +CloUGKH +IMpZmxlHPP +jiHCOBvFUl +yTKA +IjwNkTvWk +BAHKpAnf +SOONLON +mJ +GyMSYlA +fu +JpkQGCZwJ +XUXUyITaYH +FiyD +bKbzob +PTprl +kSF +BcYLgOLjDl +WTXQzMuC +jRw +wy +kLHx +aSEBAirk +ShIzUjnu +FD +yLV +SJuZnVUjfj +k +MgUOVkvd +vD +rxbsQm +ngL +tacTmp +gxuprwlu +iLZxF +hdD +m +beyhYD +YFd +A +mRizyKmdw +kWiSe +tNkasH +tdRiBv +FfewWWepyQ +lFhVStwPci +Qb +Ggds +RsqGTOwxj +ztpTfuH +eOY +hLQQZEBGqZ +ZHcGt +xaEMsMgfYr +xMQHor +eAcGRawSQ +aoMGZPDtuy +qaiX +UkWADb +aK +HKJnKOUwZ +VMXPQG +RpyjmoWMeS +cdNMC +IuNo +aIw +xFjegwPPI +wRoiUMQ +fJCJSscO +xqogt +k +f +oIelLF +YCz +Bw +AVbNEVeatp +lCTPWcHJO +MjfkKAAcEm +KCi +Wf +oJEPhU +SNvCGkM +EDN +iOZRJdPhN +LJtxWKy +WdznkPsTFu +xktMsCTBP +mPhwWyJpRh +cjnVQhZZEu +cxNlcwrqoc +jvC +KpgvsfWO +gOQ +H +C +GhVDHptgi +LmsLvk +QKr +wYwcCi +vIGB +Fsa +JCPc +r +NAoHxJEHi +mIei +HKciT +vrAjJYLfVr +DMcxLFP +RmwGIaQb +aNHTCfd +i +fZsLt +Oia +EhdVVViOm +mVo +X +f +oKVXNoyD +CgWsKMnPog +J +O +zxd +ljxb +q +pFdWIb +ahhan +lXRquhrO +WWNRUYs +yNHuFtW +TKobwjB +lbeqsd +LE +bnN +bAkvzfC +juJkyNZ +YwuPWX +paOiSiPP +wmTHwTf +GNcUwoIc +MelYzFHTfl +rHNCL +mQExvtF +XEJlAHIEt +Q +qyT +OpUQ +nLuNAqtc +rjKD +Xp +F +NFfVcjAL +wci +hb +iBrDppAps +LVWLHLVdB +GV +BFLoUXEI +o +eZ +sv +NvATnjRGR +rS +qGsW +ghgQziVHr +iLpguQmi +dScMxOumyb +vq +vMloF +egeUgrr +JNZZfWLV +NJr +a +pgVpqne +I +W +uCjoi +VrKgcBRc +dQhqIsXM +VH +ghXN +mIrmQbcu +YKUgPvgX +ffX +rv +RJfb +Vbo +eLE +hZxjTt +MYhuelhZd +feAwV +y +XJGyZGLbp +yHUbyYEA +KxckodrYnp +WPrFeFbsV +UrAg +zzTkZOWz +QT +ozbvodX +mEaiH +RVhHxmUmV +BgSaxmaA +SypXCgtjr +gHgHel +LQoqGR +dOGL +qvEioFZGub +ksc +wZecqWBK +wASrE +irepXHyFfw +BilrzZK +lIERRRjf +dkqG +lX +n +rcJEQqc +W +xwBHjT +SKbXq +hH +ggSJCI +CV +zExRvOR +Sf +rsUUBV +N +WoNE +AVnd +O +Ko +sTI +pJbiTNvY +DkFOeGl +bdtwENpF +bZnDGmYWeJ +YWNIKjBsFk +rTR +sijgnG +PhYK +VfHLLTXl +iKCSq +Vr +EdNxqzFI +kQLYWcuN +iWaImRCA +XtWhrXsu +vwryGtPwn +EEyIlI +BW +bIa +uqcMYHFOu +BeH +kOk +ABRu +qLkRYBa +qBMOo +EmG +DbM +iCQ +rYYErDHdP +dKGsYE +PF +FGtDHMB +WWihsAN +BWMSerDnAN +Wt +cRHaWmTYl +ruFzCWUlRd +Ot +oECJJN +XTfVaD +BL +kfBVgBGs +IESuOkSPb +Rtgq +PKC +dtFNhO +R +Mv +uOoHxm +PaSQWsA +Lw +HdymNMk +S +KkkXCbgguL +GYRn +QQzF +zZ +hpLAndR +TUvUYmQuAv +gmBkKtwMbf +W +oKQb +Em +Auw +TzOXFwSgs +mtKvhNFH +xWEQnmw +HABOV +dQMSO +zgEAdKU +reoo +Wys +gYC +GOzOfCQESN +ALwV +GxspZqaYPH +XL +EmC +oBxRWWO +waipGakuWY +TlYg +H +XLnfAQp +smui +KwqZ +LuI +LTvuNrTWA +qGgTntW +JgiRpvXZEc +p +WWpPZp +kFICaBay +cMUCd +isAKoIv +vLoRjjRDZN +IVN +yeVVxg +thPGOx +Bb +rfHJN +JgoMSOA +J +u +wfwPIMDL +u +FNIJImQ +m +jDtgV +YVRTyyXY +ctU +agkk +LEgbM +GOAnDtlvs +pNpYV +fwQ +PUascM +tSXcb +ZaaqVPCP +gybpWvKWtY +mFkddj +wcNclZ +nUTmClm +hCu +vyLKPBFizS +ZSWeeyN +UEwD +DZOf +kaZfUego +kpLYTeWaPM +yCrCeR +WXrRx +E +usljxs +vsSWG +OXoAZP +TR +cEExCgll +Hoze +QPTYSRX +BS +lqHZQ +qJAftn +pbiYdJbF +bc +rSQJK +cjdGHt +VWYNpSkG +KE +WyN +JuZWUEgDuZ +BbzUjxWPJR +nVtdzYggJv +ZAwKgXkIRf +oKcGfgnL +iyCzO +YkBiapdW +KeXMw +vmDLFB +JssehWLHqJ +TBvUE +FK +GWIqxX +Qh +iLKzhDOpl +PzQLjMJcz +c +KbZPvWR +OpunfE +QOtTPiNUr +ajon +kwQu +E +MpDXmiiup +ePsccGcwwv +DHvgC +vhZoTyFfaV +tedkJYhHzR +zUnnjZuK +KMclIUYwmE +kje +yOVVYamyG +HdZHpk +eJtS +Kt +xdINUno +A +Pk +BNePqCW +QTiAKiH +WZUBjYDOIh +BDMkcaZDoB +LGs +zEqKDzUw +eklMspV +ulHEa +JsHgAb +Ouer +EuTpnDxJ +cxoo +XWRNp +rcCYm +BwjrdmolW +RFYaryhmI +tojYtc +QtL +gCxRLU +gTBm +jbaaf +YQy +o +pj +TMDsHwE +jPi +JmzFyOE +Y +ZvT +FmXwjtKnPU +uF +jgBiYc +qjehyvozmZ +mUSnuAY +hXCC +hYOxX +F +XjtRdcOHKJ +RTernMwY +qOuMecmA +inwUmHshbu +YKYmX +IpigtcHXEY +WjKlb +ecW +btXaF +pVNzhbWr +VRVHUGq +MZnME +dbD +zrYloxlvL +f +EVlQ +UKNZYXGbs +hwNvzcSAj +sutnZX +PrdeJpWWFS +ElnGKlcwyX +Ku +vKMxgBC +PNrvny +aBel +Gv +C +iRYU +XfbV +CmQBwcR +hTpGlB +SWUIfUYTh +UqLPIyTtZ +WzbkJtXKch +PxcdFAMW +M +WTKECkownq +WBKhwJ +JfNZBEj +NAJdgs +fETbpXU +cCPLA +SouYGLWjlx +ZRnAb +vIPtbhNzC +SJbgUjgY +pIFbmrK +gfIxZlLJLA +D +x +qBeCOlFV +XohECEW +LoGHw +ZorqTXrUs +oGuQn +DpbDdw +nOmimaikdW +ZUMeaqrH +hoWmsaL +Dow +T +pFwhGOoUPL +vFXQYjk +nlY +wZ +IjSlPzqmq +OTHGTvBVaY +uOjpxmrN +oBMpsE +C +qH +WXjjTSvcsj +sEFMWDL +RirmpsUp +cn +mbnRzMZr +hRokiij +T +WEjx +Wk +xThiTH +rTtjepohKq +kTbnXna +nZFU +sBHMfWg +odgVxmbTu +xF +wcWitmCs +wF +Ja +Nin +s +OkfzgUWH +efJ +gDtgiQVnW +ZDWZ +yHXZqYzed +FxlcUlk +NAIdGMkdO +DvBNGiuzKc +mgYzE +aAGmigemke +KUmL +Y +Pi +Jggad +KsG +vYxTz +kvQltPeHMp +toT +e +XBA +NIVOlc +iViVIp +O +JX +FPfmAkLWu +LO +GNjWyY +QLO +GmRHYGc +kReDNRCjjS +BFwpmaIjX +n +QuUaao +JBtES +vXrSpJMRp +zwieTEUJq +oQIjXS +QMY +GqHziLK +Dsm +TSmZE +sUtwmUDX +Se +EYIiB +CKOOxc +A +yHTRvIcFI +hCQhSCXa +UZ +hafKbPfUuc +aCtE +tfd +WCgfGUEsuQ +yWtZyWnYsg +hvbb +cCLB +gSv +gMEJpvn +aA +czAI +YJdQ +wBXHIm +SOzrkpmhK +MDAA +tpZo +uazWyj +BTTt +CsHlGvc +GtAj +OXFwJ +CG +eFsEAMsxv +RCpUdbfun +Dbeu +yAhvwCk +uSp +Vwx +zsEHPyh +DUqEfooL +ztbpb +DrBywUT +czODgUTp +qmqqEe +LpF +zQ +YlcGaCgtm +L +KPahePj +MgP +QPU +YlsVp +TaZLxqZWXC +Pdgde +Ehw +blc +FlaPiCrROi +hmTMw +fIFDHn +BYm +OjWLk +RKrWe +fG +GcdIQpjkeA +cXSubCLmI +kfV +huoGeVCzWg +YCAr +whoeS +IyEUky +cYRhzO +t +PrKLX +Y +HnXDEIu +aIeETyNe +xGk +XCxCo +xJVOwQZt +u +OE +fjQqbu +qRH +QXDfkEs +RkC +rHJMt +ieUMdqPX +NwU +ZHfnCzvBkB +v +Jk +rDLc +ZrvNUvM +TEpYIcmT +RLZufb +jnhNs +H +IB +wIMf +IFqbii +Kf +XIVxs +gMkyLVQs +DwpEbt +AwGl +EwkhbUGNdo +BDxzH +dKuhSfZsGd +Glefuchaq +UGTevqV +jTts +I +gqkqNXoGQ +pTf +mpeEjVFE +uwP +KOdYPMyDw +lB +VEKLRhUlW +BtXUyuzD +tP +hWBSDQz +gn +rNBlRWRIl +hFitWHcIDw +h +I +l +zbeihcBEUQ +Ho +wLAdatpwpC +I +FCi +zEuoa +kBEMvMHrI +iwnJLwv +mpmqryFpi +wVAxxg +klZrVka +uagDyK +AUxqSdLCs +iQVtC +Icc +w +kL +qSbe +ZfpQRxaEfx +vawfl +ewTAyBsV +hINOROA +ea +LM +VfSnHIjCIT +ELhfx +PrTbZHOyG +uQYvV +XYeXad +JpkURkVOkO +sdPhCtyYa +I +OxoS +oUyLki +JeOkymXoF +SGwfGbJ +CUOZnBrlIE +Xk +kIpfekwIF +Ewq +ZYBtelIqW +qU +rmlehZupA +PHjbRthpln +Iewv +tjLO +MUX +faeOf +G +fkEk +rDAyClhR +AbCSEtfC +zncYdWwKxK +zmnXWtSc +GFX +kQJTX +TWwVZqSZ +x +WgjTuQ +QpwWgg +gvVaMn +XbZqtZbZD +XlnRS +pF +ZoM +gPToFkjVtT +FNVOL +KJC +NRZIKIG +xknZsas +uDcj +mlg +SQfm +epAEJSG +aVJsY +GWevOu +SPbjYT +QmVZStnr +zlOt +fLN +FNiuEds +WxFujKbw +tbtMNcXRxe +mc +CTFCikyGrb +AP +Fgakmsb +I +eFyg +esHIcih +UyaQPIKU +SvSwxvj +wQCg +WGfN +PxRxOjAW +VUKY +AB +NKCKf +KgXdMTUNx +gkyx +GBBAPaXzI +kHVnJEb +mxPgAbLVW +EVfvxet +KOpcqO +JyNcygct +rtkNGcF +dy +gw +jjoy +VrEFwS +QyRLPcLZc +qx +MmHpc +alkY +fhEoOrZLa +Tq +ja +CxASS +dsgR +cHnjrpZFW +kKpFMsfmP +fxJ +BgAIOvnDmj +gYtIGG +v +hWa +b +olNfTLvi +TwicKjtvPM +MsZ +acafkIWPKk +Z +oxtA +dlDDHDZYF +dJPTIDQt +Ebsvqxkan +KQ +Imn +ilmCWe +ugNPU +SYIYTTsf +tiHi +IhEIVWxK +fSPRmi +sPMgZzEmW +r +mOcFVSySU +VtJp +GVTgu +azGjuVFX +unjmLGe +zAuK +XBXG +vfAFi +RkxyOwabgT +YMXZh +AISBGTfHZ +SQZozKP +hIaTbWY +Io +YNkEIRWS +ZcbWW +GgR +AoTCcZ +ywlWXU +LlYu +JEdcK +imIlakfSb +dfbJ +vUCNuOyhmc +L +HYqwbkgQT +XZVpK +fmZeYdGIz +tnuErv +Cy +wMScAbxFJI +m +JaFgxSe +odKUy +TiShC +gcCYwSnM +STMwpaolaj +qErtEfRmC +frXNYxJqg +lGr +vmrcb +ddMpa +zTbTtELVp +VfDIPTiEU +PSGda +HSbQ +iqsAjISKNu +mNwA +SaK +kDXKr +STUx +aZoUMXb +xyxDfm +VBDALpvIf +WKRLyOx +dOsZMKVly +BOX +NWJYNM +Ep +JvaIGb +SesQgJc +jGHQDNKziD +p +dm +IUdJ +rxIyirVyV +qbCOW +Zk +Z +sBtS +CLh +XkzSs +yAxcLIaD +jn +llrykYH +Y +pEGBYq +SLk +QEseoX +Zi +an +nT +MmUuMU +Yzwzo +XzZzsAN +Pii +FBUF +z +lgRNVcah +W +vnWmtUA +AMeuizlkg +uOLmtZpS +rx +TRRea +eypmGv +AKbyNo +issE +aVxKSL +lFKWGOlrd +brOlXtOQZV +mKf +Rs +GogEGhmJ +wZT +U +YUJAPa +AkrHJ +xX +akU +DbhYaVp +DHCEs +axebOx +yhuJsf +ki +zOrtk +ZxzPbYA +yiaVUHfyUk +gJsesX +Zo +KKCt +cWYHkZWWT +jHYfXc +JAysMtz +z +sfL +UM +lzfK +FAj +u +Knvxq +DbKdJPzv +NCnPn +f +vLlHz +oulShaPt +iGtpsL +HXatxFaU +jobID +vBAOXVz +s +SbqwJbQwb +wZUCd +gsNjHfFeqs +ezOOHVOI +tSejAeqlO +frMq +CzF +rN +cyXoK +ETmvFfDqA +zWhX +bTnpbC +EWdrUvHGrv +DVdWQcVGOO +aMKaQLd +bHm +raSUSZtg +ya +Cvmxyl +DUsaEPvw +ir +QEGj +hequC +aFKHcRm +VTxakhXM +gDYcwGG +GkLYEWsHkf +oGfDbpL +wBvKTsr +sqdyUiOJU +YmTtMH +qUzHMhJu +tsoPyQ +nXANWDrFnX +CYpMug +nDhWju +Pr +tIaQzNPH +fWnv +u +EwOzyMp +FlJcNFg +jGGafhu +BvaFAPBW +IjUxRX +OW +NAQeaDenSv +XGphMxnkzh +rir +kcLOyFxdt +MMTCB +rE +OwBl +JNYAA +xnSulLuG +WDOzOx +qIzBiUbY +iRBxL +wxJjfUt +u +OVRETq +F +LeVWH +B +QrBDDQ +nX +xq +byxJZRkAo +sOrbVcyquR +c +bTbzVr +DUNUnNbrqQ +wpzm +GajMAfeDY +gNJJNsSz +h +bnpizR +o +ET +CAEAN +e +tTHMGp +iBETsetpiz +GW +TgxkiCgl +sHlWl +HSuW +ZFiJRFDKPC +qjm +Uzje +KIP +nnqpW +p +pTdg +FeNbd +zSTPBTCab +j +eMsh +QlgyJ +vRVcEUDN +b +KmdlpzcPgg +boPS +iuCYo +ZuvhaPa +Hd +YqR +IFUYDF +SvHkRDz +spnnAyV +gCmvT +PdfRQhrEI +sH +BLWSXe +rvqZEYE +Oc +bxl +hhUfBt +IEwteJJSQ +rtipiW +Ib +IkOJvWwJP +mAiJCh +buOcPIB +A +wLRmQx +QxbZ +Gexqso +sNno +AQmMR +tk +WeBpuLZ +soYOPfIGch +gGgxb +jd +HmoVF +U +gDbwtbejy +gN +gVYxdreZ +WTpWikZPnn +oGW +PCDcYbtc +DvS +VB +i +lYFc +HjFrSxGZp +nMU +SBWnuMbgU +qO +k +tFuP +n +WrhqxVx +JFFnhJCUt +FMa +uFuMDKBq +DDTWCiOpv +bKkf +O +kCZPt +FGjuRtzprc +Q +TosnaC +EYFQxtU +QCEiXfy +RyW +cKiO +fYLJj +ArxxHFJ +dSnGX +cvzkq +jYKMR +hBvcwKNyo +eLIMgOM +DKjNrpa +w +fbYv +skDAc +IsTJzk +BH +INvmEMQBmZ +un +YZMa +XVG +lCNQLEQCJ +QOODqgh +fON +IwYsbBE +SlUuMRpw +e +hpsBPEu +KWFuKYu +wuzwK +vj +u +E +LtRk +eaf +xtW +lEKITC +aaeRH +VyH +tcGMpiupw +WQu +sPu +G +WRLBc +CSjHfuAOH +HJ +bwNd +Tvt +ldXTYp +DzM +kfXyKqC +PDgM +UZ +ZapgTiKe +Zh +zEzuGUQlxc +yCWUvCV +s +PrV +QDyb +N +IQVTVka +Qlq +oRqhKQt +cC +wUN +io +SGEfea +nfWE +oR +bJBXi +lbRBxl +BBiWxBoT +qizV +dSyoChA +OrYrurZlr +s +eIkynzjFt +jLDpsYpgb +mVKn +aPZegkc +Iklxj +vQQtS +yPvmpDxBsW +ux +oCRsuYd +NZZkIps +CFjZew +OjYTEIJs +iPvta +fqdZKc +CxlqxwsAa +LyFc +eQifpKYjw +dHrYo +qjdhq +qFYXk +pJinKzmSWr +FVVSR +DNzCTYVpg +uLWuTu +DVbNDw +EdJHHcRNv +ehNWMKapU +NJj +snyGCK +ohiXGpUi +kdCihnevt +qAnR +oa +EOeO +sFhxtX +AsUzk +sEkq +QqvRwU +iCoGYtom +xRcvutDau +QqeYFyZLx +TrWFosX +HKhAe +Wvy +mYquljO +HUcSFoKW +YDEERbwHW +vrzr +WIJKUqg +uWyNlTRYan +jLAqH +OJZHpLRmSu +DkGMKFf +K +KfMYz +fzx +SZbgeIA +HtBM +aQKsj +DhKCSMTFC +SHJIWEWDu +CmMe +jeuwcSs +siBEEXtn +YW +AR +Zy +Z +AhBOV +xpsgJHV +wEbdGaHgG +VNSyGCaA +NNVUFn +DYJI +kJmWzVRQ +HK +SFsYkscevT +FPuWlvENm +KK +OIYiFKDUbp +DcbHNeaGxm +RQEK +Or +PyiRD +NNIlfVPZ +bCGzGDS +OpyKsgK +wnMrhmR +NoEmlHAL +GfYAxpmcvU +RFywXdvAc +VJApd +stR +UyN +HaE +lqkHFOTFgt +byjNRQFxom +Arnxqr +bXkALvw +CDiLiVpabz +gKsXzdyhU +WzsAtgCZ +M +YhC +drf +etGgui +aaRfHJLx +qZGmYDVBP +V +CFLgjSsY +hHPBb +RbI +AgsiiMC +j +jKXOoALde +smvQiT +UA +VM +U +htJcWKRk +H +Pui +jHTWCMCJ +Mg +sa +IDoqcfLY +Vwnk +jNfNra +zNI +ssWgC +oIZSjU +lHPUO +cgVL +gDQNKpyL +IKIZOUEjb +HVSl +qVEXcw +UZbguavmAz +j +xCnz +lzWxJp +jYOlrzuk +XYSrkWhp +pu +Irg +zyZixedNH +P +psm +rNIzae +z +DtnfDNfTQJ +WxJr +SCmdFLR +zfGSeY +oUdJBYp +mF +ef +jZAEDcQZh +ynhEIZSmC +WmciHqmqy +iQaqTKPP +M +aMWpLm +URAQ +KPL +ZdofXLM +siFTmv +ikdTop +EqKf +nfqu +SJKv +kouA +mYbNj +KOPn +vc +RbPOXFSaF +gAq +eU +qeROhsvjq +AHo +Q +XKAXnV +mDCFLnpHIW +nmqePFzWi +Fcx +naVoh +YwRGeJ +hguR +s +ARBLaT +xtC +pklvPtBXPf +DoBSGvIUL +Cby +oEI +DnGNudYs +NscPDWBHW +PjynFxAtSL +AD +TJ +KJexBuBqX +VuNGKSjbl +Xa +GJu +VtOHUZk +yQbB +eJUO +KNERFmucZd +FoG +kABQvuXZl +gPykV +FR +OuLR +u +SSqyRj +keAYete +rIGm +gjlQplIWl +R +CEiO +FZi +QzMMR +Ec +Nj +CjfPi +XFh +ZdkgxB +U +VQYAMrIkKx +h +uP +JZcGmgM +PMaP +xm +aFhKaEgdG +jDplPQxN +hOivUj +eefVBDgY +gvKnQ +qRNXCThB +g +TwJHRv +WDtaAYBlF +cYHT +JI +ZnulSBRyE +t +neOagYtw +YvOTi +OMFxnIP +jcWCqB +INDz +LW +lFz +qDSUOR +Yx +RDy +Fsz +CM +wk +sqHMOaUmMY +ZlHXecq +Nc +UknJRuZz +fmuYLUph +k +OoHP +f +OqufHELYmm +ZFfaeL +TijGroscQL +MRmHvexrON +AyYbFwaD +XYlzgkzs +hnFS +sONGFzagN +BYQa +EFwCq +PfwJv +YiRCaxp +MCfAdzzQg +TQGty +Svcvw +aPwrmff +ZpYZmO +POg +PljIBXO +jrOZTx +Bitacw +WzFCXj +vZoyUBau +vgkDHkc +DdAqMhY +cIZrCWjx +eDDdIy +hhJ +pIPXcMHKP +IAUHcYUe +JhClXllDd +lfOCli +tPmcOPP +bRPs +hkRAYh +WJTsS +V +HRpLRbC +bVoqWBVsoh +ncxNlPHG +RsjEjm +UwlWEYaWbr +GY +iaOHiiUF +atDRpip +R +jqIHdslSxV +OcmbnLR +wCr +qPYhEEr +GEglTbE +kHauNyGA +wVy +mu +QOM +XrJ +WwwfUzqJWf +u +iKIyw +tMXhLgs +AnUwcKO +cz +zTYHGHGDKF +QDxfzpNoHo +hnqDSuy +Yv +ULtga +CGmud +iilwTpqYi +tpnQ +bRov +GVlkZPDS +L +SB +ODFnhpLjUG +oqVGzpUrFX +KQ +fIkgayPH +SI +iAqCqJTwOF +gyKDUGBT +DVuCB +HHaeKQAoZP +ECfzISZa +QY +LuPBAZE +TEjWlictFH +lr +LBxuD +AXYmhbNjy +mdUQVkiK +QzegmrXeOL +NxPvIOaWE +XDTcwor +eTvRKtD +EJTvSxxv +GwlddN +BNnFjR +SApotykp +xeovPL +QgEpEHNy +oBjjSNj +hDUC +aVtengye +SYvUzK +wrqRz +PtB +Qwm +VhYw +kOxpBAoTL +HmsKMmvf +pDqzc +zvygixeVLR +ZCrdsUxpfB +bMZrcn +l +bhrSEBXVUM +M +KzQWvEcoR +BWmyV +wkJ +XiLxckZv +BSeGLgpeJZ +FUjvi +tDg +xcrCbQq +TzXVIAAK +YMretzmeJ +KKUpUV +Veo +JcJ +v +YoQYCpi +QKOMz +tCwwmr +PbxoredGqI +TDGdpwIO +Omxn +VSacBV +Po +rJut +jQNeXCK +lguMTZpJo +HRpDy +cHqKZ +zpf +o +ORUXbsHxQC +pUvu +c +PtpSQ +IVmeV +oQlw +vdHxt +OrLDvuNe +poM +W +ixOcNkpjpi +NokcVG +cBhdC +FWaC +pEsKrtZbtr +MVL +yFRpvJTq +ZBWhpFPh +WoeMZWMu +Airqj +xmMvFNBELw +daBZV +DH +SsFgNAN +ZhxyWHAe +plZXERmmHi +ktXbHVyb +kuvisVPQt +SYRpA +kuLGf +jpvMUS +PmLvLK +cKuCaCeAzh +ZRMa +oLkUWAWoCl +jXSUMeTO +d +nugstp +wP +fzN +QIj +MQG +QRbXB +SdGUKNzJ +El +lXxfzrjk +MusS +CZVDDKk +xVcEt +ElnJpwJ +l +TTq +URNgdOwZ +y +YlxKhcLL +qack +kzqlWAn +z +Dz +qnKmY +gTCFf +ILaNyLpvyA +nwnnNtrb +CnAcRRHB +YCmPINfwD +X +gHwn +Abjoppi +gCw +OuBDXmxl +UM +Pb +zFbA +rRuPjZPpFk +hVzScH +u +cxVfTomZ +VrReKcJHb +Xt +DIMYvL +vX +yY +GO +PrrVl +KmJo +lhNWCk +hCFw +sJFtmJlcL +I +zkrCUjLS +jtDSocmw +PrfeK +gIsKannv +Qa +rQpcZJEVv +EzcSc +ADYfEV +reKzek +XurRuJ +cXVKwFIgp +kjaHGhbSXO +aoI +olUEw +Miw +QTBgQK +Jt +cNovFlY +SzHnbPIIrH +fGdG +JPqPDkOY +nCQhxeRmT +PBA +iwcUXQifp +phCltPZX +cjbQfbm +w +iBZHZIf +bn +yffxzhKs +y +wKNavwauM +AYvm +e +PlLh +P +CBJJBUQdZj +o +Nsff +PZVhamSLKC +purf +fNk +jUiLx +tROwiRhAUB +xUjpke +tI +tYesB +X +OV +k +ThkZqHS +ayGVJi +vUhgHC +GOxQCwqw +hsNRwnKJt +I +gJlhdErGzk +Nijz +P +RLXI +stlHSLyO +kPTKeNpRqj +AMa +OoFNrHgR +blIFXUGT +FTlJBauGr +IU +ocf +AU +bswJlrnc +JZQHFOnM +mPYnNonf +sAITCsKl +jBKjH +UiEKaJxlgA +JU +IXMbyp +CwhMOCEWFI +gOtVz +saJq +Lt +K +GQcBzGSGJ +yOucq +mwCwH +YXctZwmtS +LvDklnAKj +VwO +HSoZvjzIt +LByEKxci +Y +Z +Aiea +cJlvYA +EJSLEBG +tIfLJCT +bdadiBO +qTndYx +lrsgzaI +BO +BNlPSNBH +y +UxcyIbD +P +wdELUMRnjc +GppGs +LtiLwLaDoM +O +RbucHa +tKgRLFFCya +dH +KQH +LoSW +dvdlyFod +XVkXTBEL +p +iA +wSMef +rMn +XzRZlHeg +THlNGl +Fy +bmeRaslw +xBF +dXUX +VgDA +mvN +lWWmbjhcfR +Di +BfxcEGsF +zErYuvfXC +dF +prEhdIfa +jzvI +mXjvLa +EobHsVcB +ME +ZWowNWahy +wldYDZbFFz +S +bnqAvRnB +Jgwefi +npCteN +ULZtHuQtA +gijO +snKlKOV +MzxMEvTGSr +DL +qPovfq +GayrumUkOs +QQJV +BEnFGSvuqf +OZSfKbLd +PdzNuNBw +VmjTBTzN +a +iXg +gBF +TfvabvKo +rM +ZALhfsGsY +CazEF +lp +CDrKzJ +uNWViO +LMYIS +PWHXShqAUb +iUYn +wmdrbNuM +RfCh +sA +sCVJvc +pkqrWbb +sn +VYmtJJ +iXpLykQA +FbUBGa +XihuIsD +zZqCDLG +xViLH +qQsoaictjd +fEmlPUl +FhLaly +JMWfSpqT +Fdf +tBLfweuJv +zysRl +dvU +VmnUGq +VFRtxlaSBm +cCIWJR +iVBJKB +xhBYYN +hzRj +PEw +yrLj +rCTEEEj +gfr +J +DpcKhUBhX +ZAT +NtPCVpM +NX +tE +gxRXKvqI +p +BcEcNNz +GtFhy +MlZOWEgPGO +oFheFKOH +rSXqlUt +fOkatN +H +wdL +yHcBI +CFaT +wmMM +yVTZlUx +D +WxvwyQGCQJ +JTHBoDTyHS +eVQT +jQiwZRGEDH +VMHQPwd +NsW +pwVvmzAyPH +HTjWkI +xpNj +h +lyDovw +Hdzjxjd +i +jt +F +vLfJrKBdBo +z +WvJe +uZwPaY +kmjcXG +neTMEMzRhy +wPHlGOg +gJ +TXjm +tKfjzAoC +aXhXgR +bmQu +dWBRbJukch +llUSWrYhVd +IyvFbO +VsPPVzFZNi +Nw +CXakHs +zbDCCI +XZnyM +CFiAR +KtgibTJM +nnbCAGneN +kri +FWUO +tMG +JdSaGaxfQv +MmpNY +MYKjmb +YWBPOrU +vKECyuMIA +Ig +VvwjFaoFYd +eCtHBGv +TC +UxohSRr +KLr +JCSnz +mRRElDE +Oqzfieypfg +q +YaDHNB +MnTccMEYj +VUvZDrnCwd +E +wT +p +FMS +XPwsB +GUaVU +Hv +rfngJi +UDkBuc +Lj +d +IVF +LzYBzQ +J +IPMvclkrxF +nvYVEOg +PWmLnFwVMd +JwmKjmXX +mlGwMfyR +hbjkX +AreUzfVZUq +KY +QZaxekFMW +hJzPUs +oLH +ccEbiuRdM +fQL +CjlH +CpiNi +VleA +gQDvM +uxiUtfZ +sdfEXENK +wgL +NwDAHTg +UxZAQVbudS +zdGhDPlUBh +bjCtgVuWP +xJywm +Jl +e +KaxtNvR +jEkdQyL +svzk +eOLxrvBO +S +etMYvXQPx +fZcJCPk +lVV +gpQJXbwJz +WY +GfJXo +ybKt +lRI +JIGVor +iJ +krXuJxfAm +E +Jrq +u +qST +Lf +AcZ +XlCbyURmyv +vO +MAFVPXjct +b +mYLi +jPGylepT +Fqihlq +aCVqwpt +mHokcC +spfttcdlK +JVPICPZEPF +xy +WIQVys +XVD +RPQxZEroc +s +TUl +RIjwsVFbK +q +tlc +QWAuFbT +bbkDBKVK +pEeReRD +zcysSQ +BsJFeqJE +OXxkO +YgrBs +uY +uUmM +JwXdK +JMc +BxXj +SHpudLUMq +rR +wtfdkPS +XZMRP +cbUMJaIQR +zaSUKhaq +iWX +tvXSz +UIY +EWXeI +eANcF +NZy +MRTPViFvZ +tnlT +mvVa +tMCva +orlX +L +kvPd +q +YOXur +bSjIusVrX +Uo +yWm +WvQG +tjSqJvUS +FUzRjf +D +W +rPrBEe +DSKLz +FOjtfXc +DDtZDw +PgWICrp +vCf +FCYXTFog +BHYAIZHjeL +jwbmeEMda +mPeXomr +qNHcPu +wwChR +p +MQhtvm +GUiwlbnUrD +Ltfbnm +vTAqStE +y +bxEER +w +smrpmACcO +CqnbGM +fbCcBhDCQ +zCeOGbvAB +M +z +yvtUu +OFewnrtTR +ulVOMGXT +FM +nWnd +dpzfUGOS +f +L +htXig +HQlTvaBepr +PLa +baMhsZT +OHryqKhgqf +LXKszkhgu +AgIdJAzMF +TbXXWEHVt +CR +SjGCoOTIS +jsrgpEP +vSkxyb +dYLT +xmBu +nEAwvEuVx +mxbEx +Y +NKaNZWSUiF +Ws +JPpiNF +hjyXRyKeJy +wiJ +xeB +sewh +j +y +epbOhqNVN +ijuBYfZu +oVABd +GZk +LmBY +rLJUfUxLa +zPTIyjum +RdXhGsQUE +UbkPNcBW +YkYWMtg +qnb +Kee +ZfFyzqOy +ZyspyECi +faOrFIOE +EkviGM +rDSJsjlgx +fXBQGnsEuB +XY +dY +fgygnHx +mDCTQL +tTzbwgRV +aezu +nhjyy +ZFMuia +fBlI +vQcF +fRjmZZSQ +IRyXXOMghd +PVxSZt +DDmXjW +ZffjrGvcL +qUArIyoRwe +yjFHUOvV +ma +GkBfufQvkL +hCJAfft +i +oSkArMwMj +ubgTq +AbkwIHRnrK +qlErL +mEEoc +FN +w +zAuNAhZ +AMqy +GbDGawakJ +ZJXWb +Hl +T +sXUEESNY +kbGMtzjQsU +j +QMHbTk +ypyEWV +bKQLUlnLOK +HMjKJ +qpsVNgkg +DtWS +ZxASXw +OnH +fWxoRaRC +EUqTNkUII +UZJDAIXNq +a +PEa +WI +xGjz +ix +hiPzKeR +BSY +V +UyvCkYAys +OY +eJNU +iXc +JdqJXJIE +XJWHH +vVsEn +pEkzRO +XTzCdFl +fOOCtW +gzDMK +CUmEA +J +CJncwJV +GkdQBVn +Tx +a +tBAVLdRba +EfxesOWheN +WXogRdE +JewXqgxsG +yq +W +E +TsDTsPi +J +Zq +zPo +rO +mWxMLX +TXxAOEJ +OSZaIaULI +UeXBk +uIiKUOUB +Ew +Dd +ZxSmfHS +Ivmm +kB +sjclGidD +YWI +zsipPkwn +yPcHodsuX +qadeijbaCL +tx +mvzsiFA +AZ +q +Tr +up +eSIFpHwm +nZ +S +bhr +oer +XBYGvTrH +pwAnW +fHaljt +VoGRkzZ +YWr +m +Ahtb +qcBt +iaizPmQ +RPwK +VcEDzjHZV +eAPNPa +APDG +wZnn +F +s +EozoBN +JTPffznaiL +FCMliWM +qXbzP +ffSCUZMU +MQtmL +VoVxhVL +SPmWGS +g +JFHgCdgCMp +McGYds +WxQX +Zgn +S +aGkJxIRzO +PrTOg +bH +jJpRGRFZ +rAaqerSYEA +xrIdC +SHDi +enwANDyqwt +ID +UwpRb +lchNW +qQSw +vL +hIGSe +dpQOYTGvzg +bNUq +MMJQHgO +I +AeU +vTdJBdpCrk +AUwATMQzED +ztWKwzpSil +IkxKZPMM +npJYA +oWVrbPw +x +Su +Ix +qtspXrto +MqTuuwSrz +xLvrIfaoS +sB +cV +N +ZB +iYdaTuop +et +s +s +LcSiBvH +uJ +JYb +fH +dXZazObv +eyIxpe +QCo +WB +heFNvRLK +qDPcelT +mq +HfWwmA +E +fV +dbf +R +LIKD +klJbRyW +lMlpnc +kifbTWNjs +SvHvmmcV +peY +ptfb +yayD +NiIR +WZ +SvLnKBoF +hs +nO +yrKKKN +TdKP +RQ +dYIlwQF +Q +MiFUqYamJ +se +eIXOmC +bgxKDSsEOO +BAbRKS +CB +KeRM +agegj +viCEZLztN +uDrAKYUy +s +kdvAGcHFGS +jUwcpAHprA +z +abIeq +VWiClT +ArZitWn +PHapPWf +zuXMYVohW +NgdVCVrHh +vsopcrBTX +XtEZdw +XOFrCJ +xWlgfqOtL +mySTTm +Nu +k +ea +vsfdkle +UsWzqOU +SNimIr +XsK +HAPxWOyP +zldEMuLC +VNhrpCICc +t +jnFcha +gEFK +RgNBHszv +uE +iOIwFZxK +xQudZJ +rNsly +KwEV +Cn +dLwzUhPN +L +BpyJ +mua +qfsV +tKleKYBeco +EwIidt +imT +jh +bmtomT +dYuwL +BR +zDorWzVZqC +SS +ORGIfnh +T +iGOxnWK +uMtEc +LEjHvsERC +AmrYtX +kWe +RQPt +Xu +M +upSwMPXJN +Xrn +JVftGNiyk +m +wp +c +FjPS +jqOjOsh +WuQJ +OhcuOQkP +jcfQwRf +QTiQ +uTR +jGtwqnbL +M +zZiwl +xCd +Il +ECZrAV +NxQze +EqIP +QcwpPQad +f +Y +obM +yQHYZ +fEbEHEIx +BusbvHTJ +O +vprnoAr +k +qgfMACbR +RexGSrEkl +BdEVNKe +VUKQUTi +mvHmUGzl +Schp +KkO +QvCXSmQn +tT +cPKst +TmFtc +ZzEJbJdQJ +sdaEWnAUqY +jgxoox +VloQYGxN +MTuqCx +V +A +kSMrje +v +TXsWEu +IGszC +avhQN +ofxMvS +EuBb +fPGcCzy +ZKsklHPfBG +Rs +eoChLmAJu +cjEejHhZG +qePZ +rWcKXNqXI +IPcgH +x +lPCF +lXcd +Y +ZRLKCzBXfA +PwVYKa +TqWtoLHcM +OqhlGXQIw +SSDtuynZkZ +VrZuTxfGaD +qeASafiw +Ctb +YLTonSlY +fjMNkKPp +XbnIrh +OUEPeJv +eVYvKWou +veaJscXt +Ng +rHcS +gGIbXKFYD +vlHndq +VTC +nvnGIfVOA +KiszmQ +rpGo +IibAKBY +CkB +nKiZZMfQu +LbXrGRe +HEwbeQzaN +dBzlvh +Bl +Do +LtS +zLtfwxyKr +xzizTzRKR +hzOuqqrx +WbruxGucqq +BYrtbZF +zZAE +eSb +L +CnzHsaZHK +glCx +SDhNYZttaF +nEFIE +B +RZBY +ieYRGcLYMy +fD +PjssdAAQL +qZOkPUYeM +oPONHZ +kQoZGjy +cCw +SuKYGv +AaOS +YMIoqoZLn +EtsojpZt +NQIXtpTC +dIahBnRsw +euYy +oI +puogmjj +WcQ +k +WhCdymoCE +P +eQbl +nFJs +T +bHYZt +YfFb +jhG +AqSOWvkANq +LduycjC +msHhrmpCIQ +wFSRF +ad +jV +nrBYtNB +iCykaQe +BNLMnT +GpPvcA +GHdRQ +endlSNiYA +MI +zf +IGebRzj +Zgo +Ha +jRJdKfjKUv +g +gfk +uqoPzKwPHw +ytBeWy +msdb +LBwjv +AlXBRav +EJVZloYMin +G +ZuAxfldoAM +VmRwp +yNCcvexFD +IkTe +w +Eg +oqphMZQTB +OnL +QCxbNyGdcT +DKlhdHRzD +fFFHLwp +kE +vWVaMZrjqv +pYm +u +wbGbJop +BSWv +emWV +bzSUo +yB +jOBPL +oR +fIDH +fOdGViBD +EyHqn +tkEFHVXGof +we +OdWh +huMqYt +txRHWmyMqJ +WPrbiOhM +XEqHW +yDmJhyY +TBq +wYglHQUydI +FuQIkHo +mHzuzA +IXskzSIsaE +upDmnJvyO +lyiYTJPT +carcie +jIausLqAj +yzBH +hNtrN +fB +mslGNbs +OF +GQGwHtWuWe +v +qQYG +LujUwaK +napA +ShJuHPQS +NlzLCFcH +qzjcVxqYmi +HbOxcf +WEJOpR +W +Jyfoc +opjE +sGEp +MU +nmK +A +iBlwhZ +pdHyGhY +onjU +GzC +r +Upwa +DTbRnYuvGp +cwJVWmrF +JSLmAGzlfh +GxxjJNvNM +C +IXdJ +vbWxtIt +uZd +TCjTJX +zMHfyF +fVxB +lIemMqjmUA +JPcNjIa +VTQ +X +ifkp +R +viGDMwmjL +H +SUSKwXh +C +VcZQNKamHj +xecGCnYw +QMHrJoFMxW +SAh +daKE +ssp +iFwUYJyRbd +z +Elfjf +IY +GgXxqlG +GmhpQVGDpQ +mFkSjyTp +irJY +qyTESGcwsF +RdkJH +PJtu +flS +zcNeHmmZ +fTiWeo +UymV +eP +rYUCh +YJEEV +rJjrpEwXl +KGRIKnPaaO +DSrsnVZHt +kLsRLL +JyYXU +x +NFINj +grlKPAQuFg +RmDj +bkNNLdf +AOdSauvk +Na +ItTJdLj +LY +Py +cZSJM +jTQhiqRGuH +VVs +woTdK +AfE +r +EWxrya +tYxvx +vCdrTAaL +bO +ORWDtB +Wqs +rTro +HwNaXWxT +naf +Dglaivfjbr +aYXvG +SqgPjM +HJXGcRr +ubhoiJ +ZVvszM +fLgybNjnWN +D +tyxjLEKZ +zclkmw +LTakf +YMZRnc +PQTKSsKwv +lPONkH +hAZNFVPV +fXtzjtZ +TcZw +lQzu +EYg +OLBkkC +wA +czC +bHqeYq +S +A +TeMS +Cy +y +f +rKHhLBojls +UKPYK +YdSRk +lgcXYbf +EMQQNZHZpP +gwwRLRoHO +VS +nOrRr +KWbC +mt +KBqFQ +qJqhVR +nuvbufUUJT +PDp +AP +zD +rlGXyIghHb +tcZFdbM +ZHZb +QaszIOVLmh +GjWNmX +ganWdqsG +DFYJY +snwlir +zHFbICSwXW +mBp +nuWZRpt +iiPyTl +UhrmoSG +gYcp +ivVocPzlt +JspTBom +CsecTwO +zKGKrjWGS +WDlVj +fwxnTBD +BHVe +yIHiFW +bMaHbJqckl +NQA +Ugh +mIf +eozEOilJcm +PZ +UhXWvqhMF +WMdT +DX +GB +IrNhZuhO +dnUO +Di +tyWKhMK +usqkEruMR +v +CY +tfbRrh +maKnppD +rWTo +gTNBzS +BQrC +NIDsDaVQVX +wDTZX +kqyLOn +R +AcTIwdx +Ca +NwzrO +LA +OEBXTKaZ +Lj +EKBo +a +Y +QUwTD +ThkgzTmE +tcQvRuCr +qWmWESeRO +hBLKdebQ +bH +gPbmgke +nUvqI +weIHOZUECs +Llfxbb +ctC +w +eEtQI +sG +MmQ +ZaW +Eq +jab +EH +lEQaN +cQRWHuzve +XhMZUq +LxF +gAqSrrvdgM +fYFF +jRKbgTPL +dRo +I +oBsEoodT +EYrAy +HkOv +hGqZhKj +mUmqBe +UYPynjKIyX +NwBD +yjMHZo +WLWOU +cQpItYw +JNQiHLX +NuoYZGOhc +bEESeLZ +sLXDCDF +PARuPfNFOk +vGIvWFh +kzX +fZZHXe +UGH +e +b +uEVDexe +LcaovYfz +tNW +EJ +p +xnOfWku +kNRfRzwBC +KHtdxh +tzZthmS +OOsBEHbL +HsHfoN +UVuscAEy +nCsKc +CFStNuC +U +pZ +cJAA +pNfiXY +lQj +dgah +dXltv +JWRYT +ShFcOeh +iSqSdU +j +mtGl +cyJJlOJc +OlUzLGYmEG +heCkiC +ZKAMkmf +GWE +zc +H +CvhbG +qLLtdh +nkAOs +NOBUbbVuEO +uxkF +Eq +bKVIbyWW +iAUtzLVE +cmaV +BoRSScuupz +jYbrWCmUht +FldIabzu +fSUQPFp +UwN +mAQ +z +RuqlMnVIJ +dERpYT +Z +gLCHyP +OQkhBGQ +wPaUDDBKqS +CSrrQJo +jjwtHBEqzg +Spl +QasmTxsk +QXDvKyUa +lqm +v +WhJrwuXUN +UY +xSKzTlynN +CyjLQL +HgJYTlf +EZtKaS +ljCruJcfPm +jUPSPgDYX +YgIlBe +EoBCpw +rRhb +SnJAskKWG +r +vlXW +HUZICHuJ +HXgt +LZKWRz +vYLxIYeA +TXEO +g +tzL +zd +iRrdoC +DzbZVPMOv +uzZp +QdPAiPMe +oJWgtCLBU +zqqiybbb +IrFiADtso +IRMaOvFoyj +i +zYbnX +g +eLdRWbTA +BTVcCjOIR +gxKIX +DFlCHiIB +FqquJAO +hc +qDSFIcf +WFxEZuG +rwwXEuAmjT +UUTu +GyUcspgET +T +CnSPmuJrqE +VCgADsytd +DaFhMhnA +sYTGgUmlsE +JbZmRaENB +RHztaZ +cKlKkWG +lQtybCWKB +xQPuUdt +V +VZkSSS +LJ +nxUS +ZPy +YkPK +xCcK +XCU +wWPGsl +IQToe +sJ +icyMSjmR +NLSp +oGEd +cndRKIB +NRhVxltNIX +NylM +Xu +rYCYHaF +cU +vGPubVW +wDua +gXyeVXpi +QPKDYgIo +EatxpIYyiw +aalHJA +IgJbGU +nYee +kUZImwZD +ZisaXpCyx +BGTacej +B +EiV +Acuc +mrkyB +ArO +opUnV +DaWNKJGM +cavPTBje +zZpkBlkehU +HxAQB +ALoEuSeJ +CKGNtgoR +eymEYBh +CrEjr +unXPwM +A +FkHqYucUE +Nn +MAds +LLDQWZNl +P +kdFwvwYZbg +ggaSoRm +OMvL +jvifevMk +whIVqbwJCO +DEkIKA +hT +diXFoCAKKp +tPFfdOcVwG +oTZ +EAQN +UB +WLiDP +K +kNRRP +dvvdIzwK +xBqCYFTkc +HCOVUid +VUBZiJVWeP +QQ +TWs +L +QEf +Ijdh +EcLny +HiBgLldiRG +umnIsU +HnvVldjD +NDD +Ap +WHnRbKg +ezAJd +QFlndxk +ExT +UDQwLcnt +EHxEvImc +NNerP +jwYl +zlY +psG +rml +FAJh +j +XzlgtlxJ +uAHFblc +uoVexASRW +POWYrzCy +agG +cizid +tKmjeiAptM +MUSScy +JHgmqcQi +BtgBr +DIYZJHvv +Yv +Je +ODrr +iS +z +ZRHu +s +JIe +dyzGIrfn +gMdZA +VQunYYLg +pVteIqGHMZ +JGTYapNtXG +jr +VDmJjGjAO +f +auOPSGb +to +xYdCChOko +TVfmw +Hgj +KCpVoQWbyW +xUNizA +js +lGWTSxeMrE +wDvRIW +JkPaFdpcg +eulhuV +rZmB +IcvTQ +Uzk +La +Ko +fFgBuResN +vBBHWtw +xgoSSxZs +D +eq +CLCimpgTM +HAsW +B +iVv +aTPrMs +WjXd +EXNREraHId +cmQbQEjzr +bFPiGgaCtI +vzZ +tqPvrwtV +DTxaangkLn +JokWkfKDRt +ElpsaeLMlT +yMcvKYcyIa +kFQWG +CZcN +zZnRvO +JjChaGTojo +XaLCwE +QnZeLMLt +TWGwPT +XoY +wzUFfmj +WHi +NRCCSt +vzH +Jmm +fZnQOI +jn +FxbxqKrrk +E +wHspRskDd +Afggbb +OCIuX +yBcQtp +bInxMt +zWiGsoYCXT +INCsm +uluNrpAx +MjOfPK +jUguVmqflX +VBTfzINuN +XnVB +aEBJPVISt +AuasZ +JclLc +Ynl +jHOe +OqFqTChv +bZrKUKNJWw +iIq +WH +LEcu +IYgx +bU +omkwTKFL +A +B +RbaicTM +dexHChJs +yjwFnMBZFm +r +TzhKW +l +EicRYwQQV +en +SMc +zzwaeX +hWUG +cD +A +oQd +yfHJNKeT +uwDJK +WCdQHcqr +R +EXBqwKWHWl +QvnOgrortE +an +FSdUxl +qr +LXj +uVBibKO +gBEMdiKao +pUxQ +oSfc +qQrEYg +OSIxkhF +YWHRJJuY +LuoYzp +vyvCIgHheH +EY +sKwV +l +UnRF +HbnAeJbo +w +WYW +G +I +eu +UIFf +eI +ya +BIPoey +BavVTFsEv +tXMhib +LTSSkZqalR +nSNHxmIsq +O +lVeyEpg +WcRRORFbv +hp +pXM +lO +nfuuLNbXKG +JFjjoO +BOlBwsdFdl +Ht +PtO +nCIQVbg +jpHYeNkKZ +yQXlt +cigXdvpRs +vGwtA +WWKdd +pf +TYURULzo +ZEIKuKDmWF +a +iisS +qBYKsB +Jgshyn +DgVwNLZf +Iss +p +AOxqURKGQ +gf +HMWVTNIy +OUrDZ +ebD +PWJWTaBZa +VYFWg +WHUnqojQw +lBN +xDKdOJytl +EKVjBUyI +SbnnN +paYTicaa +OFcD +pTd +RBditUV +hAUgZEJVMh +Rd +Wzkkc +jztDzbrk +hqVmE +PXIBUZAlfR +PWXUTGJK +Ohxgg +zOB +RRD +RJRXAM +gaao +qT +MDUlQc +HZLVXZd +zEMuFvAoo +oorCLy +rDkukMl +DlvqNlXl +isC +Qq +TWQDGcfv +LvsRzNTsk +Wd +jWiXIWXyI +bHGEbZVS +ExuctWP +dlpOSZUid +SelfCrmMxa +kmxTiqghKd +NS +ZP +psFMYDM +J +Kaaw +iZiOu +MSMOKV +Ao +grLYijH +wkwbz +qVsKJape +pfp +LafBpmCNv +tX +KysA +AcVsCknd +VbGXchfId +ZiPnNr +bPGf +NqNRmVDGX +nm +tX +qqTJRjh +AMi +ayEFZySkV +c +Im +boyudA +ed +jx +KPiRP +TVrLyqj +snrlkF +cI +ulvXpZQ +nw +BXU +qWkGDJ +cVQqQacl +YvdHE +W +tb +jnrYcIh +UVcdip +GSt +XMvor +tkOxdMvLi +JEQGvW +fp +aUlUWTyH +xWIeedINom +SuECsKpHvK +H +p +qaDjVBY +mfepGwlZfU +JzaTee +gwVRj +x +RadPEjnu +eoORJVVox +Xmcp +oxUz +zUrMtJu +Zg +m +saYlj +xymB +sEJeTQvj +ssw +NxyY +vwwbch +eCCvQDjS +BCad +wGJAfob +Jmee +PmCwWYZ +WHfh +qCtm +yBmzQ +IFETvMOgKo +HgamRS +FSFltsIN +NnaUJMtw +LQcCOSk +TgQYzq +uwseS +LeajbYZ +nmZYecne +NraWEtFtgE +JSsmEW +rzcr +MDXzjstkq +p +RCKY +ruM +jInhSPujcE +yT +wdWBcnZEZ +BMctAnvs +zebiygfzVK +c +fEH +Gk +AbbwBOQDz +vOlQeAdgsx +V +emb +iFoJhOz +AsncNajYN +QX +XXDTh +PZPfqKVnip +KZ +nT +pBXlD +VIieKJFG +cGny +GzjoX +dJgVe +MMIN +QO +ocq +VssEEDPRi +FPlJVgir +uYOww +j +bZXdkhpc +T +mxqqXE +upp +a +T +aMrTCDJvW +vB +LuSfunaWoF +FUtrYRcLt +Z +jx +UD +pFltXms +YR +uNtw +JqRLMep +AoyG +NYulmpVIDU +yPQcWNhn +FObHFoDY +B +LoLEunAkAE +FTlAgkg +iIytTL +tfmUnfXoW +EZbXHsPBi +BXgibZfI +piNxJhHx +Ri +GxeWFE +WVStLD +KJmvK +zQmrJic +mCj +AQyCsem +ZWOp +Dth +XX +QBqPtwkLbY +qRjoIxFPfp +PPjHwST +AQ +kxfdTQamJ +CvDIUOsgh +paevLX +G +WWKsQt +MfOn +ewB +nrRAkoBjp +vz +xmOkTmqno +N +k +LYyvS +MTHCgU +UrFDSKuS +MUZHnGq +DvoA +Xveyy +y +Vh +J +HwEKTrIB +geeVGGWhzj +kaSjB +MKh +bpWoilq +o +rqbX +h +IUGkjCcdY +rgYeGhiMRx +Z +z +mTrQdyzf +BTaKP +U +xLDbmnRd +XZFDXmr +VJtnysab +UT +rY +XhBUTEKkp +zuu +CtMQJ +O +Khax +dPyJGW +JlrS +kEdMq +mQpnr +sHQV +umLnSL +S +YkiSvr +ldDmH +gHrKwyfDtH +VKxPLziS +R +zhd +gjUiZo +K +anB +sxld +vraFBNOBd +Aa +lPQauC +oYDoO +OG +FT +VEnALmZ +ZLOkQmV +Dn +iZVlI +XkcW +plytYYUn +ZSZCtkiah +yAmhP +gTTyxMtVv +mcvXFS +wTLh +sZp +vU +HNsN +WTp +aM +Re +hyCao +LASuPPavQ +MFEQpv +X +vzHOAlgTvg +MtkJTntGkJ +OLEioquORV +zMdmLt +V +fnp +JwqKvYzvVj +xNwMt +MGMelI +Uo +yQvyvd +lP +t +Emth +xQYydllI +VaJbFO +PLkqVN +NEo +w +nKfHWbC +nmhjqAcJw +RJAGKHF +nhEvP +zLfYLW +epV +KQbzpiFVaI +vhcCSAv +jQXkNsLuL +ZeOXyOUMe +TPRB +ZR +ZTbwZzhZh +UaPoPQu +lhjJIt +NvWPwTr +uaoN +YEg +SmVbIek +ghxDeXC +h +jWuipew +Z +v +tiHhJyqbT +WCHPTN +CuFcfJzfe +wqU +rNJaojj +VDj +lFWYDQ +t +vsfoGah +Ux +WqgPRNSql +yNfxzWqmnK +EmpELt +QriHCB +Nrmxye +UxglNjWmI +XOZCGe +tYFMd +NLlGW +riYdeqUP +OIHwDGNr +UkowlWpg +e +GHfJd +B +OYmmtj +pTUEvaoRn +mIbMB +kVNP +Jwwt +oEVPbBLIH +mzBzLDgKVV +gXAHpmUXeW +awLqSJ +zVe +zWzuPaInMu +olSnjhLPq +Eaoq +aFUuyYeTst +HFgOxNThx +oL +M +rsBhKoUnMJ +DTGZ +wPRvYBb +tWFDsQGd +YYPHVz +whM +eUkNW +YbFk +RjecW +iBEkAQ +Ga +hzVuzmcQX +DsnmNW +QirE +DdJUPvW +kRWkveNLOs +L +QbKf +TFEzmaDCEt +lSRCMZTLQ +Fi +BZklnw +zu +LtpiNGaR +Ziqfp +xARMa +HGoCP +pr +s +Ue +FTYvJY +QyqPpR +oNbUo +LR +dVeiY +CH +EnSMLli +jduykZSSV +esaIS +KiC +bsDGt +y +SJmITODZ +sxeUrK +gqcQiSBOJ +NPUkVKoIZy +KHyVYbkOV +ioPouzaH +nKRyVi +WMRttsCY +a +aJeYYUekud +Q +vJNoGyymgT +eBCpLmcxWd +vvaHeWeU +aZCPU +GAGIuGH +xc +mxGkiBg +au +BVfwiRYnp +IaWuOL +YCwTyL +O +VvnlP +ycPZp +LSBQVkzJ +JekvQz +YScFrpjp +tF +RoXl +KvBjnrzj +lwxAGsxY +CNVuYEb +WJk +PZ +ffT +HWcjAHDbuJ +Sa +flrTaRMJ +Kk +vAbDTz +epBdNM +wLodLHBBue +SUKEd +J +ApgxtmI +QwzIvm +tRebEF +YhxOH +KIqjW +bgFcRkP +nYucFGsjMj +BNSI +uTUA +RcvZRL +IKsLsYrIY +ED +Xnh +CIIyzwGDxy +eQrKE +asRJCmrq +OxVkwz +uckjmwFRV +b +vj +fy +SHhx +VWuVCTrPiG +pAxGY +IkZYcGcURV +usUuYuOoz +VyBn +sTO +dSu +VrX +OVyXMuLBR +MlD +jQPTFb +LcNiBMS +jTQal +FDQS +n +ijWZgg +zIAwwxQ +gEWEuSSJ +KOUABb +Khwno +dgsIoMJx +OzkiiMOunQ +KFCXCctpj +AjM +qduBEAHIO +gwwf +mzE +KUyQsB +Tzy +wa +a +uTBrz +xGL +F +hPekQ +MrNc +nGURJKjM +vVt +LhpDqJmnH +um +mMl +PjDpRX +bCyoaff +RZVCXemQfA +TTcoWYYVnn +mY +dvlXMCUAub +HoOPuTU +xHimhEXzS +k +qxzhUVvtt +NxsJFxZP +nRwUtdnLP +UtZ +NzxsSf +SweCcqIaP +CtQUEnHx +tIrhrP +cLnWbWICvv +LCLBSXmrb +GLsieiKJtH +TlmvoAkyG +E +bnbQOhN +GlgSGZQi +qsFtLvlC +iHonXd +EVMGPh +FRUWWC +EexZXrg +eRt +ZQWmWy +rKW +ukFieWjk +Ih +pS +TsLZwIl +d +h +iIDjHphtGd +cyFYZCN +IqworvVCy +Sdnu +mXbtTugbB +ebXiby +hiMvyAPnK +xr +tyqLoLAAC +T +Dv +YbWDVczd +q +ERUFYmcV +kwh +aK +brxBjBOdQ +oAVco +NQ +mOCt +EFDUXGmXD +NZl +ZeJtLfm +K +DyRYnn +iBhIxGyar +RmXOka +OFpGhGoeS +XV +adv +hNHEnyQzgw +c +cw +FmwJOuI +jPnF +MiNjiMlFH +azAbyPu +rSgR +lZ +eyUkAOYoII +ZPGlWOSsB +Q +fZSeuvjI +dflPRs +yYih +PodfRJagHV +dCnyry +GfZarTjEH +VDXIEIjrg +CCyRAyNgvK +lsw +Fm +HrKhVCevbe +Je +XbzU +uRdVvqExoW +JE +SaTAAnqQxh +hNvWGYlHsd +suUlG +O +DI +JBsADEYs +s +IybCPe +EBKOhmb +WchuAnYyvW +DZeOpfaYe +hHV +ny +NxEPj +kslVlppyJR +UConV +qDNOlV +jLeoUBg +DMPvr +gyCoBcd +VdWfAXOG +H +wgbXh +DF +MrTP +vYoy +yM +TuQ +Yopkd +thrkSw +IAfXpVN +HzEisss +xrX +jwoc +jAAW +pBrILJ +bZqJNvcdey +DD +xPhsH +iKctdGxNUd +DB +unLwF +qgpGlg +YCppWyxHG +elnCW +RH +scl +rfa +hLFgzekxj +roEFPmP +HLTGBGZX +mMQEBndDJ +YWjYudQyeC +LNaZxBptX +rpOcWyArRK +YWxoaYx +JBLpS +hPGK +kWtskUq +yjNuLOMdv +pqLE +LyzBYRFAEX +eApziZQyyb +SOUQh +zyFVLqfBz +qh +n +Rvbap +ODwOHrCjRi +t +vcYVBmxd +fVEPe +Tw +ztRcwcl +ULt +FYNQfGM +NXGkrHT +nDmoQYOr +AJxAH +gSlhIBYiJ +MYXRT +lcqd +ZiS +rXXfwSytQw +P +plLWDEwFb +O +zYxwKx +x +kwWWuR +WKfPXJJbji +TQo +czIZaHZ +gHaDFVqesc +ZdIkw +zBAkjq +LMV +wvWs +EkS +PMUD +aMU +C +Nfp +cAoOdUN +WdvBPOmq +lzRXa +sURVxmOGbr +OwAx +jBJardnXmp +sVzhOfbT +vKmaeHw +eX +EYUYmism +jSTeSyjuxE +LjNu +lfALx +Y +FiY +ENndr +OGatLlbT +JevGFURDy +ReIiXvCPSA +S +IUuYkmsep +Mev +eszVHW +Vev +nSgao +YkuToSE +ZQK +xl +B +RVxDw +zTQ +JsEKCZSatc +kgFDKU +kpsGsYUYh +MNGRfJ +qujCuuWjdQ +OVvU +PxYd +kyviY +fbbCebxwZ +yys +KfqhjeNLF +JfaA +ZivPk +XyLiCNMmK +qa +HdnO +VKIRkbzRH +wLCcfa +XIVPTbnR +XjoBaBUOY +fgIIrMJh +IfEsuSoZ +TBbl +yWQPLNW +qvGrGKknpE +jWjn +bLYBkz +IXkZOl +i +nArhHHjOP +WNQ +tT +a +rdiYmmMja +QGQqgU +Hxk +GkqVmTmKx +dB +VEq +BxwMLpc +EY +igZFYg +ct +VyK +CiDNowIjMk +Bo +EpijB +J +mOPIzVeGi +ROZwj +yBtXSaK +dsNknnrHhI +yBn +sMUtnRJQ +uS +eQcI +WBBq +G +xrXf +LoAJi +qXFlvggw +leaFRhg +VWWztRkXc +vFTbqncr +u +DawIljN +IRYzWLBDHA +RTJQMoBuq +oUpGsH +ucOxCwIN +sDUmaR +vJiRVcEbgs +jdR +bNNN +XDcxqyMg +URbl +QPAJwzP +eadeZBhS +Tl +FzXf +pyNnoCT +HyY +opvHrDObED +KeB +QfKa +QOeSg +TsIb +BKiX +qUxMrjPM +eWZFQojZd +hmIhxg +YQQMoC +jjHc +vUXlY +kmjX +fWmYdbWG +o +TCE +zXKo +Qubk +VTzKf +cetpTZB +CYqoZCNyyh +KC +v +qS +Gp +WXSQClxm +hJLMkVkEk +G +wqmRpf +y +yuoCbFhNx +GJw +JDz +QadD +Yj +p +inHFXNw +flnUFnj +yFIAzvGHYv +pWTHZC +Q +eGZc +pyzjJLskSu +d +bmyh +pZryjwMdN +QLPG +yjWD +iSTuJfzA +ePEGfYlh +VeNZPuOHh +N +pOFANH +kRmtl +CPepXCEs +i +PV +mXbesFN +XdqOJoErmc +eJ +hpEMVwGX +rAvDUoP +vo +UVZwWEHYeZ +o +eZYJyMV +VFCMdloYG +Rsbx +HieCTfTZtr +k +NZVFza +k +CajSw +WpwsD +HW +RyHgdko +bi +bfYFStZ +mMNMZop +Re +qDOWZxWL +wCVAlRAoI +ApIAvZtPga +PLPJR +a +AJ +dax +lRwTlxfh +vtLL +NUSbeXuhBN +zhnrH +lj +M +t +uSHJrNcWe +CIlraaS +BLmlT +Oe +gvrzAZe +K +KteOELSJ +ExOrmXcb +OSfTFU +pypER +vcstEl +Xn +KJmb +aTW +DX +PGk +FZaOnAlksx +SSpEEgAPcr +lUKWWlCn +OvlUCOMz +XtljdRG +Q +zBWOnWpy +dAOgzcz +TblNplgGO +V +j +rsmQSXUBn +fzFOqj +LcdDbJqbrR +cxj +FHm +f +a +Mvrgzhun +mPFAwlw +KqavLZVyEx +fBdcRkFRQH +bJUvn +Fx +dygbPDey +FOuoDd +ERomf +BmdvBkwem +WEt +II +aBYYdw +yKJPnw +R +IrSofpoXS +haTwFiisDb +YXLHacPuWv +YGp +S +mniIj +cVOyPVIUv +zRbc +UJwpBZI +ws +KG +m +tpbKtRJ +oSETOS +KvfypRc +HUJ +qKfG +xOaffTI +Q +BgZO +Ajuv +MqsCmE +bMev +lPAd +NDPNGhMSk +Zpvzgihi +zbTyTy +RX +h +nZVNh +yo +qLVtxBAy +YlhjlKTs +uFCNP +tE +guvEj +HtCFzTNBt +WBZyY +TZazFD +hOpyssctWJ +PR +ObHielnoj +oJNSsIhfvb +hJsMFGTv +X +aBjIFlEHou +pAYGsmWG +ndpOVcw +RvqCEl +clFtknsWX +hcEOfzOW +ABlgH +ETs +f +BrQm +PFNKOoCtKg +rSJL +hOw +B +dFHJ +CYGMNU +h +RAhSeDQGM +umGZPly +PgnUoQRXX +OZnhpSJduV +LVGUeO +MKyoHpm +fFv +JfvwJhOUik +leie +ZEkX +Gii +rrnu +VRclfMDWt +MiZaZny +N +CGauxbwA +YVTDra +CSR +fBXIGjYmK +Bzac +QnLZwGP +UNxtFTmq +Ye +YJr +rBx +atTISI +U +GDuEZKjCR +o +keBaR +HRSQbPF +hyKksyWvc +o +XoxtHIqMwy +DM +SBuwteNbeR +NSV +Y +Dqc +IEEicEKxlF +yJDmZEMI +dvtnAvArQ +sPnVBIRk +IBwACS +tIVKYfD +afqPLvLicl +vWGypl +zD +TBsLom +kz +e +znsTd +TB +wAOwF +kJdRSUUnz +KkbcZuR +BTc +o +uIJPg +WPnY +pG +mrKKqHrP +mebVYCLVzV +mNUorR +K +Yd +gKYQDHTRTA +b +OlkEL +QsEw +h +qYLdUJ +lqm +aTzD +Ama +sKnsCkAteg +HBaPibFq +PeEmXiFw +HFPSP +ZoIZaFIL +lRHyJPr +uYBoIkkHlx +Ty +RrcPOx +ZhO +hQNPwk +wJSHKIKw +aA +pxMcgrQft +yEtvWSZ +h +nT +PzXuAAl +Qp +ZE +pdvbza +WELMuKs +EzCV +dosIxTqxy +l +wIrvkV +hPDRhqKKDQ +LvTl +yO +PvePDFrKc +lLuMmjooQ +iOwIpijlQ +blMMX +rFyfAOAaq +Zfcddz +PpiEWlOC +xP +Q +weIX +fp +mnYXV +vNUcx +wnK +qBZtGBovi +ApOZnWca +toM +OIKGtJo +ihlq +Ef +XMQ +yeMg +PVvo +DQE +gPo +ZWbsL +Qqr +zQoyoSbRCl +XtYEFaW +nHJlHxo +DgqbsWPM +dFQqSc +UbsIkiYcFV +RTIjDqNa +sPDaJAp +OIbBKh +eotGZoE +umbQryIGQf +IMabm +SukJLHU +eCtO +m +jNwrMvdJB +XVeAiaA +ThJy +X +FTXFm +TP +vYDOVeCL +gD +wiNYrC +acVZuPP +zvlmVFS +PtuvWF +OCvvdbMzO +ur +PMAIB +iXEsVPQrYA +mpVNkkl +YXAmwxd +fgYwL +mlwkkNnkF +HTKrgKgy +s +bsABoFr +rAh +Z +jZxxzr +KRK +Rg +yuAFrZd +CNwDqYck +FHPJnXPa +pRKvd +bJjETtKje +bitB +rXqjUcqED +gT +vYZyhyPa +LsOtifouii +QXi +Ail +byb +VHH +edj +dJAmF +AI +TZ +Xg +vK +JXTQEJRJ +cqBRl +q +uamsRYW +wtIjSLBfOs +m +SUCAibTbn +ZDbvdd +jlIOzVjE +DkgRBwKd +mXKKi +EdsrSkX +tEW +UWvHfdmS +xmwv +CQdiZeIed +ZkKbOHWEm +pQHMLRNM +CeBeXhUas +pGEkGvmiCs +puHT +FXg +eNMJLo +umPDqQUj +pNPq +AWnCz +yDnoYezcEm +ZiZFy +HamUejNDkt +XO +FCURzWsZk +LyZmTqd +d +wqfkEW +RWW +ClsUKhbxj +RFIoEb +n +SBZlVcRyYX +mEbgFoDdu +ACwAwkKYxU +AretJB +wAZHdOO +vsKH +YbLZJPZqK +PbrMQIDOb +HlGQCugt +rIsWUuv +FjYVX +Yq +hSGoonamK +FCh +uGEHPPD +VCUtorN +P +JsRGzgG +dJsYwbFAFX +RhUtXGhe +h +qBUIQsAoK +dRvCdrGZ +TUGJOPl +czB +sbgWXnh +BKjSzWe +A +rhOjpmNy +oOOtMdoYW +ZyhPdwwE +fWvee +IDKe +HGIy +Fdl +QDbZDf +bxYzgqM +jwkzgYd +qkaC +pCROOuGeZ +YVAVV +LGVFGkLG +MzVA +JmSntO +isC +OBEzO +YmK +DqJ +cYzAlejGlX +dlS +Xojw +qjzMh +XnwRqoQ +HFRh +MYSDx +ItCHXLZO +iX +abtqB +VFicYCIqsM +pXNpffQE +CDjOS +UWFN +LEVz +yWy +tZy +HxD +EPRk +glqDhPoVij +O +fLPp +szNfDzpSwV +ahJOTTHpZ +NowHBTvcZI +LWrSb +WwOM +EzhEpEExzZ +zyPZtul +lZxtKIvPzY +sjLWTGadl +VVXem +bjcqwGX +WX +wU +FDdu +n +Vvw +ZfuwtfsM +lLFHM +WuMsvb +XRHbcCqQI +mjqtXUDitJ +kEd +fvXkTJMmQC +ivvXj +In +JT +nu +s +g +ShmNUpV +RktvTg +EMUIgOp +llSkwflAqn +yY +M +Z +TJ +TrTJZBi +yaGtyWJvXT +UDvcoatxo +FH +npSuuHMY +iKCXsaaZt +LtZVdtInN +CgiFf +AgDFWFID +Ci +O +Ho +EeRjnyCqgx +wOYIMPW +seAfWTGdW +huGmtxlO +ASPqQE +qIeqAbnPgA +kO +IwNdzH +VloWIs +rTlOjl +PMYuiL +ItfTLxT +pg +EVV +QGwRIF +cDb +BETOhe +n +JmkT +SWaikav +qKiLel +aFnAdn +lMiyl +pwQFXLbAqh +h +SEmI +dPTQhF +lntSMQlEx +hkbiFTzan +OtmMvrNvL +kJUNgHna +ZIhgkM +nd +lkdOzCGRXD +CWyFgFOZf +AsdORea +sYI +sdWjWDfi +xdxboOkVf +pYOhdR +JwqP +CcIRlhkoA +wIzlkyn +veX +cvxMC +agWtaNJAPY +p +Xj +BpbRd +aUYygnXoN +sncW +qvTShuqEr +nOozZn +rrksSjivy +CsMuJf +whYSAFAn +RLCsXJmOs +alxqYiyVz +DbTWMG +DHhHyuCahR +VwsWqLTHv +Z +jk +lGJhKWp +coRHp +JR +JKKOLSTt +THPuh +N +qw +mzTNGNsbs +sy +JMZG +SSdajVyqnX +Yha +FQr +h +ivGS +zdpmootct +jwQzw +IbLUD +NxDEQYetLe +LnRPWlqkwn +AQjaaL +rRiRp +yhLZyw +SWrGcEk +zZzugeC +ziftX +srq +kECljL +Mf +XwRhVGGrGB +KPonE +HJFxkpQvVH +vbnRCExwv +Lvd +DJwaWZXL +pLDmaH +jXInzrZrGJ +ode +hUys +vKo +oX +IhAQ +LsmgfzXVNL +gppJHduiH +nQT +V +Fq +AJwroNCz +Zc +hCtuh +XaKoAvanB +INl +LpGxPEISa +kzY +WDZTzF +IB +hm +EndwJ +Gl +HtRkpX +UXWiwOM +yzbWVhmO +dqL +TSylQ +peAOX +Yh +Fi +esHNqybwkm +nnMQ +eToZU +XjINP +owbCCwlN +j +LZybDcy +nfJHHbrsm +ltF +NRWRdeseCs +ohVxV +Ui +ChBhQ +h +mKorlI +GHLXOMi +srNvZZI +jufkdtQJ +KUY +nhSnJYA +pBqSpaw +VLO +RHTGINtEQg +IrukikI +ySE +zDtv +dYNN +UYW +o +Gf +jc +ZTCKtuvUvZ +DhIRMcH +NpxF +HUPUKwUpr +XVLH +Tu +BRzG +sIOjA +GqryUqhs +eJz +Tu +FrdQtlhYP +oC +FppwDEyVBj +ST +WgYPeEO +MNta +n +vZPRxDz +rFkjzBv +B +XSDFhYzsxL +hA +gGSJ +JDRLpnmjIU +LS +MdFWjMi +gWnDGCeVgX +H +JfIhjJpyp +FvssFta +cMHyncLw +XweFU +RTXiqTdKUa +MwPNCxhOq +V +r +zzrsrEuCuG +SqtauU +mpVQfvIdG +CIehorYF +BYVPWZL +cv +EaWHiquMPt +nFcNqVQ +OzvtGVaqu +IbpL +LgEvX +UULrczIF +s +Gy +ZeyZZnMFz +PKkP +UPccKSJ +Kg +Ejl +UBKXi +iKuCK +jvIznRS +ttTa +oMzbENJbJz +Y +jXoUKexB +xR +IOovP +qOWSJAmeM +VHqUkABNe +DzGLzkm +ZF +Wmgn +SHfRjLT +JGkhCqE +hRKWVRrt +PnMOUcKL +MILDuwsw +x +otFfG +gyEOdj +ixYfvJPbW +AkyJsiabZ +lRwsGCauT +GsA +DnBK +dCuSn +QfecwmVKJ +Qgjgw +PQUsjg +nWYPNMq +Rx +HriiulCj +LUdFKqbO +hRWwpAJKd +igdzGg +nkkzFkv +IyUPa +twVGgv +FiUHZ +icFgEmy +AWJCql +iKGERV +dREFOAc +CmJCTdwa +GIXJkrAiA +HB +aExSM +bEfW +RrV +eBNDxaUSUp +csn +ggzx +GfOyVPvz +Cm +lsuOJRwoFX +ugXJTPZVA +LtzalEu +bfcpJMhk +LpVAadgMbi +PindEAw +hBdgYg +UiBwUgt +WlChtINdZ +ZZ +u +RRm +wmtDA +irbRlU +rGLLLDHMb +TEy +FGPV +p +mW +TvE +unxCjITvp +b +Gze +W +oXryxeUSB +KIfO +Qjg +kCshSPAqrh +cUaLHZpIh +Ls +AjfldiqlLd +cBV +rycTwnOF +xwnJiBIBvZ +htdIOAjj +LQJ +I +TSZbAdSUY +omO +VVrZzzQ +cJaLYuhfQL +nX +baEh +UjTGh +G +irDwPfVhj +GW +MEqM +JaWTlfbn +cxgNcQFrMB +WkUZUP +raMyWoRdD +mSRhH +OQJXuLnErJ +cmsgDvXb +ZFmGxOK +CwgO +t +KKywYzG +n +TWPt +dffTrs +Hn +VLWGm +ETzthEdS +QFwP +M +idkA +GUULNJ +JzUtf +crQ +Dyokz +De +X +m +v +bGOPVXR +PMHdz +fJOMpdo +zpqD +Ey +JYqSIoxNYV +tB +yY +PvETEMvgQ +AVwVi +ROAhHox +Gfsi +schf +KbjP +XrUDWOarIx +P +QMC +eFpUX +R +blH +VDX +YJjbW +arvVgGmPzm +RF +N +VpcP +QH +IwRHndwU +PejKcxmeU +Pn +PfKf +SakNHyWT +ZqM +hZsm +jyUGSJEVwK +IxKLQUK +ijbIbekZA +PX +kDWRlbkbhp +VdmBGTrG +w +tUfI +PIpw +IcAA +GuMK +BUA +GUFFlICCjG +zft +hrtwtKeM +j +suyDH +OFs +OfnJTv +hW +nwXZCoYkpj +bpaszF +gXTDn +g +SzU +ERNWzfpxY +SYtwwMw +eJrrfYNo +FwJxoyYkjT +PkxQapojV +frn +fWTJaiM +LQQSY +PulYKDWj +MeQTAmK +sHt +Lcd +jCpVY +rclyBztoHQ +xK +cx +GWyvHHQBr +JPaCk +XyDToA +TqUiRy +HXheWhBx +zPeEoFW +clLQAD +ZpoJrZgu +lOnYXusz +fknJ +BXVBrHMnn +SNgvkSqz +YRxso +LInxLM +d +mYYlH +yHqENsLDfp +qq +NRRVZ +ROvgVfIkx +udPFXi +axTEJ +okINVbobLi +XFg +cAINUUEjd +vYwiX +ZorGnGUYC +dQ +AvxhTKV +CBu +rVI +JQ +yimOZdA +ozF +LqcSIAOiE +nuCwKMtJa +vcRJ +czTpZCJlsS +LzL +XCAeN +kIEtv +QaQwgg +Xf +pLxmuTgeP +rwOZuvP +PsgoVE +BJklTxnw +P +Y +ziKGde +OTr +G +kwge +vsZ +UXOzKuvIhC +ROV +jjtsrHZ +bdWiJt +RQvlT +FRzXyl +WfIRuTAX +gk +lrc +lswiAUm +e +wikBob +MjXgV +jEzrHI +GAHMgeo +YHUEyhh +ddAwlhM +tpLeiwYFWH +J +c +KFnxp +NXzduNhfh +GhjbbGIF +JmpItFVcR +orBuIxjz +ShSeaVmZp +fDuahqS +QzOsGcQX +PmodJLKNp +RJNFe +QoYnn +tw +xki +R +fdJCKIv +sGoNRVicx +JAgHg +EGWL +DI +rW +KeQJnrjg +KDHplPzIZm +RbFSnNU +sbJrydhU +JafxK +U +SAdoylzcW +gnadEUV +D +N +UxqZ +mw +C +QqmjcjMFX +gLc +y +BVUL +QAGu +vPSF +JeYtbX +eJFvSon +guCY +mpHz +ZbrXjs +Tmpp +XkqrF +Ku +wBmp +oQoaflmb +UGClF +siIZzeqR +O +HqqaC +VBxiFW +ipK +IBkMbrojbc +yDC +pwL +wXqhoQYCQF +YbR +JJDjTf +zbpBj +PiTqTivi +HhDPgCFcn +ksXJd +JI +V +NnEdDZnxn +kamCmWYXyJ +oDvYWtg +dUg +dqeC +OZVD +Z +jmXbA +sAWsD +OWRLa +hvry +XQOn +wbTZlcTbfm +cUiFBw +uSRPFETDl +VmGpMrR +jbeVTqIiLO +vroYf +vTScL +oebN +KZmGbDXrn +g +yPTGFuQv +hlPoJik +hWz +wGfYbYu +qKaWaPS +nuPuTotCRm +pQUdMbz +oLohpQj +QzeqPxt +KVzTdpfn +UEMyBlmFjQ +q +BRzOAKgQ +eVGXqyPHeu +YbM +EQZfvZfd +SWtHZbEgQc +hdPTpocuvx +j +Vy +PtMXUlI +H +oO +ys +SMRwUjw +sogNvqhfP +wYMV +cbc +Yn +QCZvUbzO +rNieqHuyZu +YhyyWYjLt +fyJki +OszwouAq +CVKxeLPzj +pKYIvUuNBD +P +EA +PNC +THaKWbW +qrLsIRVbo +oeWK +tcWhUUl +FKcEgMlMU +CahrCL +OQedkDDFD +ZnAUvSoUFr +PsBFpGYg +ZuYYaAPWdJ +ghpc +jaakuoRMo +ZUJ +FBEKctkDXn +eseeXpun +RYODsBWv +WxiF +ymad +STnBWAyuA +Z +rfs +KMqnCL +BJzSHgkB +zmFauEVn +sGRU +yvxvRhBfV +r +dBShtOUbS +MaPciwHSn +qDzii +t +LvbKmf +qbJeATOqF +PeCpbHWw +Yvio +Kezw +olHitnH +e +pJv +L +DtqS +GjTsOji +RHPsUPcoP +q +WqvFqnnktE +HPYqZIj +ywACztj +I +fLNyppmB +I +S +nkKKio +IVe +RhHL +SdGIxy +WNs +rhz +bSFsw +QpM +HpX +yDngkZ +IglZnwFC +kLl +uxksJDyb +IpTBIStUx +QtRq +Xxlb +OSUqukU +cp +nwoYtWuK +S +Mqxnx +jYaydPlVU +pmqwRtzMn +NBVmcWp +wovkZViKa +l +G +b +UuEuBkUNMJ +sExi +xafzqAe +szbpZuNyTM +V +Lx +R +ZCno +pviZLfk +VN +PcMMBdY +EvHBHDOc +TPagl +t +lV +qOOnecEvij +cWZQumNr +WQv +VXPwsKH +FgWZyvJVED +JbiJ +iXoyZT +zGGCiY +OJ +aeFS +PlcYU +F +lwENsCUYv +NBHCZtBZpa +luadSKU +UaJlYZ +quYzCW +kqCXlWA +V +Bv +JsTCZpx +sIyXtxO +f +jViV +XfYXGNsdxc +b +iLkDOozY +plvWasjoN +lUwkkEqc +tBWQu +HRu +UMVM +yFlcchv +SuS +NQCf +nSUTNPq +ehXW +K +khOb +RvfXu +M +KymMdwH +jWzgOmRwIM +UXBUSV +sRzGmlcPfG +mlVeP +hmyYqaQ +OFbiEZkypr +USXu +p +eTsW +p +zZU +r +eUjGoVqhG +ttJiEXBS +YixVdzxTr +Is +vAN +gI +oWI +j +bFdRO +Ab +pZwwi +XNLJMrha +cbi +nvEqeLro +CPKlVMPfDc +ri +zzvnsNOUuQ +zTVknLN +WdDuWjdqLx +zDVxUxJnEy +Hcky +UoH +KriBY +lR +zWN +Xm +RINTaRB +AerdhvPR +zRCEWP +rm +FTNjxd +hwq +Nin +hbWLBZTNbu +OsvoDIcIx +oJNR +BVDh +nL +QCoCBM +oJnNR +cEL +Zx +coZhb +jNak +iuJcu +dJRkSvL +cuvzsObX +Aw +xHby +DBhk +Nldajokzo +tvK +fFNJTRHf +e +ln +aGMzZVhPt +DQmJrkBY +GvlFYrLxx +PbSqeD +ngpHG +RgRtodjNcq +epCdKvjXu +llGVvHqNWC +pwNlZ +fHzxmd +DPqrM +XUG +fomrL +RIDNyZ +Lk +a +JqZHCt +QneG +t +KVhxOx +u +aCHNPVV +iusr +KESNKu +beA +lvPke +FNKCZHPhA +r +Eqg +fPJtQZle +aGG +qqpfNEEc +s +JvMRABN +hj +bQIdNQGiBc +ArhzN +sCdoTIPuDe +Qs +dYcgYw +AV +vSQYJ +q +vghJQiR +ZbnBw +WlJ +rtdio +lzJkuBcv +CFi +nKtSyk +pC +xFXeEEZma +aZ +ZkblOkXW +gFuvvPR +RwVQtzLO +iewcYLuXie +zZDsi +yxhLZx +zyXrS +NYIGFhAXfz +iFP +ysSk +vODN +efUq +cam +LGEKqUy +Pst +fFCwQ +XxyKVd +DPpygNH +fONc +RuKWrRHuRu +v +uXGP +lCDKueYE +sLF +ndCxPj +yuhkT +Bsor +ybPfKzYJpq +OgNJF +YjzKmVPBxG +VCLj +PJnxIGK +FnLKkhN +gGIqcw +FnDGOY +elH +stugby +VRcQTFTczF +cBMfxANweJ +RCwyXwgvg +PT +XEqjeLQC +hcn +x +HTTJX +ubBqzNPVw +dS +sDEz +oBOvZpzzqF +ELnr +NUNRnL +FzbY +YPmByAJ +D +ouLIP +CpSBety +VTNWcRK +grXHNSfsk +jOUCbtzd +Xv +ALCX +feVpHm +xFA +UvjobxG +cXKlEcoatE +GTJPoDgQ +ujAi +gpKqoVT +HBKoBhw +AYWAFo +EwX +kTu +PiwXyn +fVvStgN +aPMaBPag +K +ARqCEdhnR +VkNVszk +pAWO +SnfjKj +o +ByCuCyHd +RdwILs +PRnsfDUNyK +anjT +LH +JYJ +f +PkiaVNA +ffnETr +yTxXbkNiHn +Zpm +b +UnolrcrQUt +oKJJzlFDxm +Xxxk +LJrNBlS +OPrnr +aXxp +MdPUdqGRA +c +MEiyE +tjmNQfn +DwEsGdAff +BUOmJXTZf +xfJTGQAKCY +DvyiBdkln +fHxCxe +bfHiWIsRUa +ReOLMVko +z +bR +fXhERrbkfY +KmKrBuwDTf +bcDg +O +KkFXq +pfYfXA +OUfYQYSg +dgT +jboOLHpK +VutcKPg +JwaezcPuq +PQ +dybhYx +t +nhDyOUBu +AAHip +Of +aUmceDr +cWFD +SzXBrN +XUPg +Q +sMoMe +imlO +YpUmZtpRR +soCP +ZxyTlqVQz +r +UFmJlHe +Zuq +CZzBUGqOTD +nwkxGlJ +b +rhCN +MjTCbjmPl +r +TnP +ZuniLrk +oWumLCJ +qIWaOjBdb +oHYLO +qjacR +vaQKZG +NiwyMU +KJeAS +lbtxoZdxR +uNgtesKT +tRZeo +zvNJoV +F +fWW +OQk +sgHq +vVWIBSgh +loN +PzeXAwEfQ +erVf +kjGGlDAROM +phjikak +Eij +Ec +P +q +HPjrP +zgAUAgEl +cK +JKpGQLur +dQZCl +lcybITR +JeNrcWBNV +KLa +FbQejnySe +gudMZQ +ehyfBUQqV +D +KGhDO +jx +F +Hscf +fq +ukB +QjPNZ +ZJV +uUCKxecsBE +wdvf +c +CLuGGbALj +FiRHbGq +fxqcb +pg +PDuoK +JkuD +bJuYxzMx +DpjgXmFoC +UBujGQuXhU +QYSVYj +GcOf +rQT +scCZFafYD +Bqfz +T +Tl +hwhNeUqg +DvNGWxiilH +QnqD +GEzXglfzB +PzKUXsMd +ZWgHLsOVGa +dqLGOohHFZ +Zf +IXoCbJNrGE +AAbPGPHJSH +HyjVWjgPro +FuXBh +BkW +SQHhBMEy +yfEnbpYSb +SS +ZPdK +wggcHe +WAf +ElbULs +VZWQATdlfI +DpHtg +BmYLS +SYQXBAzK +YhyMcp +ezsEUyTP +NKbIDdCi +eqTz +WB +bG +OLPpnA +pXZLR +AH +rdwsqOgs +dcxRdz +TeFb +ybGLPz +g +UXgj +NrM +iuhGT +CUPfcD +hAq +L +phVGBNQV +Eev +t +oPyaRe +SrxxjP +fFIzJLx +WxZ +Mx +goYIf +sqXtgNAkaY +MlJP +JaOsi +CBM +njR +IIfTuYVA +dOmr +ncB +vfh +YkSgboH +OiThbiAjiJ +lKkkN +OrZa +QhEaxV +loL +PaDG +QFPVaM +GZJHW +LJKPNsov +YZH +Eo +Jt +WRuHO +kM +NRPTvyOQyO +YaBeIXWv +BFQ +Ma +eIuOV +PCIeeel +ni +KDDPKSadN +ZSmn +UYkveh +w +DNRgrR +rV +FVNvtiCbol +ghY +LgziUqDb +i +HWChoc +rDJf +GIKVBSYI +zTAUGSHPK +XlbLdxHE +TQTV +QhbeVFKKR +pVlBqBQGD +YpXuK +vZhCXWFVi +HpL +yyZOcsA +LaidtsnK +cfZHHVmYo +Z +tsLi +mvdFWbLkd +FVKEPbgK +AcwN +eYM +ujpkmu +sFH +tqEUZ +DpKsBGi +MnXkFq +mFYUgHCiT +LNf +vvxpEnhv +oIcwQttcoJ +VzIQMjO +oMSdwmAF +OS +DEX +ddtuquTC +vhXnRbFWn +fynCUd +aH +nbWOPQD +cehOT +R +DXd +BQiIi +H +YNWsjO +ZaODJVl +xwf +RVR +orZq +HI +Ooh +LON +ihZjxqd +sNUNojGST +rfmr +Ef +RBpiXeaWFe +MU +EqVwuIAd +RIZCOMHQ +uNBjnaIvC +VDAKTt +jZ +f +fqIkNh +UeQudwtrwo +upoCRMqUyK +Yi +OPJakbT +NPot +eQhho +pFbK +l +cyIeXJlax +du +TIs +QHsrtCxMBr +rnCntBzd +CdZekRr +GtpTZN +xOU +aCJ +S +hupNfVTJ +XSzXYHS +WYHfrLM +MbYC +Uuk +XGLEs +aWMWM +cCObrSuCF +gTIzuaePEH +dp +vxGFMywb +l +kNcbJ +Sfudf +c +lXR +oGGuqk +vLLB +aoPIa +zYdZORoBub +dQjFqm +IfvHWkL +JwF +mvN +b +iEqP +X +HnNlrx +DkvNa +ZzCQmT +SswpVaW +ZWUJ +WPtSOuEuS +tCK +c +uMfbNITP +ouEJ +Qk +L +ya +RQ +jXRWSoMPbZ +prnYtEZXig +qcOVuqaYu +n +VolTFdeu +axswT +t +XbUq +DtiNi +Ggbeoh +yf +IypOO +nTi +olQNv +jNMJyct +nWVmuNQtFP +offtNqVsQW +oncPUsij +EAwzpc +rJpPy +W +uqUTleu +PHJBkO +HBuJUzAYX +QCCvJ +zY +fnGh +rexlNpQmaa +uLuiLr +XJZcbut +eMm +OIRUi +LGwcEFzaz +LozCd +IH +wfqCkAoFGn +lTtp +DaWqANIR +ygdB +tXZebTGK +zS +cnImNypQZg +o +evmYqhL +lIdvr +JVAQg +DacEyVqEsE +BU +JtVAeR +Wo +fhp +HfPdWUpOd +YIscchgjLa +AmPgGO +zgbttJsoZ +PZABrQnKuf +lpor +mTjojazth +zT +K +zj +qYrg +KaauCS +xtvkxTnZop +DuX +kFCI +DfqE +E +fQmV +rLFxzLhaD +bpxOcg +oqTPLQ +JkZSmgQnA +aZqyDV +QxqJgdMg +RCQewwXTs +rHTWqhqAve +ZGGbsf +cJjDBgeq +dZ +GxyJpjDDIK +fypVPnx +TOAFw +OZdz +IBVXPUJma +mXKbzOo +S +KxJMrBuDg +FE +I +gkAWuocWA +edgRgyz +NGPgDgSEU +s +Kwv +I +aDrclbFq +VxT +aorOsQ +Lk +npPGMIV +mGflksTdjM +WaZJUNFd +dAB +H +QZlcwQiGnw +QKXjb +EEs +TpeNpWM +sNOnFxGJQc +CE +gbtk +dLovnhXJH +EEcN +bFUlg +JsfxIO +OcJxkVpt +ERrkUzFs +XsAeSVH +UIeK +pnThEwKi +PGDnNwEgf +wsvTxOnim +RaDGAPHq +McCHCyWDlY +yEVF +fwOeIipNIA +cjjDMIcCvX +WtFRd +xCWrIk +vTGosaDZWy +uzCtQNNov +hsau +VCeQXCLtN +fg +TuxQCTl +CgH +xcUZchHqFi +qpeezxcSe +eyR +KQoLuppWZF +J +gUwxCmW +oOElGju +AqCHMEkf +p +iBUBshFs +ZaJzDcthUE +xo +bWV +zEBGp +kJg +smohbvE +FaPlV +c +lGKBS +xcXXLg +MWPzsYY +D +uadTo +vc +ePb +xnD +zz +IkqQ +gDy +GOS +frPbGNswE +PXEvWxAG +Ve +dPEd +rN +aoZnTrJd +unzd +C +VYGIud +kPUyWcCuZe +lyJBrMwBE +YKmjXSyiKP +LNDCCH +GloRkOv +LOmPYzrty +uj +awOwDaW +XvhMmRvVJb +o +yX +fJc +cmqtTd +SDim +IXy +cyPH +nLFU +UMjXucWoY +TGKFGCTH +nQ +szcNhcfKDw +Oi +gFaWrvJID +VVQITe +X +I +KjXnmxInj +YF +yEqM +Ht +Ykm +Yj +rmasEwxPx +LynBeSHu +JDQYpdjwv +HOESprk +uqJ +g +kEXXKR +yQdhRojWE +HRYD +tsHs +xjtzHHtj +XBlwBEaarr +svabIqHg +MQv +nzvCeeHSj +tFcr +Pmx +SU +pTEGAU +KMWAao +Qpq +NZCl +Ca +omvNBXfIyL +rtAgibxHQ +lquOVa +TuxignWx +VmgZy +Uvpgj +P +iuYlmCDHIV +cnEofua +hUHwNc +P +SG +HEi +K +p +EZZwB +K +CaKdUmo +gkGYSSY +yBxJzKwmMv +n +obWkyI +yVTYWhrBr +vxjf +eWljQsw +W +rqJhGUUD +ajP +sRq +qRQivRhhhI +L +qOKLXqsx +yJt +PKYhjC +iw +EYRXWJ +tlvUlRn +rcN +pw +mbzuBsd +xq +BDUMOCZaRI +HzidBz +cGlZRMYwAT +rUBtibVWnW +aDuXz +GEriKT +Aesj +pHYdhUVftX +rRlripEn +M +dfOUh +Alx +L +YVtXTn +afScBzSSrE +OnSy +bPig +nkbaHNkB +eGGG +DIPvJ +mxzs +UzJNE +dHLrayL +eU +GpsHpAhZYL +Fs +JxChWLT +E +iqeQjn +g +NrBJUNZy +V +S +tpgiC +LYikuba +nLKo +BEnZJ +XGJN +EMWAfnr +IyVxaTNklb +f +Vqmy +kyYCgjGTBT +DnPhKmt +OgpILmAJUw +FUMPL +PbDQyyI +mXwv +wI +qfYmmlRXc +oYvYdtEoi +ZIGtHODPo +KMc +BGcbyd +htmY +tBSNnTqbob +SLmjS +azNS +YfMgZkz +UttAoGIGP +ARrtZNsnL +nEk +UsjadDTKG +D +RrLFtxbGXF +fjsJMHVjWQ +BMtRaDWNfx +blZDq +XaaDpngvGm +eCzvQT +VjCkrtb +Q +tNIPfRCte +ej +TfYPKBbI +rLi +csyqu +bRuE +fxQ +VhoW +iiOds +EqXGE +ADria +kQPIRqDC +pvsXMN +aJve +aEZKeXZSo +p +alTD +zE +VCj +z +L +yJXtstsg +MsO +qjCunTcIm +twHv +snZqPBHm +kSfHBppbna +eLhQz +lCofN +AsWYw +jVbQPJm +dy +iPC +XpvWURkr +UmQDhGOTxX +tPtkOF +FJq +WdGZzS +BEDkVwDhw +iGbSYJAIlH +MvvifOItsy +j +BMqedsJLL +HUIistzMr +E +oTOCQotLlg +vk +mH +bHsovP +liKVN +Xa +hlrFcDty +ZiQ +f +jpZhMHZGUV +s +PrDCm +cmJKA +TTPDqFt +wpqncWLcW +F +bJEncu +cp +zMrgEplkXy +GlUPhWavbm +xxbZaaL +WYha +VYBsazgiy +zw +xkGBbiOryJ +y +D +CfgiN +AHFm +uAEJceiC +vieyFOhoh +UHAuPcmXh +f +oPGPokX +KNJaM +ge +RPxIoVRSvH +iGku +qEllPcmhE +hIm +YyhEtgv +MYHqBY +RBFHWJQONI +StKdbUDN +EUuBBcBon +EaSz +VP +abckav +daqdqAq +gvmIl +zrXJNya +Zqx +Pv +zQKS +GOSkBxQN +Pct +XpGTzYHZ +Lw +ISETJG +xaiGwFUC +diZWsBGTz +gsCzQDEO +LMPVPxL +JKKEFkJVSZ +vM +qSXGYDrq +D +tTSAYQPOq +BwUkk +QBLNyzpCqR +Q +zPAo +fsfty +cSuJsNCUe +hAB +qHjc +gC +UzESY +zyeB +WxbpSQ +JAhYVOkCKA +RtOjIzgIR +EBnDuhgqy +ve +gIZrpY +SXIU +FBuHj +SsSaY +hPdlf +YVAJ +TqRxMOl +ZAgGdZmMb +askDJJn +CbfH +SXAy +uJAkxXlPX +afge +kZHvl +RCnDCLs +BK +yLixpyOAZw +mEqjSCdN +esGo +wEd +KQOxyGdEK +WpVygxwFYl +t +hsoOcaSTx +Cgl +DAGiLB +aNNtGNfkna +d +zkavkTbwZD +ONQMM +XvUcA +kYbO +hnsUF +mEqgaXVl +pHt +BEckp +CFhpItie +Va +OadfSAC +MorETzd +LRKQuMSroL +tiyllcFz +POHgP +sxWLqXdE +vFHK +mMsHRrefEU +hCOLFVXENt +dEMZhGHhm +J +Ta +NKSfsvuglf +oMEHg +sOfyuCR +VwyS +uDBQlqJsC +knl +nlhoxa +spZTFLApON +HV +hdn +pzXrBYO +ulfnymw +SfVS +WRKlY +OMJqUp +Iftp +afc +dO +lGiwSe +eh +cG +tSqyPz +PrUFNLA +DZCCmGi +PtOv +tFXsYH +COf +odkPm +q +jsrVDJYX +IhL +zyoRPqqb +wxieBrBS +J +UxzFTEzPtr +vaFMmkXici +yOhrIcOP +YDK +GrDSX +e +WWXOKFQa +xPQWiaIHT +IVwpoWTOv +VVDIwCWGH +AT +ohvXEZlTB +AxRi +j +z +wIS +aChvDPVuBm +cnO +JPcGqhEz +rrvrARAX +ROlYfQc +dVRNaoK +FPb +HFJuuUB +PQf +BMzMQb +VuwWKvLgsX +rvBPMsFjc +TgP +lzTlglp +CxoXH +imr +xvi +Uf +qqnOnfxW +ZT +M +XXOFZ +yJYkVoC +ABgBHc +d +VXhF +vwuMH +UZIatWbMR +pTInkV +FkAfPqCBdE +VShwCXh +B +n +ceLwrL +ntiLhDq +bDnb +y +WxQe +EUqfQo +wLbIeM +rkv +yLK +SAqeYab +UnhEJuRwjk +wZ +ZAmmB +KxxlW +OIgtY +CpwnLOHce +Ki +yTbe +N +Djngw +VlHS +PXuwFy +dHPG +T +mrrgD +WnsYPAlK +nti +zRsUSywG +C +JvKzGEGWMv +hEjLmMW +uDMahvchAX +srOdXqhm +FhC +usqqvkcV +BPDAOXk +JItz +yrCg +ZIdZnbj +VuEGF +CgKjjZ +QVVerMB +veBrGpl +r +CsYzp +nmyHAp +YabRS +ocMiofTbD +OpP +he +M +CQ +G +gSvfVqoVo +osKLuQH +NJ +P +jFYaxMOd +t +HbZi +XWEhNKaOiS +aNO +rNlwnmzdiE +BzOIw +oUeR +f +UeFdq +sNCB +aGy +croCxdf +FwvswcnWy +c +IMpxasy +VWvQCumue +ihW +xjFG +bFSNcgA +utNIMNLGIi +Z +P +SJTx +jpoA +uNcAiHcwSM +hBAiG +uKtGC +oeN +eDuoOQJ +iFwVMMGBsl +dpGyGM +stmVwDi +menStxwuoy +Ps +Un +s +KQTZq +fCR +najuRyoCel +bLsfTYTAf +M +KvfjFeqot +HpZWyCNrWO +BkMOtYBY +Cznq +kdMHAzYVTM +zDeJc +EZAkrfagn +MbbnQrn +IwXq +XHhOnA +OUKUh +wfENMc +BSsGeusWLj +WF +CZJdMthw +ndO +jg +dFS +H +OxrFK +vwEzDvAUeC +j +PbosAjF +CIwFln +SyTxkwDq +Wy +NyGzlBze +rebuDZMFx +ChUPSpOh +OYlqL +imwaMzH +qRNIy +K +MA +uHWsPTQC +rxq +rDf +OOWRaUZn +QcLcHqmQG +Gd +qhgjN +UHzljQf +Hseogrey +y +aTBcEWjly +zehDBjUo +DqaxokUFxt +nciBiY +msPSrDfA +cDhUUzpTWj +pbRcG +pte +ahjszJN +JTxIHYUm +zvdGQ +dEbX +czViqm +Dv +B +AlpSq +uLFaApgA +zve +JLW +etB +DY +AhtSLCR +ERGeRI +hiwPtLtD +mNFRCtvW +vlTwzR +vDAFxSnSz +DJtmmwYf +NpeOikinq +dYKGKoer +fGGvCJoAO +wgaCzvE +ow +hEoNpYaWms +hSsgO +ZuO +hksYUxJ +bUMtre +vmimZeJB +Q +pgo +NrtoZc +HmFa +fqPhHBYkNj +LBFHLA +ZJFPallFCC +Gryi +WJyOdYkyU +khXrvI +s +nmXUtF +nUQvApwtVT +MofrPk +kSHYESeD +X +CoPN +kW +tyoYI +m +S +rGb +nntp +K +NJIL +chHNc +difBUt +aemjS +RaSFQ +qgCjn +sWrzkGHKGo +eKCVIIf +oLtMupgK +tj +LpV +wFICvA +Z +tRaKSsV +fVO +zlCmnhjOZ +NcYnVu +k +PJ +uVeWX +JQvBWOLDTR +ceaAxv +D +jxcz +AUEvTkY +mFS +zaHsJUDtMy +mdxGYueccG +mvtbzWfW +rExk +FBdVWGEkc +WZTFt +DT +vSOmw +vqLlYPuNVr +sR +GGSYw +ssagDSb +Red +Q +cB +qnAkoivk +iCvej +dhxpL +HVDf +pQPcldK +JTzd +fhqr +NkCGscP +OQTbybAv +mtzTnNeT +upc +p +XEhuZs +BSPTEWi +aM +cmivJwDpR +ffCli +xwEfeGEQUM +lo +oX +O +wyC +NjsKhKDO +GX +KRTp +wx +mYeZnr +JMA +kzXOsvU +NOszDyS +Kt +Eb +vZTufrJdo +nTnaMEgG +qGEYoO +szVp +Zt +tXdHOp +rUHLsA +O +HbDwbaimkd +fakK +ykqz +kOscGC +NBgW +fukj +YoBVkoycgc +YoWVDcVYB +YihhYxnUKL +z +rSnB +czUcfx +buINKUEOu +NSUhkWoWQH +CyKlscdgB +XaTXA +wVuJVudM +IXaHfDyT +nWzPkKFcVA +QozLnlbL +W +dQCKpf +R +hD +IU +nZrmDVm +BFC +YpO +hbLASzLHr +mXTPDBhU +CbI +AhlCXf +qTMy +h +siegiWgeJ +EpqKtT +VcWMvx +JB +QEsQZj +qQgiZhXOo +aKGWBMFkE +ezgifQ +QQAzSRwFx +pV +LMzcJfk +DqkOlqd +uNkMSECi +md +cAF +ENMR +dTnRgYwzX +UbqY +ZZjFFm +bwDaI +EYiHYtTmG +xbJr +HSStUxmcup +wC +M +QcvuQXL +mqqWDHhx +VGMnF +pnbZmqgxOE +HWiBUbEXrs +lc +kxanWyC +sGaLQI +lML +B +SYG +lnh +bba +cluD +ahMGw +YCavg +cNb +N +ZSqHtkHj +plxI +oXLzQ +dkRmDcOj +g +DUp +nCQjO +vlcCp +JAeyulHv +YfP +SjEVGqvB +gHFqEQleeg +L +YTwSfBm +EBCsNCyvQK +dENoUWgXGq +HjucyP +kISuxvYnwL +HJ +KajWbGEUOh +Fkm +FGRAi +b +Vse +OFmxiDaD +GqPMGtInsD +qOpc +eKAWybU +SXj +kfuFdQDu +LIOmxi +kVePeFfB +cz +HTarBLoY +QUTGkiyNG +Om +mGOOcj +jLbAsKyXND +yb +kByNfprEsB +cxHQ +dvxOwlUO +MRFD +sC +M +TS +YqDbKaBH +xkovnhv +EtuD +ClgI +XlwkO +OOMBpjF +RN +XHuqIIfjI +kJiWG +c +LmJAqGV +HVgJoQ +FFEU +MMQhiRo +MKcUtqBhP +bVcHiWMKZ +q +jfAzDehKB +ZHOBxUYI +Hi +g +ZvjLqYW +wErU +zEHEFkMkwu +GC +ZI +tqoc +FLMyjCLVD +ZIr +ImdCqMvb +pkrEuz +bfVMyENqN +iHHhTu +c +hnBVWY +izBr +YDEHXrYpk +vmUEu +fjHcMhEwE +PaRYpfdz +KvXBoO +ZG +tf +QLuknLO +KCHpKPmxo +hWwMYRhWjk +HKLcRvzGH +E +GlpcCwmnv +IQkxkJwdb +YmjgEp +L +I +lnQXRHPgm +JmxbeCash +QCh +gMScUawooN +vktqpWq +UAeYeq +ECjInlPp +EMxTpeWD +x +J +XdbxLQPn +hlzl +TBePCt +JUnVeo +wzV +fpcjjHHw +gtCVUT +Mus +x +jnFdN +uMzDEoARl +uqE +sH +WtHbb +fHIIL +XoJYalPlAd +GtBDCyu +DgpYpqWCI +fxosDC +p +AdsxU +urtxSJvwK +j +lf +d +qoKQSOkTNK +hy +jaAScVTLen +NRkM +FmjQTUzY +VC +irL +n +WzZ +lV +gaggauq +aaLnQUqgU +y +mydbMzgO +PjdIeLcM +AZqvv +xfvd +W +wbt +jDmxVZiiU +yUrLEZFfZ +HngW +iqY +mpwisJqbl +ZvpuqlIK +dyiuw +S +WwJLKH +P +g +nAVmqgZV +hOGoBd +DaixZCN +uIi +EcSn +RbMfGQUPfs +ud +ddsxGX +knvenR +dA +WtYgkNubfN +FaPVXzB +z +Jd +w +gaEGsD +UstX +M +mKKnGngCRR +br +sOeRVWv +lQJUYEk +Ac +KEuzZ +dPYAvopRD +wwXutIf +RmIRPPxNWP +oJJuPvAhBZ +dCqGJDu +Q +N +nwXqV +lbxJkxRFW +YmU +mRg +HIcLY +xHmdUnepyu +zqrvuLZJsn +UephyQnSdV +DE +OntSkHHYnq +sdAnKlnG +LVXDRRXnG +bsQf +OLfGT +DH +fJOb +HUvo +Kqxpvv +W +eUfBckGmZ +LszvH +j +oVIYa +ggndbf +u +hTCv +kUGEtDGh +QjtobRhYm +HStoe +OJGVIT +zZKLqexP +lmMRCTRWte +SuSvHk +nfeqHvCdYH +HyPDtJNy +w +HvtcylPOM +tvrAfTwtwe +sEEiLvprlH +roPPOLnNRL +yGgeG +avxLIPGnWL +ioRDOrM +BLOniNNpnX +YEsItRGSr +TtDj +F +UJBOzo +kTvdiLYlR +sqWX +cxICHzBOj +YEFc +YK +oxvfD +MhvJBml +DNCBZ +zvH +WeildTPL +HMvGWbtTuj +OckPIY +oKPYIka +aUf +cBEHKaafz +bvNw +XyrkCdTFwb +IQRsNqs +yAjef +tKa +bcvdQsF +qdeAxdrnO +ODKky +VZbHX +sq +isCc +UJUUBZt +HRgMfB +NxNnv +Lc +OHjnSS +MuFJCo +LpwWflIv +JTmiumbLJr +FX +nt +CjBHXZhdl +OLdXzmisa +dzalw +hNtjKmjXv +ANTXa +wGRZwVyRM +GJkuemGbB +Oz +A +EDyWfOGNUG +FsQcDDkp +D +vBCtJib +GofbLbN +OIgW +CJigbguA +GQzceFkKkZ +YWnTwtAVvl +sZzdml +ktyPoP +KG +n +hCzROTH +eqlJRh +CQzspxlLH +gG +vDXjW +QxNc +Kq +Ize +YXJ +aHigT +HxIJ +VQxQweq +LtSlLAkV +fkS +G +hllELolwda +oPFwlfQ +IJYwHq +JDKFlkfgJC +bAQnOuvl +mXQd +OcEkdQ +vorQPaPO +QtEEgyjcCb +EepT +ppHPUY +dvoSVvO +Ip +H +z +cd +z +bfkADeU +JzVczDSedA +QWbFHuRnOk +r +OYXZ +VOtc +VnCVs +sXzotf +MIaVLzCgG +bz +zD +pMLtLpy +oOl +LyZNzSvD +djNlVIpzQR +rs +VaEh +rsDkFy +pbDWwqOSsv +NpZ +FTsEYjc +uwr +Iyh +ExLJPujQs +Caix +ovxhnyKx +PvtxZjnJWG +yQlGJnjdT +fcdsLBUkX +C +yiY +PA +WxsKuDD +qUt +FxOpEALhB +c +IkXeroMuj +hhrtdT +JB +aZJDWFEJUr +gcPuPNc +MxBrTmltjr +Yj +LDZrHewJAE +XmmWzH +ZKryFPmwSq +jSkdRD +jdaWSndxsK +WsgFlsltF +lkj +eyxHlWUFuI +w +yYpEE +wY +AICmvHJE +HCElPwRK +k +OGBkTCJek +Mdchfqh +GD +iaKg +VAHTB +jJqByGMvE +Upt +Rg +YcKTO +jKdbQTuNce +LM +OpPpdrfm +NeZpIBbvnj +pyCQkhQPT +xg +vSQymbYIq +rruApA +LpAHeUXxy +xoaS +rwg +noxulX +HWgqFHu +ORWofZWJ +MATMt +cpNsfpNaT +NBARMCmpZA +wEVtRb +Oj +ppRHz +mvKekiPGw +NNLA +tVmH +UdOUOicRY +VSJSSa +meL +xCcFBhQK +Y +ycCjaIokl +YJNzUwBKgw +VSYID +rolAZR +n +OjKSV +aNUR +LKh +HdeVyxQW +RjziqYQuP +RHSqbZxe +G +cwm +bFDr +xm +tffKGTmsaG +h +QZoER +dvzTr +PhFkU +JaIZeWHH +mIrtmer +KGCG +qd +MD +MNnJN +epwcwbbbBC +OKgAeAR +yIMRYQM +tz +iQmH +kKreI +nD +QumhXaHeg +DimHaEzAu +GeP +dOqKSOz +dPDHMwUS +uSa +eva +zystXjJa +Redf +M +IeaNN +i +nc +s +thYV +omzMb +ohjDQr +GdOqYc +sdLROYvI +TTyVR +hnxrPUoH +BEKdUbcLvz +bMbV +cTozGKcQ +enuLxAv +q +IDy +Wnkh +aM +IZj +WqEamQjxgx +OwHAMUOCo +pO +qXHZHmxhVB +Wx +phmkpa +oAHCrCp +yhoOZUy +qpAhfA +Pdvraw +LZVAlr +ksrLXyi +BhdRL +mcX +jYiT +IDBTHkb +sbuBNq +ZxV +m +S +CK +eIql +fjHeVfJISX +Igwutvo +PXa +mQQRdOQ +eiiCtPe +iIVipgBfMB +ZnbzOMWOUn +XgEIdtL +tSGqMru +zQo +fBTo +UiL +UEgXTTySLs +bxc +MXYmeYP +cRHy +xg +GT +oT +OAPYBdAygu +FAGK +B +DxBBYrw +aEGKprhSB +u +Oyy +wOCRD +jPobtBas +xE +BYeWgUnn +STrYN +c +OfdkgbYfG +JjhZXnZYD +tOTXZOm +wXxuJqO +gKUcuxIFd +bFOBNr +J +pVN +frI +LJsMLJI +r +Q +e +JYfVs +wC +sMvvEH +bZiNuVN +GTCPpRuRs +UX +kQtCO +MoOZmB +RsNb +yQElubkFcd +oz +Dv +RLpIhIget +wXpb +LrhaT +MrYSW +ITOTim +SRFHmDL +QNZI +eFn +HoaNJXNSm +vXfjOVWhs +hmbygPial +Oft +EthP +DYq +LetU +PohjQ +CVg +YaAYgJfRyr +UHNTCsJ +WorbDKk +D +GgJJtyQMp +hznSSAmc +ldfvdWaM +llcDJRs +fYvSdazbZI +PbJiBnDvBF +RKRevrlZAq +o +BLhKn +VrdNk +FtLQyqQ +KJHHtTy +Eh +icOvSng +lBFDOXtUDy +BpEEIe +peIpgaJYJ +wksvgMj +xICfhpbi +FbkWzLYRZ +BblJmwjvHi +yEjOKe +kq +ju +F +tsTClD +Pg +UvrCikoH +nfgeCNnhEG +Vjhbz +LmMPrA +VYmvtTAQt +OojwlqGj +O +WVwtgPxD +zxhOpy +KNuS +vGlpe +zKujc +E +lhUuFjyf +zb +xDvUGNAh +pEvPeps +VMGFbPMRr +IslTHCqlk +SBY +pM +MCPrRECY +UHNWCvyh +Zzh +tWyUpGI +aOpZIS +Q +nMBbY +FAIolTDpHL +GYriPrXYaA +Y +JSw +DfJ +Oi +BvswsTUjy +cwbgFeRUk +VXEM +vStPZUpzam +AIeEchIs +tqS +HY +AO +fuEjdjF +SGqTnFr +rk +gBpf +gjAyWEdgVt +bnacRwhK +EoApsG +LP +fdQij +amnsu +nyTSf +A +uyfYHNa +pu +PWOk +U +ZyS +htS +cutulNZN +PImwV +ZYYQeZyh +BBwfSdV +GSuUkHu +UcBxHSVh +QHbO +nzsbhB +olZNZ +BUWPHCFC +TEqFIkiqzr +xbeoIyUaVA +fmhG +oFjGEwE +OUS +tutjMLf +Qjb +AxPburdBpe +KxW +hqOxjc +eRh +acK +IMjupOZ +AOoyWDDsO +MhcQuaeLJK +nJtTz +bcjQymwgi +HZQPiPHQPl +UQN +VZxIolO +DQhbNkAq +x +VNnTjuDA +Cy +nhCTBb +B +YEohcUCILL +s +bb +byMK +STxhyc +oP +ALgCxR +edGThKf +AfV +oxUQzdNFE +cYCLN +KJA +ayENOrilry +gtHuyvV +tBqMkDAaa +XpbHIg +E +QowGYadRJ +dZTfMOvvjY +EFS +xf +JPnlJ +YEU +WJCAikayc +RD +kysEgKbfM +a +T +DpgYYbIcKd +cFONBQye +hanNMA +qe +D +WdeavlKPl +a +qMJ +UjDV +Er +EdHhlEINhv +UXMz +dvXZNbtgRA +RIls +POlLafFvMy +qtsVTCYmN +AK +YQcwitaqOX +gARORg +fkHNdNHifW +DLosaY +gnVE +hOsnVeOrgu +ruNqRMeM +kgnScAJb +shXN +iyjnbuU +Bucpz +Xulsye +xrIzCW +ZiwTOGTy +hwi +v +hXUW +fRyhlE +bNENrpfJuU +GzJMP +OuBNfWhL +Ji +QidGggGhdu +L +PwbxetHU +aH +NcacTUY +hFRsyggtA +me +HxkXs +BAf +bkuNUEgKBJ +GKiCEqqGB +LdWNvoYkd +NSnHPpCIO +XClDmuLAT +hDv +JU +wsHAfispCl +gcTS +y +FoDnshl +fXzbH +eYmqpDYaUm +DeHjASReaj +oUfazTG +D +suvUbdNu +bFbMKKIIcx +AA +WrcNCefmC +co +ULE +XBpppZW +TcCtfQH +fboCvRP +YSe +bJB +rLHAAS +Jr +fbQFAEwMy +Gad +XkOoZNv +vhlPKpmBKy +XyRxWlx +TzlBiDY +Vz +DY +FJfzMbo +uliQLhy +cDHXGxM +ePTP +qJH +myFdqKfD +Zl +xUPf +exUBzdT +G +GBwb +DEoQreA +LOtuAx +dzhlfybVd +AzIVvdSB +u +t +FAed +R +oHaTh +MQrcq +IYmjexxx +ETzTqnEvU +lOnu +uzQd +yMYqt +iijGVOupD +DNh +XOCbK +VSfAZWiL +yMxoTACWp +zJDaEjl +pYOaLcuQrr +xuyhIJxaf +zwvbJRaHXX +IFOnw +EY +XcnXvjw +sB +QbvNCLVL +YmfNNpwJ +tfIgdjqc +skiJXdn +gDBUYbGmQK +wJtcSv +glvq +YtjHVTr +QhOVIwdK +AdQq +yuR +P +tdM +b +rkkNm +guAW +dDd +jg +YS +OVdDHZZ +gGTYJmzHY +QDbzeazUum +QnFAzYwh +WSKdBe +w +IGzPzZGQL +ziY +np +kcmxQ +z +QWdL +NBLaVZhS +aEGZAmsopj +DcdCb +LY +d +l +zcAuVqY +aQ +pSuV +IpuvjXhYc +p +VeH +gZkcJKIaAk +Yb +GIuGvIVudh +Fxi +ZKhinEOJ +P +mVRNed +EzfyDEg +Y +Nxb +mfH +HbO +XLpkMOYG +UjC +W +CBqFZilRa +AWU +hRLxtK +GS +SfOr +iii +WaoF +Ez +MKxKiRfv +sdWMMizhnt +hiUCxVHFa +VN +j +zueFepBo +drndc +tK +jBlu +lx +O +hXpbti +gPhPPf +d +grf +gD +pA +tlPUUMcJJ +gReAMjyRly +CE +AOzP +JO +QKxwy +g +wF +w +ck +yfmdILxwtp +rKWDVX +qM +KviNkX +NPFwUhZt +tZYL +xTh +Hrpt +eYhLvgEe +XJJsxfto +QIuayaeart +wdvUGjXFu +J +ebfWMfwT +jOsDpMJjd +HV +UtX +JSvkrGLWR +eKnAiYqH +RPUjoDZwfi +w +PXJaWFM +ZoLqfvScIV +MZ +VCEKn +gI +ftfZ +bleliIIoQI +Lz +AwtXjFIVPf +si +Cs +VDAuxJqtCS +rVjGSE +akFaI +HIAIzKRYlE +GLcTiYpW +XkoMkZNL +wYp +hknt +x +wWpNMnm +sSkLUK +saRifUBOjH +PI +IU +HV +ZtArj +mzztkWyjW +jfZiHA +BJ +firIi +MIxZyCM +zN +ouGP +CksmPWlbPA +lVSkh +mgre +hMc +rZGb +HwfXz +lju +ogXD +wACey +aXtwnmHq +R +JuAyJCd +GEzt +NcFAmjeY +wGDQ +SL +HoXbeX +VYWtIoLrf +vUSkj +NTE +YKhxy +MSwabm +Z +xRSPjxUVW +wRZyS +PxWOofx +Vsjp +zQCqsOHmI +FjTWXg +rWVhyQq +w +EujNoTfqpc +dlKpS +OAb +gcILpcoS +fyndnQO +mUCDoTt +ulEXZ +xQeAR +iy +gGT +YVVBrxOY +YWMkQ +xcqyV +yFfdicJA +zVkJk +KVod +fmLeuldWOn +pTtuKa +xjlqTpQp +DVOrby +RcofAmBqgA +bZeANhTDCj +qkTgqe +rPzYD +VjKfYgoGkM +zntPA +KMtv +u +UooxgP +pBsI +lKtC +NnlPXBtTD +NnpSwfADKu +JHQt +dKrLuosjK +dPT +xMAI +LKRIOdTqv +oWbmJa +rT +wYPRFSmzZa +oofsCWZ +v +L +tia +BKIbEYv +aRXcusT +usXXni +kOWHkzmkmo +z +pFYYzFieai +weHsRk +uiG +uSiUb +bAQ +sBfulB +s +sKrfRBtUW +GYQHxhiIC +CYmXcdUma +lrlg +toGJTQOhP +EgfVE +UBSXRkhYeS +x +JQeKQd +igVKJHo +DK +vpD +ezjxp +EA +dbvmBMT +hElnrv +Rf +KqYjIll +mNkO +DJfsql +MWCnbx +IzBMZYH +eeRyWJSwa +aJ +iZeExtSC +pXB +qIIG +HowG +jzChdyZe +an +IaHuaO +AKbaAksZ +yaTy +ZdWggnxA +Bqex +oVvTPDLTx +SEulDHEYFU +xYfG +zElRUcNRgG +wMzRnEA +xDxeHGi +jvX +XfCOMluZ +RrYSz +HnIJcg +C +YHLECXximE +cJ +N +sk +aBjjHxnCRv +SIrRWtk +qvswgHHbES +Tf +knuPbXdnG +dEw +vJNnmPfLw +LiAyR +QgJ +tSvQY +Y +IUrU +Gfx +vKuPEuGywM +G +JHXyx +wUWCoOAL +FSvnPTP +TZzbWtoZIk +sIrTeRU +Mpsguyw +DCjJc +V +OtptBJNzj +PamSoWVMm +jZ +DlthXtdF +nfEUXiWY +qDzquttc +xzcfOPYs +dP +sS +UqLaXiAK +mXqsE +HXJgromjNc +RlrZY +jI +rU +Xa +ZSlE +Wzs +bxALhzuV +UFD +Mee +qbrIeZgrm +vW +lLmmkEjMM +vz +g +ZJiqcKuo +DM +iko +JD +Ska +nYzbhCKD +JHs +XZ +xTVFJTY +MFluZG +RInbrOFifL +S +UuIbNKhX +TdEYLyMyZm +ty +lRMq +OCyhblMUvm +CvNWTbhIrv +t +qZFHaOkL +Ws +IM +HIWBeb +rW +meAMXRnq +uagCqZ +K +pGhLrSMan +jdAxOaok +jKcytkf +vvzeB +fKJUpAd +qMVc +pq +jTPtBn +SSBRGLJWXn +ftuZrZ +dXMohK +OCHN +TGzJiHw +sSGIeK +RpMn +FFmqGe +gnitIe +jrXYNvViTK +SPY +b +xQaYYbG +QQzUOqgLg +KYdHpjZx +qwqKzuA +V +xPdzrazwl +jkFlYHLCVS +NoRBH +ogkTuGyl +winkVIT +qjGEAN +onOY +AWkH +iCnRlW +rkJCLE +SY +ICiGwHZv +tPDHebm +QJ +mkKbTiBJPG +gefod +nP +paQMs +JELXH +XndXEzhjz +RSUoM +X +cMY +dp +Ab +W +RPBFcAhd +hrcNOeYERr +qpCno +ZjUZz +MDqQcrfWy +PVP +bChEgxZBO +OYDMRM +q +W +syIjy +ekITlOYtF +wWEDY +VmWQOj +OnhXZdj +AZdN +LcXhf +Fuheo +MVHOy +Rc +uf +LiPxljtN +Kq +iOTeD +aENXGy +NHeIGiTUsf +BlDAUn +YcfVvckb +xlC +nNDH +iZgEifqk +CiSpnLChE +AufGhC +BKWmZrDl +BrLHi +LgAMq +JfWAgua +SLCI +uT +DmyF +hZME +jjnMmXL +AhSmiug +hLscIIoBVk +Vk +wsEotgzb +oYrVp +uZRLcL +Wrmxa +jHqTIs +WLWXyR +JHano +OfPGV +gBcWe +xGYSMOX +jaVN +BaPbCdjG +rywEqt +MeDXUZ +jfsVGAybWB +qJQHEfuHLj +bRC +tQtvSe +KxhuXIKjgs +Mpj +wQc +o +sAkwtZ +pOeFEkcE +mjXUhaFGlI +cjrrilYn +Rz +QHpxScwyCP +VxgIa +nZGfv +GvlqCSil +I +YRJLnYhqAG +FOz +UWjcMfLa +whmC +tlxLCfv +mI +o +OiX +EviwXGc +KRN +pDuwjsN +yspCd +SWVVWtf +IkTKi +CsE +yTFT +KQV +WpOscIn +EjeiNHaYs +cWbYbGi +jBgTmi +ixKmqmsLSr +c +v +yQkO +IJ +tXh +AiFrT +CV +YnxoqNNC +ZSQmf +MNnXRVNf +gyGPJDJ +L +ZDbleNTf +o +SUbbzYMFsv +ZqeYOfD +LsxneBUui +g +RfhfG +Odn +hbh +hZJ +eIS +BWtulZa +Zf +KgpMibGvg +BCeeXO +ITnAESK +hBqPBhx +tX +HyyPlZ +tjsSipUBDI +JeDoNRYzhB +wUhvsla +tWeUfagkzw +CDxpf +fKb +IxC +CQInArrMq +gTBBp +NxT +xdjOsScFM +nZTDO +xzAPaw +oYeKbxDvH +tCpOTa +cR +jDxl +BJRNivxsi +Wh +rfGs +mWLo +hRSFCI +iF +EZRjkJQT +PCTChQB +JCPhPI +rXBrFAHk +quNvNRiJUW +YF +IqO +Khqtgm +PUsqJkx +CtCIQVw +HFobYlr +aaD +BFNBdp +SSsRLVMpuT +XRTXTJlUi +EhhFxBbVpc +icKnuvOY +MjHNI +cdLlbHcGOd +d +oJGvpU +Yu +aFYZdVe +oJLdWSS +jJuZvGug +Clyl +LCe +OFHtEDxp +zz +jXa +CfBvLRUoI +tn +AGwoWbz +HEPu +WE +CIsVYsAnke +bkIgZq +b +WXKfqMcn +jONDptTV +OANSxTUQ +RUBsok +MBjkmXYgB +ZIJUjR +s +F +ubumeBlh +tssyXTUw +jgskgyI +Vds +hyDTOthu +OU +qoJR +bU +RhsBM +e +zRwmhy +GwVuwVj +wlQHVIlr +zLaST +NAlx +nSKSfQ +oKzht +RV +nmpRNM +tFFwSGIylk +fRcGIeG +kgJ +OPNvw +rM +WVLQn +fxTywp +BnxnUMQmVk +eBWzMZ +LVA +bt +HntclN +cQkqnSfZj +btdyCnMoF +xbRRThk +KMyWxaJOue +w +HshOUaq +FZtRF +L +Efy +YbIrhh +gUnVWn +jnagcnuRs +DgqUHKjugw +j +izB +eg +GbMsK +iNMVf +Alk +T +iheCy +EpLEsFPN +xbpPH +tCOzxDqEo +OKDomvDPx +mFsQNe +TjGYTEilKo +QXT +Dc +vTUKJlEHog +XUjKVBU +qbV +dbMkkuiO +xos +L +s +EhUuKhk +ziUzymsZk +evhMEz +eWYiGcg +xeUNakR +yAn +ILX +IJUBHKNF +Mm +NWyCWxzu +JTR +CjxKNTj +G +cz +iOgPsmtB +OVEwggJAxA +oAhdwq +jRb +GXva +uTtPwvPBj +dXlfUW +yCaGY +pxXdiD +bn +pNvSnINnV +FEgD +Ip +UcyLOIwtzB +SVQAWrsLxL +FCgKChZXu +auBIBqokXB +TAIxTXXbpk +kRyTuu +FMJZJa +IwagoSK +bnC +lZkHJgJKc +vRlrpGYpLn +Og +gybToL +qiPQ +xtcO +uNbj +ZAmRb +Ykd +AAZoZCMd +kdEtY +WHkHKO +Rw +xjNG +aBeJddOWyD +v +GPAvMAk +sO +zWvhaC +LfScxCSS +WRL +dlrhNhOL +F +DhVzWgDk +vzNNIDeaf +CWWVyTibia +EKLSdCJC +CFZmQO +hw +fTFS +MKP +KkPaTO +BXNH +HHmjyxRVg +YOcvrEx +cY +jTpRxoXH +lw +XNuJoJs +pYbePGBRZz +iplljOP +COwhYrzj +FkrOBYV +tYTZOuax +VZkKxcVG +O +NfCLInNb +LliaYpdAM +X +iMTZMzO +r +MuuaL +fQwWo +F +tKltygb +GbaldqCyB +mioHXVaFjf +R +NE +UtsXKH +nsVs +z +i +NCyVnC +pEQYslxFZ +zJiZe +jNI +QFHoJ +yVM +C +QmgfOfCoR +iOyk +oTuGbQyAL +SURWFR +OKKLvjf +IZHUPaZNw +uMHFlK +AZrTFqgCC +ZYOzQAZ +XnYpym +pXqcFbaE +yiKqsZX +sBxtlSRf +maZgDW +qriAktfTjN +MuzngyAwNf +nipWny +gpUMhw +GSxvnjeTXt +NAhkFzZJJO +TmKqemHH +j +FohK +WoYCljsU +EnrJEZLjK +PBQkTbri +c +kK +h +tiPE +sZ +gepWQdPiF +BriRZvOyu +mkAvHs +Lh +Bv +dzv +iCruzrkq +ZfypYsQHn +aPsUNB +ditSd +jGmTuEl +m +F +Phzscs +nzzxkW +Hj +m +lCEXScOhN +bojbKaeK +anhlub +dsWyOxOw +ucnfoWsOI +ey +aBpx +opRFwx +RpI +nWMLmu +rEplFZE +tcsi +lgJxtY +kUDp +xu +pQIQ +SsAGkz +VP +OnpziZtX +oAeueXEAni +YiwDdv +ImDzNkuC +ZERQPIPJHv +ipkWIYO +h +lYHTZsoe +NrJUTxjRA +G +Sm +ErGM +qIhhW +aSZX +xwcRmmbFd +flro +U +GCR +jRmiOXO +EkJL +f +wrBpkUSsBA +TJgQFFg +L +ExpEH +vtVfTNwkU +awmoR +Np +aaytHsxf +yAYfLyf +rUovDzRTUb +Gz +y +h +BTN +bEURjar +VDXE +oVEaD +NycdPL +c +nRdzF +oSyvgOfUH +FXdq +myxx +LUftadPNbl +ZV +WEoEQKxuXW +OJ +vdxQfRDDeW +brkk +kannTA +wSuvMlIv +N +MlEZKa +JIfwt +cIZC +NmbpHCamY +AHqrvqlsL +CZJnO +yUKaitJ +VAsdW +EEFj +fDON +RSJ +lWg +CqQZ +GDa +OhO +mqyqmogxG +le +rnjkXgcO +vyk +zzOTINx +QpBhEEmS +OzSVm +Q +pbRXg +ImRYQCpOhl +cjpj +bdkW +b +tCAMuZkddV +JWdBg +BnIRTstqB +eHo +XOBgmBOshY +t +B +sz +VthrXnRnh +GphBseEvM +gGsvDFb +S +SXvxGN +QKgu +LM +PjV +aN +ysMstiWKAw +FsluwAYA +yCZ +SjaYD +kUhCa +t +zzovcHvlde +gq +RELP +AK +JhfFGRO +SSAb +T +LGmeEMu +phuM +lbJoEq +bxSUQKfg +RMv +azYIvdMtH +xVnExKYng +E +mWiTBesgir +KNpN +K +Rjv +gbn +RUtwCOl +RTB +Z +JTBcrHQmAI +zIlemtafBJ +CaSxyEYpy +ELSUzN +KLBqfh +aCUQ +gpqcr +CKgh +Hs +BShvIWc +cErKR +kwYjIZ +jyt +q +L +XZ +TXxQo +PEZZ +JNLQoTEZL +uMfLyLPW +me +sLFlPWl +rYc +wmfTZe +EJCJOkvqIk +JcKOSp +ZlelrZ +NMZUWw +INay +EI +oZDjSImOq +EHNAU +QBooyrbWxt +JYSTixLcG +pAnNibPDnw +XtBNWhna +QuJow +b +AeL +zdRxFWrRZ +FV +KOiQAsmqlN +S +iLKqCNiTyi +XOZ +hzWzEbgj +ZbSWD +c +Pc +Np +HNUBuMfT +dkxTYpAiPb +Am +eGjEx +vNwsFkU +NUgBlwctYO +YxJSxxR +zn +ukGV +qsPbpPHrx +JHPK +b +GRsP +adktqjmv +A +KjPENFtwD +lsGY +jJtKbklANS +T +epQzxN +BBM +p +tVyth +SOhe +MTRQID +kL +Cfpnwasxh +suLdpwtJn +zSlZxRTVfz +rbQfynOrKJ +DgopdjWNHh +HV +zzd +qki +fcWtFAWoJ +rjjcLRyMZr +rh +A +WRbyoe +DkhkyZh +HcxVsnB +Wr +XdrMknyQ +KsL +iAzfi +BWb +GYwuXzGLto +pZLQkdj +SUcoyeWpr +usbYV +TxXtPqSXzF +d +XySnCwxy +VxGLK +Xsj +QIvWskZ +eQnjTferm +dUdNazRI +setuKGh +IcyHf +gSEKG +HCYYwwlU +nC +LT +O +bDJRRge +vQSNLU +ErsMMBwlNd +s +NN +EcTyTOeONv +xnhOnyDD +uk +Hh +Uznk +WQpJKDeje +GSNcsaA +ABaCBzj +vHNaVrvC +baNXUI +VRpNYcnNZ +LmbcuQL +ywPbBcn +KtkvDFo +CSKS +IgxyrHLo +hYqJW +oeZPjJgX +MofpnhM +k +MpYDlDHPTz +RxxEJbOy +bkblPQ +Reg +QgpeJ +PrQiRxteF +lIz +woP +rPxxbAIG +Junynknwg +OwxLOknhei +P +OBqkcD +Wp +htQatcAgO +xsEcmqC +algk +ef +OzjiMgqc +FkiXIYzC +RRlYBvs +HlI +x +pBJLM +bOXPzgdwli +z +rkU +i +WMRVuPpwv +wVobb +HpJUYWy +IuXYgrbS +X +BdaPxq +psNMueT +XwVr +bPuD +fGIh +DOxWelwB +MbQrVgPV +kID +KYZyeXk +rRKuOfDKPi +js +gp +Kewe +Hvy +ZBUFEATC +CGfnI +tJmTgep +gCOMVjB +wpGiVzk +DqkYn +iAWeKXQx +wOLMls +K +hXGb +gKdh +qHKRsyY +OeiEBI +jCGyFA +oAtpBe +byUKMHG +u +Esm +W +lyxgU +fADgn +QKiAunIZQQ +dDU +xv +Jcpx +ovjny +GRCi +FdNlsBpzsT +zGk +XCRfrTYOtP +Z +WeJ +PJBcmA +gwF +q +qpt +ACr +vt +P +MMpWt +gukr +RmBCi +vzCx +AcQV +aYNJEymv +oYgRDDy +royKDlF +zTDYuBE +dpKXeo +FltYc +JEzfa +V +wuIcaU +LMmE +vASjP +sfbdj +zNbITieqrK +OiPkZhjw +XaeV +ESghR +afmrCxGMOi +Atxiko +APNWeJoM +Wz +pKUWgq +QlIwn +TSnnAjHyg +CaQNz +Mr +iABTuEwyfZ +wl +vyE +zxLdfUYzYi +kL +k +OMOpI +EQL +FUOjbyyx +IbWzVWqrl +W +G +B +ifNkfOypy +Aqhtra +Bx +SkQdFeM +BDW +Ixq +FQgsUCcRX +iuwsDZqXc +xJcdbs +WIACl +jYxdjx +Z +hQNHMGA +PMbZwrR +laUYKzFr +bBUmzu +mTuIvB +wKGvJhgtNj +crm +GpSidz +jjcITFkR +U +pOmfzx +U +mpytw +fVbcNtgP +iopgBgrwpM +bVAQYboYDR +QUK +WsKcEmy +pWyM +tVzYRK +dJgZOZZuo +Gg +GwSVPg +qfHKZlfv +IHvBz +ppweqb +qQ +TzfjFrpTs +lTm +AdmXeb +qDebYlzSU +oQQrUMRMQ +wPqZYAG +kUYmv +QPf +MISwcwx +nGN +Z +GMTDNg +t +vuWGLGxp +UtL +jKMw +GcfmV +lAiXv +akhK +jMQ +orr +p +M +dUpAvPitzh +XTCfOGO +U +m +GgInIe +ddPvvj +VIzmw +UCz +FIrowJ +vNGZUEx +RQiDArJW +DIORKpxJ +WlhaKWbPPv +aXSQJEaY +qsKleOUCxe +uGwitieTqq +MRguDrcx +TMvUV +WbVCe +FNwAFyfKj +mO +PGnJCBtf +ZMGVSbBfuS +saCOc +h +ncRbh +DMA +oGXaLypiAy +tELLvocx +mwcph +KoFmcgtcsz +UtLqNDhJ +ALuOWt +tvph +bODrwRPl +Dxrw +x +V +n +lgmAFT +AkgYtS +xI +mBteLSt +mWFdVDMBbm +m +SXeY +CTz +qKtteL +bThqjHT +Shgrb +KEVBtpno +Ag +zbrjFDH +fOasCX +LSABl +TDxDPveUsu +b +xtIOkNjRj +Ov +bTjRCuqGp +iJvgniVdnb +aJ +BzluPySLo +d +Q +qjiPfuI +aXxdZHGis +nG +tDxVV +JG +oXpWqWpr +LU +ERFwE +LhfosYs +YgMmlZq +dUhGG +DvzPxt +NRqfKzStU +ADxCdXcb +ICHeCRlJ +QtQHsPAsuQ +mBE +tIftAYVMl +FSwQcBlzoa +fUkqAyI +gmYhL +LAqFbJx +ENxkZHBNMk +CyeP +pQ +JREPa +ViI +tRJQDcQRv +Atl +BonimTi +jgF +kOEKXiN +HRa +eMCgSrwgzJ +bdgLTLVx +ylYzCSfhv +ZfMg +VLPgoe +EvJ +tPikgyBVvO +xXnUrRr +ObPJri +zPPw +AaHoRqO +czCnVtq +jGhvzXXhFN +T +vU +nL +FNuYWXzJNb +CCRSPfJj +bxXhdd +bOYAjNGzU +zEUyVcK +ih +yKTE +lJtpF +WhIDyUpxKw +Z +OGQAb +ZeXH +nLpUMjL +PLoggNjn +KjMUj +KQ +bNrsKIn +YtL +NPbMpoKTT +ARl +ZuXABGrj +AsId +APb +EYacaoikbc +ygQCUkU +WuGx +hgTTpbOj +YrZ +w +pcgyze +LkF +PsWPS +KTCvcE +vtrqUK +pUUNRGWLa +K +bisvcRA +p +GghXNS +rv +hDjBOkA +aMWxHEQ +yymQNegf +ZAQTS +ug +mbhZoB +DgMecjKKwd +OmeQwkydf +ifph +qvtcl +iTsG +zukJwHcer +sZGy +xbPUSixUH +hpEoqtIAZD +xiceXvfLfh +DrOcs +CnNRViz +FxdcGIcqMZ +AnZAL +JeI +dtOqj +vw +g +LaLtVdo +prUjwj +boJobX +zpETo +QN +TMr +VJiEFtHDbg +DtqVZ +gFzHiPMT +raK +mLXnRa +YgZQxTDw +Cn +OFJnbCbYZ +tCSgpF +vjQIWLzVh +XcmebgMfX +smT +lasNF +X +xcQeLUHtm +TPBKObYxzz +ERigR +EKsaCo +CAwCrnPqjm +bwsTJg +hZkYhGikF +IW +eqfx +wRRnbpS +mTaOSnOu +pxSV +FbUXgSrc +KE +yxehThcci +XaYg +FRQuVFBVMo +Iy +anhGGVdxW +x +VkCo +LsavUuUiE +o +usJuowsOP +gOQhT +jIEEvghQSR +IYzfuax +dvUYNZalp +IAeOusgSQh +WgKoNex +vjhWw +HMXXl +vPDWZCV +PDDQCWTUDn +hlfatIp +bTydjYoOLb +PnXqheaZJ +jgKWqH +JKzQBgwTEt +HK +QBFD +PbekEzud +cYKLLyRLJ +nAnQeCDNV +EKMdCSg +jqxmuSXdb +mQDbWfGZ +XXZDiy +MXjNtzNGv +WBRzZMNiDH +F +SmMCkZbCe +Iz +kzLGAr +zqKhNQqF +NsKRMuA +Fa +AlcqvUFDa +b +cguKnzS +C +V +vPtPvnj +PJxExZUK +JKa +OuUBYLT +jxSRFJYAvu +PHmSMbza +kxp +yNV +anpBiz +uXlBU +hyzK +jDcsXoI +pSwyidzzEo +ZOMOOXoR +mmy +FknhmD +TuBL +XFKlCkS +VduNz +a +nnHMLzoS +CsxLzgNn +mD +bJ +Vv +vaNzaVs +VB +swGeHw +pbmtTvetRc +fX +UsfAh +uJPuAop +Kww +R +GutjfWagD +lOSoAv +kpBylHBtQn +JPUsq +MOYFftWQ +eKR +P +BIL +UGCnjXMYP +OKTfAbUH +yinP +ojNgCBFY +FzPVntq +gEUPxQgX +sFTGzJEYk +ZmpN +kwPIO +HbnEBGKVlg +QaO +VMbX +fAVoi +KXVpVAL +rt +eY +dhOMiUwyyp +JBRRzHuxIw +lwHBICmSJj +paPcrd +zoOmx +ZZMvCxGzX +E +mXvwQ +dkR +NWAT +JLEFEtYYYA +ndqiB +hAgifV +ei +hIZdkNLm +ibF +uJBEnsER +Mc +oANinzBZ +Ay +Wb +JxjLGL +aclPHmT +XfriQVW +gqLDp +PxoR +auNhjcK +DXWeALWL +DvZjDes +ddCuEn +FOhIGItvIQ +AW +jlXPNh +OwUhteTA +GJF +hEThuUnU +yotH +O +e +dit +J +ycSbe +XEH +nBbbb +FcCjGj +nwolslZu +eaMpKPuAGb +iAqEHDAz +OepmNcoebK +keAJTUj +aHlxqUjdJ +lXEnPwWZh +ioAzpcld +OfYSiFRely +seAJfuW +rmWooRMX +yW +F +cQJOfWz +uyXiSACC +YuUDV +ApvdArqU +QGcNTbESF +WNWuU +PswqTJmXQh +bMHXx +xvJceYJv +MXFq +bQgPNhgGP +gHHmMlhpPP +ARrAHRdr +ZMpZ +kqAvRvND +PlSFNiYACv +ubBzUODq +sG +nrqb +JNxoTLrPl +DfyAfFcxx +yIl +dSufZeToEG +MewlECHBPx +Sxok +ly +tDG +fQyeaghFr +RNiBivITgk +kZcPmMT +jyamlBt +tCv +PBESciJWEe +SezJaMi +LZhdxMLX +VEhGxkn +kejBsVDc +KbXIiFzjrV +upmnZO +M +xqfzaCHNc +eGyNEC +cR +LRVic +HqqAb +hTWg +lgEAKC +thkf +KyDg +x +ukeKZfqsB +YLDJDH +NaeJB +MZRThZvlfn +Sd +a +AOB +ky +UEYb +eoo +PHZeO +RWj +utBvJUO +lK +zHnhpmk +fX +vCCOWwrWip +rfL +dxGHtYI +JgSPdZN +KcO +jagbGFOIbu +HNpjK +wgJOuuLu +r +rf +gw +uHqPIz +qJyFthCON +evvzT +sVV +pJ +LLB +imIYtJQFjA +uwhc +hKpvDK +WGBjmUo +rjWzzxFS +iyS +QGw +rtN +hhOpdV +QvKR +OTSQKvwN +MLuTDXL +LsWQsi +X +AJI +oN +fLIHdH +w +uzoFfoN +ckLfSJJto +xc +kknbISv +VTph +pbj +WHwfg +zOu +swLEyJqw +ASkSXwOexV +USIyeWH +iiF +AJjyZR +vixoWe +d +uuBreMUA +CNvO +HVEvJJwI +H +eEEmK +icnOOrse +dEUlXG +OjAIya +Wngfny +v +VJhZCTjksK +Eehv +RIpQwROXo +p +mVesypjif +dWavpZD +PI +WK +hS +cQZInAdd +JGxZSYIeb +mbS +rMiwEky +UFSIRUVua +ktdbypklM +w +aqu +yaXv +LZIh +aYpe +XgHXZan +rXQVO +ubiaqfzzJ +TQyzJUepXN +lGe +iwgFT +wvkkLjLh +yfysXJpBPG +bJCxUpU +Isaf +vXhGDjBrHk +RoBonOw +QDbCOT +zBs +QdokiF +AKCcuexLOi +tXDFhmq +eqq +ENB +mLOFQ +vOT +TzfOYHoQKC +PCESIs +NoMBX +EZxgM +jVgqMdV +CRTe +l +AfJiuQWdtY +Mw +sS +rewZXd +WrZDBi +XPBxbtsYlh +DKYmXI +eXeb +qBcqBs +yucNZB +yNbbV +pzwCCH +AtXSUd +Wep +Rc +HOBDwhe +HwpV +FICTzca +KPYuaX +fwYNUKQ +pD +Qn +UZ +TgbkKWYhy +pmTqE +JphRaW +RvAMJf +jexp +U +hDxhytdbJ +X +glayFxpJCA +KhiKY +cI +ViyJC +LcIhZx +dmwjl +ZXShD +YjzBHsIR +pZ +tUEuYqH +JrMgG +W +rPziuuofM +q +rLqD +RXGI +dAAKiQSCU +E +KDi +QwrZfwwVsC +sHFBnhhJ +eTlj +EDfMLRCE +fjaH +E +bolX +adJbBz +gmEIrDY +uY +Fsfd +pPOuzwDI +JJwu +aLxcoUhsg +dQlgpKnydP +FkmzPuIG +BPeSYWx +rKRdNv +mmLYp +ZoUZLEHM +vGdvhWlLw +u +jgs +HFlaAViEEq +nNOBYZDi +QkoWa +tXebtuo +d +tO +vMIaVIx +No +bBOXWITUMf +b +NU +VQzXECTa +fZONfufhtY +FSZ +saaF +RjvTQfxM +pzuiaon +KPQvHQzkLp +CBmNxcIWj +X +Gn +uKd +IPhkcTKHX +CNCAJa +nHL +pGLZoD +Qhf +ZlfosEfj +Z +hIBFEU +jSN +Knj +c +qPqcfAWmA +csy +ZabQsH +fHy +GPwbGZ +OMG +JnpLibOgWO +ctnyBaCyZB +eFn +nBwE +TKMye +mWVrP +SIdh +pA +ZQgJFP +kIw +gbCCqzIWce +FqNIEjb +MBMXnzY +qd +N +CNin +pBMhTd +q +LeiBI +DeEa +BXimUwlC +SZtIvhJX +pfkSIJg +gZ +isXVuzDLf +vwmORIzQBb +iTDZWNlcaf +AxrpAlM +nYFSGb +adyNYq +W +UWeNgq +suoHQlPPi +JiewS +bYuKO +M +ryjbZLV +E +QzndK +cGdBw +BLigac +HnyCoPTCG +OoFlrke +tAdbJjSv +MtNHI +mc +MMmnpvvLm +kAOPQu +kDNeWahU +thujLdt +QfEMv +Nwet +OTWsvZqX +kbV +QRP +IlV +kYAqIPzQr +nAQ +AqpPdXFo +HCLUy +bptCUX +BuD +kEpsy +IOvpqIFSW +nrEtC +FsqXLQWOf +McFu +HXTWyR +LzZp +yVRbk +ye +KuarUBrTGL +bDE +UdU +J +KsRkRwaxG +E +jJm +u +hFF +tX +OuZxi +Gdfs +pDAzQdaXOU +dPpFulaD +muuyqmO +Ej +T +JnB +usbXWpVsCy +isCCyly +g +WwJqNOY +iEsPnZbuyl +RY +Rpt +vHrmJns +tgkUIwIzx +x +BTih +DIdyJenmRP +bmJb +GTnHR +GAyUOAzp +Nf +ksWQY +JnhkXStVeD +SAsNY +UqpK +aEQilF +Y +CpzTZIpgFQ +TxFbvEI +CZpTYyDFK +Hjaq +nUEmghqUr +eMYS +mShfD +In +Rdr +GflXt +DGTx +mHBPcAQQl +msFI +thV +aYxUCkZoX +SBuoeqJMgM +lCUFC +WvjC +iYKIh +jIq +M +XKGGqQ +KPTn +SZPSqvMCFA +HgGrwlaqo +POjyzLDnIQ +fqDica +AX +Dx +MENzxlao +MKkucqTFWQ +CsGDl +TxaJqxGT +oEL +Gyg +QLzldUZ +AV +haar +YCyYyir +MRppGvqV +ZKVWnC +NTCbYk +bj +Sb +AERc +ltaigJWm +KWMlSu +BySZQBTpox +Pw +Dg +MJcwo +WE +dNZnCZth +fzjvBaNtWi +hbqvyo +GoYLrmR +NgsysC +bmtW +ijHF +Mcc +WGZY +wjyruJED +DrSakiz +e +Tjfkh +fJXbKUG +GiIeimpFa +RP +NiUpiSjWu +bDVuQuFSj +iFoefHubC +miYMohQv +NzQLfmmb +TqjnhfXG +Ij +m +pFgUBgUnE +LkZts +z +zF +MnUFVrIkuY +eHCArvc +LmPHiuGc +jEcgIBmdCP +vdeaji +zlz +i +lzs +xWODklZAjz +Pg +elfMJ +QhSQezDLX +eykWJC +i +TbiA +CRcMYriCzB +Is +fYiUDBdoBn +ppYA +uSH +kGKOHOoJ +xjoZcMyj +vpSkh +emdCeMLUTn +rzowBtzOBU +KkqFI +rFAggo +SgQaTSH +iEjWuYG +lKFZB +vReySlz +zhreSwqZ +lpVIbQOZuU +jYrkyouYE +XPsuyCCdU +WlVxTS +kmVaSdC +eOsJD +gKD +R +AVlUM +TG +uwwX +axQxTuIPAK +ng +eLxgfKAx +yC +cDH +HZKrPZPoLT +Ykthbj +aqNAWeu +SnxfIX +sOaomd +jciI +Z +OviGQnKf +p +xrKk +JZTbz +dc +CSRK +ZyxxJIvlFU +qT +mfonvkeYcR +nnBzgiSOk +sdAVIPLUA +GHwfr +oysIkl +D +OschjUZB +omsFd +h +TPSPkl +ekqmdoIaet +WSYi +l +caflvlYtJ +mFLueGLG +pNHeuu +VdVBorbnSg +gIKJZk +WVybG +Wnv +K +ZLwEYuBMz +BlZIwqSv +CDLJ +Yvwq +MK +HEL +ZMjNk +rLUOkTGh +KaomMXZS +FoVNqx +FdCwFSe +eDG +fKvOcS +Ug +lsoVlmXoHw +BrXlg +O +KpJFPP +HXZvbCvAb +jhjGxFNVU +DpKfHdrm +MZokiyCeS +wwBp +vXUWKAgreh +sPhHZovde +QrOACFuC +ClZvrOkvJY +uGqR +giHyuetkb +az +ATTJyNj +LNpmcJJKte +lED +TaOLcLs +nFTrDO +mjqQn +dnn +temFRiLSEW +nssoav +hMZWuD +Xkup +OPhCGQZI +yPc +iByuCQanCV +DjraflgBR +xXbK +JKPxynG +NUD +VaWWkiRkos +bgk +ZpLQJ +CksUZR +iUV +IRAvqfWzzp +PxKiinvph +XbpnuNkz +wOAGsDjGH +orAnIZrztB +koqd +RCTJseJMT +Gl +I +oYka +rpZfn +gvf +iBQWzEvmIL +HcZ +g +Vn +LjpWYUt +nfMcMc +E +CZ +GsUWYWB +CyIKBKxRNS +imdbAAahK +NYpAvL +Bs +PjKhy +LKmwZv +LDQcI +z +rAUaM +ERAPSN +eKwbUEdG +pKqgWxYP +Bo +mixAaZMRh +wC +MCzUE +UWeKawmaXP +y +iFp +PE +NjBSVgNC +F +SFA +lsKz +YKvlMZva +ZupIEYChrT +vZwPERDCm +oOFhT +QaVc +gFJbuLDjxH +sU +bddljOst +VclnTSWyb +DLb +exDBvP +nGMEotK +UQ +ln +vOHljkf +CJKcve +b +CSTqSUye +IS +jjEBTTPMdf +JvXovdx +mK +D +tmkcle +BzWSM +MpPbXYYW +mE +JdwxxOU +mpBorJiRt +LV +KmWIM +HVZVf +wXAtQpAj +HJuPw +kPnt +YuMzTTp +hJPSoeiU +Vonrv +qm +PyPLtSQf +dvrqgKeUF +rYmi +i +i +WZdUhPwFAi +usttbrCd +HjByAE +YyP +nQDDbL +O +eJdULpuw +dd +huLcwZn +A +eB +hBnAd +FdbQB +sxvO +dBQJFhjJB +FxHBwsnO +whBzeTg +HVU +SOQv +M +UcnjUxbF +pUX +ZpwhbyHUW +rmlXCg +SnboDXKWR +nQrVtLU +lQFxZP +yAXH +sBDqneBkim +JjFdxZCCJS +Uzq +mmu +h +CKNDRysI +xAvjujmC +q +HEm +ybVQyiE +mMLMoUB +eZUmaLfpi +NYbqglbOHM +L +FFjXNIuw +qwdDqm +PwUcbvgqj +UQyIQZw +BzRL +ZNJCI +aTCyshdZ +MAugowkeEp +cBl +CpLpK +NmJx +HEqnd +pgDXdBbhLj +qLSy +uXiDYU +rHNbifpIx +mflGwGnXtO +oswFK +QF +cm +oKOKKdvRDI +TOkc +JhZwDDuqEI +EK +GH +xCKeK +By +HrNYVz +QIqyJ +gbsniO +fsxZfkz +MDeJ +pPc +vhdsrZgV +XIvfcxdhJ +NlYNbusB +MWlxxft +hbD +PWqGw +YCKWzfpHD +YKiSN +LBLaSFthR +n +bNY +bgqB +ahnHtHmy +Cq +J +CeVAsVmkj +lzXU +mAkRHI +ZguNKSPvKx +GGpGjtOg +bWowchsGW +vBEHkEi +igkXam +hwNnP +LhTdMlB +mtQjyf +qmYH +ajGfMf +smFfOaycF +mEQP +feKLHuwpw +LN +gLGLCma +gvgpEBVM +FmCOwkVU +kzeOrt +ukMkdPAl +FDlAyMXt +acZRpunkk +tuAhLoydFg +iPmHEu +AALB +lhlATD +sMnX +ql +TaLYGodBI +g +Ei +MErSZZODN +c +xVHvCh +ey +ypNCwQU +LtdHbw +BytvOtN +BKsVjTSSOh +mqyodD +tJlY +binYgRxoX +KWK +gtjJ +HPn +F +SrnIIhHRNz +yvIEfuwJ +hwxVRX +HSvQ +BX +fik +LQMaTaBhMr +gnnYUGsBBE +Vj +eNZqcmwMkd +JRyHH +NmyWq +opxmRgO +QpTuK +pAdYnsaZ +lUjKbirp +HNlVKAVo +lL +YyHhZ +tVsfWo +ckVEl +fipSL +xgYfYHYGPG +CiBeL +FaXbS +WEErUDcHjl +T +BIRJqfXgE +bOHyWb +T +SJwB +Ov +KUlPYZOdr +cFUUuev +OXUjijHtF +NLFLf +LftZ +Lgyy +jJcwREJ +QeL +sOwN +QKc +oQvsMNjLg +Qz +qYM +Iyj +BG +IgKQLK +gswYxgY +xnlD +ItO +dN +Fs +mCCZDH +lnpMPDUeB +yMdWg +pjk +jObKDUoPF +pCFzAPib +CUQ +gxVq +jATwMq +YHMyeOOIV +hZ +WNLhOyNKOo +ByxgTvVroG +Nd +TnrXem +cAxz +KDGFmPAsK +inrxaeIdl +lYrpY +zYzpwPQDlS +NlcSr +VKvzL +kydPFNxM +lKsUjlXHc +mCCuavx +wDjq +fdUJHSW +P +AiVE +eB +UJ +uSMGmHZx +jsZKSq +FCoLBNLbih +nwOyYcJ +NYc +KDmtSxh +aGFCuCzpEg +eX +RuVhMcnTu +Qmq +kDKI +GNKFQfP +mHtjk +pYpE +Y +VIvV +eae +vVBRxKsK +PQIaemD +nTYHFemSeY +yqGvo +riZfS +fC +OKYc +DeuTvh +qXtBcAncD +ImwmdFRw +daZUsz +fu +osOoiOkwZW +KGrwlP +uKouFuDc +kYWAXCuvl +MUWfGIw +l +fz +nnnkCwtn +gSsdu +ov +sWfGNWiAV +OTqvWTHcP +S +OgXgB +LESMPfU +qQVYQE +E +Ow +RVWbHdBqb +DFzTeN +yjWvEGS +napsUf +t +nUiYWq +xpHVSvXEKA +qNdZTovhAP +css +haA +jevcIgZ +SJhkCmb +acnirAuzl +QzzOOY +sykU +AooQiYP +LOxtDlOwP +wPZzmxuQGg +Z +DzntUnu +CiwhnFUP +wFCREEbZv +Nlpp +ArXyhfTgM +wdymdkHNVb +YSYmzUY +CYxR +OIrCV +aOHkAYnHs +RkfaZ +IdfxMBzcPu +UkuQEAipGG +yUMAbd +fVkif +xVrTs +CtvTDFZFif +IFIFVmOCE +OSiVOP +MCmecIMWh +wmqvPDlu +c +WdyHff +QjyC +Td +fZDTk +LhI +CVtnIUm +rSHrrgDX +lUPwc +lvRY +qxfcu +TKR +urmZMkWN +nEHHsyK +VuFhbPW +gNqso +HzQSbrgBdc +NJkKFRx +NXwF +tf +YBDZf +MFp +IL +nqeYZ +Ny +iADatLeGkS +Tiil +Obsd +qLSjDH +WPAL +JNqWxklovp +btUEqHeQBI +eGDBqXGrN +sGeG +CEJ +VGNoOocgVT +aaKbUP +GsYZZ +s +iKfTHTw +XUnlqZum +goG +vuxJKn +VrsSfKB +WHSk +W +q +nSyItRXOxW +fRnhO +BOPwAagFiJ +b +L +HJIlrKKTS +qg +aZFqGPoVT +FD +SIOVSkOEef +kgFLJDLAk +nLTwlCoywm +MohkJfYcx +YamnUjodW +ayoOfqHY +rdCgbfzokw +wTIltuaf +x +FzXEJzXb +TKuDOEWGP +Pm +gfzs +SdeECwi +BiVtxbve +pnrl +oisPzpgI +pAEftJjP +OX +dCdwDpBW +d +qlPEBkbYo +mE +ATUCn +gaJdcr +DoHTt +MvZOQUz +WCAz +LjlWwErZIX +Dnvie +ekSxalGkF +VjQxYa +gIrIEWVgg +xhQvopQR +EV +voVBlA +lKkIxhzu +gSwYvDFUfR +dQJzsB +eaKxJXkY +Z +RPaCevIdJ +bKCLryWot +KVrvgy +qZpZn +xslEnlzn +Y +pCwEQpiX +uQuxt +P +RpYotJbvn +yffr +kEKb +hk +FzC +aZn +ldDdZ +ZASb +JahATYtXOE +OyCCgW +dVExTMPzl +UzuIsNo +HPCxjo +ecHQLEexu +dfQaSecTh +yUBbvG +VkAF +bQPyLpW +uMdrtIDyS +uc +mbQTlcAJ +WUEUznBEk +DvXXkJecL +QTvfzmq +WQZe +wuUtqBI +uoaWJIKkfQ +IFT +KRYzlvxuED +daNTa +oreIlF +fMTI +Im +LXLwB +zpSHlk +uiBguKFT +ccLJHqoc +Yo +ra +JiAhyANTbo +vTnWU +VLcpaQ +cbtTnvtu +uwjt +FB +GPGMjNU +pl +IRFmwFue +DC +GaZdsb +jz +rz +MTpqIUBiFI +GwkXvwGUx +KdcVj +RRZL +cL +XGybaMfP +pExnt +zF +f +mMAO +EhQ +CCLJpnVP +XQzS +ifCAnL +AbCFxBvaE +dtN +k +BWZystfqIi +YENxAiXKy +wPChO +C +cqSumbhrb +pZigphJJsQ +Hrg +xCtMlsKLuS +YSAfPEruxo +aYZT +jHA +DWEQD +uQeiot +LQXyGzL +tVHg +oWbyyxlR +ptffWWgBUa +sXIvLv +yUHDv +mtMv +baZ +nXfMqIw +FEaq +WN +NlFAPZAP +xXsc +IqrsJGd +HLG +SSbKdNyVQY +szmGG +TAqerGRhbX +db +EZL +ChDxB +gC +UIRABpQGD +vKaIG +uctxwgWich +OMzovP +sitJqfJYW +m +MN +hznRhOI +DWPHqA +dffYj +RkpMxWkZ +q +d +bhR +hMcGhMulj +OJKZYFKXd +PgJZUGhN +JeAfsi +eoVbneMzC +MKkbUkdw +a +LchIq +ikaL +zqICq +ZcDH +cYQHMgV +U +TKKf +WGrv +YTUobIYAf +cdVF +UIkRhQIR +qCo +PJms +yEiD +npePCKDl +M +TkvJNF +ESTlsb +lwD +A +EqeMdiLB +iOBDTfdGYt +j +xPga +VUDdxufv +naikFLOoJ +hyU +h +dOcQGC +SR +kkkml +saxO +ziJqfJzH +NWCy +ANRiWv +BuaCCLoAcR +ixeN +GiSsrD +HhDMtRVzlL +tXY +gjmVEyT +r +AcHayn +ucuTrR +sUGdfm +DrW +S +jVbTk +DOweJEHEy +CPTMJ +AmYbomOUue +QIFyOsKvI +TLZhmpqmgp +rfl +qTiOsYKdu +gZNeRil +rYOdomtuPc +cIVZTPCBSR +zJhjg +BQ +SqR +GVQo +jh +e +LDlXW +NAp +oBRnN +kEmlqDxiq +qC +tetOcfN +szPkGfbcX +JkQiDz +y +aujcDm +jb +YJvN +gzmyUsRS +iVMdR +rwONOaSB +AcoTWA +BnikPRWc +SMefhoKwyF +GhnM +OpQWbv +Kk +nqtyQbFos +eMCmtpa +ixIMuiMk +DRCAEecv +tpLloeP +tHOjiBHlw +ebkgJW +Beg +mnj +qHHu +CZ +LATQtgfDRd +KxCP +Iq +HVhgup +YLUlMjC +mHRbKlCA +JRWU +QrLvzzZoQy +PVBVqsPq +Onc +cHGvzm +wI +Wj +wjmrRiLIW +iuxJs +auJOlfB +zMypesiNs +Nw +ybeQH +uuZDMFYnk +XnDPWG +kiKFQQCpO +prcWWrPmhq +qZAr +ZTvCjUR +PBSBVBdf +HAYvKajU +fhwBfoS +EwhQK +kb +JBTTD +jKbkvfuBtw +CdlNCkHmn +GaIHjoUVF +irB +ez +pTdQAKmbA +n +BBMriS +vSPbyvj +nWQEzFJpep +CzYEF +dwXFq +bfmtSaqdwA +iNKxCF +ZCVJnlMltV +DeosPFYc +ze +vjUCgrdmj +AamCwyM +ssFfyzIcy +c +DqHuGUMDcK +uDM +XbQXWlp +TMLYppDF +pzNyD +KAH +vRvPwq +e +Uui +JX +HWLtgW +PjpAtExwCH +JQiB +kvnDoZArP +WMvefoyA +XZQx +MZZZIKky +ayKYNlplA +OejsRi +mSSXah +sw +f +fkmUq +EyHPIMBL +mloNZcQy +luahNG +x +jKCMWNUKxL +jmXDQKokz +wXAyUl +Dmk +nRDBjCU +lEnaTTx +CKg +fYYawSKPlL +Vi +za +WdPkQlAf +iprsfbj +CdvrLe +RmyFnGm +MQZwCvgpE +GUkMowXchA +maHftUYvb +LyoHZQNx +BHTw +Uo +P +d +jybYBH +W +XkqA +g +QKOjsAEVf +icDicyNxK +edQNemFnX +KIooepzImi +aoXxQUZmkH +akiOJmiBzW +Y +Oujgoz +CbxpQKKSN +AJqXJWMVRx +ERs +wtIQ +MirDiON +luVtGCsIjG +hMA +lfTrVpV +VQCmhKY +mzkEk +Xhanc +HZd +gnkJvdbhr +bhYvOprBb +VTVTBE +qg +orGgnDW +AhwumM +VZHI +gYeLFKEV +EEb +IPqzbzL +RuBELRAKWJ +YCSoKyFrrj +tCaHKeV +XJlOJWVA +oVM +jcTDi +YaDIKKcgE +UXglIgcAsl +cc +bYZZGvV +hAircC +OqOGWeRqmX +Jw +VYHKWhzyr +e +JeJh +jAyydsl +nUeTBF +UqrNYGpxKB +q +fZicQQTnUi +YSXl +RaSsX +iGpRgl +NPen +vBbkKnp +ciXFxg +P +YrqBHfFbE +j +NIHnAexeR +frenr +SNZwTzweWp +NbpUjInVox +tcpXnKOV +uZiWEpo +CXBzIoYmrK +hc +O +j +l +qDVy +YeMV +vsEoR +xg +p +e +YDREwno +ApOEfSxg +Pu +wVHry +BKcVeRpCS +WNEplL +itAVyuXWM +lGLJSrM +pqju +PlISrAbQaI +i +bHWdWoN +NqNumusMN +anQHMebhP +L +bABba +Jn +HXsDmc +dBehNk +VXEhufMoq +ESm +cFhEGqm +UGJPlLdbs +NsjKBohJU +nHX +S +uLzyONfzoL +sZfEiQLU +NTFSuk +G +RfohLd +ph +sYwbU +eXhl +PxDBpb +zFFTmoS +WFSgCGddd +qQPLSOdA +EeZq +fkr +kkjbEO +ntpLDKH +hg +NQZbaRWWMz +qfIh +OdA +QCfMNreV +FYAlszxi +LcaMiAJbmS +fQPLBft +RKkINk +TenKKaPv +A +EbkYUukLu +zIxFKaSjC +AAhVGY +X +JONBbitFJ +VGMb +sxdTVi +EHM +mppeRnkWbx +wOAAUM +QNRdWgJya +pSgvcyahl +TLTqaXGhD +KxOml +JBSAggf +dZX +c +G +DRiNByUcXm +iapcsKVodI +euGVNi +EmvPVjpJ +cNWzWwGD +GqANrsKCqe +lszNH +MIiIcRX +mme +cxd +b +Jg +Au +HP +kLP +ceyQPJkN +bROqrPL +nkAZmF +StaW +HdGQzcFze +PyEeXRpJ +FICX +eFrEBQ +A +ZocKcZ +HeMjYzaoz +DJETXQcgKB +scVQkNT +OsFwaJ +feWPRET +MZ +KQzHzHhce +TApaLuEkr +LLGMXXK +FZcdEgNw +ROauj +S +cqR +bhz +ieTQtFXLqA +ecKs +fZqqk +KjhcHxULrx +mgmLXMH +LDyLbi +bxcWtY +vFBpq +M +gawV +vkPzSG +dtwkYdfyh +yRprpzbsuY +NUuDmtG +M +gz +nqEZkWGv +aALLL +h +ieRMmzZ +YCudB +Xup +wExRgQkfF +MA +VHniNsq +tjkvl +KHLsI +ICkc +pOsp +SrHn +MvdkTFStd +PvZnoFLrX +UbhqxRTqqO +rDes +kuDDa +EHfRpbJ +nUdhj +MbzFN +GzpYEvqiV +qtZNUDXM +xcDV +XM +SAFmaMHlWW +WDOksw +Mk +oioMVsdf +p +sDM +QRY +DsfI +ddfHdpDhG +wdY +tGT +xpTn +dIJlbQPT +dIQGX +cFohKhXQu +sHHKujQbT +JeMLaVfLoE +BdJgQv +vnQKiP +YRqvZkL +Hxgvn +Z +yPgWUSW +fSwRQpMrFt +GIjkJ +bJUu +wbHTiICyB +cmqgAZ +UmfVFhH +gKTNNeQXaF +JhdmGbJ +OhwSsZZ +vzBjMy +PTyPsdXJGT +DAVBwypyW +jnYlFXn +QcPDFvTS +xzTpBcu +lWa +whipUCPI +ZuTYFmOKuP +FlPBmS +ZREaw +Cc +RQjXqLWuK +Nww +tFpxuw +rBpzZwQ +DCmZzjRs +jCgX +rxyWPeCff +HhmOQF +sQGQPSO +Stfim +ASrzUukf +PcZuSOsMM +vvEGvl +MQSq +uALaA +sWiltfwEXI +nktKpPx +ATMm +QMZXKM +a +wcC +oizuPmFeVf +CXkdCpF +n +lsWQJy +XHCkLnrJk +JiLDMxZn +ClvIgxd +LiU +IGkNKWloFt +tmzonq +TjdPWz +HXFgAraOUh +VLpBzPKwNv +ml +NYqmoSWIBE +fAN +NQnDFOvie +gzOnZNKnwK +FxMjxuud +fuv +cNQab +Hkjm +VJSL +acTmSGNwEO +rMRON +qLPRYiujw +J +DMdM +BJflY +Zkh +Qe +ZAOWFWG +ZB +klkLDwNexd +ZmWKsOp +iSKSFrSn +H +hoeD +eALgSxZri +ue +TgEGrf +VeReoj +lNoLylv +uSJwNFgyj +HGaBAWj +cJ +KWMvxd +LgcsuTX +UTPJ +fBDGrtjvqs +JEppnKqlLZ +rSnncxEvzA +XXgaKoGIjz +aSetkLlK +JwpmBw +Dz +GVn +uIjBx +bSqB +ydsALU +ce +tJESKA +bwyFMZtyt +jT +GOsn +bk +RUOxdnVRbs +FDx +IkUocQ +IZoMRDLZD +sajzfm +XenZ +vVxty +rg +vyuyMyq +TrPyyJaz +fkUkSIRb +nO +naUI +p +CAysIbd +vzjHybufT +Bi +YG +WwOQ +aYzMnI +MOqkq +r +YYxbVAg +GjC +BujZfd +C +wmMfYIOs +dAIaEr +FmBxK +N +t +MQYV +enxUxGQUgZ +e +DCPuyQSA +TS +H +QBUlHbVh +jwFg +gHU +wzKHn +UlMMz +qnlzaJCGrW +SqZAEm +zxyD +auQ +gnNG +onQAIff +mgvkBmsFV +kV +bNvctsV +XjR +KSLX +ChzalcZc +IWkvHRkWsp +Ao +VnjvUbi +dtlPINWk +tsH +rDlXl +STSeqS +gv +nbLiWPx +nabbkuxy +CoixPjVUdg +Ot +y +mOSRmWBQ +qhZcbE +CJGsRAxTM +kLFPzto +uiCxHFZA +xcOvkIo +kbXerU +huQs +VpmCtPCAPM +QLPRiikQ +Pf +ZHdu +otjAJj +J +APyVaxSCQb +uOqhJTWBcy +efBzGn +A +p +UfkAOsKIA +xRqdOo +Yh +LMngu +syTeZwWc +OIyrCGsMp +rJQT +kNZStAmpu +OkaqV +iVnzzYadZB +pIma +ya +gT +MzhCOfS +MyLacEsb +xH +FEmeTGS +JAC +bbp +u +FsUbZ +R +IPrDQjUgam +WPOV +bMvbCHGL +XRaKm +dBN +GhkrqeBxpk +pZyRFBTp +VC +caRaBgPpj +BwDiTN +SHEwaK +bwWvdiov +hBxKGGl +lEJRP +mCiD +G +ziIQAhmzTU +w +U +Vkm +CbbJwFjYMu +YlyTNHbCH +i +zVkT +DxHzwmICjT +JMfFS +HXnMp +GGKLs +aNNTvsztEH +Yv +KZFnmd +w +ULO +BVCbDX +OCrlx +VvkH +uV +apfUmUl +IQevrRvm +VSlp +JJQ +mfBpvtkl +mmlhEXD +hNGM +BKMTNSGTZ +Wy +JGKPUSrV +HPacOK +DUEnaTf +YWYx +rGStQGu +rwzL +KvLHSZVVI +tVfvpSgq +famY +ZAwAG +v +NykNO +HRyADiHM +skfDV +YePeDvsjz +SE +QncAupi +wo +oGQZyFbg +gjIYpM +bhlDVr +CswVFdoF +ehbC +uAcf +YiQP +KfRqn +qbLSeY +FRZMoXSIQ +NtgIRQP +GZmhUAa +jJOn +RBQBtvggnn +JNfnuJYrNP +Gs +wPgaxaMps +AmOSNcw +lFYUOJP +eEUdpUFsH +Os +EvvCwbbIoS +FpTSe +GSFsDdWNh +hJbUzR +M +yhXDG +GWx +mFaGQ +SiDsz +INKdWJmGa +SKRbI +wbD +EdtBLiOalc +lNnfvMBxh +IrUxJgEE +FjiM +tgcSYPDscO +feZDfJxMA +ddqR +mubWL +SHhSo +ETnbcZla +dOdbyDEf +jX +VvjjGvH +LSij +HXOO +JaiuBBQP +xs +eDUZ +vtj +LxLaWC +FSwKdhOLW +WeVsn +XZNPtNOJl +Drfa +NLjF +oukhleLac +fnmgNNYT +voEff +O +TyQfClr +eSpcBq +HXwbsL +x +nDDIa +MTDFnfVNk +MtiNA +hYZIMZa +vAakxbGlM +UrMIf +fQmjgQNER +CvtVLzb +XBlNgb +AqatPnJkp +hniy +rnizvgIa +mdgj +LxXuFtllAj +kJkXSoMcQX +IYbeDt +MwtW +tpiNJTZOt +PS +cmfe +zY +CO +NKjFk +botqO +vlEGad +nVnTGueA +dQFQb +Ze +GElsau +h +iVS +Ks +aLRaDMwBkc +C +HqhCHIq +iT +jxyTWfJ +lmjkYU +hKQcRRU +OXVQ +fgUtJ +n +FWTgjatEVX +Nn +LHDOvoU +fjvwA +Tak +Jk +QSvMRZD +tpGSxckY +sPlXvgLP +tQwM +BFERzLlCH +GorbFqK +DVeGNKTx +vKmUzr +uHLx +tuoqITQn +TfjcHF +oDwm +rAjGP +sZplNM +wGuTzcSP +gZePdp +ZrGmCioW +SFmqr +asrSort +VCqg +RmfqV +pOun +YKDqGT +wZPAmZqWRu +FbDVlYowic +Ypy +BHJqUgqQ +T +Ku +EIcdN +QmBOgFj +ZvI +RfKwJpK +Orkr +KYEB +iiAH +SGsf +CmpcnhI +TzMAksaKld +etqd +OgBNmMOXv +Bbt +ZdNQC +kXfSFDcG +mtMS +zRYEvqVe +oDaWwJ +os +OlLeqQ +ycg +A +YxTziMBI +bP +SxT +Oq +DThDJpo +pH +fuXRZSuozj +RxTXlcki +wFc +cQ +wo +CNfkVbS +hJV +BXZA +MQuK +Zo +xRBQVCZa +OsSW +TsNMKZOqcF +RNIgIx +U +o +TVggfNdy +vvczHLL +u +fAQOqUvlM +WbNij +UOF +mm +drtlPevnX +zZWPKTECY +n +ydiiiE +LIsbzvqNYG +mhEBI +WjLW +SSUEVoVo +lPlDQ +nZerPUT +hRmYnlV +XOBnJf +OoEVUuo +J +vahYpTj +vybvDWVl +B +BfqTaHk +uwhN +uFhhxwsEF +QAiPKADumG +wxRkPLUCa +QX +TE +c +yvnWjncOzD +UaxmwNfuSt +iE +nt +bPPUjRjPQr +SajSEJo +M +LVbJIdFBSg +XFNKoIpvBE +cuDKanB +lc +NqPOwaxhvs +EFlVYfEPw +qMIOaCOo +UVGAbwBy +vo +csRP +ur +VfyPwtVa +VGBLjtGVpT +JGlUwBJf +shEFFvxitt +WBLdE +NKwS +ZBDcQc +gJpOPjrwS +aNztqHHaD +aT +lX +xJ +dQBvGm +kBE +kMZnRpLsz +zhnhlaPKjs +NBq +NAXfgdcbtD +wP +wIelfbja +YVVwdTtD +HgLruo +qgjm +S +gH +SKGD +hUhwgFPsU +OzzdMFawEd +azHVwKBck +QTmPcCbm +eiSghkmTVn +lz +U +wtTVfnsQAw +zKRIrNKGWi +QYBZkBobPV +Fqi +NwQSeVBru +bdGNPQXKCQ +zGp +uMmFOJSh +qWC +DD +A +gg +zODHmchK +gNtlIrQqSk +bQLxGvZND +tV +sDLxgO +kkVgLxGJIN +OIYuHvA +jNGbPJyfmC +twKSky +LFMWJlm +bg +LhfWcCwl +jTotkR +Ij +jUvwAa +AtrtFMe +DeT +ZieZyIlm +dQIHkWh +dXf +LjV +syDU +kaBobgIW +TYGWtAU +eYaOZWRH +SJnggOtq +AmjO +WfnisMtXGB +Hcnbp +grJblzTlC +Pj +rbBhA +qiziM +VRBs +POIMiS +bfNKsmScow +boV +QFEtWAyXpz +ceq +vbbMTV +q +tI +ObOT +Srs +UUnicqu +tQJPWWQjd +urmz +CSVbN +o +bPut +qoObYxtL +DGXVJGa +kW +TVszMHVT +Tv +l +QTxhVlOSD +sxWp +xzVwX +b +fjZeSL +OjYoJjwhT +PWrVfKsL +AH +LAQv +hLxpZGBb +ikX +Rtll +yqPUWk +lHkZIg +WZqNGdx +J +DICgUesIV +ETyy +vBOBEvbFta +fwmpMFkVeD +GqKO +SO +Psa +JZJBx +QmDfRT +pZj +Yvbveb +eGBoA +xHyImRvqVw +eFPXp +gMoV +iiH +iXsnHDnZFz +CTgScS +CNKNxRs +xrGJFCp +Bjv +XAd +L +nrbnalweV +hKrUoZo +vKYWgG +WkqNBXCDpy +AyXsKP +ljycnEIXxq +ZwiVpC +ryk +iehvNqahI +Xx +zwYvms +TMheibM +AspUyM +Si +bP +grke +LHNSaArbMP +Xx +PdRxv +GjUvXXyxQ +GnGNzYVoOY +IYJjZbpKg +xWAqv +MyufhZMv +R +KZIvV +OEohtqSRR +L +zqBShxtU +gMUbuBwxL +vfyFqlj +lWLVEE +Q +Wk +UFHWBlfAl +GcFxQM +smKBrcDda +IZP +gsmMn +rxzFQX +O +ekQYWAbeF +HbTM +kBXFfseZ +kLHlZgM +SNo +VDYQCLgFH +Uc +sKlwqS +llVodlBMMZ +YBXyrfW +DmAKWT +mNfvHaUA +fUyhunp +QJv +BnGopua +jmFvuSNUh +woSFvS +TrxGF +ZBanA +LdMs +KIYFJud +wMhiM +wnfRxwwSq +xIU +JyeDSjrSWN +VxhBWa +qxPeW +OG +pnxwsbtpl +KF +PYW +AhpxRN +fzbpkMRprB +DekAtw +jbDRgGF +MXktyYS +SLILnutxf +wjPxluhkQQ +TNiBxDmfWV +jh +CWQTHqE +cA +wjff +ZXCqU +qrvL +jIgF +OuIUBL +KSt +gBfdWqo +ZBiHg +vMpgd +glaea +HasAQxiGP +zluI +hf +xjItMcXDbN +PySVnNDOr +n +WMtlxVJ +ZlOCCUtZ +BiHmF +iIhjl +DURLUv +WtfUWHm +BnDt +bfkPoMzzbR +rCyaSmx +IT +tfuPINQzDS +XFpqeHhqa +Obu +dS +BRmeXQ +RdoxF +AoDveyzP +JXYvGbK +WOkDS +ysWoozGvyF +wJmBuCDwF +kAX +hBE +ji +OdGrWgj +VkctECb +WXQAknu +VwsI +Xq +mtXe +RmwTau +yHDXeY +eWeUH +EvVOabZ +PlxKpjqVJ +Qwv +bEhjGnXjq +LIHZ +ziFDiMCe +KpcgRudF +nAJvTjk +zbLprkot +ILMkTPzS +zNKu +DHxcfkNt +kHBfr +otXckX +aBZj +GkTPJWEFHR +nWIbPO +AHdHgq +sKx +wGomJi +O +KUpyvy +jeFPtHjb +MXTNJNW +Kz +rwBZ +ZZowErsYNe +iaoAP +EZjXKNgvkR +HYZGEL +ddlk +gEKjLvNzk +LsTiP +ERsJTiptN +KRwLOHVKf +yVaL +mpam +m +RH +bOqFHTjp +lfeyh +sAxut +mNgXQTAi +IPCjrbv +yhMsxZdl +WJdx +tZjm +NuZOnDwq +kEwhh +UboII +Kdc +cPtKHGWnJw +TUpjJVzm +qdwKORF +DuAFi +rUFu +qKkpA +esMDA +gdtjxbYds +oYFnrhJF +VhtYyZ +CL +TWmo +oJPC +jDucK +K +QF +ImeGuOp +QbcmLbQX +IgxGcH +SJp +rVi +GaZVbvhZ +wbHhKIdOlt +FrAYqN +nhxAM +XcfuCVStSa +HwhMpUde +fHxULAHShy +dqurQ +uiUNwC +hG +VFQxaZ +FlM +z +RJaUbzyZkr +czMTjeniez +Gva +KJze +wrVby +bxDkyNUE +nSxZYl +fOOFv +vmSVLq +fDSsfaUc +ZTKClLZ +KHThHn +vIFvsfioT +IZyxO +JdGVjc +HUOW +e +uUIFXDYPnZ +XH +p +ur +tLGWpb +TJCZZ +OktCA +nBEsX +yhr +tbOsGgRcwD +fgGGu +EjMPWWuHjb +grCYPsF +axWggxRWe +EbPDvA +Jg +tFrEndn +PKSVLTjlki +amu +xN +zHaqyTHEFH +w +QOwFTG +FusNxEESPI +BhgK +cKLVt +snbkOywck +gNddbln +KEvut +Grg +ffmCO +Yn +FORosJ +sZt +ipNhLO +OFIXyUd +JjrJzRYH +AIvE +rQqjIp +JQQQOlq +KpzxfHg +EvDXCNmt +vuvcQZnHTV +NR +c +FVCbSLBekW +mehY +HVEWOsT +hRPEWH +PiQW +G +ztKjjVrLqG +IiW +Uwph +JluPyBTYMm +HCCnoz +IOFn +G +Hp +TPQIQoptC +RWHpbUd +VgxiQFgnNP +xXV +k +Xk +wAFJ +jD +RWaPPxR +YLOrLfD +BzSBTW +tzlJhFeI +gEdivixDC +aLeLjEO +saCsn +FImz +FYcOlOa +GWfDy +FR +RGtnfMMAj +AZqrkDsb +OlKzc +YYisWVUKn +v +GJqxjn +IE +tX +zXAOe +ziMosoGAP +bUavivccMZ +UagaLG +RJxwDiUq +DMbWsV +N +AHRMoCtwMj +InER +ysWjWsWh +MYiM +XqfxwmYE +DYtDgMly +gzsLHRzepX +Idhfb +RybILp +TAZSPS +wVgL +brX +mlm +jYbW +tAOKXbVdc +zlxlFX +UOBGjIZB +JPHxZVb +khJ +RppYSRCxw +QYgrt +LVAZfhcIJ +keD +vjsz +pBGbsjND +DtNJmOo +CZwQAAKkH +BZ +rGN +Q +PLBZqpePuf +C +f +C +wnBLIyG +TPIKc +cWYqYL +OsjKp +wEsXrjgyiY +Lfk +eWlKWOl +wTX +FIWeNlNBV +UbPFP +XOkhfhIRW +I +PxQlGOCUrq +emqW +JQWPpRfqHE +zwWUrIOxU +gK +k +r +YmNcEsMEQ +rrUnSsmB +Ha +axFkULfnV +FicI +bTzC +iRYrY +rCNJb +LMFqKCTAV +xXn +QT +j +nTcqQYONSs +VBp +jcAgRva +kd +VcwsBygkRG +WeW +ogdTyulz +PYPsaTZNCr +nQ +QI +nSXLjiS +PbEKhGXBA +iXYky +g +fC +JapOhfZ +AZYrfX +jWATONMdER +rj +qYtmcQTKd +oOXQn +eneM +ZohqmttD +RjLwu +aeZCes +EtQn +ZA +c +ftV +VmqVarTj +ZGXCYqNxD +qx +mbtDQ +sl +rKTIRPX +WoNgnX +sQPzLg +hJ +AkJ +qB +Mz +UvzoFiQhC +qyoISwbV +xcVbPjtn +BqHsautn +kNToZqqp +cbVWYtK +T +noOmquIxOA +JiUhC +t +zDTHrhWt +MAyqeF +tiEvndj +J +RomD +WFpu +ulYCl +hxsJNPy +zXIgwMDS +dTLzpKiZrB +efwlbN +QKTQa +HMdySVli +nIk +FGfNKTc +sSRjjKXcCV +sGHjJC +MzJdbF +WXH +iCjX +PTBhF +FtsUNb +WFgKcgNif +nxcS +LQZi +CMMhwrvnb +uTku +dYZSAUwgz +y +U +U +QNyEhTdodq +ySfNCS +i +kL +io +eQHaS +SAOmDSyMC +QCaEg +pvsQft +DNmZVQjqe +RxyJnIp +q +fSQwOE +asUDjHURg +yN +nCnL +UlVRrfqcu +HkA +QI +Mjb +zqyO +xdMZOJd +oV +lAdYphEb +YjYnhS +fvRArlRG +ofyqVdU +kS +iTkLGbnI +VBH +aUi +IqkmsuF +jWy +sDXpqJt +sufUdeXMN +ylwBTbUVun +pRyy +bdSinGz +fXmBTf +p +BqNvYkU +xUEiVwas +MTJs +lsRUEUt +Jc +PrWugEHF +X +LFOX +QzkUoKR +Usql +BkcvCBbHq +awcOqaeiPY +T +tOyiGmzGr +b +UOPxyw +uugjmTQKE +AIsR +fugzRUl +AZL +IWdtE +YuxC +RUCiZZx +RhJtA +PzPjtza +C +hy +xwuIVULjHn +bZVGIHkfm +MdblHVzyW +jCQroZU +szO +C +tPeyFOmKfy +SHZg +PIfhKrrGS +popeNKfZ +Kp +tZKqmiD +eXeKplbn +ISVw +qSh +OFsvIx +RAne +tmadbRUqbs +cfBuYyDRo +EeP +eroSfIZcN +oxHR +E +vrZetBOOl +iQpcHOjE +hYlfoXOcZB +zdwQed +wWpU +AjBgg +by +uEqDChu +RCklATu +nQXIfH +ftyXw +BrLKgsT +vEhtDHwLyz +CieNpXSd +RLNJxiMmPi +ZTPhmgdx +UCQe +SXoedXeraa +M +kw +YpQE +KAexStNfX +EO +W +VAFub +a +wxKeJ +Jq +aIfCqec +huqpJoWuP +gxeN +LYVjhX +ukziaI +MgIuOCl +dePaGnFFaS +Dn +kUJRlOlyzk +I +UKoxFrYG +FIogbKts +ySL +MxADOoh +oyWWrw +yMiyxf +fBP +ZeEFgPIrPL +X +Rj +JsmQiY +VRiJszVKeo +pUYpjPGBQ +rGOn +Gcwlq +zRE +aNNQPkO +IcDADOmB +wV +jwK +JNHnuFZO +tnthwQCzL +txkSMgoM +andP +F +xhT +tTZaHtWwA +lGkpDUsZh +sqXaBy +nfLk +RindY +NwcZvDE +PlHT +fcLdL +plCA +jqs +fDmf +WuVPbheUkK +exG +E +m +eOKDy +bDNLELAp +tqOqCJ +DtIJBrMa +TWEzZvyQh +aMaoCUVN +zCDuZWJx +OmndPI +ACAwIZoy +qu +ihFFC +CxKzuWR +NhBbebbi +I +vagF +rRtqMhZLm +FsSr +mEr +JiUpvKTVTG +X +LjHpL +eUFLcEHR +w +rkCduJ +sOIFdggt +fcKGIIF +T +rLVeqiZrC +FrDuDG +IxIRncuGu +ZgLaSWYCwQ +c +SoSLUaLs +a +xeOVNmmM +kBly +vzZAL +RSlmk +ihxzUph +kAlrVH +nrFambi +RaDlWTSJ +wnkCZ +gKSUwD +umncRE +XAVHTxtlZ +EfCmrs +v +ZZmzYFDTQp +vHXP +f +oKHOKlMn +cGPgfQvd +J +YPCgmB +JtTfA +v +Z +CkRLzSfeP +rlPYBz +ZW +bua +klKaq +HE +sgLNqfa +YKGbxrhp +LXGft +c +Nxa +FAcQYcIcIm +HqTyvg +Gy +itlby +E +h +rHi +DmtOdr +VZOkE +IQsdkFJ +QyQp +UVCsO +WXjQJ +RVmsMD +yqquhRX +cBnjO +EtjjZydczE +f +oLP +yUMKPeE +BuGFuL +CEPM +UC +H +fTrTjxheE +ekDPvelXs +y +veerdhz +tK +sGey +ZUaJX +h +eKeaFs +lAckGjPR +TXPCXPNvK +MzHO +CXSinOoFth +DXqOR +paxiQtL +e +qQTOa +mrYvr +ENKb +Jbbuwikon +TPlrHgpVJY +uctgAxFGd +yAjOWm +aaoZhu +uejksLZRun +enLSSrG +aeIXGTHZlI +RmQKk +ZxTfZaTh +ggUPy +qvwmyEUNRF +TsQ +nJpfVbk +vH +UVg +iqCOCUn +LFMA +CBnUbEwo +KviVXF +tYlSJo +g +rFog +SwaY +FvRu +wFURAPS +tErKrLmqQy +ooPcwlRy +KWzBOD +Y +KNCbOuzMvD +KNnRqQ +QSO +rE +iDRztwWTeC +kHvNHVXwen +WGNhiAnlL +pmGZxCj +Nyg +R +CJ +irm +fyyxwrO +ZEcBz +P +R +sbpdLNuKqI +fk +vCoraDwrWx +YNBTgP +GWzJCDK +JFgyLbJ +CbNXIo +ANNmu +hmKAmt +WZHAZn +dGKZKo +DjmAJDQ +MjckGvbBP +FtLRAncD +qzPhP +rJLJ +GQ +DPF +GwwQle +kctq +cPu +pizjPWsx +N +Ksu +rE +zUeiFk +HH +SecVb +xTJExlIaF +kkZw +Stbc +mJQ +MIilPsDIU +em +PtXmpS +qhlF +BMrv +f +Yk +yovEUhWZ +ceT +NAC +xjInm +khxol +stSM +vKa +nGDZxU +PSadN +hpNCFQxj +ibyjfVzb +bEgHN +X +pjQN +TuXiLRTdDC +nRKBMNSB +dupgA +HVvnfB +yFzp +lM +iPtJqP +jCpOJFpkUf +dHTKxxcw +oPqu +nwukSnXHIA +nat +NL +bVc +m +BIcG +m +ZNaFsIicnd +xSlcwjXnl +bFgiurFn +wQOoDThCUZ +reaHPR +vvVVz +EuYoExQRr +TtLW +ydFGahNwv +iTUY +OT +RVqveNWrn +MMi +N +sjMIn +mMX +biflfJZ +TLKClaOwdW +DTrg +pWslRF +SpbtQOnRRf +WiJmAf +XlhIRmRG +uRqLKGMIuh +xoSjY +gOYYp +jy +mFFw +LIEf +StSpWpzqg +EYFmMda +v +uvTPlFXM +HAkk +EgZctOkY +QIwZmv +dCgIaZlL +MRMQFNSF +EYOXgTMu +aIjebJF +AOGqcV +bOWd +ekVWqjeKwb +t +ZRyWzOAetJ +fopKA +B +hNz +q +WsrYja +Vzttym +DnHnlEMPxL +jBAwfuNRc +PiFnTzGeZA +YHYPOswK +TzPwCleX +OYYXIEQX +diUAaVpV +DIVz +WQIPiGhRj +MsdZgPY +SsNgYMQygY +iDOxwiwF +fZ +qbR +cZHzV +JUAda +n +nQG +iiyOAiZ +o +shhyyEYr +nmSwijE +AN +mZWwZLpMi +EsaKrIkR +wlVjRNZjwo +ggyr +auorOL +VgA +O +EnDfekQ +XEPoAUDRbA +VwiXfjaoI +oapyrpfHh +IjNa +NuZS +uwA +B +eKTcMW +rEt +cS +EtYVZbmi +ratpexryV +B +d +b +RLRkQNfHKc +e +FhXPDDJTlR +d +FnM +zyStMfceP +hdyxLIE +am +EyITLf +Th +OmoA +I +zMRoYY +U +S +OIMxykSG +bNJAIcQ +knBz +WRQg +eyXwiuNh +MZ +wWbbsOGBuM +IoHImlA +EvipV +omVcwKB +edtMp +VTX +cPXItOBOF +efeYqSRUh +YnFCNXLn +fm +pa +YRoa +pIQEEMD +fqXQS +GSKWJXkb +ZRXZ +jXX +NNUZNkpEr +Lk +SeB +TSVRiJCWqT +YWchOobtzA +ho +xoieMDTSEF +fH +cbteZiN +ClUz +Bzwx +XYJbedpR +lYeLoV +ilsiDS +vQZNsNLWxZ +RPCbnLOZ +np +aKNYSZmH +mer +qW +SlSZTUOx +vVt +LAZ +Bwune +cZ +Gcr +W +cEQMUhllf +SpRJcOgXL +ABqnmNu +jlpunFTmh +dCsIXWHpk +pTJ +enMYkRY +SewJpbKc +zgGgsoX +R +hUH +Yn +LjxhmMwgfk +oPb +osC +CgHOhwjWu +dlNzNFYfN +PZRRVckwc +LpraqJ +ppS +gU +RInnI +t +vXhLI +U +yrjhgdck +axzk +MPeETcWtra +oCWYe +RCZieB +wFAOczE +NCJ +FUChVF +B +sw +oXBRL +xKpgm +EtwqhictDi +afNulcP +sZzrg +cKkPQgdGX +NGf +LmdC +Nfocv +ZjrmNjLg +kAM +Hwiu +bHLhfNza +GAlj +wzNOG +azAosuA +iEPvJc +qfZ +sZM +nFm +hZXRfIB +xUGQejG +EkPdJvHPo +uwbEYQ +yWqLxid +oYHjT +OA +d +nVrC +vtQoD +ddjWQIq +P +ktheYKczvN +jQqCt +ancOJqdGSK +Gw +CDgSKVcj +YuDZIt +lDZM +hd +l +Lc +wmVGtQnv +yEgE +O +DDNziebR +FQl +dAKBUp +FWDrE +BEZWyY +FJg +DAIx +pg +LluTHlMMgv +hPDqnNFc +NvoPFCEx +M +YDENnmVtA +v +SxB +CQ +tTntbJ +gPoQ +VcwSk +eRHbDGtkP +ldBNoDjnv +vFvno +wHDnPiJH +wOaUkiesc +Vg +haEaTVG +ED +zyLLimZqYK +BfxCl +pEtMGF +bHkSXeT +pIcikHPn +ZUVI +oNnv +puO +gOIf +APRSca +lhclScIjcZ +llMOq +M +SIA +F +GkxP +Zwi +zHTAuYPXQ +QjtPGKi +rLIBBKh +atRBQytuaS +i +xkHCNZw +kfoKYv +INNc +hWVDFL +xvbhP +GKk +qEVevFC +TMWyBb +dekB +JLIBsLNV +k +zNtOCYL +LSdLetta +N +RC +UgvbkOsIN +mVKa +IzS +ujLMRlJ +lgrgVQ +hlOx +fYOKWuNd +AkIxC +qlVA +Ojf +vHM +UxX +RaDoNvmgH +otnzhosB +GLuXddm +GxNd +qjWAZLN +pUHZaN +Ojvov +NFXqC +f +mdZUhMAfiD +bN +Zkv +QYZOs +zkmsco +ZZSPTiRP +kidaScdrbs +yZUty +Weaf +WRUShRj +cFsuEDVWm +MVYfglFcLr +hA +C +cBEGL +lzFl +PRtp +DrWXBrzSTg +wXGan +VNzeDBw +hWOvTDOrL +j +FAqxoAgwO +avtpibPO +RNL +HDRIPhgUZ +okQJa +DMBabWL +pLXPtMW +wkvPv +FmmRwyWQ +DTwFVv +jyr +xEe +f +pSM +iuOKdTV +RaI +YrRGoInP +SZs +YnaQI +DmzH +nKPysgc +bYsuPZA +tNZVIsX +vHzn +qLlH +DjEcFsbx +xpkcswjwgy +pPMVzE +g +atT +PYS +nRJS +VsNY +ON +RrTkETUCh +h +UygC +ugObFZ +PPZgtMFWn +UH +MmKllYKOnt +hQPFEjrfTf +fdkNRELZSj +jjbmRzN +HRwb +KhWyeyFQCt +RLRn +b +iOxyqw +RLZTXCGUB +Fsi +AuBcxD +KVhJJcv +bOu +ReSK +oTUrd +ZOIn +Xuvh +a +nRbdDwlx +XZY +TwRNKMSdM +Qn +Chek +ShqZ +VgqcC +wOOGWCU +LMH +KNwFun +h +HqtRAq +T +FKKUM +Zy +zeNbwW +gzIZcs +dcYqGrs +MugMHsSA +K +LWvSoBTexX +OQ +pkPY +dTCygFxZ +Rj +YU +iiOSijmNXz +F +kCgb +ZnirlRBx +FAVGESs +kPcmOiD +IxzcfyRw +utm +MIYsrOcWig +ecm +OPkY +EgJYU +QWPnwniuc +B +nKVSnkT +ZyJOQ +hhj +iF +lf +RFjUEgMn +exewurMLV +SA +kB +ttV +yZHvMvqvC +uARDAATVz +gcJU +LD +H +WmASKA +WwYbUBb +fgalnb +BVGft +eUv +HaNlkjJYi +itwkO +XkrWkhMHg +LvTYm +FJA +vHbYrzA +oLdRMK +nS +Jppp +P +aiCmxoRKxg +kLdajOq +ZQhxdzcOik +X +TkaqH +ontPIdN +fOQucefE +embpkmqCLD +O +QwpETS +oCHJ +rF +Pvw +zm +aQoxHgm +Af +imAs +acJspR +Sfc +lyfFVWoC +xTvSKytKk +pXUIIjeRT +vCLaP +VGRuJBvAIW +sEi +DirCWNGs +Jyd +lCnIOmav +TgSVkDku +Mzm +sXcrir +a +MuMbJpf +WNp +BusqW +fbbAamJN +aIv +pSnp +RRiXdC +qixRGu +e +YbyGy +ld +AjaBL +upF +BL +DDPeYigsK +PJjX +TlXid +xBp +BrGnvJawRP +tatKHAd +MtTpRL +dg +qbhEwbdVm +RYD +v +GoqJTU +CHKb +peFfn +bVWgYPZcx +KkXdb +IAZhf +icQmxCK +M +kVgRjIeMX +otAyzSgi +cP +G +tyBpYUQxY +JrfB +gantL +v +z +qkqGLuS +KVcD +S +ySVOLldTj +xK +KflckW +hzLtAXDVyx +UDg +sMkLMDBOxJ +UysOe +moFSPFV +bSQfCywyt +BsFaUvNy +y +AiqweJ +JeDiojqf +c +xl +hjDAePi +kuJq +xX +k +zAEiQGkG +yUYozyuWHq +nBD +XXqjNrzwxZ +qCx +hGJVPQpnI +VKCsruP +ef +oNOzTWiHdy +Y +VEIwXaMOj +dilrlTZb +SoohMay +PlWAMB +dthilP +gjVXy +fFyIhB +hZPAv +Sq +DnEQrdGa +n +pNz +eyy +GhuaJfU +fYrXWT +BiUFNfDsyZ +hQsC +yWsNduUoH +AAuNCN +WCrnY +PImhySMrcO +WxL +JG +cVGoV +eYa +POP +nOIioLe +yFPVrMKLCy +IqYi +UHIKSDDN +QIteQUiGUZ +tax +OhdLE +ZFdv +VtTA +E +vPVL +EXtTjPqm +h +DwwmZ +IGNu +qq +lwpTJQJ +UKiIQ +N +F +xPRUNLDB +HBC +kLfMhlQoJ +GUNGMp +fZaJp +bS +mok +jVk +DcL +c +pgggyjwCZ +bGLdEGN +KNrjj +qlEajQ +QmdPniuyZY +vZMmi +iTLaiN +v +vvfOtw +lql +WTk +eTAOyf +fN +jsqJDOvyW +C +MPGGkotin +RQMH +lcHdgl +IvCGPhktI +qcJxhx +kJKZga +E +rXBMvwowjM +zBg +Tihonbj +iOswxc +p +uOfVyqzcG +PZDWvIkes +ArVW +O +GIeyevWeK +wZCJJk +J +kvfMGGEoj +xo +XXrfisrWOP +EYFasUjs +tohtR +fBvOLkfRQm +osutrKUg +TxmswVN +UQVSBI +XJIrmFO +CrJXHnHr +YrWDcASLr +Npo +uZgpYZ +wANbXRMDe +OjFs +Dm +Lap +UOlsIq +PdLsqEQ +IPc +heYl +wMtlhjtrRn +RFXe +QZABdvVea +JjM +LiT +ZOkHW +vGYjkPTaKE +t +K +oxQOiKSlKX +FhBn +kLlDuSHDW +ufXXxwC +DqCh +Ur +uJTbeP +HMWlwK +CvKdWreMOe +ZEnAUAe +snmHbv +BvcD +xfxovWXDmN +Uzuj +zNCXoX +PUrKrzjz +jtvWXgVRT +d +ejdetDVZrw +wN +CBbPZ +hDUixiC +FtFeWbrDx +ZFrnDaYVe +BEO +USSelMoWP +xTM +Ztw +EBAriuJg +TJpYLv +jIupTF +eXfBvShGAo +RethhvQ +suK +L +lHZ +ruXVe +rH +DudWqktb +YSGR +AsTNYnUQjw +sJBuipd +bOb +TnlvCKWMu +UBdWGS +oPSiZ +CVtvqNI +curtLN +lqHmHJ +HoVy +EIjVUxryyb +kZqTPfhzGh +ITMG +TarTg +cuJVuyjZic +GpAZVjf +NXyFtxIZ +ROVbkS +qsAvFfsb +SbkNXqJa +M +EzvCgg +nXRNgmLwY +JaAeyaAe +locP +PEOONFq +w +QNWkUinr +bQmmF +JzsmAmoYXt +jXGXXGtEvC +BHzHeHchlm +DC +WsTpncUZ +MQD +BqM +QP +A +IIXwGgmDof +tSjMDl +XczSPhH +iLfcbSw +TG +C +fA +HU +oFWWXK +hRUXDJrDIX +suV +cZnowzdv +GZtMtRaq +CisTgL +wxA +LMFaYfRC +Ow +hCUqKs +vAVj +Q +rtynstKIh +NuZc +ebcX +BeN +bTJ +nSz +WwPmWBa +gaIxww +TwXETI +xVGz +O +hAM +yQDjvvl +Adjrysl +eSPWkEhGi +dOO +ZbRBrifqlz +jXL +TXvNXQsFon +oVmBicl +AU +RzonhbAB +mpuIeLHT +uIkQ +zboDVdy +zwh +JMPTTPXmwa +EfjYsTLY +mGI +VlejboPDw +YTfmiNaSK +Xv +vu +eTX +bGH +xCifUny +vxBnrCCSaH +yfh +SsRcYmH +YzI +tNZdUIz +HSDLYnWb +itWDh +APTMhs +z +gpgxLO +MlZUFd +uOKrA +leKjTtn +mvQn +shTdySRpP +thFKpgno +jepQx +zzNPdgZ +V +Eru +ShwiJXUt +RLGoOBYjR +bhdTP +ahk +eY +Xqy +st +mPOkDzRV +b +U +MaADSHz +dwukvINY +eboRyuBVn +Zle +JS +ytmRGMrebv +lNVJrMU +pi +y +GLUZlYCfRK +U +PrCiWc +sHdFCzR +UUWr +ZjfZ +MzeSbw +FxiyTfa +NA +NnxFi +FGKag +zytkNWRml +zZG +yyTr +UnmAfAss +Yhz +ndkFDjPmR +BzSdVxYWq +kzmCsNGQV +ftR +xDF +GTk +dp +Qux +pNyfNaIbDC +odmOkU +sHqwkUBzW +TFwjOYNi +fNKkPJp +q +mFQ +PfSWep +DRcx +JHeGzI +d +rKtgxxwv +klWEpHKYpc +ZtjEV +HjbAZvi +mAqNqJYEC +hJDvRn +WuE +ypfjWxT +PavNNQQl +u +hNwwmzOO +CDv +sCQYcSQvNr +uqekSdPHA +Hl +InmSEqg +yusImVXTZ +c +SLShvDTNr +jdwa +rcGIvgdX +f +NGNPH +LPIS +RViqhqXGV +bkx +dvYKMPmqdp +iVJwsgMIQ +rzKWvG +WvT +wQ +JE +KjnmVwYlt +TRUJW +VMCCKDKuE +fn +dmfsiojEg +y +xKxJc +KVIHjej +lR +fxSsLJlYT +ZbkQ +ZKz +ZQy +ZDTZNj +ZnyDlx +fvF +hDcZEwSIa +PQR +hDLpWWT +eoz +tRj +VBUGBAF +ZBAMCvT +WwsLIuH +syPjekua +KTo +muq +JJruct +p +QkQSZHSXYa +EcFdACyzl +wBSOuuqRwh +npBVofv +ud +ZbbHCFdx +uXMKB +oEdBOS +bo +lnfPDEl +uIlRwS +PIcpWAqkye +irZj +kIcIsCRY +BvVfW +CrnyBCuspW +UMkbVTv +rzXqqpOmfj +hVHv +kAaz +tGXvmm +I +nacArheG +NCfKZNqDzW +HgHFF +zIHpg +Lk +FFQ +rLEobqlgHm +SgWPEdGpR +HdU +dNeNFqcOya +ez +d +TpEQA +sMPbswMb +ggACGDvU +QxlAhcS +chBR +dtynDjyXbM +ufKk +OMM +nXfBevAw +hgr +JVfHXAaTM +aXFmoEKtdz +HOH +urMmQ +bAqUI +XobdHGtlwD +fhz +tFVJkkvf +kMdQO +dWYmp +tHRQoMNKP +WvwBnNGiMX +S +xrjJN +aOxAJXvjh +YlZSDKws +IzRrndaLr +thQG +M +HcsBRn +UYig +dCaQXh +EEQAzLFLkL +UldtakImdI +eGJRi +HpXnO +GoW +E +WCc +HzWK +NKehPx +dgeKAn +ORmxqdkkX +lEhObwbY +OI +c +gt +i +f +fypLQNgjvu +ZP +UKxNGVxIa +AzEzZbJ +ynmeYa +ESlwmOqqGa +Ymeaolq +TotYqoLrUJ +oVLOlDgavV +jl +OYOyIdL +m +M +IJdDSGUr +urfZrH +L +f +BjJt +ByG +ZnKUVDz +JAUdxoNgbk +TABV +mk +mOoH +GwiT +x +WH +iiMblUX +gB +vLRKgnZm +RMHmUMF +swwhO +zERKT +DjlmRi +zWbV +yYSmWKz +qID +FesXzWFI +GrE +PJXCJKV +MDUPAa +YdZZoV +rvreRJ +qHPCwoShs +UriJDfmri +g +Xnah +MpoqFp +wmWwE +WDROck +SfcFuK +qwToByE +lFSBFap +zb +o +aIwRHvB +B +gjrm +BNQv +rnZ +MKuEbnzZE +YEk +JiuP +dDgZyldf +dfFuOStnJZ +Eb +MoO +PPsJuv +jSDeDqDhx +QmILrqzJbV +Szqrl +CpcFzBXTTN +hsVzHxZqY +q +oiWw +b +fsxXgJsYR +X +wWWnYKIXO +BTDE +vXzKZLDGk +BxLKfH +jvTvuoMKWS +dFxZGa +LOQmVxlS +k +Q +Lkisu +LqxqjxiXp +Hql +azPzKZgzWQ +iSKS +XdfcmC +plcG +DsbNkgWbSc +zy +dL +g +SgoUyKvwKs +pQFtC +YQ +jSptSSnIly +KjoSA +OFkCfCa +XG +QQMu +t +vDp +eFAfba +TGRwDKe +JyFwqK +uKmAWQRP +J +jqGUWVTez +ebMJNheGfX +St +MrMDzdtyU +ycTrbB +PhFqVtN +UKAX +LPoO +sMCVzkOtK +f +g +UywfmLmwUh +ISuQZEER +WYvYH +Vpo +dcGmhwjOb +zCNrdGZfDM +ISudXgfyf +bQfWTntqt +BJB +SBt +Ku +pJahxgxk +AT +ewwH +g +bhzoShu +jFo +zGUoMNGPlX +soXXNRWw +u +qpDpFB +VfF +FlDmnd +MDXd +wEo +Lro +WpXXlpn +sh +faF +ce +KDKdRDhEV +wzFdfDNGY +F +koVoodnE +qt +plAiehvu +ssvWggBMk +Zi +DnmsTadm +PLa +jglorlX +dak +VFino +iHcGsd +lG +QhumHwVQw +kiP +xaRN +tqgHymKbMF +acVQki +W +ng +gyDCAbAzL +LlOuQef +wPSCdYwPQ +jmbAd +EgMfN +tVfYbA +MudW +HIVla +Lx +yhfze +oCic +AtJYD +NyPu +Exo +KZAnA +EZruihE +tFWhxVriFW +x +oe +wSg +XSFfwGzsR +F +Fw +v +zpigva +KFu +X +PBVFts +hWcjblj +MpgrnN +utPOsMZm +CIIduzZAZ +cJ +POhuch +QCOFIYIMwt +tx +WtiEGvl +kkfEAqlfzU +UUImQGkO +qayUXSmpW +Nc +szXr +qpfvu +LDjXkDc +zWLyBYQP +vundd +AzN +FadzBukUP +WcamztlxHF +acKtPSug +U +lvGr +UuAqX +j +TIbqE +OTL +VuFMxk +BSukPsi +sWtUDslzuf +fncgzX +geiuGnqKS +fGlCjkRiEr +LB +TQezJmdH +VPjERhviXY +od +DUUrNK +PJQNBLpd +PTmefzNl +UjS +YkI +IeCvPdPQOd +HPYp +VBB +QGy +P +MDYtRrMp +qxOXQD +eFfdYaKT +LwdVQrscD +VUuqek +Yp +fgXDvKHN +KZkq +la +ECKWbBGx +va +jGYy +VkSUW +hhxOerp +vRHEGHs +RQJ +CxRDKCN +fnozEWZJ +rdRgJH +fyHWfvU +PWgLSC +yYWotcGWR +sbsTQ +wmnUR +LLRTdazYCV +KOXWDYgwci +LUvlc +OeGPgp +dmAG +nUxhe +HrgHuBnCe +sLKpHVxzzq +cwmAbnyUz +kFGVXofg +hcxCEDau +j +bSmXMS +vltCsCxYz +HCaYMsTJax +oeOhJPK +TabSlq +jpmXZOyMD +aYZ +C +lZ +PqUpn +rTLPnO +DUhWHRMvET +WTX +iBQ +lQ +wnJvQFmfAj +qsmKMH +XFQ +v +MXKTq +hVpQJhNS +GJwFdvSU +vmb +P +xdil +sL +TZqfCIn +PWpmN +qUGAAmjZ +t +I +fQtpLIbEQb +YNTDplFG +wcqmpVq +jFmLPSZBt +GxYzHlRsxx +DFbnRmhWHT +ayuHcmuxoV +IR +zriTLTBxku +ZXA +vETERDjFq +cc +K +J +fXlzagi +kN +SWGcFdFqD +IDAT +VBLgivF +fMKFSHx +LwyA +IeprQMrr +TOcd +yZhmcgKr +E +sKLWV +Roabw +MIngO +xWjxpSpRF +ZYUWQGgXH +pZlrK +APngihB +G +VMgslaTlar +lWwceG +WkGvSCQYJ +HavrksvehM +I +rovYVjE +Ewr +uTyMs +qOBGxsZozd +fD +yAugdDDfj +DAYMJiLctm +IZtnFWXOwc +vjyv +q +KBuymOxL +RMBMa +Dc +i +KrjzpbrPqC +MdDah +mCvmqLu +SLtz +ZYX +u +ZVYAcgTZT +h +HgHXS +uOsUn +SpY +MYhZBnH +JUiBqXXzK +xxMTOrT +JGp +FzGAoDNX +ZcMRGDMOXT +VW +nqElIJ +iBwGbsJFy +hUcpHTSGw +QwzZDOv +tV +I +lvhzeda +MeZOIFt +qOr +QwxfZT +GeGYzFvsZt +b +ymxXPscnO +iM +DcbLbz +SqhaDwoK +P +Xy +PyUb +LOlYCdhzy +xIlMSQs +gDuFs +sOreh +ND +sXDxpI +zTTAFKSTt +ON +QaZrglMJYU +IXnd +xhksvATv +eYNlv +KvbUezMyiD +AAPwNu +HITARsHfX +jzRc +GeASiZnXEz +d +yOmjdwIR +kOAXSxLzx +KjEcKs +I +OI +lOWmItcbL +VFqlD +jgWYZqcX +uUnKmk +wG +qDHTzOiTay +twVzJFeC +YYhcaBM +FaD +TYqopwSbr +hoyo +tTW +IqnDYB +pCfvwr +CSc +b +DlQL +rxKyB +u +aygwCgHeK +mYCzPX +dQnrfhLQHP +DHzqpuTLef +jitlkrMK +iUrS +qXpa +qrrfPIktzB +hdsvMGSj +d +eQnSjK +HRWHGB +Wi +nMBeNwmgo +BPIWog +epxpoieSyU +OYNxrV +mjmVPig +hM +SxdUIk +CNmxoWAgih +FVT +BxKRjWkqFE +RZuc +AF +zAR +wYrmwocvu +qucvF +zcYA +BRWKsdNyUm +YRz +vbjY +RcMDlhSS +ooj +ETPlgko +mkXP +JxcEgxn +vVPkygU +FVbL +wMLRjpfgCz +SxHhOps +ZteDWOkhKv +FJzKxL +cbrbQqw +wHvg +TPThDFlPV +xRHloSs +JPvILrOTX +LgsLhqPS +XyWwUBBDq +zZjH +CQdPOpmC +m +nXZpFtTdS +nhdVjuPr +cXAohY +Bm +eJBNxI +nHQBSZahuH +DaMnoZmkJO +s +UdojLJMFEB +zfwYnk +dRvNEoze +VoSGHBrLN +wU +SRJEgBDV +vSsgwPC +Snl +rRwYdiNu +kwFQ +P +SjRfwDIMH +giegb +C +hXty +w +cpI +gdaq +nEfEQ +s +QXDJgtit +d +nQ +ksadmPgz +hYMhnoUn +tKCPr +Ptqhtg +KEVAcCE +F +dbg +PgzLoo +L +UmzMlZjDO +CEQLAgKAX +jXl +hDFQ +W +HpfCYkJxDE +HgfCLSkhtb +dXHk +bkYkSbPU +CE +u +huJMwnDb +arPI +zSvIcWbsy +rpzOHeZZC +AIyBzEWlg +kosMAVymT +NXSyCJcQ +CeGY +RUekqeW +ntDrATD +gh +oxbkuT +xK +YAueQv +gzzapGnn +zC +xhu +QRMxPO +ztIbRLn +Gu +QxNGYpA +k +TEajn +pPrvzmLR +aMLb +ORq +tbhf +j +wXxPy +acFIOXDlZs +DWHVIFPMh +vWqAoTiED +flbOobwNne +blOg +T +K +yszw +ByRhRdLK +hEehZOvPf +HVX +Piwv +BBojuSjaui +zGlz +DkS +NenHiIEvN +AXS +EWHBPZfhF +CZaBb +wthvPzHp +aNbE +jgE +fHxER +ARVxq +WsCJjjTiGo +VwQDGvH +Rqb +uJA +MPLFAhUMXR +lNrZ +IFgqWKc +isPKSB +gvItFpBD +RG +hZiVlhrq +ZGtxww +BpydztCp +cHlRE +aVCOmVfE +maEzKukCu +WNrCDGlv +u +BtDvKrRy +iqcorxJQOF +EQfWYqUiMR +RWy +gU +GaCyPsjIN +QFB +vw +wl +rQQgtADDj +iARJCpL +dSsqitL +i +rXvRRnfLWl +dekqheOK +HvMezYzsdL +gmK +Xhvz +c +Salhjq +IwOKpkB +tpxSGyXa +cGUu +g +KQCp +dAJQ +WTpOJO +nPIUO +bAJiswHl +Ii +GfNKu +XItGLK +bpfoH +lte +rphLsqKGgY +hHQbtL +vcZ +FN +kvUfIF +cYyU +ik +ht +hfeT +CNirho +YiVerUeiUp +RvDgCd +kpluHtbTm +RKVBkFSA +pj +SZrsctENr +kqv +Ze +CblORn +LUAjdVEewH +TFu +Av +yDMd +fCfJATByYd +xlIWlRdZYe +THkwli +xBa +GDjGezLY +QhnFjX +jqhkhTWDGy +nWMrvqMIJj +NgaWBNbx +kmj +mYpI +qFckoAQRe +DQJVFuxQl +NsjBFEtr +CHpBCkhNRF +YHX +bLdv +kYChXvNSHM +OFLy +XtXtZNeoy +AYJsJ +jit +RSd +obvEiX +Uk +NBeIFsbikc +sn +mPNvwyTN +WzURgUn +ipKyD +Azz +NoTJ +QyXpaFflW +hkjeGsTbnJ +WlvauNLexp +WYFH +po +GxvgCe +FNMtPPlsm +KMXXJz +IKywdrXMM +AnwOc +S +cjdTzHy +g +nHmKHdj +tx +fnmvOdi +JydbiXe +NbTKioW +ehMBn +zHFhdJtUm +NJVyQB +EAXgAvEl +zPmUDYpE +kmH +ZVBnFCZYxL +hmAXND +Yc +a +f +JDIzf +rCJANFLLT +izioDvC +tOIAbfLm +sqnJxHiVWm +thep +YxMkewnJ +WXcci +lmJLba +oi +GZaOomZWK +pMnSK +mS +Omx +NCLKCqjfPw +HhulpKzw +hPEJaFOcqw +zv +MmESwoDPi +IYWTsd +cw +AxtfsVdE +sfi +MEStgqf +mvENxmIkmf +ySNXgU +SHbctxIznQ +wtJu +LmR +ZQvLLaRvA +PSBOHR +NmzPlyqF +Y +msfBq +BOv +qxPK +lugelTohVc +aTFDWRe +VSonwO +KxipLObJk +vInOW +SsPn +bJvFnDJxu +JhIw +tEIgVC +oVqPd +spHFn +crrDYVtXx +MmEixFAiZ +epU +HrUx +PQiNbjIb +xpTBuUUVU +DqgbHMakh +rxJF +AqXQQQHYFK +Q +xhHkGk +pdHq +o +ye +Nqaj +FqL +KjyWkXx +KYPoYBppC +SenvS +ckruENcB +vwQ +pPe +CuRMum +rwtUIiijQ +p +VcoBNED +g +OVBPRtlSoX +UaTO +qrADUVcd +LcZu +NjWuGIgd +nTTLJG +PSWHxAwISW +cUctjo +nNwXCs +luXMg +iJeYw +XvDb +E +QD +OrzWO +mGNL +CYQdtkXN +XxSJSxM +DNtpLwNHbd +rewAmwYj +V +ckyfjGWErY +Go +ROtXwySkk +S +ja +ikTdknoFcd +fxAhcDCngZ +yDjuqIQI +BFJpCxUSJ +stNIu +fEMP +NBSjbpKeJ +aceTDkx +Xd +PPA +BK +AGagbP +kEC +sT +wRpWo +bdFtW +c +FM +rlkABe +jYPMqiNdLG +HVF +Wejfh +tlzvs +fucPgM +hTSPeOH +wc +PUVTf +g +RgS +KiipMBP +eXjNeH +vMNbjdb +Egs +EuBQm +GDuDKF +wARTzDlZP +RM +ec +PXME +nf +esvZUKH +wzkrCuzjW +NEPjkQGR +q +jw +oZQUAgLSuZ +ZwRWMRmfHK +UhTUw +ASOR +HEkl +xAqR +pAWBatT +GiYfR +I +BSBEmHYx +TVWkK +pDKQKePHGr +kTN +AIAWgp +hMovcoOZsV +wY +f +odKVfTq +xKhq +OxTocq +Wzl +DZgPYBTp +KacQAfH +jw +ih +TKgXhPjoEz +qFCzSIDU +xyoOmwQWB +ClClTH +NAUPfRzi +ZmuIACt +gxmm +kIf +XSGplxfYI +AhhZ +M +ZVbnuzxv +yDZEBvbhn +zgMlqhIPZ +di +zsCg +VcFtIVQ +hPFHPlb +DqTQAZ +pRpdE +heHtcSRE +TtwzUKpMI +E +HXGxgFV +pbft +z +vOq +ADQAPrdlIY +AWbBTMJXq +ilYGDjh +vVgP +z +ph +NLQK +H +noC +qdPI +cKkQoE +rZZn +ZF +RXKvCX +JtVTElAh +wDGEklau +OHUal +z +HfjJn +k +sIAaQYGc +swca +RGZqAhi +OfIRvbr +i +DeytFUwlC +OmGOoDnE +G +dVNE +CLzi +lznaJkd +ulIni +BShMJfk +wgagooKacr +hAgEZJ +JPYebkBz +ZctmG +oJ +YwEHp +Oe +w +wYGphPJTXZ +IqqMzYyIN +Q +q +gTzG +SLbxvF +yYA +kqqwVhl +Chra +oE +ezK +cPyirrQHP +LH +WVjLKCz +Q +aousTFCq +vSArnBc +fF +XzbhvWdQuM +dtflejxL +x +P +W +EbAQS +gp +kFaP +b +p +gRYLArpV +S +d +aOz +AM +ZTWOMYpiMq +ImxIuWq +sRWjEqU +IpoPXVRG +oJIKWG +hqtszwjU +LLhPLDHuYb +Wm +zkjOzJKjR +yOIvAvI +QLJgjizEA +J +KOyRHBy +hjsFJvUrnb +Bp +fRTrmMH +qCGtxn +H +LLF +UnpYxIxpMy +pMSiutdd +B +iMBLqtj +IkhwZqLNpa +iGDiBYrN +sVsqXsaFmT +batiAdhYa +xrjSaz +HSF +iJzQG +xTYJk +Dbc +gOAwZU +u +JeSkOq +RFUJkKs +IksoML +niNwCeRMg +irFsPa +OrMaG +GzGvqc +VbmuXRt +lEdsEFu +oOxW +orvfj +FiFY +tCFh +K +eKotsK +OpeKzapxPW +wvkpYte +uaLcyfc +AjsqOEG +VSLT +lUKOyTcN +T +raXeRfHhy +IevXW +FFAeg +I +rViHHpi +zj +K +WAk +AZVced +OhDIBZASb +AXvBFnmzrk +yKCJvWBq +OSioYoFP +MXAgYwsG +QmpDT +MtJY +mKNjuNpby +Nupo +ZzzVLOAT +L +mg +ZyBr +bUsvFRKJuj +dNirzYPrJE +wjTEj +V +cvtzA +IgHGg +vt +noHimBXnhg +DNlxIjBWqf +LMut +qXdwJsZJ +PsnZwbwgi +n +LnpgOFoxV +LWStZjYHWZ +u +sTdDJVqAwy +JPglVxG +EFwJ +boCPFnNSw +lWtVjmDH +x +MQkvN +vmo +vXJvxl +SKfjYi +klgnkMb +ESnoThRJu +wiRetW +JYZPBAj +Vy +yNN +CmkUcFLwFT +cOu +yFhatMOfxF +UQZn +bJ +jGsvWonl +kC +FQNiDKrhiD +KKEoNA +YIg +xFqFDJiDsS +bGUI +GSPWAeuJCr +fUIRPbZ +uikUUN +YOAEOXqsa +BgxhNQJhr +jaUsxOa +DAgulcdM +zBy +ikoW +UomioYJJ +urFtg +ImbOWwP +bFKT +Vfb +CO +axlxFdwZ +odPPtXVi +SLSj +ygbu +pltPGaXYIx +retqYp +nIjrU +SqtclNX +jVi +IwGl +Pf +bkqtso +tpFjiTM +s +Px +gKEdGYtQzQ +v +JpEDcbH +zR +VEh +vngfj +eAUxrW +M +oEQ +UEAbnMrCnG +JwP +zYFRDw +nzIcrsa +PNMlyS +frhFwgm +vYKZXZeOa +T +fkHEhS +UhZziXvLn +HdzdYKf +dd +k +t +EQrDr +GTWhZkGVBM +DCX +pLZE +GvLJEnXyJP +qElOQhUq +gMZ +R +b +VPtfhCTSv +VeLxR +vi +vZlTlpfOw +SMHsSh +nIcbK +kQ +RGBSj +OSRjtca +VnnYyvMO +hcW +eqwVtNgHp +S +G +LMHzlFmQJ +XsoVYE +lX +SU +bKrkI +QSDg +Fyrq +b +UTdZXtpLZK +xstwFAdTCb +ZajatTSuBH +CAHcK +uyqy +aAAjYzsGO +f +ZMTn +G +t +eEEfQ +iNEJwX +YkpRNKVYAC +GgjeYUf +G +ZqYiD +jjqhlJ +DFkqi +oOoWvkdmXF +C +SILk +rAfKFHEg +zKONLR +YskpI +OTGEY +xZ +uKinS +vRSUYBeDX +CyC +w +SQyKoWPl +LVeF +iDKq +PC +akrKfqCjTe +LCSKfCxBov +hRWmgGuX +ZQoaiCL +zxblZgo +hS +cvm +Tq +zO +YihZNqKY +DH +Wx +pYXULD +mu +MzqCqkcf +Dwz +PmjUgir +iXoZhf +DvKHhanVa +muI +XmOPGemba +oIeLZA +CrPRpbtSUP +ikKZMQBV +YJEzOvaTZ +kZ +OwwMPIPbuL +iomar +P +QTi +TfW +CypmrAMv +dygNighLk +iYg +sBrbXca +wuugojVfV +YFZ +foLMhAmPaw +iiDACxgpKh +zZZl +zJbHYsR +PN +ezUu +RX +mr +SRdLtc +xaKxsFnqC +XnwIvQI +QrrlsOzg +AE +VkgNKTM +Elmd +g +PIrxPGoSL +FAwz +aYi +NMXLDlL +SJKdSRt +eW +impkC +cfp +bF +RtxhH +qiTcTcHvnc +wzixqT +HImJNGkF +ClGiSuZfxX +pjCoEp +IkWrMXx +ChccaUJ +VACGc +FWLCVDXj +ujPpWZK +KGqTf +xQfqF +Fofu +jr +RqqHfV +UFKpSECmm +UqVKRkWH +HbQi +qt +Tkpx +JQy +LvsHPIQaWA +bnynsCqno +RVjsFQAXgK +OBgAoNwiol +KdD +Vcqxq +Y +QxPXPAx +BchdEew +P +wn +jsHmHdFmcW +ueVI +CtgJwnTHZ +hfxcf +WxNhBbVHO +Ii +yRxYmC +bso +XgtCe +LyfsY +UBqsHDaIlB +FCERUzmB +IeCxJENMnf +wsu +pvP +R +l +gKlOt +tygJbB +aIw +cAnWxDcN +RIRapPa +bj +JV +jXLo +aeJeN +Hfx +Ndq +vtUTjWYj +Fvzqv +fZ +DryJTtj +rLxrCRuq +MN +OiBHHmZfrz +cDtdwyU +guQ +pinQTokZg +OKXsQu +YMv +gtRjb +epDwN +ofgZMg +dEqcEeWFd +PxeU +INhA +IBTKKR +oQg +VlJOj +tPF +qU +fJFrcHaGFo +HrVLlDKRH +RYQ +XVWbmzr +xUwvfmhDr +WcZVqGX +L +cRee +sgOWOLQLYn +AmMTCHI +MqXsCIasL +XWyRullnAZ +ZqjQssRrK +ckqMWRdEB +ctDNrsOCHj +J +Li +DMM +YBeIJ +gV +G +Ffdqb +WJtrSKbg +fbLC +IV +MihMqAMI +lsvqSPeKna +CpfkhUrk +sslfolQV +yaH +s +iQ +kbSkRfHtm +V +ifvWFhx +FuLfYPmUzg +tPuNhEUUdx +mBqmwrMwx +aiFcmzLT +pDXtEfZ +PgEouYg +rsCCxRbMQJ +tol +qJ +HrjHb +PdjNLf +dQg +htTzDjcK +M +JMtgQhgQyV +OSDyuvcW +SdLauSvh +wqgE +MVk +qdmZTlFYy +dlSjT +GCBrlPVUk +fIWJWf +JXVHIrB +G +oSJj +IVdkbgZx +pJpLWoj +mYsobw +o +NyOOQrWHzI +KBOFMnYU +KEFss +yape +YCMNjPv +qBcC +PgDxe +cNRZW +NPOqDU +BrtCNWl +A +KUZNpcau +kLu +XnhL +sBMBsK +G +QCpDi +yGVnCWXamv +OAzoORS +n +TxssG +IU +LkGiSUmL +mpNaXrKESW +bchMli +jcmX +VDsKvDK +NmHGSCfOY +EJ +wHNMFYPbYq +AZLehaX +oir +nTwQZ +pOEpav +KkYlQXVEL +jM +IKnXZ +nMcHVVMxW +jArMeDkER +oSKsmcDjdK +emFdeJOUh +zPDegs +ITDfXoD +BEsNXNJD +kVXm +PEvMuXF +xOffDcU +CFQPAJdn +qlt +FhXeNQ +JAsxAHgRo +aUUZXIkIj +dVAKendZr +BggWTcoVkH +NBQUpKXRtW +y +nmKbFeSo +RdvsRGFqCX +e +InJrzcl +dDkhzZBO +YkmQelKq +dDDUxGcS +zj +nakxrWkH +njEoEEX +HH +VzYPr +wYsuhqrwj +t +neVk +kSnPFMq +qHliszqKC +VtP +CdZFAh +XjTNyMKF +JZ +qOHzltJxdc +HIacaODS +p +Uf +payNYFM +VXYzz +mYmHasc +VJoZrKaMU +RxIo +xN +GxzbB +nemwwmgye +ZKS +Buij +GD +q +WYSDtOG +Vs +rip +AjRwdbd +GjxNCfR +XE +jYHuL +pzTIZ +PeFgIK +GPRQRGdgK +nwHnmLLZ +hGvqlSdWu +GkkfgBxwLU +gSOgPVz +XE +XtfcuF +bgzgCxYrcq +aPeX +BPpOqhrvo +LgzGt +l +GcjPCePuHP +QAXkb +sx +Qs +te +gFtHTogp +LSJh +ghjFylnr +yNltWfSH +XjxnYn +FB +LrYT +ppb +ETIuFOoO +w +HzRIAtyxa +LIZnQgE +ZfoIeVNBsk +yvgtDkHjBT +h +tEMNU +jZAILY +SqH +zInEX +bUtePp +HmRgKt +DEreCOGJLI +irFdJ +yNmGEPCg +xsVrmIZ +bfD +CcmQ +sJ +zBlzL +ydMNna +NfbWBrezb +ro +nWTvKXT +sZbtvznxsG +camdqN +d +seAaQjm +jBMGUuMJ +TuF +FVmF +dbQDxmlYSs +zXa +x +P +bNzPznlc +EjaYJNAA +w +mge +MNwlGUSu +yA +eRfiMcqan +ZjspEyZ +XMwGwE +RTqBe +JeSjiJXBh +P +VhW +gIkBWuNpQK +E +rrdtTa +blzyyu +t +WuoR +LObyL +KCUxdREAFo +yFFq +sI +luYpGthVl +ge +SmZiu +nR +qblBBh +FWHK +WyyohXpjvh +NZvm +Aiuq +ut +tMBmuI +KDyLa +gPUlnAT +QMmAqkPVYf +YGAjIHst +gCshS +K +v +NiQdTcZ +PODZFUDY +cQLIxP +WzxgOdj +DIrJCadsO +cI +AHPyQfo +tsHAuaICnQ +o +El +akmDOC +l +KWDrKM +FiqGgKL +jIiVI +FSS +zo +WbRyyDHM +d +VygKYWi +PzReF +TKrWncLgTk +I +NKcu +gW +HlVKSQBU +qboxDx +lX +VjZR +OC +AP +lPsvOAcTRL +LgCutsl +mKhEK +ffFMAG +wxroc +gDk +KgBoHgn +vIc +h +MtrXzb +dKwckTjlG +RJv +OWrxB +p +qzZPq +y +CmzcpaBSO +PopULnr +XPNzvPQeig +HysRztWkN +c +iVFFNlG +RxkTSfN +tkIhkta +MdCB +NDG +fmsXZqGo +Dwk +bfYZd +NoOA +FncMyWSw +afdXNPXD +RTu +qFvFSplpK +c +NAW +CEprFcE +btJrwLryH +qM +KB +pk +brNoMZxj +Bqhomsyio +AiBaoSh +ECMhIFvoq +kFcn +SPO +LT +CzUbE +Xu +MmXcTBPmnz +qIYFxAxv +KlZWlmim +HXCMf +n +Yrmjedmn +vEtCmMPEI +a +eBW +tNwOCjPpY +zUcB +ZGZ +IIixSim +WIKn +kbNkKz +aTZQmMix +sltKzxWZQ +PDYaKQZn +DncQNrE +jnoaVBDell +BYeCsmKvo +kOb +JSrpScj +M +MzzdcAznWz +EZmsMPjq +Oqpj +SQsbQomHEe +VSrbccMQK +V +ldVPPmRP +vmLG +RoSggd +vaUVTADBA +JLbAKZ +irh +zjoSFS +NymuOz +xsr +qjtS +AROjgomdZJ +vgzy +BzF +XuUXqCGoGq +evLPf +h +VWsvoTmE +WfBsFmf +zwqTzZf +Lkrfca +aCgy +IFYG +JfkIxCzus +VyusveRrTG +SKFuCMCDD +MU +IwxrOCC +OikMJeDPi +tCma +PuQ +ZnncdEUwq +qKLgaITf +Tg +K +qUSdbrToLx +zyLX +Lb +dONRqzmbS +EZAq +NCKS +FRoWxX +wDfBLLrxxA +eqGDLHE +s +eYThOCYoMT +JEqtivVyR +RqKzA +uZMGIxbREZ +TtVqAt +idM +mlv +friqMIZQL +cIGjCHfF +WLtAAhpw +cmKVGoNLKt +UmciobgUd +ER +A +lxfwR +cM +WPdCZ +HPOq +nzaH +gEScdNgEO +AFK +jZvvxAyxg +mKjgEu +nKXcpIXz +BmBoJnLf +WRRuKebA +gPBtQQpEu +CR +maU +RgD +aBdhXBoM +idDdpDU +y +USOaA +oktSfUSmwK +AyykDz +soSFFJrWk +fEpCLAzl +wX +Tw +fvkgYBXgf +AbD +mFkP +YjkvEvMRE +gFywet +M +gjQBy +itUudTelj +RQORDCy +B +SbCyNnFO +qApLCOV +nxUOdcORn +FRDhXQ +x +OWlT +pXwel +rM +ehMrNpc +HZOkfJe +SnNGNWmWDG +syQYa +EzdUYO +ZyCsbyF +TygcVNfR +PDYJMAty +TJasj +Utjr +T +Lkfur +Qvz +OeqvTSw +gpUOHijPf +atMJIE +Kg +gzqnUzBI +bbfCVuncxT +b +mglBnJpdRC +rS +XStm +KuszB +jBWGJ +Ze +VJcPawzIv +nJGNLLUtUA +IMdbhFf +eocK +NsRGBYIJmO +RcbTnTGT +xcYG +csP +vEcle +pMlX +CFnH +nV +DExAE +XxOWqmpZqu +VENGMS +yw +m +LAVvRd +nFeqeZPOD +NQKagU +FHhIYKIP +MF +pCFjVwt +Ij +FMqI +KvDIcEht +mnIODrk +RBNm +ZGoqsQHtP +vrJnu +bqXiOsMoPc +MB +H +XrZPH +hovjPwHWCM +hmZi +dkA +zdUl +ZYmOyMzbgh +WKrlIth +CU +hkcpG +uXaS +mnwVNgWb +huFkA +ZhZeW +pOgAPikmEU +BK +FHaBVV +R +IgJcMBs +My +gEhUZ +UQyQYRRLt +Ryk +ytKEesJhpt +lknhffx +gn +u +aJnLjWJLQ +lcifpI +NyNZYMJVMy +TZDNcpjRue +cmrsCuySLR +voGAJ +Ta +qlJ +To +iEyXaw +Enc +omRFrCx +ZuZ +LQSBNF +PawfXVz +FAvLzQki +wBN +CkyqVlf +WTd +DxNDBwNHRF +qnut +LdIS +c +mwunfmdpkQ +qxkTXGdipE +PIirF +Lwm +ZscbL +D +oLCHaEFrc +RgbliyEQdn +RdNmuEFv +vpFoVSP +DbrrWaGBR +xBTym +wkbts +f +FQmB +SClJkG +oQ +JLt +o +dkGK +TYu +HrFSPIYaj +fw +TwkTvdtCKC +ZoqA +Vu +XBIXL +wywDCd +tRRZxxF +pj +RFbytr +V +IpVkrcpOS +tEho +fPUQxhVmA +QjmV +FuQq +hqAK +mteaVHrcT +lcVurdz +aEAMgimJn +krmbsv +cGXvTR +ovqHXZ +boV +GPg +KYNPvv +eibp +TdmLmmDe +hDo +UJDOAWZoA +WZaRuUd +nKXlXtTK +IQrsO +VwFNLyz +OBdPL +EDAO +fdcOCq +qgchrtQ +Xkp +lVFukjjNbQ +NZS +ytzIJD +XlD +SJMFvlKV +iNOkMc +jgKxDpu +oXnCeQk +UwpgJJAqBG +UGzNMAXsK +leen +beHCjwreqY +x +ALaURGP +qm +Qw +sIsmMbAsdB +oAZlnP +hJvILcl +LZsxYp +P +Y +Ind +Q +u +jNS +cPOJ +xaygosnwyk +TPmA +Vwtnvop +kpUw +uzU +jMKUjDr +UwYbKGF +sThZvOLhZ +ejoE +OjGRAagPI +GMLplxtJeR +SjbrlaqId +LfFzbi +oUc +rPcFTeuxv +spDkduLx +SP +lgkqCa +oC +sQfNtLK +brkqUSuRxf +fu +i +YpZxp +enu +IBCpwl +BzSojdeg +mSPQUTiyVa +ITYCCJqVwm +bhnPeGoJI +Stm +uBq +pjdLdreRrY +ugonPTFcf +Ep +rSpFVqa +N +zbHQtwdO +htnztJEz +i +bYyTZvp +A +T +CPDeGTptms +WnRw +sMGJn +TYtK +ATyCpKofCV +J +Ldy +ZkI +wdJoYAJWP +oufVfrewr +jng +SgYv +HIsVkhNzs +JtbpCwFHg +SOJASwazy +FbSLwThoAL +mJvqka +JYNyMUd +nPSAF +IJchrNnfe +QJaLDGBZ +rzzxwa +AiAbmCFik +PHMwY +iXk +UarXn +jiVZc +CZEuqJo +mzbVIifnd +tVW +i +v +QHBsj +tFb +oZu +RLsx +RBZRFU +IYTai +dTdAkuDwJ +NCHUzk +WHPOAFWR +xKEv +VqsVOYm +RlJA +XhddR +QWmpaNXZoq +OkZpeY +KZQzpku +Lil +GrsZbnDS +q +tD +m +PerO +a +xcyA +xhKvH +spSSrt +HUYvoDq +DKSNuZ +cRNsK +nwdnvtB +eCfUHLoB +geXrYmZq +UcCx +tuXxE +XkzN +mjqNVjq +zyY +hMBYpgxMJl +uZlfIfzuhd +HPyfJ +qO +by +LTbyNdpad +zwjjnsquJx +zUdTcxd +KLPdwwj +gI +dIyVqI +HNUQ +WeYYTZ +BaRGt +uJkokAtQ +NVOSdd +kQ +cjykYLInR +BGsPZ +DiH +GnCTHwCAgB +aSpvx +E +mJPB +NxuLQY +eRwyeUbgl +DhOUziBF +SM +zmEaWFdZN +btbJheLjd +UxDUzP +DWmhMKBq +A +hOlrUhXbxq +yqs +gbmiVDjrN +sPdXpdOK +wgXJvWu +McLbbSlg +iBzPT +nSIpAFi +j +xvog +iePw +jg +pBjJklJK +cC +HWLV +Dlr +yDxyeeYqw +XAoof +EewMpM +gCchyOwqf +vBxS +vir +rfrouO +vKqwqXuJTq +BinSNcv +d +sSrYa +stXdFxnkBb +uQShvF +hmz +bo +nv +DEBpzTh +YiDDTh +VmvXnwzk +XBwdfpU +TtIePJt +mKIDV +GnFEJqQ +TzkBpCqJL +nep +UaVQDGF +tuAyNTweW +gcknfNt +qufY +OlDwINp +BHdqxUaG +FUTxj +kSBiVvE +zBZoweGQVR +tu +upQd +KzAUmgskR +TrmVkgNz +RiKPkVsG +FXQN +hkmKRfDX +M +BpFDJRDbXM +ewh +la +iDH +yFiwjEIiC +TuoduyyN +dypupoVKD +j +LHYBidPsI +UcPHUW +HAxs +ZkiHh +C +n +pGTjM +fJeFG +WzDse +QMOoKU +ObiVY +UpgRxhfzJ +SrFotshP +EygdQYyWUI +VWlGHt +t +XwwmNKuMn +WLfRY +f +OTnvTHT +a +W +Jr +BpaJPSDsQw +SH +LYU +FPrZSTq +zASy +iHRSmj +h +BJqRlMUZVZ +BshZpTbmQ +aiCwQeC +NyzYYrWG +lIElT +RZTvcLP +CoSUhOHyk +lSpb +UepSdMM +ZsTDKdpH +NGPyijs +fcM +LWatmwSyh +KUkTlWD +YHRBxy +pXBDqEp +dEDSjm +s +CMHUdsJPwA +UU +HPcd +hwjnjlv +nqXbdvU +OhgZBqFjd +CiEtGwxGeN +IaNZTQxqS +YSbDYJd +daHvtQMfL +VYrnCpM +B +khZZC +hzdcSmoDJ +cU +JKVwRuii +yVnsPh +HT +PRsflG +VMLzFVIe +LPWJ +GWufa +nhivi +GbMhmZt +MYyVHOSa +QXzziDuT +megDWJBtxn +IOndnmh +PpsxilxOpc +OzzPYPIY +jLoWgXEzy +SFgLjVUGa +zUznjh +nQpdM +GvsMgswZgO +OAOYJnLZLE +CxAoJJ +dKHkBNXKSq +WnvAyGyyl +NItfM +JwWiXSxmsp +eJ +DwJmCGUozA +MgtrE +PfZGHjWuxE +UvKfg +yfaK +UNzybitMI +soXfFTZRUH +M +DXIBYaoY +fnPDjy +PspGwowgwv +Fdx +UHRGFNS +JE +e +byfBrH +qaTplW +elL +BGol +jTmAVF +SbPefw +a +LeTcaToNDG +w +uKjWhmZTgQ +WbqY +BaeGQ +kNulppHCOl +PWAGBIY +PY +ofSPZB +hAgrXcS +O +JYiiO +rlgcjItNE +crXp +Gerdexn +aI +hIjrGMqBg +WzHMnyQ +VqhVRnP +g +RKaXE +WzNLSO +RxeYysBrmh +fAPYuyz +OqlOtVN +RtKfRRvyy +rVoMdyvtG +dQh +bzAJqYbirX +sLkSGKEZD +vWjyuuUokC +mqSMfuADe +IPjYDG +glbzGlHm +ZRpjkmnJYe +iZTMr +NaWAyJFmC +OcCFFQwu +pUxJTNt +YsLxazDoJM +NSDWHmgcD +e +xbQ +nWCpHAMyq +ObvUZF +oyFVhx +SMtbRbv +PV +KLkA +OUnsFlBMrv +cHToHBSH +bhHKAV +VtuAFyFo +YfFKYuJ +ZtzZcfOn +YXIFc +GyFyB +lnIXtvyNa +VtYNKQhgZ +HPiKSjPXy +mGs +zj +j +FjJ +PXszsqlm +pJb +TTL +nBp +UjE +pyqhSTAZRA +sxmUDYlWX +tDmROAXDFj +JQCI +ynvrXtat +cupC +S +M +CiWTeg +dvuwGUeLCn +tyNQhyRYKk +zFU +BXjdW +yKqKa +OEKuNR +jEyGsy +TaDQn +m +OelFqg +dtAii +wnrOuyBybq +WHxEOPhhqQ +ZX +h +cSnPD +XhoIVfuzq +njuumMeK +Mlwh +m +jq +mX +nu +JbKELRil +aVY +vOLQ +uCKmNx +Df +yAWivV +Njnkk +hDeKkHVPOW +Xfr +hWpdTcD +HsZx +PtjgBcR +RrLRLTW +pFrYDaA +KIuw +NJ +YFi +HfVuco +yKTtGjz +iidomAndW +MbbRL +QaradKf +DI +QUTIjLdQPi +IdPdqy +YxMrc +yrdJu +ErP +kIHmDXznw +CSXSd +QeWgiyZNfO +KsOyc +jtQ +uRVSVfxHq +r +cIFyer +Bpq +AGGy +blLoBbfE +Wqju +fcyp +P +YmCK +kygo +Q +hASfyJ +DSZUDeKWRU +Jo +nBQpQRjEz +tU +HDoOYO +XYsKM +Hd +TwBQMGBHvB +bTb +J +PRPX +Exj +ULCuKhtmRF +q +CDX +conJwJBEAw +pIJuyUOdWp +GCCKTq +rPTHxdO +NsYTIhC +pGqekfwmXJ +MqXq +gzyqkvjj +ckNAlTz +dRbD +jQHKV +ikXBFv +BMPgA +sBrcDD +LeLANbgIO +ODLvppUxGM +aGv +YblLZ +OEE +jthAdVtfe +FUrEnXE +zqcSHU +iZLWLKTpu +Abfel +n +tuQxBkv +BiJAtNgx +GLWB +oEwZSUhcSG +LSfXm +FXLvuazb +cjGSgHOb +Pu +JDFjaAZ +nc +AVHOG +xNl +n +yCehf +Hx +m +xbX +eMFp +UNKUVqgosL +rKXX +lTblx +iN +pEZ +bwzbGFaJeH +q +ecmjQbMYI +ingoCd +zPNAfh +Vvbun +evdW +cgxSJjmtqV +VYd +IIWH +NAGcx +AQCQ +MFzmFPB +eDXfTE +uaTA +LJPtT +NWAGl +kqAvVRcU +CEhjvotcL +ZCj +Y +N +ySGuka +yqLnDk +SOVrUOi +gi +HzsEdNgqu +HNadDfEZiO +KyrSG +Qty +NdjC +Bb +NreE +qLJRgXylw +w +GC +jaX +qpBSGsFur +YCFNcaqmvp +fetW +pJZgN +fEUdi +whNBXgU +w +lpCSJ +PxATnTG +mUhdTyCzgn +wNocArxMIa +H +O +TqgwHnYml +GTa +IdwvJ +rzyWkMtbA +CUXCFrc +zcnMmT +c +BxJlghRNnd +fFQ +zVqdcvu +k +IRlHeZVJIi +siiey +jvTxgf +xkbhvCD +eTXzLUQ +t +Mgsfj +QCUGQhTa +RIJUVEby +pzPUBPryYR +ToOBXzr +bMtZkZwoNI +ETbHZCobKN +O +eQCrw +JJbrd +ZWZXKVU +ICNWEoThX +joqPHvFi +KV +NsUmgdAmGF +I +hxTo +jsALLrCy +qCyfguVOs +SVxWgsOQG +Qi +Kcz +rGro +vzMiksvcS +NrBwuKjuqD +g +dfKlBs +cFIjS +WZwxkgXnt +ksy +OWi +drLk +BZvTrOu +NdGP +aKHXZ +VeNwCPV +yxizrVUsP +EIItoYv +ev +GvNXr +IU +LFBep +PUJyEtaBY +R +tBjQx +XlSbVPEShU +gN +LgM +XNqtq +NL +iOvSxWILvs +Ca +OhuxCL +qNOSnmZ +hUNnN +GTFr +xopoq +yV +vRIXhatNzE +xprbrgwSB +UEVkVBUW +u +zypA +WxCNJqiRFa +PhL +CFjXQLuC +XAtCSe +UQknlvqfM +vmCz +tvplKpnf +McI +FyEQuynvzC +PZDP +NCEMfujfB +hTALw +VaAFnzF +HU +T +v +wphmlN +Zq +fcFc +BZiwH +VRYDCYIQF +YYN +MKc +OFV +NJMmKSElm +xjOrlQCRGH +MNZGdM +gXTT +M +nd +nLutWtuEC +C +vIIebqM +izsd +I +Hg +ZRqgYpYqnm +ynwKxfjsoh +jsX +v +BxqBUcBd +s +mdUvwtBZ +Txm +dt +wiZDcRFWHo +Sp +dMUbYc +NzTEQlFj +Yqb +Vn +yT +sQHNY +Yj +SnVVeXWn +ZCdNkSY +hbeVzfO +l +fRJ +tNjJ +dFcpirjVmZ +cQvmr +RV +U +gRgBpr +xbYxWRnfH +dra +H +uTMDSAtp +Q +d +Ag +fKbO +CDtmJ +wbdrSFV +RHmva +l +xfTzGT +i +quigVIGfAf +DYmKPWqgEK +HJ +BQJtHpK +KP +Yn +nsAzU +jlpNxf +qxsto +QNgJPvBG +eIBCri +jBOPAdhb +hiJZ +QolmNSO +c +SqTPkNBxq +OPrkI +S +Ofza +xTdPgbA +HBsNaX +nF +yUAJD +NUQwwnRLw +H +AKuXcw +vJW +qcOCHnUbZ +fujAPf +Si +hcAbySFLfS +RjriiBUbfA +wTZFtXDFfY +LEJPOmfWGX +GGGr +Qhi +MFIluAyRV +FqObjoTSC +bUMClokS +n +bxDgBi +kDB +tkXH +anlKQtT +vCIG +TEDf +YgonyE +RZYTXgtdtQ +XvRAOFq +v +QRsm +dGjU +ncQxo +oZtXcLm +im +FCTgz +tqkMDLiaZi +MU +kOpvwgdNdi +rgSzak +sKtgeBVMbV +TfPrFJwuR +AUv +GiCkjgVZI +eNqpcvkKH +yzF +OueFi +BtqfIJh +fSq +nPedmp +PJnOzT +qS +T +ZwdDgq +DhtK +CfaXZaXlA +Kvmr +kKPreMwDy +ByfKETd +Aa +RcQccVW +V +opKGE +bpzDAVmPg +TCe +UFV +j +bkrf +FFSvYWwr +EvEvcptQ +ZZqsC +vfjJwbiGF +sKzPOwWstD +thfcZthWs +GBeUqm +mujBlIZOSj +BZdW +c +eeBDC +lGXm +tRBjSMtnZt +WbObqVJ +KJoEDQDe +BOHd +CELIyzo +qUnAhlBy +PSl +bq +ygaAnyBqN +mlsoEzIOS +rzaSsV +kVwwKGyHx +StgIRJq +W +p +iXeUzQP +c +Ji +VwUWZTZc +wv +zmGMYWe +LKrt +tE +lrLcb +AJkypgNZx +O +loHlyRkFRE +tvHiDxag +w +r +wW +UOzNUvhhH +hYVzWVB +hIxZff +z +TW +vEsR +TJ +Hybx +GOkHbMaf +uWBHwHKFeN +Mw +Pr +rRbTuLqLSz +MeVlDTckc +mi +HyyKG +PBzi +cwF +NdnwhDy +LpX +ryG +a +u +u +ydknq +mDsG +fwOmiEzPz +Wa +umE +c +zbhZl +BCbKLXmn +lbHAoe +GlFssQV +HxluxsV +bMdTm +RhQavG +zXhBXveqV +mmKIZTWM +Tkc +Z +qqyhTDAgu +WwLFCdjbQa +kEZGGxLnFN +slp +Vupyo +aFH +eyArYXjer +bsyZVNAX +vzXSEcLjr +jVZAc +KjjaO +IzwnPQQlI +q +ybdq +HRjQhJggbx +bbaZSijw +oJuSS +enYIJyBpTb +eHdQG +XVcyaQz +UJj +OAQtBnhZU +FKUiqti +YJChu +qJJ +GFnUZAv +PUxrQklTot +JjwyfZ +gdTZIUYZm +FF +HOam +hRUtvyVHAh +LnjMlf +IExGUmB +Hb +B +wRPnsxuUoX +tpdeve +hCRrOLP +lCV +cvVq +wTcoW +t +zNr +aINfevAHJb +Hlw +SIFGzC +plso +ywODl +RmtAEvTsmC +qwZBk +syjXOwViKb +UwYcCATq +jTlVoUSe +KCyp +MxvHoBwv +rkDHapu +hzaXt +QxBOJNGs +JsbnjClz +ys +WXmBrgj +Vyfg +Q +HUiXzjCy +MdG +G +xGNbnw +MQAm +ik +lHRBY +vBJbK +YGXiB +rDtR +nMgmrnQ +yCfhVKUj +KiP +imJn +eNwMhNKPL +sptlWAsiA +YOTweT +bOMedYqM +qHtpazeq +F +KOnqJ +Qn +KV +lDM +rvCWmtGxF +mYrNeNyyc +ku +riWMA +mfapuVCD +VQSAFCW +GNVGvu +axBEEvro +SWH +KvoLJqY +hALS +MVnn +LxPvBOw +oYLSNJB +hO +B +ttdSxBzobD +xzYbdudmk +hEHExAtNq +PIRokKRjl +aKexosfql +FGOkCXuhjn +BD +u +ZLn +HvKe +J +nrGE +piKkDRoYP +FTIw +NEarPHIDF +GxGsUOLHNx +yaU +I +Q +GUTKnDnC +aGsrUPMXQ +Qpgt +nDcVvzjTa +LpDCHMqJ +C +BRapkAr +AReokHnc +HtcA +hGwIzDO +JxLs +E +gJyBH +lqpYhnsyf +erZk +uOrvGCBa +nfnQkANu +hnTXgGS +cwDVAIjeTG +mfZly +iAwYWs +ihni +FSxtUkKF +LNq +YmfCLJkOz +qQ +ZCRaKsbI +FM +jtVN +Vf +czISVYdra +DMLF +vi +sZjpAG +TEmoEeEnK +akkXlm +idg +MkdQ +IO +NfwINnTUr +jM +VlGZso +CttV +pclswqZ +cVfWMBcnwY +AcaOqWSXW +eTWtgD +qvlJjyb +vbkpzRYmd +SnO +hUd +SQpp +jzJVtHI +KK +kGpFHTnZ +MVOVFq +qOAH +cJMQxNHyYk +uuvoRCyZ +Zl +ebFIK +Wx +mWnXcBMtt +mafTJ +vEVYIFICD +yKQnZK +MkVNFZIsTc +BKZNfH +BzMAFHnrDn +tQS +eDej +WyH +QulvJLp +JyFdjKY +NgosqqBu +pXL +EpcMQmXNra +EMhuU +lvsV +MjjLYv +ZAtEIeUiA +WhcU +uujhkNmTe +t +qbdna +lYZPAdKQu +XtNcnkL +VVajGGfPDf +NvJF +eizUHb +vfGjCRkKK +HKar +kqljHC +uV +BfiObGJ +pRu +Ilj +izxT +xAfpc +NrfmId +lXz +AuqnoW +a +hQ +eAgxfWUUOk +LlHS +BOIENxI +SJEFVjDhN +k +GiqOw +qaT +xGBqoUS +FWO +JToBZdnJ +QpA +BdCWFOvuNZ +OVwpjk +mJUAI +pdXMcXr +lvRO +RAggQ +Qbc +eXRKESITlt +tUtDsjMqgK +qSjutenUa +RVbN +BjQbLHrz +Km +RDzPbmg +x +MZObMciMCE +NWoWN +olouedJ +VyqVF +do +MeXAp +VovmlWbC +LDOJ +us +sTMpwpA +Ml +KlQ +LEjzNJYdj +zrW +B +FTOrgviSRF +ZdwF +Z +AB +DVak +VjSEXuF +T +eXhcUXgKC +RbpGtkhuj +JREIBMzBT +x +kCjdGlA +rbx +tzScw +ofwaSXfd +gQ +Sqzp +qEcyo +whDLlI +ltfsxQ +i +sBuxtgyvhR +HD +xRZsUZ +GJLKhX +QrzafF +UZQbPqK +noBWX +CfPOj +h +wj +CjjSq +smlAPj +AS +dxRY +wWcQEm +oEIyVWxn +ZQzaBTpgrV +ukxcLTch +bNBM +XRE +iciuuiwS +BK +sjCVN +oyLuawyBJ +kmniWyNNxd +PXjXYh +DxBeMwGll +Nwa +r +iZQZL +zGZdy +NQGMwPF +lgI +y +SvIat +tFdhRirB +kejoYzMoZC +dqfFB +vJ +gL +zByQpyZJt +Fan +vjFupg +UNzT +AQGRtesrMT +uoYTT +i +UqOIvc +e +wFHF +SwJ +BFD +KOpTzpowD +h +GlFHUNGgcF +qdXRs +ynQKfuJ +P +IK +xaMkklJL +QT +C +xKTF +FXoKb +yBEejIok +VypoelJy +zE +LoHwMW +ZQCzEP +iIt +FEjTMQJXd +OM +q +ddHR +Hcf +lF +gtzGRgJfBg +xY +VMAieupN +cXZUZzjy +TYNuUVU +xMSMWaBDv +qfbTykP +ccmXm +a +AWB +L +Fwr +qQp +cnDRQrfkQ +jpgwoX +IDpz +FpSqwqxPgd +jZBv +vXOQOADwQ +UVwNTmYCTV +mb +YB +t +o +DvqsQa +hdfshDL +yIjWX +hpr +GcRtBHGm +RODQbjMbn +owoYqS +aoXRJBhN +IblNxUmw +CD +vgUhk +ihQZF +rS +ogQTpOdth +g +MaXeOH +TP +rJNCC +rFzVfjgXZ +Vr +PaynxZiv +XLu +Ji +fKSe +XkaC +vxKYIQK +AdeBxp +eFFBsx +jqpxF +uhvt +Z +ekCqiFa +KboxhZSSf +eal +xjejldNaO +kMmYwaUJ +eETHZGqf +kVoJzHq +Wpuijj +qVXIxHnBpL +STphtCE +AkgMOkE +JpqeOpn +ZqlMxTy +dkSnfe +xdt +MMGQY +G +VyRCsjs +aufPuMiYMr +goXAMdz +L +niAnu +cenREbdVI +WQu +OXbgz +bOoThuzOaf +fBmW +QBoc +Q +IoHqsfkKX +wjdhJlHa +CcAGA +lZkxCDYJn +eSEPotmjw +LMhMYlVRcz +B +zNKnIPOrgN +Y +CyeNqCW +sPKzFNXwsb +ljjC +WJVf +hBU +iOc +OmvPWV +tx +ZrBzf +xvpuj +kOaxLh +ftmpTZ +IS +MfLnqTJJ +JEdmKVJP +ETFOBGd +cHpf +vB +spNO +ZZqVHpHdsN +ubqKOUcb +eX +ssvuQiaNb +XS +RgVw +LVlESZL +X +xZTNNzY +tYhObTwR +tPPaJ +Dj +amsx +DuPwNLJIH +KC +HCMQn +wAGhWpvj +yIwuJ +zH +VqAFf +Oe +VwDFDrQh +zMamXR +bcyfHyXmp +YHKN +a +stmtKcOtc +Ji +mwPcfO +XV +mzEDSOgq +lIOBZlDOb +rBvxpozyXw +ncmTMaIT +EwodsV +GV +GlihHPbk +DdmbA +ViLMNIdr +BllHBR +SLXqvK +ILVbDdV +GahU +GuaPcQ +tfBCvFFowN +SLO +b +i +AGNSQXjf +MHN +OAywfZl +ik +SDLEmM +gAxbp +zGfvYVOj +BahV +kDULvOYcbC +SvcBXzo +wqt +PxhfPJlw +ie +QCoXOucu +uycWN +SCKGgZ +pdgKvHcHKP +i +EMjOG +tvxP +AbIWGiQ +ebxdcRao +KLDGxVg +nrJ +hIs +gjusAfR +nUh +fXBoWK +kmmbtHpE +uRxCLaUPdY +LF +PXuwdbzc +ynSM +IrkngXj +RUZsk +SckZPUbBsO +RiTGBcw +m +cFhq +odlJp +qwLmK +UgDBiObT +kFn +AT +L +iDtp +evvI +LaSUyn +tFYidcfKrC +i +TYhTmlyCr +REtUj +KaBvGC +ErvVJX +sQGzxRmj +vQi +qnokgWXUF +mokYyOqVg +R +cOYJMbStu +hCcuSVjMn +g +G +RJQLP +aU +YelKXbDYCK +YRlwxi +l +L +ZWjYIvj +IEkISCVA +aPmnpD +zKKixpSBBv +T +EwOoT +ALP +iyf +Mn +mEwGXPdaOt +f +USzrI +G +lXMnlPEU +fHgeXEESD +obxwNooCCy +bz +yNUoFyhx +hQ +rHjwPBAPYV +vbfUQ +RgtapNFMM +vTlk +Fern +grBkeSy +hFCsGgV +sk +AALYZdqIf +GjZOssEeF +nn +Zt +ZqaUCZ +izuhb +iLu +NYPOzjkC +krRxcn +nhPJxvFatf +zHWQTq +ScqUlO +dB +lVkEc +b +UE +XTFBWpTx +ZVfsZdrdy +ixMjGlWS +rSdSf +NEXZqxc +EW +kugEKow +E +IkWwMkUHrY +r +kOOywPGHtu +vV +UDhSHpTnSD +roYQoUVgE +qPipS +PJeTN +CYXu +LJVQw +gtT +QZiRHeb +NAwdQDBvl +jQ +OGTHANlwFv +VUqYGlHEIo +MQexaafO +NK +A +bRwuUP +qrL +gBiYQaGdNY +dZhhBKt +rgEJujlM +PCJQSVffU +gWKGVyrKG +NOASsXoZi +tYI +edofF +aU +exkaqEMv +pBVOjx +Kr +VN +CDqpIYg +tqgJHX +rDGHGnKqF +HlITxDBkf +y +nY +O +DQNfUnG +iHJYrHOxBD +MtUW +ohyKrEbRvN +fhHmfit +bvMdFaRZFu +FfXpJmu +ClZYuH +nSBaZf +QSIqOue +eK +OqQOt +hKZKIeRnja +RAnLGnUTui +VwmAfl +ZBC +cBh +MQ +KbKLBHX +wS +DnLc +muQCLa +cVYZzNHOf +aqtMnHyE +aVvyzNyq +KlVCCdzfw +qdxvRNUVeg +qmLsm +x +xKrD +HIgxmE +MKDrF +fkkp +ulgKmRQUwW +GlDBV +EE +swcrSAKHe +vnWKSPbKW +lFAdSlBeN +UOOtSU +Yb +OnJJpbk +K +Gjkkt +FfOygOGqa +lcNgSVjg +ryK +FRc +EwXhyKejeq +jMUBgYswyB +kLPPgP +MHGJ +KpCQOpt +sA +umW +HNpIjlAA +Q +gNh +ZJjnIZ +IGnRFpjLd +R +E +Qox +DkBOomfj +zlzOr +KpDvVbi +AjYPCyWe +rfrNApNZnL +buA +wMWZEwSTK +eXv +MyJQAxZFZ +aqZQU +HSwwpRpmnO +xlXgh +cqFg +sbpQp +BPUQRC +dq +PJ +Q +Le +WqgQcl +zCuuI +PbGLUnw +wzj +yITgDspg +IKyndzU +EcoHDAZ +OIR +L +baX +MgxG +q +g +fFXTVsufdc +EC +TZRfTQo +w +OQxbdO +RirxDX +kWeHCLj +Dna +CSPKkVQ +NktgbTno +YzVznDXSZ +MTgZlohT +MS +GRiqutxH +xMaUAEiDi +r +PELKw +NOnYpIe +uTuclL +lJXfyhkIvz +vyCOpDJrN +tDEIcKtg +tqRJhuv +Vj +RyEQe +GX +GUffOxd +cafpwZEnV +ioQfNeSQL +iNiom +JyIrlxjfI +YdH +USKJF +tgrZeESLeH +DUnzjMf +WkUXXhGz +jgnqfkRf +HdPOKxbfLq +b +KHSKMD +zKCIsabKQ +vAdgpMawN +lnrY +WhwP +jx +F +XnQwxr +CgCNHewiqx +ZAJncXik +QHywBKc +VvyFgKbPp +TZJL +iYxAaQyrb +dBujwDNOZn +dczk +z +jjz +TY +vAg +Q +uCCFaIWD +kXTP +I +qD +reUNq +Drcnrn +KgHNo +kh +LJf +NI +kGzmKy +fuSImUCXwc +oQM +jzjJoPPo +VqpuG +Qtck +xayX +CLUk +yHM +PyYu +OQcsepg +DdC +XXIXoLE +RwbsrUO +zsl +gbHl +kWTElJ +oSbRor +zcTbAk +ZYmYnaRrQ +ZRcp +Szobd +DVowIUIBQf +hbhvB +IlFmGOCEEn +dlUPde +ZQ +qZxWyFwvEq +CDPrej +fqEMsIKlEp +CUSZJ +FR +rjKeOckLhl +dOmTYS +jthrH +vHhpLxVeh +Eq +eCo +IRKmDKxQm +oSYEKUnb +Sq +qIErlL +QesWF +yFtUy +QL +jpecU +UvufvOQA +uDrkCH +sa +eK +d +kleRKEcU +yBLocTwXy +eOlvSGr +fZZT +FYTuj +wJemojRav +xgJ +XLWOp +CLpoxkE +dDxN +UdgzEbfAD +cFnfnsLqQc +cY +k +ICWpcTjbug +aqLsotS +u +TBgmXWKM +Nk +BS +oxwBhSbzsL +DAWsiWrZ +dybpFcvT +C +y +zNSGQH +aEIgFYDnK +VnUe +vpEFQA +P +RNPbjI +ZWDZQTz +BvhjKXl +EpNf +pDzL +DMkREr +zkTc +g +MiQ +qafVhGIYLQ +VuBodzFFN +SnCbpUj +FZWJQ +mdDagJqa +qKtWPosyrV +IF +AXTvzcHMfo +e +yglMpyFUv +QW +IWzjOLf +BVy +WYBx +DPr +XpsluBozL +lU +Dwnjdnr +Wrk +CPDM +siNuynOWfA +PPItAue +hQEKLQasB +BVulY +Ywfd +TzTggWf +pl +N +kuAsgSexu +vQYPvWtiyH +VlgvEPbm +CGWqFadj +SOMtTbIDDP +IjexV +e +RnkvLdf +WERla +oQTeymG +qAkXLkDWRi +HIqtYrkksp +Y +lAfbZG +NTUNy +GjW +mYd +UaOxWC +dq +q +IhX +dLMvO +wmaQFLE +akaEICQv +hEyUrpA +FTE +sdpzSU +KjUKtNtF +frnULrs +Undtu +WjFMAriPOr +g +qE +Ldz +uIqcPVl +Gf +tusnbSi +tWjj +kWEXInxLcU +afGw +z +slOkGzw +BXs +IK +i +AaskxE +nE +yhVa +WszX +wDsR +sHgQUp +Ui +ygr +YGw +B +UsxcjpSfDy +iNYid +pkyBB +IHnFG +Jhnr +k +Ddxaz +EJMbtDtMI +IDFJjqERr +oAeOLEgi +rPnNB +e +vnng +Pt +kq +lQwn +brLEWMGNls +Qk +q +Ylfyrt +djOLdbPhD +dv +UEFieYmAN +zzF +qbWwtHRF +oydBK +mr +CWpP +mkQzli +MXTK +NoQPBf +LuoNaoqOM +vUSifwgNHG +O +yJSKkn +jQtwyv +tyj +obFItkt +ANivUYETfA +teOXEAaBzE +ChgLrSiTW +zfV +QgPwbwljs +WwJVMVOdsE +uv +QiIntmdzK +qZy +FYOdDA +lqYfXfvLD +Yjgb +TWT +iOZuVQ +feAR +DszlqMp +N +DMhX +DHDQQO +RXycA +FCa +yWAAXePOZ +l +rYU +DYZrhyYWh +AUEVQTVlG +q +m +dcB diff --git a/java-basic/learn-source-jdk7/pom.xml b/java-basic/learn-source-jdk7/pom.xml new file mode 100644 index 00000000..39251272 --- /dev/null +++ b/java-basic/learn-source-jdk7/pom.xml @@ -0,0 +1,18 @@ + + + + 4.0.0 + cn.lastwhisper + learn-source-jdk7 + 1.0-SNAPSHOT + + + + junit + junit + 4.13 + + + \ No newline at end of file diff --git a/java-basic/learn-source-jdk7/src/main/java/cn/lastwhisper/learn7/util/collection/HashMap7MultiThread.java b/java-basic/learn-source-jdk7/src/main/java/cn/lastwhisper/learn7/util/collection/HashMap7MultiThread.java new file mode 100644 index 00000000..6c2ac43a --- /dev/null +++ b/java-basic/learn-source-jdk7/src/main/java/cn/lastwhisper/learn7/util/collection/HashMap7MultiThread.java @@ -0,0 +1,53 @@ +package cn.lastwhisper.learn7.util.collection; + +import java.util.HashMap; +import java.util.concurrent.CountDownLatch; + +/** + * HashMap 在多线程环境成环 + * @author lastwhisper + * @date 2020/4/14 + */ +public class HashMap7MultiThread { + + // 多线程共享的HashMap + static HashMap shareMap = new HashMap<>(); + + static class AddTask implements Runnable { + int start = 0; + CountDownLatch latch; + + public AddTask(int start, CountDownLatch latch) { + this.start = start; + this.latch = latch; + } + + @Override + public void run() { + try { + for (int i = start; i < 100000; i += 2) { + shareMap.put(Integer.toString(i), Integer.toBinaryString(i)); + } + } finally { + latch.countDown(); + } + } + } + + public static void main(String[] args) throws InterruptedException { + CountDownLatch latch = new CountDownLatch(2); + + Thread t1 = new Thread(new AddTask(0, latch)); + Thread t2 = new Thread(new AddTask(1, latch)); + t1.start(); + t2.start(); + + try { + latch.await(); + System.out.println(shareMap.size()); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + +} diff --git a/java-basic/learn-source-jdk7/src/main/java/cn/lastwhisper/learn7/util/collection/HashMap7Test.java b/java-basic/learn-source-jdk7/src/main/java/cn/lastwhisper/learn7/util/collection/HashMap7Test.java new file mode 100644 index 00000000..d90308e7 --- /dev/null +++ b/java-basic/learn-source-jdk7/src/main/java/cn/lastwhisper/learn7/util/collection/HashMap7Test.java @@ -0,0 +1,118 @@ +package cn.lastwhisper.learn7.util.collection; + +import org.junit.Test; + +import java.util.HashMap; + +/** + * + * @author lastwhisper + * @date 2020/3/26 + */ +public class HashMap7Test { + + /* + * 一、重要参数 + * 1.DEFAULT_INITIAL_CAPACITY = 16 默认哈希表的容量 + * 2.DEFAULT_LOAD_FACTOR = 0.75f 默认负载因子 + * 3.loadFactor 自定义负载因子(一般不会指定,默认0.75f,用来算threshold) + * 4.size k-v对的数量 + * 5.threshold 阈值,addEntry方法中size>=threshold&&null != table[K的Hash索引]时,哈希表将会扩容。 + * + * 二、Hash索引:int index = hash(K) % Array.length ===> HashMap的策略HashCode(K) & (Array.length-1) + * 三、Hash冲突:开放寻址法、拉链法===> HashMap的策略 拉链法 + * 四、为什么数组的大小是2^n? + * (1)加快哈希计算 + * (2)减少哈希冲突 + * n 为 2 的整数次幂,这样 n-1 后之前为 1 的位后面全是 1,这样就能保证 (n-1) & hash 后相应的位数既可能是 0 又可能是 1, + * 这取决于 hash 的值,这样能保证散列的均匀,同时与运算效率高如果 n 不是 2 的整数次幂,会造成更多的 hash 冲突 + * 五、hash(K)扰动函数的原理? + * JDK 源码中 HashMap 的 hash 方法原理是什么? - 胖君的回答 - 知乎 + * https://www.zhihu.com/question/20733617/answer/111577937 + * 六、inflateTable()函数计算threshold的值,inflateTable()会被Map参数构造函数和put()函数调用,计算规则: + * (1)threshold初始化,有三种情况: + * (a)HashMap 无参构造函数,threshold=DEFAULT_INITIAL_CAPACITY + * (b)HashMap initialCapacity参数构造函数,threshold=initialCapacity + * (c)HashMap Map参数构造函数,threshold=Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1, + * DEFAULT_INITIAL_CAPACITY) + * (2)int capacity = roundUpToPowerOf2(threshold),找大于或等于threshold的2的幂次,capacity将作为HashMap内数组的容量 + * (3)threshold = capacity * loadFactor,threshold值确定 + * + * 七、初始化容量:initialCapacity=expectSize / 0.75f + 1.0f + * 比如,需要在HashMap中存储27个K-V。 + * (1)错误:设置initialCapacity=27,capacity=32,threshold=24=32*0.75=capacity*loadFactor + * 当你连续存储到满了24个以后,再存入第25个K-V的时候,size=24>=threshold=24,有可能触发扩容。 + * (2)正确:设置initialCapacity=37=27 / 0.75f + 1.0f,capacity=64,threshold=48=64*0.75=capacity*loadFactor + * 当你连续存储到满了24个以后,再存入第25个K-V的时候,size=24=threshold=12,有可能触发扩容。 + * 八、put(): + * (1)K=null单独处理,存入数组下标0的位置 + * (2)hash(K)存在&&K存在(内存地址相同||equals),覆盖值 + * 前两种情况不会触发扩容 + * (3)K不为前两种情况,满足(size >= threshold) && (null != table[K的Hash索引]) + * 触发扩容 + * 九、resize()与transfer():put(addEntry)和putAll时会调用 + * resize()会创建原数组容量两倍的新数组,transfer()负责将老数组的链表转移到新数组 + * transfer()步骤: + * 遍历该链表中的结点e,重复1、2、3、4步骤 + * (1)暂存Entry next = e.next + * (2)rehash(数组长度变了,需要重新计算hash,找到在新数组的位置)找到e在新数组的位置newTable[i],将e.next指向newTable[i] + * (3)将新数组位置替换成e, newTable[i] = e,完成头插法 + * (4)e = next; + * 十、并发读写成环或丢数据 + * + * https://blog.csdn.net/Lammonpeter/article/details/104271481 + * http://www.imooc.com/article/292265 + * https://zhuanlan.zhihu.com/p/96426441 + * + * + */ + + // 一个可能要扩容的HashMap + HashMap possibleResizeMap = new HashMap() {{ + this.put("1", "1"); + this.put("2", "2"); + this.put("3", "3"); + this.put("4", "4"); + this.put("5", "5"); + this.put("6", "6"); + this.put("7", "7"); + this.put("8", "8"); + this.put("9", "9"); + this.put("10", "10"); + this.put("11", "11"); + this.put("12", "12"); + /*--------------不扩容------------*/ + // size=12 >= threshold=12满足,但是null != table[bucketIndex]不满足 + this.put("13", "13"); + this.put("14", "14"); + + }}; + + @Test + public void testHashCode() { + + } + + @Test + public void testRepetitionK() { + possibleResizeMap.put("1", "1"); + } + + @Test + public void testResize() { + /*--------------扩容------------*/ + // size=14 >= threshold=12满足,同时null != table[bucketIndex]满足 + possibleResizeMap.put("15", "15"); + } + + @Test + public void testGet() { + possibleResizeMap.get(null); + possibleResizeMap.get("14"); + possibleResizeMap.get("15"); + } + + +} diff --git a/java-basic/learn-source-jdk8/READMD.md b/java-basic/learn-source-jdk8/READMD.md new file mode 100644 index 00000000..c1cfc4ca --- /dev/null +++ b/java-basic/learn-source-jdk8/READMD.md @@ -0,0 +1,3 @@ +# jdk1.8.0_241环境下 + + diff --git a/java-basic/learn-source-jdk8/pom.xml b/java-basic/learn-source-jdk8/pom.xml new file mode 100644 index 00000000..3de1810f --- /dev/null +++ b/java-basic/learn-source-jdk8/pom.xml @@ -0,0 +1,121 @@ + + + + 4.0.0 + cn.lastwhisper + learn-source-jdk8 + 1.0-SNAPSHOT + + + 1.8 + 4.3.5.RELEASE + + + + + + org.projectlombok + lombok + 1.18.24 + + + + org.apache.commons + commons-lang3 + 3.4 + + + + com.alibaba + fastjson + 1.2.47 + + + + + org.slf4j + slf4j-api + 1.7.9 + + + ch.qos.logback + logback-core + 1.2.3 + + + ch.qos.logback + logback-classic + 1.2.3 + + + + + junit + junit + 4.12 + + + + com.google.guava + guava + 23.0 + + + + commons-collections + commons-collections + 3.2.2 + + + + + org.springframework + spring-core + ${spring-version} + + + org.springframework + spring-beans + ${spring-version} + + + org.springframework + spring-aop + ${spring-version} + + + org.springframework + spring-context + ${spring-version} + + + org.springframework + spring-context-support + ${spring-version} + + + + org.springframework + spring-tx + 4.3.17.RELEASE + + + + + + org.springframework.boot + spring-boot-starter-web + 1.5.8.RELEASE + + + org.codehaus.groovy + groovy-all + 2.4.15 + compile + + + + + \ No newline at end of file diff --git a/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/common/ReflectUtils.java b/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/common/ReflectUtils.java new file mode 100644 index 00000000..53fdca24 --- /dev/null +++ b/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/common/ReflectUtils.java @@ -0,0 +1,54 @@ +package cn.lastwhisper.learn8.common; + +import java.lang.reflect.Field; + +public class ReflectUtils { + + public static Field getField(Object target, String fieldName) { + if (target == null) { + return null; + } + if ("".equals(fieldName)) { + return null; + } + Field field = null; + Class clazz = target.getClass(); + for (; clazz != Object.class; clazz = clazz.getSuperclass()) { + try { + field = clazz.getDeclaredField(fieldName); + field.setAccessible(true); + return field; + } catch (Exception e) { + + } + } + return null; + } + + /** + * 通过字段名从对象或对象的父类中得到字段的值 + * @param target 对象实例 + * @param fieldName 字段名 + * @return 字段对应的值 + */ + public static Object getValue(Object target, String fieldName) { + Object obj = null; + try { + obj = getField(target, fieldName).get(target); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + return obj; + + } + + public static void setValue(Object target, String fieldName, Object value) { + try { + Field field = getField(target, fieldName); + field.set(target,value); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + + } +} diff --git a/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/lang/LongTest.java b/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/lang/LongTest.java new file mode 100644 index 00000000..bb94cd38 --- /dev/null +++ b/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/lang/LongTest.java @@ -0,0 +1,56 @@ +package cn.lastwhisper.learn8.lang; + +import lombok.extern.slf4j.Slf4j; +import org.junit.Test; + +/** + * Long + * @author lastwhisper + * @date 2020/4/12 + */ +@Slf4j +public class LongTest { + + /** + * Long常量池 + */ + @Test + public void testLongCache() { + Long.valueOf(128); + Long.valueOf(129); + + Long.parseLong("128"); + Long.valueOf("128"); + } + + + @Test + public void testParse() throws InterruptedException { + log.info("----"); + Thread.sleep(1000L); + String s = "100"; + int valueOf = 0; + int parseLong = 0; + for (int j = 0; j < 100; j++) { + long beginTime = System.currentTimeMillis(); + for (int i = 0; i < 1000; i++) { + Long.valueOf(s); + } + long valueOfTime = System.currentTimeMillis() - beginTime; + long beginTime1 = System.currentTimeMillis(); + for (int i = 0; i < 1000; i++) { + Long.parseLong(s); + } + long parseLongTime = System.currentTimeMillis() - beginTime1; + + if (valueOfTime > parseLongTime) { + valueOf++; + } else { + parseLong++; + } + } + System.out.println("valueOf 累计" + valueOf); + System.out.println("parseLong 累计" + parseLong); + + } +} diff --git a/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/lang/StringTest.java b/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/lang/StringTest.java new file mode 100644 index 00000000..3c361f9f --- /dev/null +++ b/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/lang/StringTest.java @@ -0,0 +1,130 @@ +package cn.lastwhisper.learn8.lang; + +import cn.lastwhisper.learn8.common.ReflectUtils; +import com.alibaba.fastjson.JSON; +import com.google.common.base.Joiner; +import com.google.common.base.Splitter; +import com.google.common.collect.Lists; +import lombok.extern.slf4j.Slf4j; +import org.junit.Assert; +import org.junit.Test; + +import java.io.UnsupportedEncodingException; +import java.util.List; + +/** + * 学习String + * @author lastwhisper + * @date 2020/3/30 + */ +@Slf4j +public class StringTest { + + @Test + public void testValue(){ + String str = "hello world"; + // 拿到 string 里面的数组 + char[] value = (char[]) ReflectUtils.getValue(str,"value"); + log.info("修改之前{}", value); + ReflectUtils.setValue(str,"value","hello java".toCharArray()); + log.info("修改之后{}", str); + } + + /** + * String 不变性 + */ + @Test + public void testFinal() { + String s = "hello"; + s = "world"; + + String str = "hello world !!"; + // 这种写法是替换不掉的,必须接受 replace 方法返回的参数才行,这样才行:str = str.replace("l","dd"); + str.replace("l", "dd"); + } + + /** + * String decode + */ + @Test + public void testGibberish() throws UnsupportedEncodingException { + String str = "nihao 你好 喬亂"; + byte[] bytes = str.getBytes("ISO-8859-1"); + String s2 = new String(bytes, "ISO-8859-1"); + log.info(s2); + } + + /** + * String 相等判断 + */ + @Test + public void testEquals() { + String s1 = "A"; + String s2 = new String("A"); + String s3 = new String("a"); + Assert.assertTrue(s1.equals(s2)); + Assert.assertTrue(s1.equalsIgnoreCase(s3)); + } + + /** + * String 替换、删除 + * replace 并不只是替换一个,是替换所有匹配到的字符或字符串 + * replaceAll 替换所有,并支持正则 + */ + @Test + public void testReplace() { + String str = "hello word !!"; + log.info("替换之前 :{}", str); + str = str.replace('l', 'd'); + log.info("替换所有字符 :{}", str); + str = str.replaceAll("d", "l"); + log.info("替换全部 :{}", str); + str = str.replaceFirst("l", ""); + log.info("替换第一个 l :{}", str); + } + + /** + * String 拆分和合并 + */ + @Test + public void testSplit() { + String s = "boo:and:foo"; + log.info("s.split(\":\") 结果:{}", JSON.toJSONString(s.split(":"))); + log.info("s.split(\":\",2) 结果:{}", JSON.toJSONString(s.split(":", 2))); + log.info("s.split(\":\",5) 结果:{}", JSON.toJSONString(s.split(":", 5))); + log.info("s.split(\":\",-2) 结果:{}", JSON.toJSONString(s.split(":", -2))); + log.info("s.split(\"o\") 结果:{}", JSON.toJSONString(s.split("o"))); + log.info("s.split(\"o\",2) 结果:{}", JSON.toJSONString(s.split("o", 2))); + + String a1 = ",a, , b c ,"; + log.info("a.split(\",\") 结果:{}", JSON.toJSONString(a1.split(","))); + + List list = Splitter.on(',') + .trimResults()// 去掉空格 + .omitEmptyStrings()// 去掉空值 + .splitToList(a1); + log.info("Guava 去掉空格的分割方法:{}", JSON.toJSONString(list)); + } + + /** + * String 拆分和合并 + */ + @Test + public void testJoin() { + String s = "hello"; + String s1 = "china"; + log.info("String join api 一个字符串:{}", String.join(",", s1)); + log.info("String join api 不能join多个字符串:{}", String.join(",", s1).join(",", "null")); + + // 依次 join 多个字符串 + Joiner joiner = Joiner.on(",").skipNulls(); + String result = joiner.join("hello", null, "china"); + log.info("Guava join api 多个字符串:{}", result); + + List list = Lists.newArrayList("hello", "china", null); + log.info("Guava join api 自动删除 list 中空值:{}", joiner.join(list)); + + log.info("String join api 不删除 list 中空值:{}", String.join(",", list)); + } + +} diff --git a/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/lang/thread/ThreadTest.java b/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/lang/thread/ThreadTest.java new file mode 100644 index 00000000..4248e924 --- /dev/null +++ b/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/lang/thread/ThreadTest.java @@ -0,0 +1,11 @@ +package cn.lastwhisper.learn8.lang.thread; + +/** + * Thread + * @author lastwhisper + * @date 2020/4/18 + */ +public class ThreadTest { + + +} diff --git a/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/util/ArraysTest.java b/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/util/ArraysTest.java new file mode 100644 index 00000000..030a6792 --- /dev/null +++ b/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/util/ArraysTest.java @@ -0,0 +1,87 @@ +package cn.lastwhisper.learn8.util; + +import com.alibaba.fastjson.JSON; +import com.google.common.collect.ImmutableList; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.junit.Test; + +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; + +/** + * Arrays + * @author lastwhisper + * @date 2020/4/12 + */ +@Slf4j +public class ArraysTest { + + @Data + static class SortDTO { + private String sortTarget; + + public SortDTO(String sortTarget) { + this.sortTarget = sortTarget; + } + } + + /** + * Arrays 排序 + */ + @Test + public void testSort() { + List list = ImmutableList.of( + new SortDTO("300"), + new SortDTO("50"), + new SortDTO("200"), + new SortDTO("220") + ); + // 我们先把数组的大小初始化成 list 的大小,保证能够正确执行 toArray + SortDTO[] array = new SortDTO[list.size()]; + list.toArray(array); + + log.info("排序之前:{}", JSON.toJSONString(array)); + Arrays.sort(array, Comparator.comparing(SortDTO::getSortTarget)); + log.info("排序之后:{}", JSON.toJSONString(array)); + } + + /** + * Arrays 二分查找 + */ + @Test + public void testBinarySearch() { + List list = ImmutableList.of( + new SortDTO("300"), + new SortDTO("50"), + new SortDTO("200"), + new SortDTO("220") + ); + + SortDTO[] array = new SortDTO[list.size()]; + list.toArray(array); + + log.info("搜索之前:{}", JSON.toJSONString(array)); + Arrays.sort(array, Comparator.comparing(SortDTO::getSortTarget)); + log.info("先排序,结果为:{}", JSON.toJSONString(array)); + int index = Arrays.binarySearch(array, new SortDTO("200"), + Comparator.comparing(SortDTO::getSortTarget)); + if (index < 0) { + throw new RuntimeException("没有找到 200"); + } + log.info("搜索结果:{}", JSON.toJSONString(array[index])); + } + + /** + * Arrays copy + */ + @Test + public void testCopyOf() { + char[] original = new char[]{'1', '2', '3', '4', '5', '6', '7'}; + char[] chars = Arrays.copyOfRange(original, 2, 4); + log.info("copyOfRange:{}", Arrays.toString(chars)); + } + + +} diff --git a/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/util/CollectionsTest.java b/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/util/CollectionsTest.java new file mode 100644 index 00000000..b8b77c25 --- /dev/null +++ b/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/util/CollectionsTest.java @@ -0,0 +1,28 @@ +package cn.lastwhisper.learn8.util; + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections.list.UnmodifiableList; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * Collections + * @author lastwhisper + * @date 2020/4/12 + */ +@Slf4j +public class CollectionsTest { + + @Test + public void unmodifiable(){ + List list = new ArrayList<>(); + List unmodifiableList = UnmodifiableList.decorate(list); + +// Collections.synchronizedList() + + } + +} diff --git a/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/util/ObjectsTest.java b/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/util/ObjectsTest.java new file mode 100644 index 00000000..62420e05 --- /dev/null +++ b/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/util/ObjectsTest.java @@ -0,0 +1,15 @@ +package cn.lastwhisper.learn8.util; + +import lombok.extern.slf4j.Slf4j; + +/** + * Objects + * @author lastwhisper + * @date 2020/4/12 + */ +@Slf4j +public class ObjectsTest { + + + +} diff --git a/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/util/collection/ArrayListTest.java b/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/util/collection/ArrayListTest.java new file mode 100644 index 00000000..284cf810 --- /dev/null +++ b/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/util/collection/ArrayListTest.java @@ -0,0 +1,127 @@ +package cn.lastwhisper.learn8.util.collection; + +import cn.lastwhisper.learn8.common.ReflectUtils; +import com.alibaba.fastjson.JSON; +import com.google.common.collect.Lists; +import lombok.extern.slf4j.Slf4j; +import org.junit.Assert; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; + +/** + * ArrayList + * @author lastwhisper + * @date 2020/4/12 + */ +@Slf4j +public class ArrayListTest { + + /** + * ArrayList初始化 + */ + @Test + public void testInitBug() { + // Arrays.asList 返回的是具体的类型 + List list = Arrays.asList("hello,world"); + Object[] objArray = list.toArray(); + log.info(objArray.getClass().getSimpleName());//Object[] + // objArray 元素的类型是 String,储存 Object 就会报错, + // 因为 jvm 不清楚你存储的 Object 真实类型是不是 String + objArray[0] = new Object(); + } + + /** + * ArrayList扩容机制 + * + * 创建ArrayList不指定初始容量,第一次add时直接扩容到DEFAULT_CAPACITY=10 + * 所以如果能确定ArrayList的大小一定要指定初始容量 + * + * add逻辑: + * ensureCapacityInternal——确保内部需要的容量够用minCapacity=size + 1 + * calculateCapacity——判断ArrayList是否是第一次创建且未指定初始容量,如果是minCapacity=DEFAULT_CAPACITY + * ensureExplicitCapacity——minCapacity>elementData.length,扩容1.5*elementData.length + */ + @Test + public void testGrow() { + List arrayList = new ArrayList<>(); + + Object[] elementData = (Object[]) ReflectUtils.getValue(arrayList, "elementData"); + Assert.assertEquals(0, elementData.length); + + // 此处应该扩容 0->10 + arrayList.add(1); + elementData = (Object[]) ReflectUtils.getValue(arrayList, "elementData"); + Assert.assertEquals(10, elementData.length); + arrayList.add(2); + arrayList.add(3); + arrayList.add(4); + arrayList.add(5); + arrayList.add(6); + arrayList.add(7); + arrayList.add(8); + arrayList.add(9); + arrayList.add(10); + // 此处应该扩容 10->15 + arrayList.add(11); + + elementData = (Object[]) ReflectUtils.getValue(arrayList, "elementData"); + Assert.assertEquals(15, elementData.length); + } + + + /** + * 测试ArrayList在创建迭代器后,使用iterator.remove()单线程修改 + * + * fail-fast + * + * 一般都是用增强for循环遍历集合,增强for只是个语法糖,本质上还是迭代器遍历。 + * modCount和expectedModCount其实就是个版本号,通过modCount和expectedModCount能感知到ArrayList是否被并发读写, + * ArrayList是非线程安全的,并发读写极有可能出错,于是JDK直接提供了快速失败机制,省的你出现奇怪的错误。 + * + * 通过这个快速失败机制也能看出来,JDK就是要告诉你ArrayList不能并发读写,就算你能容忍并发读写带来的错误也不行, + * 人家的设计理念就不允许你这么做。 + */ + @Test + public void testFailFast() { + List arrayList = new ArrayList(){{ + add("a"); + add("b"); + add("c"); + add("d"); + }}; + + // java.util.ConcurrentModificationException + //for (String data : arrayList) { + // if (data.equals("a")) { + // arrayList.remove("a"); + // } + // System.out.println(data); + //} + + // java.util.ConcurrentModificationException + //Iterator iterator = arrayList.iterator(); + //while (iterator.hasNext()) { + // String data = iterator.next(); + // if (data.equals("a")) { + // arrayList.remove("a"); + // } + // System.out.println(data); + //} + + Iterator iterator = arrayList.iterator(); + while (iterator.hasNext()) { + String data = iterator.next(); + if (data.equals("a")) { + iterator.remove(); + } + System.out.println(data); + } + System.out.println("size=" + arrayList.size()); + } + + +} diff --git a/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/util/collection/HashMap8MultiThread.java b/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/util/collection/HashMap8MultiThread.java new file mode 100644 index 00000000..06a36801 --- /dev/null +++ b/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/util/collection/HashMap8MultiThread.java @@ -0,0 +1,54 @@ +package cn.lastwhisper.learn8.util.collection; + +import java.util.HashMap; +import java.util.concurrent.CountDownLatch; + +/** + * HashMap 在多线程环境成环 + * @author lastwhisper + * @date 2020/4/14 + */ +public class HashMap8MultiThread { + + // 多线程共享的HashMap + static HashMap shareMap = new HashMap<>(); + + static class AddTask implements Runnable { + int start = 0; + CountDownLatch latch; + + public AddTask(int start, CountDownLatch latch) { + this.start = start; + this.latch = latch; + } + + @Override + public void run() { + try { + for (int i = start; i < 100000; i += 2) { + shareMap.put(Integer.toString(i), Integer.toBinaryString(i)); + } + } finally { + latch.countDown(); + } + } + } + + public static void main(String[] args) throws InterruptedException { + CountDownLatch latch = new CountDownLatch(2); + + Thread t1 = new Thread(new AddTask(0, latch)); + Thread t2 = new Thread(new AddTask(1, latch)); + t1.start(); + t2.start(); + + try { + latch.await(); + System.out.println(shareMap.size()); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + } + +} diff --git a/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/util/collection/HashMap8Test.java b/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/util/collection/HashMap8Test.java new file mode 100644 index 00000000..758685e7 --- /dev/null +++ b/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/util/collection/HashMap8Test.java @@ -0,0 +1,118 @@ +package cn.lastwhisper.learn8.util.collection; + +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author lastwhisper + * @date 2020/3/26 + */ +public class HashMap8Test { + + /* + * 一、重要参数 + * 1.DEFAULT_INITIAL_CAPACITY = 16 默认哈希表的容量 + * 2.DEFAULT_LOAD_FACTOR = 0.75f 默认负载因子 + * 3.loadFactor 自定义负载因子(一般不会指定,默认0.75f,用来算threshold) + * 4.size k-v对的数量 + * 5.threshold 阈值,addEntry方法中size>=threshold&&null != table[K的Hash索引]时,哈希表将会扩容。 + * + * 6.TREEIFY_THRESHOLD = 8 链表可能转换为红黑树的基本阈值(链表长度>=8) + * 7.UNTREEIFY_THRESHOLD = 6 哈希表扩容后,如果发现红黑树节点数小于6,则退化为链表 + * 8.MIN_TREEIFY_CAPACITY = 64 链表转换为红黑树的另一个条件,哈希表长度必须大于等于64才会转换,否则会扩容 + * + * 二、Hash索引:int index = hash(K) % Array.length ===> HashMap的策略HashCode(K) & (Array.length-1) + * 三、Hash冲突:开放寻址法、拉链法===> HashMap的策略 拉链法 + * 四、为什么数组的大小是2^n? + * (1)加快哈希计算 + * (2)减少哈希冲突 + * n 为 2 的整数次幂,这样 n-1 后之前为 1 的位后面全是 1,这样就能保证 (n-1) & hash 后相应的位数既可能是 0 又可能是 1, + * 这取决于 hash 的值,这样能保证散列的均匀,同时与运算效率高如果 n 不是 2 的整数次幂,会造成更多的 hash 冲突 + * 五、hash(K)扰动函数的原理? + * https://www.zhihu.com/question/20733617/answer/111577937 + * + * 六、threshold计算规则: + * (1)threshold初始化,有三种情况: + * (a)HashMap 无参构造函数,threshold=0 + * (b)HashMap initialCapacity参数构造函数,threshold=initialCapacity + * (c)HashMap Map参数构造函数,threshold=((float)s / loadFactor) + 1.0F + * (2)tableSizeFor()会在HashMap四个构造函数初始化时调用 + * int threshold = tableSizeFor(threshold),找大于或等于threshold的2的幂次,该值作为数组大小 + * (3)resize()时,执行threshold = capacity * loadFactor,threshold值确定 + * + * 七、初始化容量:initialCapacity=expectSize / 0.75f + 1.0f + * 比如,需要在HashMap中存储27个K-V。 + * (1)错误:设置initialCapacity=27,capacity=32,threshold=24=32*0.75=capacity*loadFactor + * 当你连续存储到满了24个以后,再存入第25个K-V的时候,size=24>=threshold=24,有可能触发扩容。 + * (2)正确:设置initialCapacity=37=27 / 0.75f + 1.0f,capacity=64,threshold=48=64*0.75=capacity*loadFactor + * 当你连续存储到满了24个以后,再存入第25个K-V的时候,size=24=threshold=12,有可能触发扩容。 + * 八、put(): + * + * 九、resize(): + * + * + */ + + // 一个可能要扩容的HashMap + HashMap possibleResizeMap = new HashMap() {{ + this.put("1", "1"); + this.put("2", "2"); + this.put("3", "3"); + this.put("4", "4"); + this.put("5", "5"); + this.put("6", "6"); + this.put("7", "7"); + this.put("8", "8"); + this.put("9", "9"); + this.put("10", "10"); + this.put("11", "11"); + this.put("12", "12"); + /*--------------不扩容------------*/ + // size=12 >= threshold=12满足,但是null != table[bucketIndex]不满足 + this.put("13", "13"); + this.put("14", "14"); + + }}; + + @Test + public void testConstruct() { + new HashMap<>(possibleResizeMap); + } + + @Test + public void testPut() { + //HashMap hashMap = new HashMap<>(); + //hashMap.put("1", "1"); + Integer[] integers = new Integer[10]; + for (Integer integer : integers) { + System.out.println(integer); + } + } + + @Test + public void testResize() { + /*--------------扩容------------*/ + // size=14 >= threshold=12满足,同时null != table[bucketIndex]满足 + possibleResizeMap.put("15", "15"); + } + + @Test + public void testResize2() { + HashMap data = new HashMap<>(2); + data.put("rows", "rows"); + data.put("total", "total"); + } + + @Test + public void testGet() { + possibleResizeMap.get(null); + possibleResizeMap.get("14"); + possibleResizeMap.get("15"); + } + + +} diff --git a/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/util/collection/LinkedHashMapTest.java b/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/util/collection/LinkedHashMapTest.java new file mode 100644 index 00000000..977059f1 --- /dev/null +++ b/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/util/collection/LinkedHashMapTest.java @@ -0,0 +1,105 @@ +package cn.lastwhisper.learn8.util.collection; + +import com.alibaba.fastjson.JSON; +import lombok.extern.slf4j.Slf4j; +import org.junit.Assert; +import org.junit.Test; + +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * LinkedHashMap + * @author lastwhisper + * @date 2020/4/13 + */ +@Slf4j +public class LinkedHashMapTest { + + /** + * 最近最少使用到的(least recently used) + * LinkedHashMap继承HashMap,LinkedHashMap实现LRU核心方法: + * + * LinkedHashMap队头是最近最少使用的结点,队尾是最近最常使用的 + * + * void afterNodeAccess(Node p) { } + * HashMap putVal的元素已经存在时回调,当前该节点移动到队尾 + * + * void afterNodeInsertion(boolean evict) { } + * HashMap putVal时回调 + * + * boolean removeEldestEntry(Map.Entry eldest) + * 留着用户重写,默认返回false。返回true时,删除最近最少使用的元素,也就是队头。 + * + * void afterNodeRemoval(Node p) { } + * HashMap remove时回调,删除HashMap remove的元素 + * + * + */ + + /** + * 稳定性 + */ + @Test + public void testInsertOrder() { + LinkedHashMap map = new LinkedHashMap() {{ + put(10, 10); + put(9, 9); + put(20, 20); + put(1, 1); + }}; + Assert.assertNotNull(map.get(9)); + Assert.assertNotNull(map.get(20)); + Assert.assertNotNull(map.get(9)); + log.info(JSON.toJSONString(map)); + + } + + /** + * lru + */ + @Test + public void testAccessOrder() { + LinkedHashMap map = new LinkedHashMap(4,0.75f,true) { + { + put(10, 10); + put(9, 9); + put(20, 20); + put(1, 1); + } + @Override + protected boolean removeEldestEntry(Map.Entry eldest) { + return size() > 3; + } + }; + + log.info("初始化:{}",JSON.toJSONString(map)); + Assert.assertNotNull(map.get(9)); + log.info("map.get(9):{}",JSON.toJSONString(map)); + Assert.assertNotNull(map.get(20)); + log.info("map.get(20):{}",JSON.toJSONString(map)); + + } + + @Test + public void testIterator(){ + LinkedHashMap map = new LinkedHashMap(4,0.75f,true) { + { + put(10, 10); + put(9, 9); + put(20, 20); + put(1, 1); + } + }; + + log.info("迭代访问 start"); + Iterator> iterator = map.entrySet().iterator(); + while (iterator.hasNext()){ + Map.Entry entry = iterator.next(); + log.info(JSON.toJSONString(entry)); + } + log.info("迭代访问 end"); + } + +} diff --git a/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/util/collection/LinkedListTest.java b/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/util/collection/LinkedListTest.java new file mode 100644 index 00000000..598e7e04 --- /dev/null +++ b/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/util/collection/LinkedListTest.java @@ -0,0 +1,65 @@ +package cn.lastwhisper.learn8.util.collection; + +import lombok.extern.slf4j.Slf4j; +import org.junit.Test; + +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.ListIterator; + +/** + * LinkedList + * + * @author lastwhisper + * @date 2020/4/13 + */ +@Slf4j +public class LinkedListTest { + + @Test + public void testFastFail() { + List linkedList = new LinkedList(){{ + add("a"); + add("b"); + add("c"); + add("d"); + }}; + + // java.util.ConcurrentModificationException + Iterator iterator = linkedList.iterator(); + while (iterator.hasNext()) { + String data = iterator.next(); + if (data.equals("a")) { + linkedList.remove("a"); + } + System.out.println(data); + } + System.out.println("size=" + linkedList.size()); + } + + @Test + public void testItertor() { + List list = new LinkedList<>(); + list.add("s1"); + list.add("s3"); + list.add("s3"); + list.add(null); + list.add("s4"); + + ListIterator listIterator = list.listIterator(); + while (listIterator.hasNext()) { + String s = listIterator.next(); + log.info("从头到尾迭代顺序:" + s); + } + + while (listIterator.hasPrevious()) { + String s = listIterator.previous(); + if (s.equals("s5")) { + listIterator.remove(); + } + log.info("从尾到头迭代顺序:" + s); + } + } + +} diff --git a/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/util/collection/TreeMapTest.java b/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/util/collection/TreeMapTest.java new file mode 100644 index 00000000..0dbb91ce --- /dev/null +++ b/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/util/collection/TreeMapTest.java @@ -0,0 +1,81 @@ +package cn.lastwhisper.learn8.util.collection; + +import com.alibaba.fastjson.JSON; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.junit.Assert; +import org.junit.Test; + +import java.util.*; + +/** + * TreeMap + * @author lastwhisper + * @date 2020/4/13 + */ +@Slf4j +public class TreeMapTest { + + @Data + class DTO implements Comparable { + + private Integer id; + + public DTO(Integer id) { + this.id = id; + } + + @Override + public int compareTo(DTO o) { + //默认从小到大排序 + return id - o.getId(); + } + } + + + @Test + public void testIterator() { + TreeMap m = new TreeMap<>(); + m.put("asdf", "nihao"); + m.put("sdf", "nihao"); + m.put("df", "nihao"); + m.keySet().iterator(); + } + + @Test + public void testRegionSearch() { + TreeMap rankingMap = new TreeMap<>(); + rankingMap.put(1,1); //ranking 1 ->1 + rankingMap.put(2,2); //ranking 2 ->2 + rankingMap.put(3,3); //ranking 3 -> 3 + rankingMap.put(4,4); //ranking 4-10 ->4 + rankingMap.put(11,5); //ranking 11-20 ->5 + rankingMap.put(21,6); //ranking 21-30 ->6 + rankingMap.put(31,7); //ranking >= 31 ->7 + + Assert.assertEquals(6, (int) rankingMap.floorEntry(30).getValue()); + Assert.assertEquals(7, (int) rankingMap.floorEntry(71).getValue()); + } + + @Test + public void testTwoComparable() { + // 第一种排序,从小到大排序,实现 Comparable 的 compareTo 方法进行排序 + List list = new ArrayList<>(); + for (int i = 5; i > 0; i--) { + list.add(new DTO(i)); + } + Collections.sort(list); + log.info(JSON.toJSONString(list)); + + // 第二种排序,从大到小排序,利用外部排序器 Comparator 进行排序 + Comparator comparator = (Comparator) (o1, o2) -> o2.getId() - o1.getId(); + List list2 = new ArrayList<>(); + for (int i = 5; i > 0; i--) { + list2.add(new DTO(i)); + } + Collections.sort(list, comparator); + log.info(JSON.toJSONString(list2)); + } + + +} diff --git a/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/util/concurrent/collection/ConcurrentHashMapTest.java b/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/util/concurrent/collection/ConcurrentHashMapTest.java new file mode 100644 index 00000000..540e5587 --- /dev/null +++ b/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/util/concurrent/collection/ConcurrentHashMapTest.java @@ -0,0 +1,26 @@ +package cn.lastwhisper.learn8.util.concurrent.collection; + +import lombok.extern.slf4j.Slf4j; +import org.junit.Assert; +import org.junit.Test; + +import java.util.Map; +import java.util.TreeMap; +import java.util.concurrent.ConcurrentHashMap; + +/** + * ConcurrentHashMap + * @author lastwhisper + * @date 2020/4/16 + */ +@Slf4j +public class ConcurrentHashMapTest { + + @Test + public void testRegionSearch() { + ConcurrentHashMap map = new ConcurrentHashMap<>(); + map.put("1","1"); + + } + +} diff --git a/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/util/concurrent/collection/CopyOnWriteArrayListTest.java b/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/util/concurrent/collection/CopyOnWriteArrayListTest.java new file mode 100644 index 00000000..6f1b2603 --- /dev/null +++ b/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/util/concurrent/collection/CopyOnWriteArrayListTest.java @@ -0,0 +1,30 @@ +package cn.lastwhisper.learn8.util.concurrent.collection; + +import lombok.extern.slf4j.Slf4j; +import org.junit.Test; + +import java.util.Iterator; +import java.util.concurrent.CopyOnWriteArrayList; + +/** + * CopyOnWriteArrayList + * @author lastwhisper + * @date 2020/4/16 + */ +@Slf4j +public class CopyOnWriteArrayListTest { + + @Test + public void testIterator() { + CopyOnWriteArrayList list = new CopyOnWriteArrayList(); + list.add("10"); + list.add("20"); + list.add("30"); + Iterator iterator = list.iterator(); + list.add("50"); + iterator.next(); + list.add("50"); + } + + +} diff --git a/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/util/concurrent/executor/FutureTest.java b/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/util/concurrent/executor/FutureTest.java new file mode 100644 index 00000000..1b8b1e3f --- /dev/null +++ b/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/util/concurrent/executor/FutureTest.java @@ -0,0 +1,84 @@ +package cn.lastwhisper.learn8.util.concurrent.executor; + +import lombok.extern.slf4j.Slf4j; +import org.junit.Test; + +import java.util.concurrent.*; + +/** + * Future + * @author lastwhisper + * @date 2020/4/18 + */ +@Slf4j +public class FutureTest { + + /** + * Callable 有返回值 + */ + @Test + public void testCallable() throws ExecutionException, InterruptedException { + FutureTask futureTask = new FutureTask<>(new Callable() { + @Override + public String call() throws Exception { + TimeUnit.SECONDS.sleep(5); + return "return val"; + } + }); + log.info("do some thing..."); + futureTask.run(); + String result = futureTask.get(); + log.info("拿到值了,为 {}", result); + } + + /** + * Runnable 无返回值 + * 适配器 + * + */ + @Test + public void testRunnable() throws ExecutionException, InterruptedException { + FutureTask futureTask = new FutureTask(new Runnable() { + @Override + public void run() { + log.info("{} is run", Thread.currentThread().getName()); + } + }, null); + futureTask.run(); + String result = futureTask.get(); + log.info("run end,result is {}", result); + } + + @Test + public void testGet() throws ExecutionException, InterruptedException { + ThreadPoolExecutor executor = new ThreadPoolExecutor(3, 3, 0L, TimeUnit.MILLISECONDS, + new LinkedBlockingQueue<>()); + FutureTask futureTask = new FutureTask(new Callable() { + @Override + public String call() throws Exception { + Thread.sleep(3000); + return "我是子线程" + Thread.currentThread().getName(); + } + }); + executor.submit(futureTask); + String result = (String) futureTask.get(); + log.info("result is {}", result); + executor.shutdown(); + } + + @Test + public void testThreadByCallable() throws ExecutionException, InterruptedException { + FutureTask futureTask = new FutureTask(new Callable() { + @Override + public String call() throws Exception { + Thread.sleep(3000); + String result = "我是子线程" + Thread.currentThread().getName(); + log.info("子线程正在运行:{}", Thread.currentThread().getName()); + return result; + } + }); + new Thread(futureTask).start(); + log.info("返回的结果是 {}", futureTask.get()); + } + +} diff --git a/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/util/concurrent/queue/ArrayBlockingQueueDemo.java b/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/util/concurrent/queue/ArrayBlockingQueueDemo.java new file mode 100644 index 00000000..c4978bf9 --- /dev/null +++ b/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/util/concurrent/queue/ArrayBlockingQueueDemo.java @@ -0,0 +1,90 @@ +package cn.lastwhisper.learn8.util.concurrent.queue; + +import org.junit.Test; + +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.TimeUnit; + +/** + * 阻塞队列 + * @author lastwhisper + */ +public class ArrayBlockingQueueDemo { + ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(3); + + // 抛异常 + @Test + public void testThrowException() { + System.out.println(blockingQueue.add("a")); + System.out.println(blockingQueue.add("b")); + System.out.println(blockingQueue.add("c")); + + try { + System.out.println(blockingQueue.add("x")); + } catch (Exception e) { + e.printStackTrace(); + } + + System.out.println(blockingQueue.element()); + System.out.println(blockingQueue.remove()); + System.out.println(blockingQueue.remove()); + System.out.println(blockingQueue.remove()); + try { + //当阻塞队列空时,再往队列Remove元素时候回抛出NoSuchElementException + System.out.println(blockingQueue.remove()); + } catch (Exception e) { + e.printStackTrace(); + } + + } + + // 特殊值 + @Test + public void testReturnBool() { + System.out.println(blockingQueue.offer("a")); + System.out.println(blockingQueue.offer("b")); + System.out.println(blockingQueue.offer("c")); + // 插入方法,成功返回true 失败返回false + System.out.println(blockingQueue.offer("x")); + + System.out.println(blockingQueue.poll()); + System.out.println(blockingQueue.poll()); + System.out.println(blockingQueue.poll()); + //移除方法,成功返回元素,队列里面没有就返回null + System.out.println(blockingQueue.poll()); + } + + // 一直阻塞 + @Test + public void testBlock() throws InterruptedException { + blockingQueue.put("a"); + blockingQueue.put("b"); + blockingQueue.put("c"); + // 当阻塞队列满时,生产者继续往队列里面put元素,队列会一直阻塞直到put数据or响应中断退出 + blockingQueue.offer("x"); + + System.out.println(blockingQueue.take()); + System.out.println(blockingQueue.take()); + System.out.println(blockingQueue.take()); + //当阻塞队列空时,消费者试图从队列take元素,队列会一直阻塞消费者线程直到队列可用. + System.out.println(blockingQueue.take()); + } + + // 超时退出 + @Test + public void testIncorruptible() throws InterruptedException { + blockingQueue.offer("a"); + blockingQueue.offer("b"); + blockingQueue.offer("c"); + System.out.println(blockingQueue.size()); + // 当阻塞队列满时,队列会阻塞生产者线程一定时间,超过后限时后生产者线程就会退出 + blockingQueue.offer("x", 2L, TimeUnit.SECONDS); + + System.out.println(blockingQueue.poll()); + System.out.println(blockingQueue.poll()); + System.out.println(blockingQueue.poll()); + System.out.println(blockingQueue.size()); + System.out.println(blockingQueue.poll(2L, TimeUnit.SECONDS)); + } + +} diff --git a/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/util/concurrent/queue/DelayQueueTest.java b/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/util/concurrent/queue/DelayQueueTest.java new file mode 100644 index 00000000..d2f1f834 --- /dev/null +++ b/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/util/concurrent/queue/DelayQueueTest.java @@ -0,0 +1,98 @@ +package cn.lastwhisper.learn8.util.concurrent.queue; + +import lombok.Data; +import lombok.extern.slf4j.Slf4j; + +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.DelayQueue; +import java.util.concurrent.Delayed; +import java.util.concurrent.TimeUnit; + +/** + * DelayQueue + * @author lastwhisper + * @date 2020/4/17 + */ +@Slf4j +public class DelayQueueTest { + + static class Product implements Runnable { + + private final BlockingQueue queue; + + public Product(BlockingQueue queue) { + this.queue = queue; + } + + @Override + public void run() { + try { + log.info("begin put"); + long beginTime = System.currentTimeMillis(); + queue.put(new DelayedDTO(System.currentTimeMillis() + 2000L, beginTime));//延迟 2 秒执行 + queue.put(new DelayedDTO(System.currentTimeMillis() + 5000L, beginTime));//延迟 5 秒执行 + queue.put(new DelayedDTO(System.currentTimeMillis() + 1000L * 10, beginTime));//延迟 10 秒执行 + log.info("end put"); + } catch (InterruptedException e) { + log.error("" + e); + } + } + } + + static class Consumer implements Runnable { + + private final BlockingQueue queue; + + public Consumer(BlockingQueue queue) { + this.queue = queue; + } + + @Override + public void run() { + try { + log.info("Consumer begin"); + queue.take().run(); + queue.take().run(); + queue.take().run(); + log.info("Consumer end"); + } catch (InterruptedException e) { + log.error("" + e); + } + } + } + + @Data + static class DelayedDTO implements Delayed { + Long s; + Long beginTime; + + public DelayedDTO(Long s, Long beginTime) { + this.s = s; + this.beginTime = beginTime; + } + + @Override + public long getDelay(TimeUnit unit) { + return unit.convert(s - System.currentTimeMillis(), TimeUnit.MILLISECONDS); + } + + @Override + public int compareTo(Delayed o) { + return (int) (this.getDelay(TimeUnit.MILLISECONDS) - o.getDelay(TimeUnit.MILLISECONDS)); + } + + public void run() { + log.info("延迟了{}秒钟才执行", (System.currentTimeMillis() - beginTime) / 1000); + } + } + + public static void main(String[] args) throws InterruptedException { + BlockingQueue q = new DelayQueue<>(); + DelayQueueTest.Product p = new DelayQueueTest.Product(q); + DelayQueueTest.Consumer c = new DelayQueueTest.Consumer(q); + new Thread(c).start(); + new Thread(p).start(); + + } + +} diff --git a/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/util/concurrent/queue/LinkedBlockingQueueTest.java b/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/util/concurrent/queue/LinkedBlockingQueueTest.java new file mode 100644 index 00000000..9fd01c55 --- /dev/null +++ b/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/util/concurrent/queue/LinkedBlockingQueueTest.java @@ -0,0 +1,94 @@ +package cn.lastwhisper.learn8.util.concurrent.queue; + +import lombok.extern.slf4j.Slf4j; +import org.junit.Test; + +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; + +/** + * LinkedBlockingQueue + * @author lastwhisper + * @date 2020/4/17 + */ +@Slf4j +public class LinkedBlockingQueueTest { + + LinkedBlockingQueue blockingQueue = new LinkedBlockingQueue<>(3); + + // 抛异常 + @Test + public void testThrowException() { + System.out.println(blockingQueue.add("a")); + System.out.println(blockingQueue.add("b")); + System.out.println(blockingQueue.add("c")); + + try { + System.out.println(blockingQueue.add("x")); + } catch (Exception e) { + e.printStackTrace(); + } + + System.out.println(blockingQueue.element()); + System.out.println(blockingQueue.remove()); + System.out.println(blockingQueue.remove()); + System.out.println(blockingQueue.remove()); + try { + //当阻塞队列空时,再往队列Remove元素时候回抛出NoSuchElementException + System.out.println(blockingQueue.remove()); + } catch (Exception e) { + e.printStackTrace(); + } + + } + + // 特殊值 + @Test + public void testReturnBool() { + System.out.println(blockingQueue.offer("a")); + System.out.println(blockingQueue.offer("b")); + System.out.println(blockingQueue.offer("c")); + // 插入方法,成功返回true 失败返回false + System.out.println(blockingQueue.offer("x")); + + System.out.println(blockingQueue.poll()); + System.out.println(blockingQueue.poll()); + System.out.println(blockingQueue.poll()); + //移除方法,成功返回元素,队列里面没有就返回null + System.out.println(blockingQueue.poll()); + } + + // 一直阻塞 + @Test + public void testBlock() throws InterruptedException { + blockingQueue.put("a"); + blockingQueue.put("b"); + blockingQueue.put("c"); + // 当阻塞队列满时,生产者继续往队列里面put元素,队列会一直阻塞直到put数据or响应中断退出 + blockingQueue.offer("x"); + System.out.println(blockingQueue.take()); + System.out.println(blockingQueue.take()); + System.out.println(blockingQueue.take()); + //当阻塞队列空时,消费者试图从队列take元素,队列会一直阻塞消费者线程直到队列可用. + System.out.println(blockingQueue.take()); + } + + // 超时退出 + @Test + public void testIncorruptible() throws InterruptedException { + blockingQueue.offer("a"); + blockingQueue.offer("b"); + blockingQueue.offer("c"); + System.out.println(blockingQueue.size()); + // 当阻塞队列满时,队列会阻塞生产者线程一定时间,超过后限时后生产者线程就会退出 + blockingQueue.offer("x", 2L, TimeUnit.SECONDS); + + System.out.println(blockingQueue.poll()); + System.out.println(blockingQueue.poll()); + System.out.println(blockingQueue.poll()); + System.out.println(blockingQueue.size()); + System.out.println(blockingQueue.poll(2L, TimeUnit.SECONDS)); + } + + +} diff --git a/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/util/concurrent/queue/SynchronousQueueTest.java b/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/util/concurrent/queue/SynchronousQueueTest.java new file mode 100644 index 00000000..55981e6f --- /dev/null +++ b/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/util/concurrent/queue/SynchronousQueueTest.java @@ -0,0 +1,68 @@ +package cn.lastwhisper.learn8.util.concurrent.queue; + +import lombok.extern.slf4j.Slf4j; + +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.SynchronousQueue; + +/** + * SynchronousQueue + * @author lastwhisper + * @date 2020/4/17 + */ +@Slf4j +public class SynchronousQueueTest { + + static class Product implements Runnable { + + private final BlockingQueue queue; + + public Product(BlockingQueue queue) { + this.queue = queue; + } + + @Override + public void run() { + try { + log.info("begin put"); + queue.put("nihao"); + log.info("end put"); + } catch (InterruptedException e) { + } + } + + } + + static class Consumer implements Runnable { + + private final BlockingQueue queue; + + public Consumer(BlockingQueue queue) { + this.queue = queue; + } + + @Override + public void run() { + try { + log.info("Consumer begin"); + String name = (String) queue.take(); + log.info("Consumer end :{}", name); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + + public static void main(String[] args) throws InterruptedException { + BlockingQueue q = new SynchronousQueue(true); + Product p = new Product(q); + Consumer c = new Consumer(q); + new Thread(c).start(); + log.info("sleeping"); + Thread.sleep(5000L); + log.info("sleepEnd"); + new Thread(p).start(); + } + + +} diff --git a/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/util/concurrent/queue/my/LinkedBlockingQueue.java b/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/util/concurrent/queue/my/LinkedBlockingQueue.java new file mode 100644 index 00000000..fb9e6a81 --- /dev/null +++ b/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/util/concurrent/queue/my/LinkedBlockingQueue.java @@ -0,0 +1,196 @@ +package cn.lastwhisper.learn8.util.concurrent.queue.my; + +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.ReentrantLock; + +/** + * 链表实现的阻塞队列 + * @author lastwhisper + * @date 2020/4/17 + */ +public class LinkedBlockingQueue implements Queue { + + /** + * 容量 + */ + private final Integer capacity; + /** + * 队列的大小,使用 AtomicInteger 来保证其线程安全 + */ + private final AtomicInteger count = new AtomicInteger(); + /** Lock held by take, poll, etc */ + private final ReentrantLock takeLock = new ReentrantLock(); + /** Wait queue for waiting takes */ + private final Condition notEmpty = takeLock.newCondition(); + /** Lock held by put, offer, etc */ + private final ReentrantLock putLock = new ReentrantLock(); + /** Wait queue for waiting puts */ + private final Condition notFull = putLock.newCondition(); + /** + * 链表头 + */ + private transient Node head; + /** + * 链表尾 + */ + private transient Node tail; + + public LinkedBlockingQueue() { + this(Integer.MAX_VALUE); + } + + /** + * 初始化 + * + * @param capacity 队列容量 + */ + public LinkedBlockingQueue(Integer capacity) { + // 边界检查 + if (capacity == null || capacity < 0) { + throw new IllegalArgumentException("capacity is null or less zero"); + } + this.capacity = capacity; + head = tail = new Node<>(null); + } + + /** + * 实现思路: + * 1、put元素不为空 + * 2、上put锁 + * 3、队满,put操作阻塞 + * 4、队不满,元素入队 + * 5、校验队列长度是否小于容量,小于则唤醒其他put操作 + * 6、释放put锁 + * 7、校验队列长度是否等于1,等于则唤醒take操作(这个1是刚put的,可能有take在阻塞中) + * @param item 元素 + * @return boolean + */ + @Override + public void put(E item) throws InterruptedException { + // 1、put元素不为空 + if (item == null) { + throw new NullPointerException(); + } + + int c = -1; + + final ReentrantLock putLock = this.putLock; + final Condition notFull = this.notFull; + final AtomicInteger count = this.count; + // 2、上put锁 + putLock.lockInterruptibly(); + try { + // 3、队满,put操作阻塞 + while (count.get() == capacity) {//为什么是while,不是if?防止虚假唤醒 + notFull.await(); + } + // 4、队不满,元素入队 + enqueue(new Node<>(item)); + // 5、校验队列长度是否小于容量,小于则唤醒其他put操作 + c = count.getAndIncrement();// 旧值 + if (c + 1 < capacity) { + notFull.signal(); + } + } finally { + // 6、释放put锁 + putLock.unlock(); + } + // 7、校验队列长度是否等于1,等于则唤醒take操作(这个1是刚put的,可能有take在阻塞中) + if (c == 0) { + signalNotEmpty(); + } + } + + /** + * 实现思路: + * 1、上take锁 + * 2、队空,take操作阻塞 + * 3、队不空,从对头拿一个元素 + * 4、校验队列长度是否大于0,大于则唤醒其他take操作 + * 5、释放take锁 + * 6、校验队列长度是否等于capacity-1,等于则唤醒put操作(这个-1是刚take的,可能有put在阻塞中) + * @return 元素 + */ + @Override + public E take() throws InterruptedException { + E e; + int c; + + final ReentrantLock takeLock = this.takeLock; + final AtomicInteger count = this.count; + final Condition notEmpty = this.notEmpty; + // 1、上take锁 + takeLock.lockInterruptibly(); + try { + // 2、队空,take操作阻塞 + while (count.get() == 0) {//为什么是while,不是if?防止虚假唤醒 + notEmpty.await(); + } + // 3、队不空,从对头拿一个元素 + e = dequeue(); + c = count.getAndDecrement(); // 次处为旧值,旧值=新值 + 1。为啥是拿旧值? + // 4、校验队列长度是否大于0,大于则唤醒其他take操作 + if (c > 1) { + notEmpty.signal(); + } + } finally { + // 5、释放take锁 + takeLock.unlock(); + } + // 6、校验队列长度是否等于capacity-1,等于则唤醒put操作(这个-1是刚take的,可能有put在阻塞中) + if (c == capacity) + signalNotFull(); + return e; + } + + private void signalNotEmpty() { + final ReentrantLock takeLock = this.takeLock; + takeLock.lock(); + try { + notEmpty.signal(); + } finally { + takeLock.unlock(); + } + } + + private void signalNotFull() { + final ReentrantLock putLock = this.putLock; + putLock.lock(); + try { + notFull.signal(); + } finally { + putLock.unlock(); + } + } + + /** + * 结点出队(队头) + * + */ + private E dequeue() { + // 取出头节点 + Node h = head; + // 头节点的下一个节点为 first + Node first = h.next; + // 使 h 的下一个节点指向自己 + h.next = h; // help GC + // 给链表头赋值 + head = first; + // 取出链表头值 + E x = first.item; + // 旧头节点指向 null,帮助 GC + first.item = null; + // 返回旧头节点值 + return x; + } + + /** + * 结点入队(队尾) + * + * @param node 结点 + */ + private void enqueue(Node node) { + tail = tail.next = node; + } +} diff --git a/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/util/concurrent/queue/my/Queue.java b/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/util/concurrent/queue/my/Queue.java new file mode 100644 index 00000000..385f94c5 --- /dev/null +++ b/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/util/concurrent/queue/my/Queue.java @@ -0,0 +1,35 @@ +package cn.lastwhisper.learn8.util.concurrent.queue.my; + +/** + * 队列接口 + * @author lastwhisper + * @date 2020/4/17 + */ +public interface Queue { + + // 队列中元素的基本结构 + class Node { + // 数据本身 + E item; + // 下一个元素 + Node next; + + // 构造器 + public Node(E item) { + this.item = item; + } + } + + /** + * 放数据 + * @param item 入参 + */ + void put(E item) throws InterruptedException; + + /** + * 拿数据,返回一个泛型值 + * @return 数据 + */ + E take() throws InterruptedException; + +} diff --git a/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/util/concurrent/queue/my/QueueTest.java b/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/util/concurrent/queue/my/QueueTest.java new file mode 100644 index 00000000..6807dc40 --- /dev/null +++ b/java-basic/learn-source-jdk8/src/main/java/cn/lastwhisper/learn8/util/concurrent/queue/my/QueueTest.java @@ -0,0 +1,73 @@ +package cn.lastwhisper.learn8.util.concurrent.queue.my; + +import java.util.concurrent.TimeUnit; + +/** + * + * @author lastwhisper + * @date 2020/4/18 + */ +public class QueueTest { + + public static void main(String[] args) throws InterruptedException { + Queue blockingQueue = new LinkedBlockingQueue<>(3); + System.out.println("/*----------------capacity=3---------------*/"); + blockingQueue.put("a"); + blockingQueue.put("b"); + blockingQueue.put("c"); + System.out.println("thread name:" + Thread.currentThread().getName() + + ",put a、b、c三个元素"); + + new Thread(new Runnable() { + @Override + public void run() { + try { + System.out.println("thread name:" + Thread.currentThread().getName() + + ",5秒后执行take操作"); + TimeUnit.SECONDS.sleep(5); + blockingQueue.take(); + System.out.println("thread name:" + Thread.currentThread().getName() + + ",take操作执行,take a,并唤醒put操作"); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + }).start(); + + System.out.println("thread name:" + Thread.currentThread().getName() + + ",开始执行put操作,队满一直阻塞"); + blockingQueue.put("d"); + System.out.println("thread name:" + Thread.currentThread().getName() + + ",put操作被唤醒,put d"); + blockingQueue.take(); + blockingQueue.take(); + blockingQueue.take(); + System.out.println("thread name:" + Thread.currentThread().getName() + + ",take操作执行,take b c d"); + + new Thread(new Runnable() { + @Override + public void run() { + try { + System.out.println("thread name:" + Thread.currentThread().getName() + + ",5秒后执行put操作"); + TimeUnit.SECONDS.sleep(5); + blockingQueue.put("d"); + System.out.println("thread name:" + Thread.currentThread().getName() + + ",put操作执行,put d,并唤醒take操作"); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + }).start(); + + System.out.println("thread name:" + Thread.currentThread().getName() + + ",开始执行take操作,队空一直阻塞"); + blockingQueue.take(); + System.out.println("thread name:" + Thread.currentThread().getName() + + ",take操作被唤醒,take d"); + + } + + +} diff --git a/java-basic/pom.xml b/java-basic/pom.xml deleted file mode 100644 index efafaacd..00000000 --- a/java-basic/pom.xml +++ /dev/null @@ -1,51 +0,0 @@ - - - 4.0.0 - - cn.lastwhisper - java-basic - pom - 1.0-SNAPSHOT - - concurrent - jvm - jdk5 - design-pattern - interview - jdk8 - jdk9 - jdk11 - jdk12 - jdk13 - - - - - junit - junit - 4.12 - - - mysql - mysql-connector-java - 5.1.38 - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - - 1.8 - 1.8 - - - - - - - \ No newline at end of file diff --git a/java-basic/spring/pom.xml b/java-basic/spring/pom.xml deleted file mode 100644 index 2343431c..00000000 --- a/java-basic/spring/pom.xml +++ /dev/null @@ -1,49 +0,0 @@ - - - 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 2.1.7.RELEASE - - - cn.lastwhisper - spring - 0.0.1-SNAPSHOT - spring - Demo project for Spring Boot - - - 1.8 - - - - - org.springframework.boot - spring-boot-starter - - - - org.springframework.boot - spring-boot-starter-web - 2.1.7.RELEASE - - - - org.springframework.boot - spring-boot-starter-test - test - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - - diff --git a/java-basic/spring/src/main/java/cn/lastwhisper/spring/Application.java b/java-basic/spring/src/main/java/cn/lastwhisper/spring/Application.java deleted file mode 100644 index f4503838..00000000 --- a/java-basic/spring/src/main/java/cn/lastwhisper/spring/Application.java +++ /dev/null @@ -1,46 +0,0 @@ -package cn.lastwhisper.spring; - -import cn.lastwhisper.spring.ioc.entity.Person; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.context.ConfigurableApplicationContext; - -@SpringBootApplication -public class Application { - - /** - * BeanDefinitionRegistry - * |--registerBeanDefinition将BeanDefinition注册到BeanFactory的实现类DefaultListableBeanFactory的beanDefinitionMap中 - * DefaultListableBeanFactory - * - * BeanFactory - * ApplicationContext - * - * AbstractBeanFactory - * |--getBean调用doGetBean;转换beanName、从缓存中加载实例、实例化Bean、检查parentBeanFactory、初始化依赖的Bean、创建Bean - * - * AOP原理 - * AbstractBeanFactory - * |--getBean——》doGetBean——》createBean - * AbstractAutowireCapableBeanFactory - * |--createBean——》doCreateBean——》initializeBean——》 - * pplyBeanPostProcessorsAfterInitialization——》postProcessAfterInitialization - * BeanPostProcessor由AbstractAutoProxyCreator等类实现 - * |--postProcessAfterInitialization - * AbstractAutoProxyCreator - * |--postProcessAfterInitialization——》wrapIfNecessary——》createProxy创建代理——》getProxy - * ProxyCreatorSupport - * |--createAopProxy(); - * |--AopProxyFactory是一个接口,默认使用DefaultAopProxyFactory实现 - * DefaultAopProxyFactory - * |--createAopProxy(AdvisedSupport config)在这个里面就有SpringAOP的选用策略,config可由用户自定义,控制选用策略 - * - */ - public static void main(String[] args) { - ConfigurableApplicationContext context = SpringApplication.run(Application.class, args); - Person person = (Person) context.getBean("person"); - System.out.println(person); - } - - -} diff --git a/java-basic/spring/src/main/java/cn/lastwhisper/spring/ioc/config/ApplicationConfig.java b/java-basic/spring/src/main/java/cn/lastwhisper/spring/ioc/config/ApplicationConfig.java deleted file mode 100644 index 958149f4..00000000 --- a/java-basic/spring/src/main/java/cn/lastwhisper/spring/ioc/config/ApplicationConfig.java +++ /dev/null @@ -1,20 +0,0 @@ -package cn.lastwhisper.spring.ioc.config; - -import cn.lastwhisper.spring.ioc.entity.Person; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -/** - * @author lastwhisper - */ -@Configuration -public class ApplicationConfig { - //@Bean(name = "person") - //public Person initPerson() { - // Person person = new Person(); - // person.setId(1L); - // person.setName("jack"); - // return person; - //} - -} diff --git a/java-basic/spring/src/main/java/cn/lastwhisper/spring/ioc/entity/Person.java b/java-basic/spring/src/main/java/cn/lastwhisper/spring/ioc/entity/Person.java deleted file mode 100644 index 83cc57da..00000000 --- a/java-basic/spring/src/main/java/cn/lastwhisper/spring/ioc/entity/Person.java +++ /dev/null @@ -1,39 +0,0 @@ -package cn.lastwhisper.spring.ioc.entity; - -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; - -/** - * @author lastwhisper - */ -@Component("person") -public class Person { - @Value("1") - private Long id; - @Value("jack") - private String name; - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - @Override - public String toString() { - return "Person{" + - "id=" + id + - ", name='" + name + '\'' + - '}'; - } -} diff --git a/java-basic/spring/src/test/java/cn/lastwhisper/spring/ApplicationTests.java b/java-basic/spring/src/test/java/cn/lastwhisper/spring/ApplicationTests.java deleted file mode 100644 index 82affdd9..00000000 --- a/java-basic/spring/src/test/java/cn/lastwhisper/spring/ApplicationTests.java +++ /dev/null @@ -1,17 +0,0 @@ -package cn.lastwhisper.spring; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit4.SpringRunner; - -@RunWith(SpringRunner.class) -@SpringBootTest -public class ApplicationTests { - - @Test - public void contextLoads() { - - } - -} diff --git a/lesson-code/design/fsm/README.md b/lesson-code/design/fsm/README.md new file mode 100644 index 00000000..c16d0458 --- /dev/null +++ b/lesson-code/design/fsm/README.md @@ -0,0 +1,4 @@ +有限状态机 +- switch-case +- driver-table +- state-pattern \ No newline at end of file diff --git a/lesson-code/design/fsm/pom.xml b/lesson-code/design/fsm/pom.xml new file mode 100644 index 00000000..169ad03f --- /dev/null +++ b/lesson-code/design/fsm/pom.xml @@ -0,0 +1,16 @@ + + + 4.0.0 + + cn.cunchang + fsm + 1.0-SNAPSHOT + + + 8 + 8 + + + \ No newline at end of file diff --git a/lesson-code/design/fsm/src/main/java/cn/cunchang/ApplicationDemo.java b/lesson-code/design/fsm/src/main/java/cn/cunchang/ApplicationDemo.java new file mode 100644 index 00000000..28a885ae --- /dev/null +++ b/lesson-code/design/fsm/src/main/java/cn/cunchang/ApplicationDemo.java @@ -0,0 +1,11 @@ +package cn.cunchang; + +public class ApplicationDemo { + public static void main(String[] args) { + MarioStateMachine mario = new MarioStateMachine(); + mario.obtainMushRoom(); + int score = mario.getScore(); + State state = mario.getCurrentState(); + System.out.println("mario score: " + score + "; state: " + state); + } +} \ No newline at end of file diff --git a/lesson-code/design/fsm/src/main/java/cn/cunchang/MarioStateMachine.java b/lesson-code/design/fsm/src/main/java/cn/cunchang/MarioStateMachine.java new file mode 100644 index 00000000..3014a29d --- /dev/null +++ b/lesson-code/design/fsm/src/main/java/cn/cunchang/MarioStateMachine.java @@ -0,0 +1,42 @@ +package cn.cunchang; + +public class MarioStateMachine { + private int score; + private State currentState; + + public MarioStateMachine() { + this.score = 0; + this.currentState = State.SMALL; + } + + public void obtainMushRoom() { + //TODO + } + + public void obtainCape() { + //TODO + } + + public void obtainFireFlower() { + //TODO + } + + public void meetMonster() { + //TODO + } + + public int getScore() { + return this.score; + } + + public State getCurrentState() { + return this.currentState; + } + + public void print() { + int score = this.score; + State state = this.currentState; + System.out.println("mario score: " + score + "; state: " + state); + } + +} \ No newline at end of file diff --git a/lesson-code/design/fsm/src/main/java/cn/cunchang/State.java b/lesson-code/design/fsm/src/main/java/cn/cunchang/State.java new file mode 100644 index 00000000..9aad3f87 --- /dev/null +++ b/lesson-code/design/fsm/src/main/java/cn/cunchang/State.java @@ -0,0 +1,17 @@ +package cn.cunchang; + +public enum State { + SMALL(0), + SUPER(1), + FIRE(2), + CAPE(3); + private int value; + + private State(int value) { + this.value = value; + } + + public int getValue() { + return this.value; + } +} \ No newline at end of file diff --git a/lesson-code/design/fsm/src/main/java/cn/cunchang/state/v1/ApplicationDemo.java b/lesson-code/design/fsm/src/main/java/cn/cunchang/state/v1/ApplicationDemo.java new file mode 100644 index 00000000..493c5eaf --- /dev/null +++ b/lesson-code/design/fsm/src/main/java/cn/cunchang/state/v1/ApplicationDemo.java @@ -0,0 +1,20 @@ +package cn.cunchang.state.v1; + +public class ApplicationDemo { + public static void main(String[] args) { + MarioStateMachine mario = new MarioStateMachine(); + // 吃了蘑菇 + mario.obtainMushRoom(); + mario.print(); + // 获得斗篷 + mario.obtainCape(); + mario.print(); + // 遇到怪物 + mario.meetMonster(); + mario.print(); + // 获得火焰 + mario.obtainFireFlower(); + mario.print(); + } + +} \ No newline at end of file diff --git a/lesson-code/design/fsm/src/main/java/cn/cunchang/state/v1/CapeMario.java b/lesson-code/design/fsm/src/main/java/cn/cunchang/state/v1/CapeMario.java new file mode 100644 index 00000000..5deb00b8 --- /dev/null +++ b/lesson-code/design/fsm/src/main/java/cn/cunchang/state/v1/CapeMario.java @@ -0,0 +1,36 @@ +package cn.cunchang.state.v1; + +public class CapeMario implements IMario { + + private MarioStateMachine stateMachine; + + public CapeMario(MarioStateMachine stateMachine) { + this.stateMachine = stateMachine; + } + + @Override + public State getName() { + return State.CAPE; + } + + @Override + public void obtainMushRoom() { + + } + + @Override + public void obtainCape() { + + } + + @Override + public void obtainFireFlower() { + + } + + @Override + public void meetMonster() { + stateMachine.setCurrentState(new SmallMario(stateMachine)); + stateMachine.setScore(stateMachine.getScore()-200); + } +} \ No newline at end of file diff --git a/lesson-code/design/fsm/src/main/java/cn/cunchang/state/v1/FireMario.java b/lesson-code/design/fsm/src/main/java/cn/cunchang/state/v1/FireMario.java new file mode 100644 index 00000000..0223438f --- /dev/null +++ b/lesson-code/design/fsm/src/main/java/cn/cunchang/state/v1/FireMario.java @@ -0,0 +1,36 @@ +package cn.cunchang.state.v1; + +public class FireMario implements IMario { + + private MarioStateMachine stateMachine; + + public FireMario(MarioStateMachine stateMachine) { + this.stateMachine = stateMachine; + } + + @Override + public State getName() { + return State.FIRE; + } + + @Override + public void obtainMushRoom() { + + } + + @Override + public void obtainCape() { + + } + + @Override + public void obtainFireFlower() { + + } + + @Override + public void meetMonster() { + stateMachine.setCurrentState(new SmallMario(stateMachine)); + stateMachine.setScore(stateMachine.getScore()-300); + } +} \ No newline at end of file diff --git a/lesson-code/design/fsm/src/main/java/cn/cunchang/state/v1/IMario.java b/lesson-code/design/fsm/src/main/java/cn/cunchang/state/v1/IMario.java new file mode 100644 index 00000000..60624030 --- /dev/null +++ b/lesson-code/design/fsm/src/main/java/cn/cunchang/state/v1/IMario.java @@ -0,0 +1,14 @@ +package cn.cunchang.state.v1; + +public interface IMario { //所有状态类的接口 + State getName(); + + //以下是定义的事件 + void obtainMushRoom(); + + void obtainCape(); + + void obtainFireFlower(); + + void meetMonster(); +} \ No newline at end of file diff --git a/lesson-code/design/fsm/src/main/java/cn/cunchang/state/v1/MarioStateMachine.java b/lesson-code/design/fsm/src/main/java/cn/cunchang/state/v1/MarioStateMachine.java new file mode 100644 index 00000000..c982ae1a --- /dev/null +++ b/lesson-code/design/fsm/src/main/java/cn/cunchang/state/v1/MarioStateMachine.java @@ -0,0 +1,50 @@ +package cn.cunchang.state.v1; + +public class MarioStateMachine { + private int score; + private IMario currentState; // 不再使用枚举来表示状态 + + public MarioStateMachine() { + this.score = 0; + this.currentState = new SmallMario(this); + } + + public void obtainMushRoom() { + this.currentState.obtainMushRoom(); + } + + public void obtainCape() { + this.currentState.obtainCape(); + } + + public void obtainFireFlower() { + this.currentState.obtainFireFlower(); + } + + public void meetMonster() { + this.currentState.meetMonster(); + } + + public int getScore() { + return this.score; + } + + public State getCurrentState() { + return this.currentState.getName(); + } + + public void setScore(int score) { + this.score = score; + } + + public void setCurrentState(IMario currentState) { + this.currentState = currentState; + } + + public void print(){ + int score = this.score; + State state = this.currentState.getName(); + System.out.println("mario score: " + score + "; state: " + state); + } + +} \ No newline at end of file diff --git a/lesson-code/design/fsm/src/main/java/cn/cunchang/state/v1/SmallMario.java b/lesson-code/design/fsm/src/main/java/cn/cunchang/state/v1/SmallMario.java new file mode 100644 index 00000000..48a92fb5 --- /dev/null +++ b/lesson-code/design/fsm/src/main/java/cn/cunchang/state/v1/SmallMario.java @@ -0,0 +1,38 @@ +package cn.cunchang.state.v1; + +public class SmallMario implements IMario { + + private MarioStateMachine stateMachine; + + public SmallMario(MarioStateMachine stateMachine) { + this.stateMachine = stateMachine; + } + + @Override + public State getName() { + return State.SMALL; + } + + @Override + public void obtainMushRoom() { + stateMachine.setCurrentState(new SuperMario(stateMachine)); + stateMachine.setScore(stateMachine.getScore()+100); + } + + @Override + public void obtainCape() { + stateMachine.setCurrentState(new CapeMario(stateMachine)); + stateMachine.setScore(stateMachine.getScore()+200); + } + + @Override + public void obtainFireFlower() { + stateMachine.setCurrentState(new FireMario(stateMachine)); + stateMachine.setScore(stateMachine.getScore()+300); + } + + @Override + public void meetMonster() { + + } +} \ No newline at end of file diff --git a/lesson-code/design/fsm/src/main/java/cn/cunchang/state/v1/State.java b/lesson-code/design/fsm/src/main/java/cn/cunchang/state/v1/State.java new file mode 100644 index 00000000..ad6436bf --- /dev/null +++ b/lesson-code/design/fsm/src/main/java/cn/cunchang/state/v1/State.java @@ -0,0 +1,18 @@ +package cn.cunchang.state.v1; + +public enum State { + SMALL(0), + SUPER(1), + CAPE(2), + FIRE(3), + ; + private int value; + + private State(int value) { + this.value = value; + } + + public int getValue() { + return this.value; + } +} \ No newline at end of file diff --git a/lesson-code/design/fsm/src/main/java/cn/cunchang/state/v1/SuperMario.java b/lesson-code/design/fsm/src/main/java/cn/cunchang/state/v1/SuperMario.java new file mode 100644 index 00000000..08bd431d --- /dev/null +++ b/lesson-code/design/fsm/src/main/java/cn/cunchang/state/v1/SuperMario.java @@ -0,0 +1,38 @@ +package cn.cunchang.state.v1; + +public class SuperMario implements IMario { + + private MarioStateMachine stateMachine; + + public SuperMario(MarioStateMachine stateMachine) { + this.stateMachine = stateMachine; + } + + @Override + public State getName() { + return State.SUPER; + } + + @Override + public void obtainMushRoom() { + + } + + @Override + public void obtainCape() { + stateMachine.setCurrentState(new CapeMario(stateMachine)); + stateMachine.setScore(stateMachine.getScore()+200); + } + + @Override + public void obtainFireFlower() { + stateMachine.setCurrentState(new FireMario(stateMachine)); + stateMachine.setScore(stateMachine.getScore()+300); + } + + @Override + public void meetMonster() { + stateMachine.setCurrentState(new SmallMario(stateMachine)); + stateMachine.setScore(stateMachine.getScore()-100); + } +} \ No newline at end of file diff --git a/lesson-code/design/fsm/src/main/java/cn/cunchang/state/v2/ApplicationDemo.java b/lesson-code/design/fsm/src/main/java/cn/cunchang/state/v2/ApplicationDemo.java new file mode 100644 index 00000000..0a525009 --- /dev/null +++ b/lesson-code/design/fsm/src/main/java/cn/cunchang/state/v2/ApplicationDemo.java @@ -0,0 +1,21 @@ +package cn.cunchang.state.v2; + +public class ApplicationDemo { + public static void main(String[] args) { + MarioStateMachine mario = new MarioStateMachine(); + mario.print(); + // 吃了蘑菇 + mario.obtainMushRoom(); + mario.print(); + // 获得斗篷 + mario.obtainCape(); + mario.print(); + // 遇到怪物 + mario.meetMonster(); + mario.print(); + // 获得火焰 + mario.obtainFireFlower(); + mario.print(); + } + +} \ No newline at end of file diff --git a/lesson-code/design/fsm/src/main/java/cn/cunchang/state/v2/CapeMario.java b/lesson-code/design/fsm/src/main/java/cn/cunchang/state/v2/CapeMario.java new file mode 100644 index 00000000..8eb2d47a --- /dev/null +++ b/lesson-code/design/fsm/src/main/java/cn/cunchang/state/v2/CapeMario.java @@ -0,0 +1,38 @@ +package cn.cunchang.state.v2; + +public class CapeMario implements IMario { + private static final CapeMario instance = new CapeMario(); + + private CapeMario() { + } + + public static CapeMario getInstance() { + return instance; + } + + @Override + public State getName() { + return State.CAPE; + } + + @Override + public void obtainMushRoom(MarioStateMachine stateMachine) { + + } + + @Override + public void obtainCape(MarioStateMachine stateMachine) { + + } + + @Override + public void obtainFireFlower(MarioStateMachine stateMachine) { + + } + + @Override + public void meetMonster(MarioStateMachine stateMachine) { + stateMachine.setCurrentState(SmallMario.getInstance()); + stateMachine.setScore(stateMachine.getScore()-200); + } +} \ No newline at end of file diff --git a/lesson-code/design/fsm/src/main/java/cn/cunchang/state/v2/FireMario.java b/lesson-code/design/fsm/src/main/java/cn/cunchang/state/v2/FireMario.java new file mode 100644 index 00000000..6bb65309 --- /dev/null +++ b/lesson-code/design/fsm/src/main/java/cn/cunchang/state/v2/FireMario.java @@ -0,0 +1,39 @@ +package cn.cunchang.state.v2; + +public class FireMario implements IMario { + + private static final FireMario instance = new FireMario(); + + private FireMario() { + } + + public static FireMario getInstance() { + return instance; + } + + @Override + public State getName() { + return State.FIRE; + } + + @Override + public void obtainMushRoom(MarioStateMachine stateMachine) { + + } + + @Override + public void obtainCape(MarioStateMachine stateMachine) { + + } + + @Override + public void obtainFireFlower(MarioStateMachine stateMachine) { + + } + + @Override + public void meetMonster(MarioStateMachine stateMachine) { + stateMachine.setCurrentState(SmallMario.getInstance()); + stateMachine.setScore(stateMachine.getScore()-300); + } +} \ No newline at end of file diff --git a/lesson-code/design/fsm/src/main/java/cn/cunchang/state/v2/IMario.java b/lesson-code/design/fsm/src/main/java/cn/cunchang/state/v2/IMario.java new file mode 100644 index 00000000..c680d09e --- /dev/null +++ b/lesson-code/design/fsm/src/main/java/cn/cunchang/state/v2/IMario.java @@ -0,0 +1,14 @@ +package cn.cunchang.state.v2; + +public interface IMario { //所有状态类的接口 + State getName(); + + //以下是定义的事件 + void obtainMushRoom(MarioStateMachine stateMachine); + + void obtainCape(MarioStateMachine stateMachine); + + void obtainFireFlower(MarioStateMachine stateMachine); + + void meetMonster(MarioStateMachine stateMachine); +} \ No newline at end of file diff --git a/lesson-code/design/fsm/src/main/java/cn/cunchang/state/v2/MarioStateMachine.java b/lesson-code/design/fsm/src/main/java/cn/cunchang/state/v2/MarioStateMachine.java new file mode 100644 index 00000000..777e9f19 --- /dev/null +++ b/lesson-code/design/fsm/src/main/java/cn/cunchang/state/v2/MarioStateMachine.java @@ -0,0 +1,50 @@ +package cn.cunchang.state.v2; + +public class MarioStateMachine { + private int score; + private IMario currentState; // 不再使用枚举来表示状态 + + public MarioStateMachine() { + this.score = 0; + this.currentState = SmallMario.getInstance(); + } + + public void obtainMushRoom() { + this.currentState.obtainMushRoom(this); + } + + public void obtainCape() { + this.currentState.obtainCape(this); + } + + public void obtainFireFlower() { + this.currentState.obtainFireFlower(this); + } + + public void meetMonster() { + this.currentState.meetMonster(this); + } + + public int getScore() { + return this.score; + } + + public State getCurrentState() { + return this.currentState.getName(); + } + + public void setScore(int score) { + this.score = score; + } + + public void setCurrentState(IMario currentState) { + this.currentState = currentState; + } + + public void print(){ + int score = this.score; + State state = this.getCurrentState(); + System.out.println("mario score: " + score + "; state: " + state); + } + +} \ No newline at end of file diff --git a/lesson-code/design/fsm/src/main/java/cn/cunchang/state/v2/SmallMario.java b/lesson-code/design/fsm/src/main/java/cn/cunchang/state/v2/SmallMario.java new file mode 100644 index 00000000..9e36e300 --- /dev/null +++ b/lesson-code/design/fsm/src/main/java/cn/cunchang/state/v2/SmallMario.java @@ -0,0 +1,42 @@ +package cn.cunchang.state.v2; + +public class SmallMario implements IMario { + + private static final SmallMario instance = new SmallMario(); + + private SmallMario() { + } + + public static SmallMario getInstance() { + return instance; + } + + + @Override + public State getName() { + return State.SMALL; + } + + @Override + public void obtainMushRoom(MarioStateMachine stateMachine) { + stateMachine.setCurrentState(SuperMario.getInstance()); + stateMachine.setScore(stateMachine.getScore() + 100); + } + + @Override + public void obtainCape(MarioStateMachine stateMachine) { + stateMachine.setCurrentState(CapeMario.getInstance()); + stateMachine.setScore(stateMachine.getScore() + 200); + } + + @Override + public void obtainFireFlower(MarioStateMachine stateMachine) { + stateMachine.setCurrentState(FireMario.getInstance()); + stateMachine.setScore(stateMachine.getScore() + 300); + } + + @Override + public void meetMonster(MarioStateMachine stateMachine) { + + } +} \ No newline at end of file diff --git a/lesson-code/design/fsm/src/main/java/cn/cunchang/state/v2/State.java b/lesson-code/design/fsm/src/main/java/cn/cunchang/state/v2/State.java new file mode 100644 index 00000000..4f50886d --- /dev/null +++ b/lesson-code/design/fsm/src/main/java/cn/cunchang/state/v2/State.java @@ -0,0 +1,18 @@ +package cn.cunchang.state.v2; + +public enum State { + SMALL(0), + SUPER(1), + CAPE(2), + FIRE(3), + ; + private int value; + + private State(int value) { + this.value = value; + } + + public int getValue() { + return this.value; + } +} \ No newline at end of file diff --git a/lesson-code/design/fsm/src/main/java/cn/cunchang/state/v2/SuperMario.java b/lesson-code/design/fsm/src/main/java/cn/cunchang/state/v2/SuperMario.java new file mode 100644 index 00000000..3bb18d68 --- /dev/null +++ b/lesson-code/design/fsm/src/main/java/cn/cunchang/state/v2/SuperMario.java @@ -0,0 +1,41 @@ +package cn.cunchang.state.v2; + +public class SuperMario implements IMario { + + private static final SuperMario instance = new SuperMario(); + + private SuperMario() { + } + + public static SuperMario getInstance() { + return instance; + } + + @Override + public State getName() { + return State.SUPER; + } + + @Override + public void obtainMushRoom(MarioStateMachine stateMachine) { + + } + + @Override + public void obtainCape(MarioStateMachine stateMachine) { + stateMachine.setCurrentState(CapeMario.getInstance()); + stateMachine.setScore(stateMachine.getScore()+200); + } + + @Override + public void obtainFireFlower(MarioStateMachine stateMachine) { + stateMachine.setCurrentState(FireMario.getInstance()); + stateMachine.setScore(stateMachine.getScore()+300); + } + + @Override + public void meetMonster(MarioStateMachine stateMachine) { + stateMachine.setCurrentState(SmallMario.getInstance()); + stateMachine.setScore(stateMachine.getScore()-100); + } +} \ No newline at end of file diff --git a/lesson-code/design/fsm/src/main/java/cn/cunchang/switchcase/ApplicationDemo.java b/lesson-code/design/fsm/src/main/java/cn/cunchang/switchcase/ApplicationDemo.java new file mode 100644 index 00000000..bc2ad543 --- /dev/null +++ b/lesson-code/design/fsm/src/main/java/cn/cunchang/switchcase/ApplicationDemo.java @@ -0,0 +1,21 @@ +package cn.cunchang.switchcase; + +public class ApplicationDemo { + public static void main(String[] args) { + MarioStateMachine mario = new MarioStateMachine(); + mario.print(); + // 吃了蘑菇 + mario.obtainMushRoom(); + mario.print(); + // 获得斗篷 + mario.obtainCape(); + mario.print(); + // 遇到怪物 + mario.meetMonster(); + mario.print(); + // 获得火焰 + mario.obtainFireFlower(); + mario.print(); + } + +} \ No newline at end of file diff --git a/lesson-code/design/fsm/src/main/java/cn/cunchang/switchcase/MarioStateMachine.java b/lesson-code/design/fsm/src/main/java/cn/cunchang/switchcase/MarioStateMachine.java new file mode 100644 index 00000000..b4ba58f5 --- /dev/null +++ b/lesson-code/design/fsm/src/main/java/cn/cunchang/switchcase/MarioStateMachine.java @@ -0,0 +1,66 @@ +package cn.cunchang.switchcase; + +import java.util.Objects; + +public class MarioStateMachine { + private int score; + private State currentState; + + public MarioStateMachine() { + this.score = 0; + this.currentState = State.SMALL; + } + + public void obtainMushRoom() { + if (Objects.equals(this.currentState, State.SMALL)) { + this.score += 100; + this.currentState = State.SUPER; + } + } + + public void obtainCape() { + if (Objects.equals(this.currentState, State.SMALL) || + Objects.equals(this.currentState, State.SUPER)) { + this.score += 200; + this.currentState = State.CAPE; + } + } + + public void obtainFireFlower() { + if (Objects.equals(this.currentState, State.SMALL) || + Objects.equals(this.currentState, State.SUPER)) { + this.score += 300; + this.currentState = State.FIRE; + } + } + + public void meetMonster() { + if (Objects.equals(this.currentState, State.SUPER)) { + this.score -= 100; + this.currentState = State.SMALL; + } + if (Objects.equals(this.currentState, State.CAPE)) { + this.score -= 200; + this.currentState = State.SMALL; + } + if (Objects.equals(this.currentState, State.FIRE)) { + this.score -= 300; + this.currentState = State.SMALL; + } + } + + public int getScore() { + return this.score; + } + + public State getCurrentState() { + return this.currentState; + } + + public void print(){ + int score = this.score; + State state = this.currentState; + System.out.println("mario score: " + score + "; state: " + state); + } + +} \ No newline at end of file diff --git a/lesson-code/design/fsm/src/main/java/cn/cunchang/switchcase/State.java b/lesson-code/design/fsm/src/main/java/cn/cunchang/switchcase/State.java new file mode 100644 index 00000000..e73af6b9 --- /dev/null +++ b/lesson-code/design/fsm/src/main/java/cn/cunchang/switchcase/State.java @@ -0,0 +1,18 @@ +package cn.cunchang.switchcase; + +public enum State { + SMALL(0), + SUPER(1), + CAPE(2), + FIRE(3), + ; + private int value; + + private State(int value) { + this.value = value; + } + + public int getValue() { + return this.value; + } +} \ No newline at end of file diff --git a/lesson-code/design/fsm/src/main/java/cn/cunchang/table/ApplicationDemo.java b/lesson-code/design/fsm/src/main/java/cn/cunchang/table/ApplicationDemo.java new file mode 100644 index 00000000..89934837 --- /dev/null +++ b/lesson-code/design/fsm/src/main/java/cn/cunchang/table/ApplicationDemo.java @@ -0,0 +1,21 @@ +package cn.cunchang.table; + +public class ApplicationDemo { + public static void main(String[] args) { + MarioStateMachine mario = new MarioStateMachine(); + mario.print(); + // 吃了蘑菇 + mario.obtainMushRoom(); + mario.print(); + // 获得斗篷 + mario.obtainCape(); + mario.print(); + // 遇到怪物 + mario.meetMonster(); + mario.print(); + // 获得火焰 + mario.obtainFireFlower(); + mario.print(); + } + +} \ No newline at end of file diff --git a/lesson-code/design/fsm/src/main/java/cn/cunchang/table/Event.java b/lesson-code/design/fsm/src/main/java/cn/cunchang/table/Event.java new file mode 100644 index 00000000..3f3103ee --- /dev/null +++ b/lesson-code/design/fsm/src/main/java/cn/cunchang/table/Event.java @@ -0,0 +1,17 @@ +package cn.cunchang.table; + +public enum Event { + GOT_MUSHROOM(0), + GOT_CAPE(1), + GOT_FIRE(2), + MET_MONSTER(3); + private int value; + + private Event(int value) { + this.value = value; + } + + public int getValue() { + return this.value; + } +} \ No newline at end of file diff --git a/lesson-code/design/fsm/src/main/java/cn/cunchang/table/MarioStateMachine.java b/lesson-code/design/fsm/src/main/java/cn/cunchang/table/MarioStateMachine.java new file mode 100644 index 00000000..a80a0a78 --- /dev/null +++ b/lesson-code/design/fsm/src/main/java/cn/cunchang/table/MarioStateMachine.java @@ -0,0 +1,63 @@ +package cn.cunchang.table; + +import static cn.cunchang.table.State.*; + +public class MarioStateMachine { + private int score; + private State currentState; + private static final State[][] transitionTable = { + {SUPER, CAPE, FIRE, SMALL}, + {SUPER, CAPE, FIRE, SMALL}, + {CAPE, CAPE, CAPE, SMALL}, + {FIRE, FIRE, FIRE, SMALL} + }; + private static final int[][] actionTable = { + {+100, +200, +300, +0}, + {+0, +200, +300, -100}, + {+0, +0, +0, -200}, + {+0, +0, +0, -300} + }; + + public MarioStateMachine() { + this.score = 0; + this.currentState = State.SMALL; + } + + public void obtainMushRoom() { + executeEvent(Event.GOT_MUSHROOM); + } + + public void obtainCape() { + executeEvent(Event.GOT_CAPE); + } + + public void obtainFireFlower() { + executeEvent(Event.GOT_FIRE); + } + + public void meetMonster() { + executeEvent(Event.MET_MONSTER); + } + + private void executeEvent(Event event) { + int stateValue = currentState.getValue(); + int eventValue = event.getValue(); + this.currentState = transitionTable[stateValue][eventValue]; + this.score += actionTable[stateValue][eventValue]; + } + + public int getScore() { + return this.score; + } + + public State getCurrentState() { + return this.currentState; + } + + public void print(){ + int score = this.score; + State state = this.currentState; + System.out.println("mario score: " + score + "; state: " + state); + } + +} \ No newline at end of file diff --git a/lesson-code/design/fsm/src/main/java/cn/cunchang/table/State.java b/lesson-code/design/fsm/src/main/java/cn/cunchang/table/State.java new file mode 100644 index 00000000..4c5d346f --- /dev/null +++ b/lesson-code/design/fsm/src/main/java/cn/cunchang/table/State.java @@ -0,0 +1,19 @@ +package cn.cunchang.table; + +public enum State { + SMALL(0), + SUPER(1), + CAPE(2), + FIRE(3), + + ; + private int value; + + private State(int value) { + this.value = value; + } + + public int getValue() { + return this.value; + } +} \ No newline at end of file diff --git a/lesson-code/java-common-mistakes/pom.xml b/lesson-code/java-common-mistakes/pom.xml new file mode 100644 index 00000000..45a476a1 --- /dev/null +++ b/lesson-code/java-common-mistakes/pom.xml @@ -0,0 +1,50 @@ + + + 4.0.0 + + cn.cunchang + java-common-mistakes + 1.0-SNAPSHOT + + + 8 + 8 + + + + + + org.slf4j + slf4j-api + 1.7.26 + + + + ch.qos.logback + logback-classic + 1.2.3 + + + + org.projectlombok + lombok + 1.18.20 + + + + junit + junit + 4.13.1 + + + + org.jodd + jodd-core + 5.1.6 + + + + + \ No newline at end of file diff --git a/lesson-code/java-common-mistakes/src/main/java/cn/cunchang/TestSomething.java b/lesson-code/java-common-mistakes/src/main/java/cn/cunchang/TestSomething.java new file mode 100644 index 00000000..760789ab --- /dev/null +++ b/lesson-code/java-common-mistakes/src/main/java/cn/cunchang/TestSomething.java @@ -0,0 +1,45 @@ +package cn.cunchang; + +import org.junit.Test; + +import java.time.LocalDate; +import java.time.Period; +import java.time.format.DateTimeFormatter; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +/** + * @author cunchang + * @date 2021/7/13 9:55 上午 + */ +public class TestSomething { + + @Test + public void test1() { + String payload = IntStream.rangeClosed(1, 1000000) + .mapToObj((item) -> "a") + .collect(Collectors.joining("")); + System.out.println(payload.length()); + } + + @Test + public void test2() { +// LocalDate startDate = LocalDate.now().plusDays(-17L); + LocalDate startDate = LocalDate.parse("20210701", DateTimeFormatter.ofPattern("yyyyMMdd")); + LocalDate endDate = LocalDate.parse("20210713", DateTimeFormatter.ofPattern("yyyyMMdd")); + + endDate = endDate.plusDays(1L); + + Period between = Period.between(startDate, endDate); + System.out.println(between.getDays()); + + int i=0; + while (startDate.isBefore(endDate)) { + i++; + System.out.println(startDate); + startDate = startDate.plusDays(1L); + } + System.out.println("i:"+i); + } + +} diff --git a/lesson-code/java-common-mistakes/src/main/java/cn/cunchang/repeatcode/Cart.java b/lesson-code/java-common-mistakes/src/main/java/cn/cunchang/repeatcode/Cart.java new file mode 100644 index 00000000..fee2e880 --- /dev/null +++ b/lesson-code/java-common-mistakes/src/main/java/cn/cunchang/repeatcode/Cart.java @@ -0,0 +1,22 @@ +package cn.cunchang.repeatcode; + +import lombok.Data; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; + +//购物车 +@Data +public class Cart { + //商品清单 + private List items = new ArrayList<>(); + //总优惠 + private BigDecimal totalDiscount; + //商品总价 + private BigDecimal totalItemPrice; + //总运费 + private BigDecimal totalDeliveryPrice; + //应付总价 + private BigDecimal payPrice; +} \ No newline at end of file diff --git a/lesson-code/java-common-mistakes/src/main/java/cn/cunchang/repeatcode/Db.java b/lesson-code/java-common-mistakes/src/main/java/cn/cunchang/repeatcode/Db.java new file mode 100644 index 00000000..af3c6249 --- /dev/null +++ b/lesson-code/java-common-mistakes/src/main/java/cn/cunchang/repeatcode/Db.java @@ -0,0 +1,31 @@ +package cn.cunchang.repeatcode; + +import java.math.BigDecimal; +import java.util.HashMap; +import java.util.Map; + +public class Db { + + private static Map items = new HashMap<>(); + + static { + items.put(1L, new BigDecimal("10")); + items.put(2L, new BigDecimal("20")); + } + + public static BigDecimal getItemPrice(long id) { + return items.get(id); + } + + public static String getUserCategory(long userId) { + + if (userId == 1L) return "Normal"; + if (userId == 2L) return "Vip"; + if (userId == 3L) return "Internal"; + return "Normal"; + } + + public static int getUserCouponPercent(long userId) { + return 90; + } +} \ No newline at end of file diff --git a/lesson-code/java-common-mistakes/src/main/java/cn/cunchang/repeatcode/Item.java b/lesson-code/java-common-mistakes/src/main/java/cn/cunchang/repeatcode/Item.java new file mode 100644 index 00000000..bfcb1b3c --- /dev/null +++ b/lesson-code/java-common-mistakes/src/main/java/cn/cunchang/repeatcode/Item.java @@ -0,0 +1,20 @@ +package cn.cunchang.repeatcode; + +import lombok.Data; + +import java.math.BigDecimal; + +//购物车中的商品 +@Data +public class Item { + //商品ID + private long id; + //商品数量 + private int quantity; + //商品单价 + private BigDecimal price; + //商品优惠 + private BigDecimal couponPrice; + //商品运费 + private BigDecimal deliveryPrice; +} \ No newline at end of file diff --git a/lesson-code/java-common-mistakes/src/main/java/cn/cunchang/repeatcode/NormalUserCart.java b/lesson-code/java-common-mistakes/src/main/java/cn/cunchang/repeatcode/NormalUserCart.java new file mode 100644 index 00000000..d9d7968c --- /dev/null +++ b/lesson-code/java-common-mistakes/src/main/java/cn/cunchang/repeatcode/NormalUserCart.java @@ -0,0 +1,42 @@ +package cn.cunchang.repeatcode; + + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class NormalUserCart { + public Cart process(long userId, Map items) { + Cart cart = new Cart(); + + //把Map的购物车转换为Item列表 + List itemList = new ArrayList<>(); + items.entrySet().stream().forEach(entry -> { + Item item = new Item(); + item.setId(entry.getKey()); + item.setPrice(Db.getItemPrice(entry.getKey())); + item.setQuantity(entry.getValue()); + itemList.add(item); + }); + cart.setItems(itemList); + + //处理运费和商品优惠 + itemList.stream().forEach(item -> { + //运费为商品总价的10% + item.setDeliveryPrice(item.getPrice().multiply(BigDecimal.valueOf(item.getQuantity())).multiply(new BigDecimal("0.1"))); + //无优惠 + item.setCouponPrice(BigDecimal.ZERO); + }); + + //计算纯商品总价 + cart.setTotalItemPrice(cart.getItems().stream().map(item -> item.getPrice().multiply(BigDecimal.valueOf(item.getQuantity()))).reduce(BigDecimal.ZERO, BigDecimal::add)); + //计算运费总价 + cart.setTotalDeliveryPrice(cart.getItems().stream().map(Item::getDeliveryPrice).reduce(BigDecimal.ZERO, BigDecimal::add)); + //计算总优惠 + cart.setTotalDiscount(cart.getItems().stream().map(Item::getCouponPrice).reduce(BigDecimal.ZERO, BigDecimal::add)); + //应付总价=商品总价+运费总价-总优惠 + cart.setPayPrice(cart.getTotalItemPrice().add(cart.getTotalDeliveryPrice()).subtract(cart.getTotalDiscount())); + return cart; + } +} \ No newline at end of file diff --git a/lesson-code/java-common-mistakes/src/main/java/cn/cunchang/repeatcode/wrong/InternalUserCart.java b/lesson-code/java-common-mistakes/src/main/java/cn/cunchang/repeatcode/wrong/InternalUserCart.java new file mode 100644 index 00000000..1f6857a2 --- /dev/null +++ b/lesson-code/java-common-mistakes/src/main/java/cn/cunchang/repeatcode/wrong/InternalUserCart.java @@ -0,0 +1,40 @@ +package cn.cunchang.repeatcode.wrong; + +import cn.cunchang.repeatcode.Cart; +import cn.cunchang.repeatcode.Db; +import cn.cunchang.repeatcode.Item; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class InternalUserCart { + + public Cart process(long userId, Map items) { + Cart cart = new Cart(); + + List itemList = new ArrayList<>(); + items.entrySet().stream().forEach(entry -> { + Item item = new Item(); + item.setId(entry.getKey()); + item.setPrice(Db.getItemPrice(entry.getKey())); + item.setQuantity(entry.getValue()); + itemList.add(item); + }); + cart.setItems(itemList); + + itemList.stream().forEach(item -> { + //免运费 + item.setDeliveryPrice(BigDecimal.ZERO); + //无优惠 + item.setCouponPrice(BigDecimal.ZERO); + }); + + cart.setTotalItemPrice(cart.getItems().stream().map(item -> item.getPrice().multiply(BigDecimal.valueOf(item.getQuantity()))).reduce(BigDecimal.ZERO, BigDecimal::add)); + cart.setTotalDeliveryPrice(cart.getItems().stream().map(Item::getDeliveryPrice).reduce(BigDecimal.ZERO, BigDecimal::add)); + cart.setTotalDiscount(cart.getItems().stream().map(Item::getCouponPrice).reduce(BigDecimal.ZERO, BigDecimal::add)); + cart.setPayPrice(cart.getTotalItemPrice().add(cart.getTotalDeliveryPrice()).subtract(cart.getTotalDiscount())); + return cart; + } +} \ No newline at end of file diff --git a/lesson-code/java-common-mistakes/src/main/java/cn/cunchang/repeatcode/wrong/NormalUserCart.java b/lesson-code/java-common-mistakes/src/main/java/cn/cunchang/repeatcode/wrong/NormalUserCart.java new file mode 100644 index 00000000..8f238dba --- /dev/null +++ b/lesson-code/java-common-mistakes/src/main/java/cn/cunchang/repeatcode/wrong/NormalUserCart.java @@ -0,0 +1,45 @@ +package cn.cunchang.repeatcode.wrong; + +import cn.cunchang.repeatcode.Cart; +import cn.cunchang.repeatcode.Db; +import cn.cunchang.repeatcode.Item; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class NormalUserCart { + public Cart process(long userId, Map items) { + Cart cart = new Cart(); + + //把Map的购物车转换为Item列表 + List itemList = new ArrayList<>(); + items.entrySet().stream().forEach(entry -> { + Item item = new Item(); + item.setId(entry.getKey()); + item.setPrice(Db.getItemPrice(entry.getKey())); + item.setQuantity(entry.getValue()); + itemList.add(item); + }); + cart.setItems(itemList); + + //处理运费和商品优惠 + itemList.stream().forEach(item -> { + //运费为商品总价的10% + item.setDeliveryPrice(item.getPrice().multiply(BigDecimal.valueOf(item.getQuantity())).multiply(new BigDecimal("0.1"))); + //无优惠 + item.setCouponPrice(BigDecimal.ZERO); + }); + + //计算纯商品总价 + cart.setTotalItemPrice(cart.getItems().stream().map(item -> item.getPrice().multiply(BigDecimal.valueOf(item.getQuantity()))).reduce(BigDecimal.ZERO, BigDecimal::add)); + //计算运费总价 + cart.setTotalDeliveryPrice(cart.getItems().stream().map(Item::getDeliveryPrice).reduce(BigDecimal.ZERO, BigDecimal::add)); + //计算总优惠 + cart.setTotalDiscount(cart.getItems().stream().map(Item::getCouponPrice).reduce(BigDecimal.ZERO, BigDecimal::add)); + //应付总价=商品总价+运费总价-总优惠 + cart.setPayPrice(cart.getTotalItemPrice().add(cart.getTotalDeliveryPrice()).subtract(cart.getTotalDiscount())); + return cart; + } +} diff --git a/lesson-code/java-common-mistakes/src/main/java/cn/cunchang/repeatcode/wrong/VipUserCart.java b/lesson-code/java-common-mistakes/src/main/java/cn/cunchang/repeatcode/wrong/VipUserCart.java new file mode 100644 index 00000000..bc99fa4b --- /dev/null +++ b/lesson-code/java-common-mistakes/src/main/java/cn/cunchang/repeatcode/wrong/VipUserCart.java @@ -0,0 +1,46 @@ +package cn.cunchang.repeatcode.wrong; + +import cn.cunchang.repeatcode.Cart; +import cn.cunchang.repeatcode.Db; +import cn.cunchang.repeatcode.Item; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class VipUserCart { + + public Cart process(long userId, Map items) { + Cart cart = new Cart(); + + List itemList = new ArrayList<>(); + items.entrySet().stream().forEach(entry -> { + Item item = new Item(); + item.setId(entry.getKey()); + item.setPrice(Db.getItemPrice(entry.getKey())); + item.setQuantity(entry.getValue()); + itemList.add(item); + }); + cart.setItems(itemList); + + itemList.stream().forEach(item -> { + //运费为商品总价的10% + item.setDeliveryPrice(item.getPrice().multiply(BigDecimal.valueOf(item.getQuantity())).multiply(new BigDecimal("0.1"))); + //购买两件以上相同商品,第三件开始享受一定折扣 + if (item.getQuantity() > 2) { + item.setCouponPrice(item.getPrice() + .multiply(BigDecimal.valueOf(100 - Db.getUserCouponPercent(userId)).divide(new BigDecimal("100"))) + .multiply(BigDecimal.valueOf(item.getQuantity() - 2))); + } else { + item.setCouponPrice(BigDecimal.ZERO); + } + }); + + cart.setTotalItemPrice(cart.getItems().stream().map(item -> item.getPrice().multiply(BigDecimal.valueOf(item.getQuantity()))).reduce(BigDecimal.ZERO, BigDecimal::add)); + cart.setTotalDeliveryPrice(cart.getItems().stream().map(Item::getDeliveryPrice).reduce(BigDecimal.ZERO, BigDecimal::add)); + cart.setTotalDiscount(cart.getItems().stream().map(Item::getCouponPrice).reduce(BigDecimal.ZERO, BigDecimal::add)); + cart.setPayPrice(cart.getTotalItemPrice().add(cart.getTotalDeliveryPrice()).subtract(cart.getTotalDiscount())); + return cart; + } +} \ No newline at end of file diff --git a/lesson-code/java-common-mistakes/src/main/java/cn/cunchang/threadpool/ExtremeThreadPoolExecutor.java b/lesson-code/java-common-mistakes/src/main/java/cn/cunchang/threadpool/ExtremeThreadPoolExecutor.java new file mode 100644 index 00000000..caff249b --- /dev/null +++ b/lesson-code/java-common-mistakes/src/main/java/cn/cunchang/threadpool/ExtremeThreadPoolExecutor.java @@ -0,0 +1,72 @@ +package cn.cunchang.threadpool; + +import java.util.concurrent.*; + +/** + * @description 自定义激进线程池,在核心线程数满了后,新的任务来了,直接创建线程,直到达到最大线程数,此时再新来任务,此时再加入阻塞队列 + * @author: darren + * @data: 2020-03-12 10:19 + */ +public class ExtremeThreadPoolExecutor extends ThreadPoolExecutor { + + /** + * 构造方法 + * @param corePoolSize 核心线程数 + * @param maximumPoolSize 最大线程数 + * @param keepAliveTime 非核心线程数保留时长 + * @param unit 非核心线程数保留时长单位 + * @param blockQueueSize 阻塞队列长度 + */ + public ExtremeThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, int blockQueueSize) { + super(corePoolSize, maximumPoolSize, keepAliveTime, unit, new ExtremeBlockQueue(blockQueueSize), Executors.defaultThreadFactory(), new ExtremePolicy()); + + } + + /** + * 自定义阻塞队列 + * @param + */ + static class ExtremeBlockQueue extends LinkedBlockingQueue { + public ExtremeBlockQueue(int capacity) { + super(capacity); + } + + /** + * 覆盖默认的offer方法,触发拒绝策略执行 + * @param runnable + * @return + */ + @Override + public boolean offer(Runnable runnable) { + return false; + } + + /** + * 拒绝策略触发后,真正的保存进阻塞队列 + * @param runnable + * @return + */ + public boolean extremeOffer(Runnable runnable) { + return super.offer(runnable); + } + } + + /** + * 自定义拒绝策略 + */ + static class ExtremePolicy implements RejectedExecutionHandler { + @Override + public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { + //线程池非关闭 + if (!e.isShutdown()) { + //真正入阻塞队列,若阻塞队列已满,则抛出RejectedExecutionException + if (!((ExtremeBlockQueue)e.getQueue()).extremeOffer(r)) { + //可以真正进行触发策略的执行(不管是默认的,还是自定义的) + throw new RejectedExecutionException("Task " + r.toString() + + " rejected from " + + e.toString()); + } + } + } + } +} \ No newline at end of file diff --git a/lesson-code/java-common-mistakes/src/main/java/cn/cunchang/threadpool/README.md b/lesson-code/java-common-mistakes/src/main/java/cn/cunchang/threadpool/README.md new file mode 100644 index 00000000..77b8f832 --- /dev/null +++ b/lesson-code/java-common-mistakes/src/main/java/cn/cunchang/threadpool/README.md @@ -0,0 +1,20 @@ + +```properties + +-Xms100m -Xmx100m -XX:+HeapDumpOnOutOfMemoryError + +java.lang.OutOfMemoryError: GC overhead limit exceeded +Dumping heap to java_pid7565.hprof ... +Heap dump file created [163563855 bytes in 0.990 secs] +Exception in thread "main" *** java.lang.instrument ASSERTION FAILED ***: "!errorOutstanding" with message can't create name string at JPLISAgent.c line: 807 +[INFO ] 2021-07-13 14:54:06.416 cn.cunchang.threadpool.ThreadPoolOOMTest lambda$printStats$4 81 [pool-2-thread-1] Pool Size: 1 +java.lang.OutOfMemoryError: GC overhead limit exceeded +at java.util.concurrent.LinkedBlockingQueue.offer(LinkedBlockingQueue.java:416) +at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1371) +at cn.cunchang.threadpool.ThreadPoolOOMTest.newFixedThreadPool_oom(ThreadPoolOOMTest.java:37) +at cn.cunchang.threadpool.ThreadPoolOOMTest.main(ThreadPoolOOMTest.java:21) + +``` + + + diff --git a/lesson-code/java-common-mistakes/src/main/java/cn/cunchang/threadpool/ThreadPoolExpansiveTest.java b/lesson-code/java-common-mistakes/src/main/java/cn/cunchang/threadpool/ThreadPoolExpansiveTest.java new file mode 100644 index 00000000..e516c5fb --- /dev/null +++ b/lesson-code/java-common-mistakes/src/main/java/cn/cunchang/threadpool/ThreadPoolExpansiveTest.java @@ -0,0 +1,74 @@ +package cn.cunchang.threadpool; + +import jodd.util.concurrent.ThreadFactoryBuilder; +import lombok.extern.slf4j.Slf4j; + +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.IntStream; + +/** + * + * @author cunchang + * @date 2021/7/14 6:34 下午 + */ +@Slf4j +public class ThreadPoolExpansiveTest { + + public static void main(String[] args) throws InterruptedException { + System.out.println("总条数:20,成功条数:"+right());; + } + + /** + * 线程池最大线程扩容太晚,导致任务丢弃 + * + * @return + * @throws InterruptedException + */ + public static int right() throws InterruptedException { + //使用一个计数器跟踪完成的任务数 + AtomicInteger atomicInteger = new AtomicInteger(); + //创建一个具有2个核心线程、5个最大线程,使用容量为10的ArrayBlockingQueue阻塞队列作为工 + ThreadPoolExecutor threadPool = new ThreadPoolExecutor( + 2, 5, + 5, TimeUnit.SECONDS, + new ArrayBlockingQueue<>(10), + new ThreadFactoryBuilder().setNameFormat("demo-threadpool-%d").get(), + new ThreadPoolExecutor.AbortPolicy()); + //threadPool.allowCoreThreadTimeOut(true); +// printStats(threadPool); + //每隔1秒提交一次,一共提交20次任务 + IntStream.rangeClosed(1, 20).forEach(i -> { + + try { + TimeUnit.SECONDS.sleep(1); + } catch (InterruptedException e) { + e.printStackTrace(); + } + int id = atomicInteger.incrementAndGet(); + try { + + threadPool.submit(() -> { + log.info("{} started", id); + //每个任务耗时10秒 + try { + TimeUnit.SECONDS.sleep(10); + } catch (InterruptedException e) { + } + log.info("{} finished", id); + }); + } catch (Exception ex) { + //提交出现异常的话,打印出错信息并为计数器减一 + log.error("error submitting task {}", id, ex); + atomicInteger.decrementAndGet(); + } + }); + + TimeUnit.SECONDS.sleep(60); + return atomicInteger.intValue(); + } + + +} diff --git a/lesson-code/java-common-mistakes/src/main/java/cn/cunchang/threadpool/ThreadPoolOOMTest.java b/lesson-code/java-common-mistakes/src/main/java/cn/cunchang/threadpool/ThreadPoolOOMTest.java new file mode 100644 index 00000000..20792a7b --- /dev/null +++ b/lesson-code/java-common-mistakes/src/main/java/cn/cunchang/threadpool/ThreadPoolOOMTest.java @@ -0,0 +1,97 @@ +package cn.cunchang.threadpool; + +import jodd.util.concurrent.ThreadFactoryBuilder; +import lombok.extern.slf4j.Slf4j; + +import java.util.UUID; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +/** + * 线程池oom + * + * @author cunchang + * @date 2021/7/13 1:49 上午 + */ +@Slf4j +public class ThreadPoolOOMTest { + + public static void main(String[] args) throws InterruptedException { + // Executors.newFixedThreadPool,固定线程,队列无限大,导致oom +// newFixedThreadPool_oom(); + + // Executors.newCachedThreadPool,无限创建线程,导致oom +// newCachedThreadPool_oom(); + + } + + /** + * -Xms10m -Xmx10m -XX:+HeapDumpOnOutOfMemoryError + *

+ * 任务较多并且执行较慢的话,队列可能会快速积压,导致oom + * + * @throws InterruptedException + */ + public static void newFixedThreadPool_oom() throws InterruptedException { + + ThreadPoolExecutor threadPool = (ThreadPoolExecutor) Executors.newFixedThreadPool(1); + printStats(threadPool); + for (int i = 0; i < 100000000; i++) { + threadPool.execute(() -> { + String payload = IntStream.rangeClosed(1, 1000000) + .mapToObj(__ -> "a") + .collect(Collectors.joining("")) + UUID.randomUUID().toString(); + try { + TimeUnit.HOURS.sleep(1); + } catch (InterruptedException e) { + } + log.info(payload); + }); + } + + threadPool.shutdown(); + threadPool.awaitTermination(1, TimeUnit.HOURS); + } + + /** + * @throws InterruptedException + */ + public static void newCachedThreadPool_oom() throws InterruptedException { + + ThreadPoolExecutor threadPool = (ThreadPoolExecutor) Executors.newCachedThreadPool(); + printStats(threadPool); + for (int i = 0; i < 100000000; i++) { + threadPool.execute(() -> { + String payload = IntStream.rangeClosed(1, 1000000) + .mapToObj(__ -> "a") + .collect(Collectors.joining("")) + UUID.randomUUID().toString(); + try { + TimeUnit.HOURS.sleep(1); + } catch (InterruptedException e) { + } + log.info(payload); + }); + } + + threadPool.shutdown(); + threadPool.awaitTermination(1, TimeUnit.HOURS); + } + + + private static void printStats(ThreadPoolExecutor threadPool) { + Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(() -> { + log.info("========================="); + log.info("Pool Size: {}", threadPool.getPoolSize()); + log.info("Active Threads: {}", threadPool.getActiveCount()); + log.info("Number of Tasks Completed: {}", threadPool.getCompletedTaskCount()); + log.info("Number of Tasks in Queue: {}", threadPool.getQueue().size()); + + log.info("========================="); + }, 0, 1, TimeUnit.SECONDS); + } +} diff --git a/lesson-code/java-common-mistakes/src/main/resources/logback.xml b/lesson-code/java-common-mistakes/src/main/resources/logback.xml new file mode 100644 index 00000000..920d0c29 --- /dev/null +++ b/lesson-code/java-common-mistakes/src/main/resources/logback.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + System.err + + + ${pattern} + + + + + + + + + \ No newline at end of file diff --git a/log/jcl/pom.xml b/log/jcl/pom.xml new file mode 100644 index 00000000..faa3e775 --- /dev/null +++ b/log/jcl/pom.xml @@ -0,0 +1,30 @@ + + + 4.0.0 + + cn.cunchang + jcl + 1.0-SNAPSHOT + + + + commons-logging + commons-logging + 1.2 + + + + log4j + log4j + 1.2.17 + + + + junit + junit + 4.13 + + + \ No newline at end of file diff --git a/log/jcl/src/main/java/cn/cunchang/JCLTest.java b/log/jcl/src/main/java/cn/cunchang/JCLTest.java new file mode 100644 index 00000000..b2473a05 --- /dev/null +++ b/log/jcl/src/main/java/cn/cunchang/JCLTest.java @@ -0,0 +1,35 @@ +package cn.cunchang; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.junit.Test; + +/** + * 全称为Jakarta Commons Logging,是Apache提供的一个通用日志API。 + *

+ * 它是为 "所有的Java日志实现"提供一个统一的接口,它自身也提供一个日志的实现,但是功能非常常弱 (SimpleLog)。 + * 所以一般不会单独使用它。他允许开发人员使用不同的具体日志实现工具: Log4j, Jdk 自带的日志(JUL) + *

+ * JCL 有两个基本的抽象类:Log(基本记录器)和LogFactory(负责创建Log实例)。 + */ +public class JCLTest { + + /** + * 不引入log4j,使用jul + * 引入log4j,使用log4j + */ + @Test + public void testQuick() { + // 创建日志对象 + Log log = LogFactory.getLog(this.getClass()); + // 日志记录输出 + log.fatal("fatal"); + log.error("error"); + log.warn("warn"); + log.info("info"); + log.debug("debug"); + } + + + +} diff --git a/log/jcl/src/main/resources/log4j.properties b/log/jcl/src/main/resources/log4j.properties new file mode 100644 index 00000000..8308f75b --- /dev/null +++ b/log/jcl/src/main/resources/log4j.properties @@ -0,0 +1,11 @@ +# 指定 RootLogger 顶级父元素默认配置信息 +# 指定日志级别=trace,使用的 apeender 为=console +log4j.rootLogger = trace,console + +# 指定控制台日志输出的 appender +log4j.appender.console = org.apache.log4j.ConsoleAppender +# 指定消息格式 layout +log4j.appender.console.layout = org.apache.log4j.PatternLayout +# 指定消息格式的内容 +log4j.appender.console.layout.conversionPattern = [%-10p]%r %l %d{yyyy-MM-dd HH:mm:ss.SSS} %m%n + diff --git a/log/jul/pom.xml b/log/jul/pom.xml new file mode 100644 index 00000000..4bc8c1d8 --- /dev/null +++ b/log/jul/pom.xml @@ -0,0 +1,20 @@ + + + 4.0.0 + + cn.cunchang + jul + 1.0-SNAPSHOT + + + + + junit + junit + 4.13 + + + + \ No newline at end of file diff --git a/log/jul/src/main/java/cn/cunchang/JULTest.java b/log/jul/src/main/java/cn/cunchang/JULTest.java new file mode 100644 index 00000000..ad97168f --- /dev/null +++ b/log/jul/src/main/java/cn/cunchang/JULTest.java @@ -0,0 +1,180 @@ +package cn.cunchang; + +import cn.cunchang.log.MyJULLogFilter; +import org.junit.Test; + +import java.io.IOException; +import java.io.InputStream; +import java.util.logging.*; + +public class JULTest { + + + @Test + public void testQuick() { + // 1、创建日志记录器对象 Logger + Logger logger = Logger.getLogger(this.getClass().getName()); + // 2、日志记录输出 + logger.info("hello jul"); + + logger.log(Level.INFO, "info msg"); + String name = "jack"; + int age = 18; + logger.log(Level.INFO, "用户信息:{0},{1}", new Object[]{name, age}); + } + + /** + * 日志级别分类 + * + * @see java.util.logging.Level 中定义了日志的级别 + */ + @Test + public void testLogLevel() { + // 1.获取日志对象 + Logger logger = Logger.getLogger(this.getClass().getName()); + // 2.日志记录输出 + logger.severe("severe"); + logger.warning("warning"); + logger.info("info"); + logger.config("cofnig"); + logger.fine("fine"); + logger.finer("finer"); + logger.finest("finest"); + } + + /** + * 自定义日志配置 + * + * @throws Exception + */ + @Test + public void testLogConfig() throws Exception { + // 1.获取日志对象 + Logger logger = Logger.getLogger(this.getClass().getName()); + + // 自定义日志配置 + // a.关闭系统默认配置 + logger.setUseParentHandlers(false); + // b.创建handler对象 + ConsoleHandler consoleHandler = new ConsoleHandler(); + // c.创建formatter对象 + SimpleFormatter simpleFormatter = new SimpleFormatter(); + // d.进行关联 + consoleHandler.setFormatter(simpleFormatter); + logger.addHandler(consoleHandler); + // e.设置日志级别 + logger.setLevel(Level.ALL); + consoleHandler.setLevel(Level.ALL); + + // 输出到日志文件 + FileHandler fileHandler = new FileHandler(System.getProperty("user.home") + "/logs/jul.log"); + fileHandler.setFormatter(simpleFormatter); + logger.addHandler(fileHandler); + + // 2.日志记录输出 + logger.severe("severe"); + logger.warning("warning"); + logger.info("info"); + logger.config("config"); + logger.fine("fine"); + logger.finer("finer"); + logger.finest("finest"); + } + + /** + * Logger之间的父子关系

+ *

+ * JUL中Logger之间存在父子关系,这种父子关系通过树状结构存储, + * JUL在初始化时会创建一个顶层 RootLogger作为所有Logger父Logger, + * 存储上作为树状结构的根节点。并父子关系通过路径来关联。 + */ + @Test + public void testLogParent() { + // 日志记录器对象父子关系 + Logger logger1 = Logger.getLogger("cn.cunchang.log"); + Logger logger2 = Logger.getLogger("cn.cunchang"); + + System.out.println("父子日志记录器:" + (logger1.getParent() == logger2)); + // 所有日志记录器对象的顶级父元素 class为java.util.logging.LogManager$RootLogger name为"" + System.out.println("logger2 parent:" + logger2.getParent() + + ",name:" + logger2.getParent().getName()); + } + + /** + * 日志配置文件

+ * /Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/jre/lib + *

+ * 默认配置文件路径$JAVAHOME\jre\lib\logging.properties + */ + @Test + public void testProperties() throws IOException { + // 读取自定义配置文件 + InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("jul.properties"); + // 获取日志管理器对象 + LogManager logManager = LogManager.getLogManager(); + // 日志管理区加载配置文件 + logManager.readConfiguration(inputStream); + + Logger logger = Logger.getLogger(this.getClass().getName()); + logger.severe("severe"); + logger.warning("warning"); + logger.info("info"); + logger.config("config"); + logger.fine("fine"); + logger.finer("finer"); + logger.finest("finest"); + } + + /** + * JUL的架构实现 + */ + @Test + public void testLogInner() throws IOException { + /* + * 1、获取日志对象logger + * 1.1、初始化LogManager,LogManager.getLogManager() + * - 初始化rootLogger为java.util.logging.LogManager.RootLogger + * - 设置rootLogger的级别为Level.INFO + * - 将rootLogger添加到LogManager + * 1.2、初始化Logger,LogManager.demandLogger(name, resourceBundleName, caller); + * - name一般是包名,logger只会初始化一次 + * - 初始化Logger时默认使用rootLogger的配置(handler、format等) + * + */ +// Logger logger = Logger.getLogger(this.getClass().getName()); + // cn.cunchang.log.MyJULLogFilter会过滤掉"cn.cunchang.log" + Logger logger = Logger.getLogger("cn.cunchang.log"); + + // 2、自定义日志配置 + // a.关闭系统默认配置 + logger.setUseParentHandlers(false); + // b.创建handler对象,用来处理日志输出位置 + ConsoleHandler consoleHandler = new ConsoleHandler(); + // c.创建formatter对象,是用来格式化LogRecord的 + SimpleFormatter simpleFormatter = new SimpleFormatter(); + // d.进行关联 + consoleHandler.setFormatter(simpleFormatter); + logger.addHandler(consoleHandler); + // e.设置日志级别 + logger.setLevel(Level.ALL); + // f.设置日志过滤器,日志级别之外更细粒度的控制 + logger.setFilter(new MyJULLogFilter()); + consoleHandler.setLevel(Level.ALL); + + /* + * 3、日志记录输出 + * msg会被封装成LogRecord + */ + logger.severe("severe"); + logger.warning("warning"); + logger.info("info"); + logger.config("config"); + logger.fine("fine"); + logger.finer("finer"); + logger.finest("finest"); + + + + + } +} diff --git a/log/jul/src/main/java/cn/cunchang/log/MyJULLogFilter.java b/log/jul/src/main/java/cn/cunchang/log/MyJULLogFilter.java new file mode 100644 index 00000000..6c970d66 --- /dev/null +++ b/log/jul/src/main/java/cn/cunchang/log/MyJULLogFilter.java @@ -0,0 +1,24 @@ +package cn.cunchang.log; + +import java.util.logging.Filter; +import java.util.logging.LogRecord; + +/** + * @author cunchang + */ +public class MyJULLogFilter implements Filter { + + /** + * + * @param record + * @return + */ + @Override + public boolean isLoggable(LogRecord record) { + if (record.getLoggerName().equals("cn.cunchang.log")) { + return false; + } + return true; + } + +} diff --git a/log/jul/src/main/resources/jul.properties b/log/jul/src/main/resources/jul.properties new file mode 100644 index 00000000..7029cd72 --- /dev/null +++ b/log/jul/src/main/resources/jul.properties @@ -0,0 +1,38 @@ +# RootLogger 顶级父元素指定的默认处理器为:ConsoleHandler +handlers= java.util.logging.FileHandler + +# RootLogger 顶级父元素默认的日志级别为:ALL +.level= ALL + +# 自定义 Logger 使用 +cn.cunchang.handlers = java.util.logging.ConsoleHandler +cn.cunchang.level = CONFIG + +# 关闭默认配置 +cn.cunchang.useParentHanlders = false + + +# 向日志文件输出的 handler 对象 +# 指定日志文件路径 /logs/java0.log +java.util.logging.FileHandler.pattern = /Users/cunchang/logs/java%u.log +# 指定日志文件内容大小 +java.util.logging.FileHandler.limit = 50000 +# 指定日志文件数量 +java.util.logging.FileHandler.count = 1 +# 指定 handler 对象日志消息格式对象 +java.util.logging.FileHandler.formatter = java.util.logging.SimpleFormatter +# 指定以追加方式添加日志内容 +java.util.logging.FileHandler.append = true + + +# 向控制台输出的 handler 对象 +# 指定 handler 对象的日志级别 +java.util.logging.ConsoleHandler.level = ALL +# 指定 handler 对象的日志消息格式对象 +java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter +# 指定 handler 对象的字符集 +java.util.logging.ConsoleHandler.encoding = UTF-8 + +# 指定日志消息格式 +java.util.logging.SimpleFormatter.format = %4$s: %5$s [%1$tc]%n + diff --git a/log/log4j/pom.xml b/log/log4j/pom.xml new file mode 100644 index 00000000..0cd10d5b --- /dev/null +++ b/log/log4j/pom.xml @@ -0,0 +1,30 @@ + + + 4.0.0 + + cn.cunchang + log4j + 1.0-SNAPSHOT + + + + log4j + log4j + 1.2.17 + + + + junit + junit + 4.12 + + + + mysql + mysql-connector-java + 8.0.21 + + + \ No newline at end of file diff --git a/log/log4j/src/main/java/cn/cunchang/Log4jTest.java b/log/log4j/src/main/java/cn/cunchang/Log4jTest.java new file mode 100644 index 00000000..1af1f2f4 --- /dev/null +++ b/log/log4j/src/main/java/cn/cunchang/Log4jTest.java @@ -0,0 +1,170 @@ +package cn.cunchang; + + +import org.apache.log4j.BasicConfigurator; +import org.apache.log4j.Logger; +import org.apache.log4j.PropertyConfigurator; +import org.apache.log4j.helpers.Loader; +import org.apache.log4j.helpers.LogLog; +import org.junit.Test; + + +/** + * @author cunchang + */ +public class Log4jTest { + + /** + * 日志级别 + * fatal 指出每个严重的错误事件将会导致应用程序的退出。 + * error 指出虽然发生错误事件,但仍然不影响系统的继续运行。 + * warn 表明会出现潜在的错误情形。 + * info 一般和在粗粒度级别上,强调应用程序的运行全程。 + * debug 一般用于细粒度级别上,对调试应用程序非常有帮助。 + * trace 是程序追踪,可以用于输出程序运行中的变量,显示执行的流程。 + *

+ * 一般只使用4个级别,优先级从高到低为 ERROR > WARN > INFO > DEBUG + */ + @Test + public void testQuick() { + // 初始化系统配置,不需要配置文件 + BasicConfigurator.configure(); + // 创建日志记录器对象 + Logger logger = Logger.getLogger(this.getClass()); + // 日志记录输出 + logger.info("hello log4j"); + + // 日志级别 + logger.fatal("fatal");// 严重错误,一般会造成系统崩溃和终止运行 + logger.error("error");// 错误信息,但不会影响系统运行 + logger.warn("warn");// 警告信息,可能会发生问题 + logger.info("info");// 程序运行信息,数据库的连接、网络、IO操作等 + logger.debug("debug");// 调试信息,一般在开发阶段使用,记录程序的变量、参数 + logger.trace("trace");// 追踪信息,记录程序的所有流程信 + } + + /** + * 熟悉log4j组件和配置文件 + */ + @Test + public void test组件和配置文件() { + PropertyConfigurator.configure(Loader.getResource("log4j_组件和配置文件.properties")); + Logger logger = Logger.getLogger(this.getClass()); + + // 日志级别 + logger.fatal("fatal"); + logger.error("error"); + logger.warn("warn"); + logger.info("info"); + logger.debug("debug"); + logger.trace("trace"); + } + + + /** + * log4j内部日志 LogLog + */ + @Test + public void test内部日志() { + // 开启内部日志 + LogLog.setInternalDebugging(true); + + PropertyConfigurator.configure(Loader.getResource("log4j_组件和配置文件.properties")); + Logger logger = Logger.getLogger(this.getClass()); + + logger.fatal("fatal"); + logger.error("error"); + logger.warn("warn"); + logger.info("info"); + logger.debug("debug"); + logger.trace("trace"); + } + + /** + * log4j Layout配置 + */ + @Test + public void testLayout配置() { + // 开启内部日志 + LogLog.setInternalDebugging(true); + PropertyConfigurator.configure(Loader.getResource("log4j_Layout配置.properties")); + Logger logger = Logger.getLogger(this.getClass()); + + logger.fatal("fatal"); + logger.error("error"); + logger.warn("warn"); + logger.info("info"); + logger.debug("debug"); + logger.trace("trace"); + } + + /** + * log4j FileAppender配置 + */ + @Test + public void testFileAppender配置() { + // 开启内部日志 + LogLog.setInternalDebugging(true); + PropertyConfigurator.configure(Loader.getResource("log4j_FileAppender配置.properties")); + Logger logger = Logger.getLogger(this.getClass()); + + for (int i = 0; i < 100; i++) { + logger.fatal("fatal"); + logger.error("error"); + logger.warn("warn"); + logger.info("info"); + logger.debug("debug"); + logger.trace("trace"); + } + } + + + /** + * log4j JDBCAppender配置 + */ + @Test + public void testJDBCAppender配置() { + // 开启内部日志 + LogLog.setInternalDebugging(true); + PropertyConfigurator.configure(Loader.getResource("log4j_JDBCAppender配置.properties")); + Logger logger = Logger.getLogger(this.getClass()); + + for (int i = 0; i < 100; i++) { + logger.fatal("fatal"); + logger.error("error"); + logger.warn("warn"); + logger.info("info"); + logger.debug("debug"); + logger.trace("trace"); + } + } + + + /** + * 自定义Logger是为了,不同业务日志输出到不同位置
+ * 比如业务代码输出到文件,log4j日志输出到控制台 + */ + @Test + public void testCustomLogger() { + // 开启内部日志 + LogLog.setInternalDebugging(true); + PropertyConfigurator.configure(Loader.getResource("log4j_自定义Logger.properties")); + // 自定义 cn.cunchang + Logger myLogger = Logger.getLogger(this.getClass()); + myLogger.fatal("myLogger fatal"); + myLogger.error("myLogger error"); + myLogger.warn("myLogger warn"); + myLogger.info("myLogger info"); + myLogger.debug("myLogger debug"); + myLogger.trace("myLogger trace"); + // 自定义 org.apache + Logger rootLogger = Logger.getLogger(Logger.class); + rootLogger.fatal("rootLogger fatal"); + rootLogger.error("rootLogger error"); + rootLogger.warn("rootLogger warn"); + rootLogger.info("rootLogger info"); + rootLogger.debug("rootLogger debug"); + rootLogger.trace("rootLogger trace"); + } + +} diff --git a/log/log4j/src/main/resources/log.sql b/log/log4j/src/main/resources/log.sql new file mode 100644 index 00000000..629df2f8 --- /dev/null +++ b/log/log4j/src/main/resources/log.sql @@ -0,0 +1,17 @@ +use xxx_project_db; + +CREATE TABLE `log` ( + `id` INT(11) NOT NULL AUTO_INCREMENT, + `project_name` VARCHAR(255) DEFAULT NULL COMMENT '目项名', + `create_date` VARCHAR(255) DEFAULT NULL COMMENT '创建时间', + `level` VARCHAR(255) DEFAULT NULL COMMENT '优先级', + `category` VARCHAR(255) DEFAULT NULL COMMENT '所在类的全名', + `file_name` VARCHAR(255) DEFAULT NULL COMMENT '输出日志消息产生时所在的文件名称 ', + `thread_name` VARCHAR(255) DEFAULT NULL COMMENT '日志事件的线程名', + `line` VARCHAR(255) DEFAULT NULL COMMENT '号行', + `all_category` VARCHAR(255) DEFAULT NULL COMMENT '日志事件的发生位置', + `message` VARCHAR(4000) DEFAULT NULL COMMENT '输出代码中指定的消息', + PRIMARY KEY (`id`) +); + + diff --git a/log/log4j/src/main/resources/log4j/log4j.properties b/log/log4j/src/main/resources/log4j/log4j.properties new file mode 100644 index 00000000..9237fb3b --- /dev/null +++ b/log/log4j/src/main/resources/log4j/log4j.properties @@ -0,0 +1,79 @@ +# 指定 RootLogger 顶级父元素默认配置信息 +# 指定日志级别=trace,使用的 apeender 为=console +log4j.rootLogger = trace,console + +# 自定义 logger 对象设置 +log4j.logger.cn.cunchang = info,console +log4j.logger.org.apache = error + +# 指定控制台日志输出的 appender +log4j.appender.console = org.apache.log4j.ConsoleAppender +# 指定消息格式 layout +log4j.appender.console.layout = org.apache.log4j.PatternLayout +# 指定消息格式的内容 +log4j.appender.console.layout.conversionPattern = [%-10p]%r %l %d{yyyy-MM-dd HH:mm:ss.SSS} %m%n + + +# %m 输出代码中指定的日志信息 +# %p 输出优先级,及 DEBUG、INFO 等 +# %n 换行符(Windows平台的换行符为 "\n",Unix 平台为 "\n") +# %r 输出自应用启动到输出该 log 信息耗费的毫秒数 +# %c 输出打印语句所属的类的全名 +# %t 输出产生该日志的线程全名 +# %d 输出服务器当前时间,默认为 ISO8601,也可以指定格式,如:%d{yyyy年MM月dd日 HH:mm:ss} +# %l 输出日志时间发生的位置,包括类名、线程、及在代码中的行数。如:Test.main(Test.java:10) +# %F 输出日志消息产生时所在的文件名称 +# %L 输出代码中的行号 +# %% 输出一个 "%" 字符 + +# 日志文件输出的 appender 对象 +log4j.appender.file = org.apache.log4j.FileAppender +# 指定消息格式 layout +log4j.appender.file.layout = org.apache.log4j.PatternLayout +# 指定消息格式的内容 +log4j.appender.file.layout.conversionPattern = [%-10p]%r %l %d{yyyy-MM-dd HH:mm:ss.SSS} %m%n +# 指定日志文件保存路径 +log4j.appender.file.file = /Users/cunchang/logs/log4j.log +# 指定日志文件的字符集 +log4j.appender.file.encoding = UTF-8 + + +# 按照文件大小拆分的 appender 对象 +# 日志文件输出的 appender 对象 +log4j.appender.rollingFile = org.apache.log4j.RollingFileAppender +# 指定消息格式 layout +log4j.appender.rollingFile.layout = org.apache.log4j.PatternLayout +# 指定消息格式的内容 +log4j.appender.rollingFile.layout.conversionPattern = [%-10p]%r %l %d{yyyy-MM-dd HH:mm:ss.SSS} %m%n +# 指定日志文件保存路径 +log4j.appender.rollingFile.file = /Users/cunchang/logs/log4j.log +# 指定日志文件的字符集 +log4j.appender.rollingFile.encoding = UTF-8 +# 指定日志文件内容的大小 +log4j.appender.rollingFile.maxFileSize = 1MB +# 指定日志文件的数量 +log4j.appender.rollingFile.maxBackupIndex = 10 + + +# 按照时间规则拆分的 appender 对象 +log4j.appender.dailyFile = org.apache.log4j.DailyRollingFileAppender +# 指定消息格式 layout +log4j.appender.dailyFile.layout = org.apache.log4j.PatternLayout +# 指定消息格式的内容 +log4j.appender.dailyFile.layout.conversionPattern = [%-10p]%r %l %d{yyyy-MM-dd HH:mm:ss.SSS} %m%n +# 指定日志文件保存路径 +log4j.appender.dailyFile.file = /Users/cunchang/logs/log4j.log +# 指定日志文件的字符集 +log4j.appender.dailyFile.encoding = UTF-8 +# 指定日期拆分规则 +log4j.appender.dailyFile.datePattern = '.'yyyy-MM-dd-HH-mm-ss + + +#mysql +log4j.appender.logDB=org.apache.log4j.jdbc.JDBCAppender +log4j.appender.logDB.layout=org.apache.log4j.PatternLayout +log4j.appender.logDB.Driver=com.mysql.jdbc.Driver +log4j.appender.logDB.URL=jdbc:mysql://localhost:3306/xxx_project_db +log4j.appender.logDB.User=root +log4j.appender.logDB.Password=123456 +log4j.appender.logDB.Sql=INSERT INTO log(project_name,create_date,level,category,file_name,thread_name,line,all_category,message) values('shop','%d{yyyy-MM-dd HH:mm:ss}','%p','%c','%F','%t','%L','%l','%m') \ No newline at end of file diff --git "a/log/log4j/src/main/resources/log4j_FileAppender\351\205\215\347\275\256.properties" "b/log/log4j/src/main/resources/log4j_FileAppender\351\205\215\347\275\256.properties" new file mode 100644 index 00000000..00e0891c --- /dev/null +++ "b/log/log4j/src/main/resources/log4j_FileAppender\351\205\215\347\275\256.properties" @@ -0,0 +1,64 @@ +# 指定 RootLogger 顶级父元素默认配置信息 +# 指定日志级别=trace,使用的 appender= +log4j.rootLogger = trace,dailyFile + +# 指定控制台日志输出的 appender +log4j.appender.console = org.apache.log4j.ConsoleAppender +# 指定消息格式 layout +log4j.appender.console.layout = org.apache.log4j.PatternLayout +# 指定消息格式的内容 +log4j.appender.console.layout.conversionPattern = [%-10p]%r %l %d{yyyy-MM-dd HH:mm:ss.SSS} %m%n + +# %m 输出代码中指定的日志信息 +# %p 输出优先级,及 DEBUG、INFO 等 +# %n 换行符(Windows平台的换行符为 "\n",Unix 平台为 "\n") +# %r 输出自应用启动到输出该 log 信息耗费的毫秒数 +# %c 输出打印语句所属的类的全名 +# %t 输出产生该日志的线程全名 +# %d 输出服务器当前时间,默认为 ISO8601,也可以指定格式,如:%d{yyyy年MM月dd日mm毫秒 HH:mm:ss.SSS} +# %l 输出日志时间发生的位置,包括类名、线程、及在代码中的行数。如:Test.main(Test.java:10) +# %F 输出日志消息产生时所在的文件名称 +# %L 输出代码中的行号 +# %% 输出一个 "%" 字符 + + +# 日志文件输出的 appender 对象 +log4j.appender.file = org.apache.log4j.FileAppender +# 指定消息格式 layout +log4j.appender.file.layout = org.apache.log4j.PatternLayout +# 指定消息格式的内容 +log4j.appender.file.layout.conversionPattern = [%-10p]%r %l %d{yyyy-MM-dd HH:mm:ss.SSS} %m%n +# 指定日志文件保存路径 +log4j.appender.file.file = /Users/cunchang/logs/log4j.log +# 指定日志文件的字符集 +log4j.appender.file.encoding = UTF-8 + +# 按照文件大小拆分的 appender 对象 +# 日志文件输出的 appender 对象 +log4j.appender.rollingFile = org.apache.log4j.RollingFileAppender +# 指定消息格式 layout +log4j.appender.rollingFile.layout = org.apache.log4j.PatternLayout +# 指定消息格式的内容 +log4j.appender.rollingFile.layout.conversionPattern = [%-10p]%r %l %d{yyyy-MM-dd HH:mm:ss.SSS} %m%n +# 指定日志文件保存路径 +log4j.appender.rollingFile.file = /Users/cunchang/logs/log4j.log +# 指定日志文件的字符集 +log4j.appender.rollingFile.encoding = UTF-8 +# 指定日志文件内容的大小 +log4j.appender.rollingFile.maxFileSize = 1KB +# 指定日志文件的数量,现象超过1KB生成一个新日志文件 +log4j.appender.rollingFile.maxBackupIndex = 10 + + +# 按照时间规则拆分的 appender 对象 +log4j.appender.dailyFile = org.apache.log4j.DailyRollingFileAppender +# 指定消息格式 layout +log4j.appender.dailyFile.layout = org.apache.log4j.PatternLayout +# 指定消息格式的内容 +log4j.appender.dailyFile.layout.conversionPattern = [%-10p]%r %l %d{yyyy-MM-dd HH:mm:ss.SSS} %m%n +# 指定日志文件保存路径 +log4j.appender.dailyFile.file = /Users/cunchang/logs/log4j.log +# 指定日志文件的字符集 +log4j.appender.dailyFile.encoding = UTF-8 +# 指定日期拆分规则,现象按照秒生成一个新日志文件 +log4j.appender.dailyFile.datePattern = '.'yyyy-MM-dd-HH-mm-ss diff --git "a/log/log4j/src/main/resources/log4j_JDBCAppender\351\205\215\347\275\256.properties" "b/log/log4j/src/main/resources/log4j_JDBCAppender\351\205\215\347\275\256.properties" new file mode 100644 index 00000000..06c08cae --- /dev/null +++ "b/log/log4j/src/main/resources/log4j_JDBCAppender\351\205\215\347\275\256.properties" @@ -0,0 +1,72 @@ +# 指定 RootLogger 顶级父元素默认配置信息 +# 指定日志级别=trace,使用的 appender= +log4j.rootLogger = trace,logDB + +# 指定控制台日志输出的 appender +log4j.appender.console = org.apache.log4j.ConsoleAppender +# 指定消息格式 layout +log4j.appender.console.layout = org.apache.log4j.PatternLayout +# 指定消息格式的内容 +log4j.appender.console.layout.conversionPattern = [%-10p]%r %l %d{yyyy-MM-dd HH:mm:ss.SSS} %m%n + +# %m 输出代码中指定的日志信息 +# %p 输出优先级,及 DEBUG、INFO 等 +# %n 换行符(Windows平台的换行符为 "\n",Unix 平台为 "\n") +# %r 输出自应用启动到输出该 log 信息耗费的毫秒数 +# %c 输出打印语句所属的类的全名 +# %t 输出产生该日志的线程全名 +# %d 输出服务器当前时间,默认为 ISO8601,也可以指定格式,如:%d{yyyy年MM月dd日mm毫秒 HH:mm:ss.SSS} +# %l 输出日志时间发生的位置,包括类名、线程、及在代码中的行数。如:Test.main(Test.java:10) +# %F 输出日志消息产生时所在的文件名称 +# %L 输出代码中的行号 +# %% 输出一个 "%" 字符 + + +# 日志文件输出的 appender 对象 +log4j.appender.file = org.apache.log4j.FileAppender +# 指定消息格式 layout +log4j.appender.file.layout = org.apache.log4j.PatternLayout +# 指定消息格式的内容 +log4j.appender.file.layout.conversionPattern = [%-10p]%r %l %d{yyyy-MM-dd HH:mm:ss.SSS} %m%n +# 指定日志文件保存路径 +log4j.appender.file.file = /Users/cunchang/logs/log4j.log +# 指定日志文件的字符集 +log4j.appender.file.encoding = UTF-8 + +# 按照文件大小拆分的 appender 对象 +# 日志文件输出的 appender 对象 +log4j.appender.rollingFile = org.apache.log4j.RollingFileAppender +# 指定消息格式 layout +log4j.appender.rollingFile.layout = org.apache.log4j.PatternLayout +# 指定消息格式的内容 +log4j.appender.rollingFile.layout.conversionPattern = [%-10p]%r %l %d{yyyy-MM-dd HH:mm:ss.SSS} %m%n +# 指定日志文件保存路径 +log4j.appender.rollingFile.file = /Users/cunchang/logs/log4j.log +# 指定日志文件的字符集 +log4j.appender.rollingFile.encoding = UTF-8 +# 指定日志文件内容的大小 +log4j.appender.rollingFile.maxFileSize = 1KB +# 指定日志文件的数量,现象超过1KB生成一个新日志文件 +log4j.appender.rollingFile.maxBackupIndex = 10 + +# 按照时间规则拆分的 appender 对象 +log4j.appender.dailyFile = org.apache.log4j.DailyRollingFileAppender +# 指定消息格式 layout +log4j.appender.dailyFile.layout = org.apache.log4j.PatternLayout +# 指定消息格式的内容 +log4j.appender.dailyFile.layout.conversionPattern = [%-10p]%r %l %d{yyyy-MM-dd HH:mm:ss.SSS} %m%n +# 指定日志文件保存路径 +log4j.appender.dailyFile.file = /Users/cunchang/logs/log4j.log +# 指定日志文件的字符集 +log4j.appender.dailyFile.encoding = UTF-8 +# 指定日期拆分规则,现象按照秒生成一个新日志文件 +log4j.appender.dailyFile.datePattern = '.'yyyy-MM-dd-HH-mm-ss + +#mysql +log4j.appender.logDB=org.apache.log4j.jdbc.JDBCAppender +log4j.appender.logDB.layout=org.apache.log4j.PatternLayout +log4j.appender.logDB.Driver=com.mysql.jdbc.Driver +log4j.appender.logDB.URL=jdbc:mysql://localhost:3306/xxx_project_db +log4j.appender.logDB.User=root +log4j.appender.logDB.Password=123456 +log4j.appender.logDB.Sql=INSERT INTO log(project_name,create_date,level,category,file_name,thread_name,line,all_category,message) values('shop','%d{yyyy-MM-dd HH:mm:ss}','%p','%c','%F','%t','%L','%l','%m') \ No newline at end of file diff --git "a/log/log4j/src/main/resources/log4j_Layout\351\205\215\347\275\256.properties" "b/log/log4j/src/main/resources/log4j_Layout\351\205\215\347\275\256.properties" new file mode 100644 index 00000000..ca84b449 --- /dev/null +++ "b/log/log4j/src/main/resources/log4j_Layout\351\205\215\347\275\256.properties" @@ -0,0 +1,23 @@ +# 指定 RootLogger 顶级父元素默认配置信息 +# 指定日志级别=trace,使用的 apeender 为=console +log4j.rootLogger = trace,console + +# 指定控制台日志输出的 appender +log4j.appender.console = org.apache.log4j.ConsoleAppender +# 指定消息格式 layout +log4j.appender.console.layout = org.apache.log4j.PatternLayout +# 指定消息格式的内容 +log4j.appender.console.layout.conversionPattern = [%-10p]%r %l %d{yyyy-MM-dd HH:mm:ss.SSS} %m%n + +# %m 输出代码中指定的日志信息 +# %p 输出优先级,及 DEBUG、INFO 等 +# %n 换行符(Windows平台的换行符为 "\n",Unix 平台为 "\n") +# %r 输出自应用启动到输出该 log 信息耗费的毫秒数 +# %c 输出打印语句所属的类的全名 +# %t 输出产生该日志的线程全名 +# %d 输出服务器当前时间,默认为 ISO8601,也可以指定格式,如:%d{yyyy年MM月dd日 HH:mm:ss} +# %l 输出日志时间发生的位置,包括类名、线程、及在代码中的行数。如:Test.main(Test.java:10) +# %F 输出日志消息产生时所在的文件名称 +# %L 输出代码中的行号 +# %% 输出一个 "%" 字符 + diff --git "a/log/log4j/src/main/resources/log4j_\347\273\204\344\273\266\345\222\214\351\205\215\347\275\256\346\226\207\344\273\266.properties" "b/log/log4j/src/main/resources/log4j_\347\273\204\344\273\266\345\222\214\351\205\215\347\275\256\346\226\207\344\273\266.properties" new file mode 100644 index 00000000..bbdd578c --- /dev/null +++ "b/log/log4j/src/main/resources/log4j_\347\273\204\344\273\266\345\222\214\351\205\215\347\275\256\346\226\207\344\273\266.properties" @@ -0,0 +1,9 @@ +# 指定 RootLogger 顶级父元素默认配置信息 +# 指定日志级别=trace,使用的 apeender 为=console +log4j.rootLogger = trace,console + +# 指定控制台日志输出的 appender +log4j.appender.console = org.apache.log4j.ConsoleAppender +# 指定消息格式 layout +log4j.appender.console.layout = org.apache.log4j.SimpleLayout + diff --git "a/log/log4j/src/main/resources/log4j_\350\207\252\345\256\232\344\271\211Logger.properties" "b/log/log4j/src/main/resources/log4j_\350\207\252\345\256\232\344\271\211Logger.properties" new file mode 100644 index 00000000..4e18c1d3 --- /dev/null +++ "b/log/log4j/src/main/resources/log4j_\350\207\252\345\256\232\344\271\211Logger.properties" @@ -0,0 +1,78 @@ +# 指定 RootLogger 顶级父元素默认配置信息 +# 指定日志级别=trace,使用的 appender=console +log4j.rootLogger = trace,console + +# 自定义 logger 对象设置,会继承rootLogger的日志级别(覆盖)和appender(追加) +# 指定日志级别=info,使用的 appender=file +log4j.logger.cn.cunchang = info,file +log4j.logger.org.apache = error + + +# 指定控制台日志输出的 appender +log4j.appender.console = org.apache.log4j.ConsoleAppender +# 指定消息格式 layout +log4j.appender.console.layout = org.apache.log4j.PatternLayout +# 指定消息格式的内容 +log4j.appender.console.layout.conversionPattern = [%-10p]%r %l %d{yyyy-MM-dd HH:mm:ss.SSS} %m%n + +# %m 输出代码中指定的日志信息 +# %p 输出优先级,及 DEBUG、INFO 等 +# %n 换行符(Windows平台的换行符为 "\n",Unix 平台为 "\n") +# %r 输出自应用启动到输出该 log 信息耗费的毫秒数 +# %c 输出打印语句所属的类的全名 +# %t 输出产生该日志的线程全名 +# %d 输出服务器当前时间,默认为 ISO8601,也可以指定格式,如:%d{yyyy年MM月dd日mm毫秒 HH:mm:ss.SSS} +# %l 输出日志时间发生的位置,包括类名、线程、及在代码中的行数。如:Test.main(Test.java:10) +# %F 输出日志消息产生时所在的文件名称 +# %L 输出代码中的行号 +# %% 输出一个 "%" 字符 + + +# 日志文件输出的 appender 对象 +log4j.appender.file = org.apache.log4j.FileAppender +# 指定消息格式 layout +log4j.appender.file.layout = org.apache.log4j.PatternLayout +# 指定消息格式的内容 +log4j.appender.file.layout.conversionPattern = [%-10p]%r %l %d{yyyy-MM-dd HH:mm:ss.SSS} %m%n +# 指定日志文件保存路径 +log4j.appender.file.file = /Users/cunchang/logs/log4j.log +# 指定日志文件的字符集 +log4j.appender.file.encoding = UTF-8 + +# 按照文件大小拆分的 appender 对象 +# 日志文件输出的 appender 对象 +log4j.appender.rollingFile = org.apache.log4j.RollingFileAppender +# 指定消息格式 layout +log4j.appender.rollingFile.layout = org.apache.log4j.PatternLayout +# 指定消息格式的内容 +log4j.appender.rollingFile.layout.conversionPattern = [%-10p]%r %l %d{yyyy-MM-dd HH:mm:ss.SSS} %m%n +# 指定日志文件保存路径 +log4j.appender.rollingFile.file = /Users/cunchang/logs/log4j.log +# 指定日志文件的字符集 +log4j.appender.rollingFile.encoding = UTF-8 +# 指定日志文件内容的大小 +log4j.appender.rollingFile.maxFileSize = 1KB +# 指定日志文件的数量,现象超过1KB生成一个新日志文件 +log4j.appender.rollingFile.maxBackupIndex = 10 + +# 按照时间规则拆分的 appender 对象 +log4j.appender.dailyFile = org.apache.log4j.DailyRollingFileAppender +# 指定消息格式 layout +log4j.appender.dailyFile.layout = org.apache.log4j.PatternLayout +# 指定消息格式的内容 +log4j.appender.dailyFile.layout.conversionPattern = [%-10p]%r %l %d{yyyy-MM-dd HH:mm:ss.SSS} %m%n +# 指定日志文件保存路径 +log4j.appender.dailyFile.file = /Users/cunchang/logs/log4j.log +# 指定日志文件的字符集 +log4j.appender.dailyFile.encoding = UTF-8 +# 指定日期拆分规则,现象按照秒生成一个新日志文件 +log4j.appender.dailyFile.datePattern = '.'yyyy-MM-dd-HH-mm-ss + +#mysql +log4j.appender.logDB=org.apache.log4j.jdbc.JDBCAppender +log4j.appender.logDB.layout=org.apache.log4j.PatternLayout +log4j.appender.logDB.Driver=com.mysql.jdbc.Driver +log4j.appender.logDB.URL=jdbc:mysql://localhost:3306/xxx_project_db +log4j.appender.logDB.User=root +log4j.appender.logDB.Password=123456 +log4j.appender.logDB.Sql=INSERT INTO log(project_name,create_date,level,category,file_name,thread_name,line,all_category,message) values('shop','%d{yyyy-MM-dd HH:mm:ss}','%p','%c','%F','%t','%L','%l','%m') \ No newline at end of file diff --git a/log/log4j2/pom.xml b/log/log4j2/pom.xml new file mode 100644 index 00000000..0ae7422a --- /dev/null +++ b/log/log4j2/pom.xml @@ -0,0 +1,53 @@ + + + 4.0.0 + + cn.cunchang + log4j2 + 1.0-SNAPSHOT + + + + + org.slf4j + slf4j-api + 1.7.26 + + + + + org.apache.logging.log4j + log4j-slf4j-impl + 2.9.1 + + + + + org.apache.logging.log4j + log4j-api + 2.11.1 + + + + org.apache.logging.log4j + log4j-core + 2.11.1 + + + + + com.lmax + disruptor + 3.3.4 + + + + + junit + junit + 4.12 + + + \ No newline at end of file diff --git a/log/log4j2/src/main/java/cn/cunchang/Log4j2Test.java b/log/log4j2/src/main/java/cn/cunchang/Log4j2Test.java new file mode 100644 index 00000000..81add656 --- /dev/null +++ b/log/log4j2/src/main/java/cn/cunchang/Log4j2Test.java @@ -0,0 +1,27 @@ +package cn.cunchang; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.junit.Test; + +public class Log4j2Test { + + // 定义日志记录器对象 + public static final Logger log = LogManager.getLogger(Log4j2Test.class); + + /** + * log4j-api 门面 + * log4j-core 实现 + */ + @Test + public void testQuick() { + // 日志消息输出 + log.fatal("fatal"); + log.error("error"); + log.warn("warn"); + log.info("inf"); + log.debug("debug"); + log.trace("trace"); + } + +} diff --git a/log/log4j2/src/main/java/cn/cunchang/Slf4jTest.java b/log/log4j2/src/main/java/cn/cunchang/Slf4jTest.java new file mode 100644 index 00000000..7c3cd86e --- /dev/null +++ b/log/log4j2/src/main/java/cn/cunchang/Slf4jTest.java @@ -0,0 +1,25 @@ +package cn.cunchang; + +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class Slf4jTest { + + public static final Logger log = LoggerFactory.getLogger(Slf4jTest.class); + + /** + * slf4j-api 门面 + * log4j-slf4j-impl 适配器 + * log4j-core 实现 + */ + @Test + public void test日志门面() { + // 日志输出 + log.error("error"); + log.warn("wring"); + log.info("info"); // 默认级别 + log.debug("debug"); + log.trace("trace"); + } +} diff --git a/log/log4j2/src/main/resources/AsyncAppender/log4j2.xml b/log/log4j2/src/main/resources/AsyncAppender/log4j2.xml new file mode 100644 index 00000000..743d75d8 --- /dev/null +++ b/log/log4j2/src/main/resources/AsyncAppender/log4j2.xml @@ -0,0 +1,69 @@ + + + + + + + /Users/cunchang/logs/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git "a/log/log4j2/src/main/resources/AsyncLogger\345\205\250\345\261\200/log4j2.component.properties" "b/log/log4j2/src/main/resources/AsyncLogger\345\205\250\345\261\200/log4j2.component.properties" new file mode 100644 index 00000000..36ce3003 --- /dev/null +++ "b/log/log4j2/src/main/resources/AsyncLogger\345\205\250\345\261\200/log4j2.component.properties" @@ -0,0 +1,2 @@ +# 全局异步 +Log4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector \ No newline at end of file diff --git "a/log/log4j2/src/main/resources/AsyncLogger\345\205\250\345\261\200/log4j2.xml" "b/log/log4j2/src/main/resources/AsyncLogger\345\205\250\345\261\200/log4j2.xml" new file mode 100644 index 00000000..8deb2c1f --- /dev/null +++ "b/log/log4j2/src/main/resources/AsyncLogger\345\205\250\345\261\200/log4j2.xml" @@ -0,0 +1,62 @@ + + + + + + + /Users/cunchang/logs/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git "a/log/log4j2/src/main/resources/AsyncLogger\346\267\267\345\220\210/log4j2.xml" "b/log/log4j2/src/main/resources/AsyncLogger\346\267\267\345\220\210/log4j2.xml" new file mode 100644 index 00000000..493a7152 --- /dev/null +++ "b/log/log4j2/src/main/resources/AsyncLogger\346\267\267\345\220\210/log4j2.xml" @@ -0,0 +1,71 @@ + + + + + + + /Users/cunchang/logs/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/log/log4j2/src/main/resources/log4j2.xml b/log/log4j2/src/main/resources/log4j2.xml new file mode 100644 index 00000000..493a7152 --- /dev/null +++ b/log/log4j2/src/main/resources/log4j2.xml @@ -0,0 +1,71 @@ + + + + + + + /Users/cunchang/logs/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/log/logback/pom.xml b/log/logback/pom.xml new file mode 100644 index 00000000..a040d86d --- /dev/null +++ b/log/logback/pom.xml @@ -0,0 +1,31 @@ + + + 4.0.0 + + cn.cunchang + logback + 1.0-SNAPSHOT + + + + org.slf4j + slf4j-api + 1.7.26 + + + + ch.qos.logback + logback-classic + 1.2.3 + + + + junit + junit + 4.13 + + + + \ No newline at end of file diff --git a/log/logback/src/main/java/cn/cunchang/LogbackTest.java b/log/logback/src/main/java/cn/cunchang/LogbackTest.java new file mode 100644 index 00000000..016b7846 --- /dev/null +++ b/log/logback/src/main/java/cn/cunchang/LogbackTest.java @@ -0,0 +1,107 @@ +package cn.cunchang; + +import ch.qos.logback.classic.LoggerContext; +import ch.qos.logback.classic.joran.JoranConfigurator; +import ch.qos.logback.core.util.StatusPrinter; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.InputStream; + +public class LogbackTest { + + public static final Logger log = LoggerFactory.getLogger(LogbackTest.class); + + @Test + public void testQuick() { + log.error("error"); + log.warn("wring"); + log.info("info"); + log.debug("debug");// 默认级别 + log.trace("trace"); + } + + /** + * logback自动加载配置文件的优先级如下: + * 1.classpath下的logback-test.xml + * 2.classpath下的logback.groovy + * 3.classpath下的logback.xml + * 4.META-INF/services/ch.qos.logback.classic.spi.Configurator中的 logback 配置实现类 + * 5.logback自带的默认配置文件BasicConfigurator + */ + @Test + public void test配置文件() { + reloadConfig("logback_配置文件.xml"); + log.error("error"); + log.warn("wring"); + log.info("info"); + log.debug("debug"); + log.trace("trace"); + } + + @Test + public void testAppender配置() { +// reloadConfig("logback_FileAppender配置.xml"); + reloadConfig("logback_HtmlAppender配置.xml"); + log.error("error"); + log.warn("wring"); + log.info("info"); + log.debug("debug"); + log.trace("trace"); + } + + @Test + public void testRollingFileAppender配置() { + reloadConfig("logback_RollingFileAppender配置.xml"); + for (int i = 0; i < 100; i++) { + log.error("error"); + log.warn("wring"); + log.info("info"); + log.debug("debug"); + log.trace("trace"); + } + } + + @Test + public void test异步配置() { + reloadConfig("logback_异步配置.xml"); + for (int i = 0; i < 100; i++) { + log.error("error"); + log.warn("wring"); + log.info("info"); + log.debug("debug"); + log.trace("trace"); + } + } + + @Test + public void test自定义logger() { + reloadConfig("logback_自定义logger.xml"); + log.error("error"); + log.warn("wring"); + log.info("info"); + log.debug("debug"); + log.trace("trace"); + } + + /** + * 加载自定义logback配置文件 + * + * @param logbackConfigPath + */ + public void reloadConfig(String logbackConfigPath) { + LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory(); + + InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(logbackConfigPath); + JoranConfigurator joranConfigurator = new JoranConfigurator(); + joranConfigurator.setContext(loggerContext); + loggerContext.reset(); + try { + joranConfigurator.doConfigure(inputStream); + } catch (Exception e) { + log.error("logbackConfigPath Load logback config file error. Message: {}", e.getMessage()); + } + StatusPrinter.printInCaseOfErrorsOrWarnings(loggerContext); + } +} diff --git a/log/logback/src/main/java/cn/cunchang/logback.xml b/log/logback/src/main/java/cn/cunchang/logback.xml new file mode 100644 index 00000000..bb729b31 --- /dev/null +++ b/log/logback/src/main/java/cn/cunchang/logback.xml @@ -0,0 +1,102 @@ + + + + + + + + + + + + + + + System.err + + + ${pattern} + + + + + + + ${log_dir}/logback.log + + + ${pattern} + + + + + + + ${log_dir}/logback.html + + + + %-5level%d{yyyy-MM-dd HH:mm:ss.SSS}%c%M%L%thread%m + + + + + + + + + ${log_dir}/roll_logback.log + + + ${pattern} + + + + + ${log_dir}/rolling.%d{yyyy-MM-dd}.log%i.gz + + 1MB + + + + + ERROR + ACCEPT + DENY + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git "a/log/logback/src/main/resources/logback_FileAppender\351\205\215\347\275\256.xml" "b/log/logback/src/main/resources/logback_FileAppender\351\205\215\347\275\256.xml" new file mode 100644 index 00000000..9c14c7e3 --- /dev/null +++ "b/log/logback/src/main/resources/logback_FileAppender\351\205\215\347\275\256.xml" @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + System.err + + + ${pattern} + + + + + + + ${log_dir}/logback.log + + + ${pattern} + + + + + + + + + + \ No newline at end of file diff --git "a/log/logback/src/main/resources/logback_HtmlAppender\351\205\215\347\275\256.xml" "b/log/logback/src/main/resources/logback_HtmlAppender\351\205\215\347\275\256.xml" new file mode 100644 index 00000000..ea130174 --- /dev/null +++ "b/log/logback/src/main/resources/logback_HtmlAppender\351\205\215\347\275\256.xml" @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + System.err + + + ${pattern} + + + + + + + ${log_dir}/logback.log + + + ${pattern} + + + + + + + ${log_dir}/logback.html + + + + %-5level%d{yyyy-MM-dd HH:mm:ss.SSS}%c%M%L%thread%m + + + + + + + + + + + + \ No newline at end of file diff --git "a/log/logback/src/main/resources/logback_RollingFileAppender\351\205\215\347\275\256.xml" "b/log/logback/src/main/resources/logback_RollingFileAppender\351\205\215\347\275\256.xml" new file mode 100644 index 00000000..8541e05b --- /dev/null +++ "b/log/logback/src/main/resources/logback_RollingFileAppender\351\205\215\347\275\256.xml" @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + System.err + + + ${pattern} + + + + + + + ${log_dir}/roll_logback.log + + + ${pattern} + + + + + ${log_dir}/rolling.%d{yyyy-MM-dd}.log%i.gz + + 1KB + + + + + ERROR + + ACCEPT + + DENY + + + + + + + + + + + \ No newline at end of file diff --git "a/log/logback/src/main/resources/logback_\345\274\202\346\255\245\351\205\215\347\275\256.xml" "b/log/logback/src/main/resources/logback_\345\274\202\346\255\245\351\205\215\347\275\256.xml" new file mode 100644 index 00000000..026a3b1f --- /dev/null +++ "b/log/logback/src/main/resources/logback_\345\274\202\346\255\245\351\205\215\347\275\256.xml" @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + System.err + + + ${pattern} + + + + + + + ${log_dir}/roll_logback.log + + + ${pattern} + + + + + ${log_dir}/rolling.%d{yyyy-MM-dd}.log%i.gz + + 1KB + + + + + ERROR + + ACCEPT + + DENY + + + + + + + + + + + + + + + + \ No newline at end of file diff --git "a/log/logback/src/main/resources/logback_\350\207\252\345\256\232\344\271\211logger.xml" "b/log/logback/src/main/resources/logback_\350\207\252\345\256\232\344\271\211logger.xml" new file mode 100644 index 00000000..8e69e606 --- /dev/null +++ "b/log/logback/src/main/resources/logback_\350\207\252\345\256\232\344\271\211logger.xml" @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + System.err + + + ${pattern} + + + + + + + + \ No newline at end of file diff --git "a/log/logback/src/main/resources/logback_\351\205\215\347\275\256\346\226\207\344\273\266.xml" "b/log/logback/src/main/resources/logback_\351\205\215\347\275\256\346\226\207\344\273\266.xml" new file mode 100644 index 00000000..920d0c29 --- /dev/null +++ "b/log/logback/src/main/resources/logback_\351\205\215\347\275\256\346\226\207\344\273\266.xml" @@ -0,0 +1,37 @@ + + + + + + + + + + + System.err + + + ${pattern} + + + + + + + + + \ No newline at end of file diff --git a/log/slf4j/pom.xml b/log/slf4j/pom.xml new file mode 100644 index 00000000..7f99bc0e --- /dev/null +++ b/log/slf4j/pom.xml @@ -0,0 +1,81 @@ + + + 4.0.0 + + cn.cunchang + slf4j + 1.0-SNAPSHOT + + + + + + org.slf4j + slf4j-api + 1.7.27 + + + + + + + ch.qos.logback + logback-classic + 1.2.3 + + + + + + org.slf4j + log4j-over-slf4j + 1.7.25 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + junit + junit + 4.13 + + + + \ No newline at end of file diff --git a/log/slf4j/src/main/java/cn/cunchang/Log4jTest.java b/log/slf4j/src/main/java/cn/cunchang/Log4jTest.java new file mode 100644 index 00000000..f85201f8 --- /dev/null +++ b/log/slf4j/src/main/java/cn/cunchang/Log4jTest.java @@ -0,0 +1,22 @@ +package cn.cunchang; + +import org.apache.log4j.Logger; +import org.junit.Test; + +public class Log4jTest { + + // 定义 log4j 日志记录器 + public static final Logger LOGGER = Logger.getLogger(Log4jTest.class); + + /** + * 桥接器
+ * logback替换log4j,代码不需要修改 + * + * + */ + @Test + public void test桥接器() { + LOGGER.info("hello lgo4j"); + } + +} diff --git a/log/slf4j/src/main/java/cn/cunchang/Slf4jTest.java b/log/slf4j/src/main/java/cn/cunchang/Slf4jTest.java new file mode 100644 index 00000000..7458e505 --- /dev/null +++ b/log/slf4j/src/main/java/cn/cunchang/Slf4jTest.java @@ -0,0 +1,40 @@ +package cn.cunchang; + +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class Slf4jTest { + + public static final Logger log = LoggerFactory.getLogger(Slf4jTest.class); + + /** + * http://slf4j.org/manual.html + * 适配器
+ * slf4j-simple、logback、nop、log4j、jul + * + */ + @Test + public void test日志门面() { + // 日志输出 + log.error("error"); + log.warn("wring"); + log.info("info"); // 默认级别 + log.debug("debug"); + log.trace("trace"); + + // 使用占位符输出日志信息 + String name = "寸长"; + Integer age = 18; + log.info("用户:{},{}",name,age); + + // 将系统的异常信息输出 + try { + int i = 1/0; + } catch (Exception e) { + // e.printStackTrace(); + log.error("出现异常:",e); + + } + } +} diff --git a/log/slf4j/src/main/resources/log4j.properties b/log/slf4j/src/main/resources/log4j.properties new file mode 100644 index 00000000..cd822732 --- /dev/null +++ b/log/slf4j/src/main/resources/log4j.properties @@ -0,0 +1,10 @@ +# 指定 RootLogger 顶级父元素默认配置信息 +# 指定日志级别=trace,使用的 apeender 为=console +log4j.rootLogger = trace,console + +# 指定控制台日志输出的 appender +log4j.appender.console = org.apache.log4j.ConsoleAppender +# 指定消息格式 layout +log4j.appender.console.layout = org.apache.log4j.PatternLayout +# 指定消息格式的内容 +log4j.appender.console.layout.conversionPattern = [%-10p]%r %l %d{yyyy-MM-dd HH:mm:ss.SSS} %m%n diff --git a/log/springboot-log/pom.xml b/log/springboot-log/pom.xml new file mode 100644 index 00000000..7b35ca05 --- /dev/null +++ b/log/springboot-log/pom.xml @@ -0,0 +1,45 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.4.1 + + + cn.cunchang + springboot-log + 0.0.1-SNAPSHOT + springboot-log + Demo project for Spring Boot + + + 1.8 + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/log/springboot-log/src/main/java/cn/cunchang/SpringbootLogApplication.java b/log/springboot-log/src/main/java/cn/cunchang/SpringbootLogApplication.java new file mode 100644 index 00000000..181d8374 --- /dev/null +++ b/log/springboot-log/src/main/java/cn/cunchang/SpringbootLogApplication.java @@ -0,0 +1,13 @@ +package cn.cunchang; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class SpringbootLogApplication { + + public static void main(String[] args) { + SpringApplication.run(SpringbootLogApplication.class, args); + } + +} diff --git a/log/springboot-log/src/main/resources/application.properties b/log/springboot-log/src/main/resources/application.properties new file mode 100644 index 00000000..699f0a1a --- /dev/null +++ b/log/springboot-log/src/main/resources/application.properties @@ -0,0 +1,15 @@ +# 指定自定义 logger 对象日志级别 +logging.level.cn.cunchang=trace + +# 指定控制台输出消息格式 +logging.pattern.console=[%-5level] %d{yyyy-MM-dd HH:mm:ss} %c [%thread]===== %msg %n + +# 指定存放日志文件的具体路径 +# logging.file=/Users/cunchang/logs/springboot.log +# 指定日志文件存放的目录,默认的文件名 spring.log +logging.file.path=/Users/cunchang/logs/springboot/ +# 指定日志文件消息格式 +logging.pattern.file=[%-5level] %d{yyyy-MM-dd HH:mm:ss} %c [%thread]===== %msg %n + +# 指定项目使用的具体环境 +spring.profiles.active=pro diff --git a/log/springboot-log/src/main/resources/logback-spring.xml b/log/springboot-log/src/main/resources/logback-spring.xml new file mode 100644 index 00000000..58c707c8 --- /dev/null +++ b/log/springboot-log/src/main/resources/logback-spring.xml @@ -0,0 +1,28 @@ + + + + + + + + + + System.err + + + + ${pattern} + + + [%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} %c %M %L [%thread] xxxxxxxx %m %n + + + + + + + + + \ No newline at end of file diff --git a/log/springboot-log/src/main/resources/logconfig/application.properties b/log/springboot-log/src/main/resources/logconfig/application.properties new file mode 100644 index 00000000..699f0a1a --- /dev/null +++ b/log/springboot-log/src/main/resources/logconfig/application.properties @@ -0,0 +1,15 @@ +# 指定自定义 logger 对象日志级别 +logging.level.cn.cunchang=trace + +# 指定控制台输出消息格式 +logging.pattern.console=[%-5level] %d{yyyy-MM-dd HH:mm:ss} %c [%thread]===== %msg %n + +# 指定存放日志文件的具体路径 +# logging.file=/Users/cunchang/logs/springboot.log +# 指定日志文件存放的目录,默认的文件名 spring.log +logging.file.path=/Users/cunchang/logs/springboot/ +# 指定日志文件消息格式 +logging.pattern.file=[%-5level] %d{yyyy-MM-dd HH:mm:ss} %c [%thread]===== %msg %n + +# 指定项目使用的具体环境 +spring.profiles.active=pro diff --git a/log/springboot-log/src/main/resources/logconfig/log4j2.xml b/log/springboot-log/src/main/resources/logconfig/log4j2.xml new file mode 100644 index 00000000..dd6d85f9 --- /dev/null +++ b/log/springboot-log/src/main/resources/logconfig/log4j2.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/log/springboot-log/src/main/resources/logconfig/logback.xml b/log/springboot-log/src/main/resources/logconfig/logback.xml new file mode 100644 index 00000000..0ba3fcf9 --- /dev/null +++ b/log/springboot-log/src/main/resources/logconfig/logback.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + System.err + + + ${pattern} + + + + + + + + + \ No newline at end of file diff --git a/log/springboot-log/src/test/java/cn/cunchang/SpringbootLogApplicationTests.java b/log/springboot-log/src/test/java/cn/cunchang/SpringbootLogApplicationTests.java new file mode 100644 index 00000000..c928c823 --- /dev/null +++ b/log/springboot-log/src/test/java/cn/cunchang/SpringbootLogApplicationTests.java @@ -0,0 +1,29 @@ +package cn.cunchang; + +import org.apache.logging.log4j.LogManager; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class SpringbootLogApplicationTests { + + // 声明日志记录器对象 + public static final Logger log = LoggerFactory.getLogger(SpringbootLogApplicationTests.class); + + @Test + public void contextLoads() { + // 打印日志信息 + log.error("error"); + log.warn("warn"); + log.info("info"); // 默认日志级别 + log.debug("debug"); + log.trace("trace"); + + // 使用 lo4j2 使用桥接器切换为 slf4j 门面和 logback 日志实现 + org.apache.logging.log4j.Logger logger = LogManager.getLogger(SpringbootLogApplicationTests.class); + logger.info("log4j2 info"); + } + +} diff --git "a/log/\346\227\245\345\277\227\346\212\200\346\234\257 \357\274\210\344\270\212\357\274\211.pdf" "b/log/\346\227\245\345\277\227\346\212\200\346\234\257 \357\274\210\344\270\212\357\274\211.pdf" new file mode 100644 index 00000000..89ce79a2 Binary files /dev/null and "b/log/\346\227\245\345\277\227\346\212\200\346\234\257 \357\274\210\344\270\212\357\274\211.pdf" differ diff --git "a/log/\346\227\245\345\277\227\346\212\200\346\234\257 \357\274\210\344\270\213\357\274\211.pdf" "b/log/\346\227\245\345\277\227\346\212\200\346\234\257 \357\274\210\344\270\213\357\274\211.pdf" new file mode 100644 index 00000000..37892c3a Binary files /dev/null and "b/log/\346\227\245\345\277\227\346\212\200\346\234\257 \357\274\210\344\270\213\357\274\211.pdf" differ diff --git a/mvc/README.MD b/mvc/README.MD new file mode 100644 index 00000000..4a3b8f1b --- /dev/null +++ b/mvc/README.MD @@ -0,0 +1,13 @@ +mvc学习 + +# 1.servlet +servlet3.0 + + + +# 2.springmvc + +springmvc项目依赖tomcat, +并且起始url:http://localhost:8080/springmvc/ + + diff --git a/mvc/pom.xml b/mvc/pom.xml index e38a8bc2..7243315b 100644 --- a/mvc/pom.xml +++ b/mvc/pom.xml @@ -1,16 +1,17 @@ - 4.0.0 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 - cn.lastwhisper - mvc - 1.0-SNAPSHOT - - springmvc - - pom + cn.lastwhisper + mvc + 1.0-SNAPSHOT + + springmvc + springmvc-annotation + + pom diff --git a/mvc/servlet/.classpath b/mvc/servlet/.classpath new file mode 100644 index 00000000..16d8665a --- /dev/null +++ b/mvc/servlet/.classpath @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/mvc/servlet/.project b/mvc/servlet/.project new file mode 100644 index 00000000..0b3daad5 --- /dev/null +++ b/mvc/servlet/.project @@ -0,0 +1,31 @@ + + + servlet + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.wst.common.project.facet.core.builder + + + + + org.eclipse.wst.validation.validationbuilder + + + + + + org.eclipse.jem.workbench.JavaEMFNature + org.eclipse.wst.common.modulecore.ModuleCoreNature + org.eclipse.wst.common.project.facet.core.nature + org.eclipse.jdt.core.javanature + org.eclipse.wst.jsdt.core.jsNature + + diff --git a/mvc/servlet/.settings/.jsdtscope b/mvc/servlet/.settings/.jsdtscope new file mode 100644 index 00000000..92e666d7 --- /dev/null +++ b/mvc/servlet/.settings/.jsdtscope @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/mvc/servlet/.settings/org.eclipse.core.resources.prefs b/mvc/servlet/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 00000000..a7d4c48b --- /dev/null +++ b/mvc/servlet/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +encoding//WebContent/note.txt=GBK diff --git a/mvc/servlet/.settings/org.eclipse.jdt.core.prefs b/mvc/servlet/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000..0c68a61d --- /dev/null +++ b/mvc/servlet/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,7 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/mvc/servlet/.settings/org.eclipse.wst.common.component b/mvc/servlet/.settings/org.eclipse.wst.common.component new file mode 100644 index 00000000..e078d255 --- /dev/null +++ b/mvc/servlet/.settings/org.eclipse.wst.common.component @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/mvc/servlet/.settings/org.eclipse.wst.common.project.facet.core.xml b/mvc/servlet/.settings/org.eclipse.wst.common.project.facet.core.xml new file mode 100644 index 00000000..f2dd0216 --- /dev/null +++ b/mvc/servlet/.settings/org.eclipse.wst.common.project.facet.core.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/mvc/servlet/.settings/org.eclipse.wst.jsdt.ui.superType.container b/mvc/servlet/.settings/org.eclipse.wst.jsdt.ui.superType.container new file mode 100644 index 00000000..3bd5d0a4 --- /dev/null +++ b/mvc/servlet/.settings/org.eclipse.wst.jsdt.ui.superType.container @@ -0,0 +1 @@ +org.eclipse.wst.jsdt.launching.baseBrowserLibrary \ No newline at end of file diff --git a/mvc/servlet/.settings/org.eclipse.wst.jsdt.ui.superType.name b/mvc/servlet/.settings/org.eclipse.wst.jsdt.ui.superType.name new file mode 100644 index 00000000..05bd71b6 --- /dev/null +++ b/mvc/servlet/.settings/org.eclipse.wst.jsdt.ui.superType.name @@ -0,0 +1 @@ +Window \ No newline at end of file diff --git a/mvc/servlet/WebContent/META-INF/MANIFEST.MF b/mvc/servlet/WebContent/META-INF/MANIFEST.MF new file mode 100644 index 00000000..254272e1 --- /dev/null +++ b/mvc/servlet/WebContent/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Class-Path: + diff --git a/mvc/servlet/WebContent/index.jsp b/mvc/servlet/WebContent/index.jsp new file mode 100644 index 00000000..bff1c815 --- /dev/null +++ b/mvc/servlet/WebContent/index.jsp @@ -0,0 +1,12 @@ +<%@ page language="java" contentType="text/html; charset=UTF-8" + pageEncoding="UTF-8"%> + + + + +Insert title here + + + helloServlet + + \ No newline at end of file diff --git a/mvc/servlet/WebContent/note.txt b/mvc/servlet/WebContent/note.txt new file mode 100644 index 00000000..16933874 --- /dev/null +++ b/mvc/servlet/WebContent/note.txt @@ -0,0 +1,22 @@ +Shared libraries⣩ / runtimes pluggabilityʱ + +1Servletɨ裬ǰӦÿһjar + ServletContainerInitializerʵ +2ṩServletContainerInitializerʵࣻ + ڣMETA-INF/services/javax.servlet.ServletContainerInitializer + ļݾServletContainerInitializerʵȫ + +ܽ᣺Ӧõʱ򣬻ɨ赱ǰӦÿһjar +META-INF/services/javax.servlet.ServletContainerInitializer +ָʵ࣬ʵķȤͣ + + +ServletContainerInitializer +@HandlesTypes + +https://www.cnblogs.com/zhulibin2012/p/11111485.html + + + + + diff --git a/mvc/servlet/build/classes/META-INF/services/javax.servlet.ServletContainerInitializer b/mvc/servlet/build/classes/META-INF/services/javax.servlet.ServletContainerInitializer new file mode 100644 index 00000000..ce4ba53e --- /dev/null +++ b/mvc/servlet/build/classes/META-INF/services/javax.servlet.ServletContainerInitializer @@ -0,0 +1 @@ +cn.lastwhisper.servlet.MyServletContainerInitializer \ No newline at end of file diff --git a/mvc/servlet/build/classes/cn/lastwhisper/service/AbstractHelloService.class b/mvc/servlet/build/classes/cn/lastwhisper/service/AbstractHelloService.class new file mode 100644 index 00000000..5ed306ab Binary files /dev/null and b/mvc/servlet/build/classes/cn/lastwhisper/service/AbstractHelloService.class differ diff --git a/mvc/servlet/build/classes/cn/lastwhisper/service/HelloService.class b/mvc/servlet/build/classes/cn/lastwhisper/service/HelloService.class new file mode 100644 index 00000000..fa8bf628 Binary files /dev/null and b/mvc/servlet/build/classes/cn/lastwhisper/service/HelloService.class differ diff --git a/mvc/servlet/build/classes/cn/lastwhisper/service/HelloServiceExt.class b/mvc/servlet/build/classes/cn/lastwhisper/service/HelloServiceExt.class new file mode 100644 index 00000000..a74484bf Binary files /dev/null and b/mvc/servlet/build/classes/cn/lastwhisper/service/HelloServiceExt.class differ diff --git a/mvc/servlet/build/classes/cn/lastwhisper/service/HelloServiceImpl.class b/mvc/servlet/build/classes/cn/lastwhisper/service/HelloServiceImpl.class new file mode 100644 index 00000000..fcd72c2f Binary files /dev/null and b/mvc/servlet/build/classes/cn/lastwhisper/service/HelloServiceImpl.class differ diff --git a/mvc/servlet/build/classes/cn/lastwhisper/servlet/HelloServlet.class b/mvc/servlet/build/classes/cn/lastwhisper/servlet/HelloServlet.class new file mode 100644 index 00000000..ea0e7aa8 Binary files /dev/null and b/mvc/servlet/build/classes/cn/lastwhisper/servlet/HelloServlet.class differ diff --git a/mvc/servlet/build/classes/cn/lastwhisper/servlet/MyServletContainerInitializer.class b/mvc/servlet/build/classes/cn/lastwhisper/servlet/MyServletContainerInitializer.class new file mode 100644 index 00000000..3cbcff3a Binary files /dev/null and b/mvc/servlet/build/classes/cn/lastwhisper/servlet/MyServletContainerInitializer.class differ diff --git a/mvc/servlet/build/classes/cn/lastwhisper/servlet/UserFilter.class b/mvc/servlet/build/classes/cn/lastwhisper/servlet/UserFilter.class new file mode 100644 index 00000000..01ed9760 Binary files /dev/null and b/mvc/servlet/build/classes/cn/lastwhisper/servlet/UserFilter.class differ diff --git a/mvc/servlet/build/classes/cn/lastwhisper/servlet/UserListener.class b/mvc/servlet/build/classes/cn/lastwhisper/servlet/UserListener.class new file mode 100644 index 00000000..25b26a24 Binary files /dev/null and b/mvc/servlet/build/classes/cn/lastwhisper/servlet/UserListener.class differ diff --git a/mvc/servlet/build/classes/cn/lastwhisper/servlet/UserServlet.class b/mvc/servlet/build/classes/cn/lastwhisper/servlet/UserServlet.class new file mode 100644 index 00000000..253929bd Binary files /dev/null and b/mvc/servlet/build/classes/cn/lastwhisper/servlet/UserServlet.class differ diff --git a/mvc/servlet/src/META-INF/services/javax.servlet.ServletContainerInitializer b/mvc/servlet/src/META-INF/services/javax.servlet.ServletContainerInitializer new file mode 100644 index 00000000..ce4ba53e --- /dev/null +++ b/mvc/servlet/src/META-INF/services/javax.servlet.ServletContainerInitializer @@ -0,0 +1 @@ +cn.lastwhisper.servlet.MyServletContainerInitializer \ No newline at end of file diff --git a/mvc/servlet/src/cn/lastwhisper/service/AbstractHelloService.java b/mvc/servlet/src/cn/lastwhisper/service/AbstractHelloService.java new file mode 100644 index 00000000..42381c4f --- /dev/null +++ b/mvc/servlet/src/cn/lastwhisper/service/AbstractHelloService.java @@ -0,0 +1,5 @@ +package cn.lastwhisper.service; + +public abstract class AbstractHelloService implements HelloService { + +} diff --git a/mvc/servlet/src/cn/lastwhisper/service/HelloService.java b/mvc/servlet/src/cn/lastwhisper/service/HelloService.java new file mode 100644 index 00000000..f5917186 --- /dev/null +++ b/mvc/servlet/src/cn/lastwhisper/service/HelloService.java @@ -0,0 +1,5 @@ +package cn.lastwhisper.service; + +public interface HelloService { + +} diff --git a/mvc/servlet/src/cn/lastwhisper/service/HelloServiceExt.java b/mvc/servlet/src/cn/lastwhisper/service/HelloServiceExt.java new file mode 100644 index 00000000..3db836e0 --- /dev/null +++ b/mvc/servlet/src/cn/lastwhisper/service/HelloServiceExt.java @@ -0,0 +1,5 @@ +package cn.lastwhisper.service; + +public interface HelloServiceExt extends HelloService { + +} diff --git a/mvc/servlet/src/cn/lastwhisper/service/HelloServiceImpl.java b/mvc/servlet/src/cn/lastwhisper/service/HelloServiceImpl.java new file mode 100644 index 00000000..9603563f --- /dev/null +++ b/mvc/servlet/src/cn/lastwhisper/service/HelloServiceImpl.java @@ -0,0 +1,5 @@ +package cn.lastwhisper.service; + +public class HelloServiceImpl implements HelloService { + +} diff --git a/mvc/servlet/src/cn/lastwhisper/servlet/HelloServlet.java b/mvc/servlet/src/cn/lastwhisper/servlet/HelloServlet.java new file mode 100644 index 00000000..8dfbcabe --- /dev/null +++ b/mvc/servlet/src/cn/lastwhisper/servlet/HelloServlet.java @@ -0,0 +1,41 @@ +package cn.lastwhisper.servlet; + +import java.io.IOException; +import javax.servlet.ServletException; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * Servlet implementation class HelloServlet + */ +@WebServlet(name = "helloServlet", urlPatterns = { "/helloServlet" }) +public class HelloServlet extends HttpServlet { + private static final long serialVersionUID = 1L; + + /** + * @see HttpServlet#HttpServlet() + */ + public HelloServlet() { + super(); + // TODO Auto-generated constructor stub + } + + /** + * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) + */ + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + // TODO Auto-generated method stub + response.getWriter().append("Served at: ").append(request.getContextPath()); + } + + /** + * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) + */ + protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + // TODO Auto-generated method stub + doGet(request, response); + } + +} diff --git a/mvc/servlet/src/cn/lastwhisper/servlet/MyServletContainerInitializer.java b/mvc/servlet/src/cn/lastwhisper/servlet/MyServletContainerInitializer.java new file mode 100644 index 00000000..39e2ac90 --- /dev/null +++ b/mvc/servlet/src/cn/lastwhisper/servlet/MyServletContainerInitializer.java @@ -0,0 +1,57 @@ +package cn.lastwhisper.servlet; + +import java.util.EnumSet; +import java.util.Set; + +import javax.servlet.DispatcherType; +import javax.servlet.FilterRegistration; +import javax.servlet.ServletContainerInitializer; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.ServletRegistration; +import javax.servlet.annotation.HandlesTypes; + +import cn.lastwhisper.service.HelloService; + + +//容器启动的时候会将@HandlesTypes指定的这个类型下面的子类(实现类,子接口等)传递过来; +//传入感兴趣的类型; +@HandlesTypes(value={HelloService.class}) +public class MyServletContainerInitializer implements ServletContainerInitializer { + + /** + * 应用启动的时候,会运行onStartup方法; + * + * Set> arg0:感兴趣的类型的所有子类型; + * ServletContext arg1:代表当前Web应用的ServletContext;一个Web应用一个ServletContext; + * + * 1)、使用ServletContext注册Web组件(Servlet、Filter、Listener或者阿里巴巴的连接池Filter) + * 2)、使用编码的方式,在项目启动的时候给ServletContext里面添加组件; + * 必须在项目启动的时候来添加; + * 1)、ServletContainerInitializer得到的ServletContext; + * 2)、ServletContextListener得到的ServletContext; + */ + @Override + public void onStartup(Set> arg0, ServletContext sc) throws ServletException { + // TODO Auto-generated method stub + System.out.println("感兴趣的类型:"); + for (Class claz : arg0) { + System.out.println(claz); + } + + //注册组件 ServletRegistration + ServletRegistration.Dynamic servlet = sc.addServlet("userServlet", new UserServlet()); + //配置servlet的映射信息 + servlet.addMapping("/user"); + + + //注册Listener + sc.addListener(UserListener.class); + + //注册Filter FilterRegistration + FilterRegistration.Dynamic filter = sc.addFilter("userFilter", UserFilter.class); + //配置Filter的映射信息 + filter.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/*"); + } + +} \ No newline at end of file diff --git a/mvc/servlet/src/cn/lastwhisper/servlet/UserFilter.java b/mvc/servlet/src/cn/lastwhisper/servlet/UserFilter.java new file mode 100644 index 00000000..c84a5024 --- /dev/null +++ b/mvc/servlet/src/cn/lastwhisper/servlet/UserFilter.java @@ -0,0 +1,35 @@ +package cn.lastwhisper.servlet; + +import java.io.IOException; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; + +public class UserFilter implements Filter { + + @Override + public void destroy() { + // TODO Auto-generated method stub + + } + + @Override + public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2) + throws IOException, ServletException { + // 过滤请求 + System.out.println("UserFilter...doFilter..."); + //放行 + arg2.doFilter(arg0, arg1); + } + + @Override + public void init(FilterConfig arg0) throws ServletException { + // TODO Auto-generated method stub + + } + +} \ No newline at end of file diff --git a/mvc/servlet/src/cn/lastwhisper/servlet/UserListener.java b/mvc/servlet/src/cn/lastwhisper/servlet/UserListener.java new file mode 100644 index 00000000..b35a97ed --- /dev/null +++ b/mvc/servlet/src/cn/lastwhisper/servlet/UserListener.java @@ -0,0 +1,29 @@ +package cn.lastwhisper.servlet; +import javax.servlet.ServletContext; +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; + +/** + * 监听项目的启动和停止 + * @author lfy + * + */ +public class UserListener implements ServletContextListener { + + + //监听ServletContext销毁 + @Override + public void contextDestroyed(ServletContextEvent arg0) { + // TODO Auto-generated method stub + System.out.println("UserListener...contextDestroyed..."); + } + + //监听ServletContext启动初始化 + @Override + public void contextInitialized(ServletContextEvent arg0) { + // TODO Auto-generated method stub + ServletContext servletContext = arg0.getServletContext(); + System.out.println("UserListener...contextInitialized..."); + } + +} \ No newline at end of file diff --git a/mvc/servlet/src/cn/lastwhisper/servlet/UserServlet.java b/mvc/servlet/src/cn/lastwhisper/servlet/UserServlet.java new file mode 100644 index 00000000..2f97a6b6 --- /dev/null +++ b/mvc/servlet/src/cn/lastwhisper/servlet/UserServlet.java @@ -0,0 +1,18 @@ +package cn.lastwhisper.servlet; + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +public class UserServlet extends HttpServlet { + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + // TODO Auto-generated method stub + resp.getWriter().write("tomcat..."); + } + +} diff --git a/mvc/springmvc-annotation/pom.xml b/mvc/springmvc-annotation/pom.xml new file mode 100644 index 00000000..bc9fbc84 --- /dev/null +++ b/mvc/springmvc-annotation/pom.xml @@ -0,0 +1,42 @@ + + + + mvc + cn.lastwhisper + 1.0-SNAPSHOT + + 4.0.0 + war + springmvc-annotation + + + + org.springframework + spring-webmvc + 4.3.11.RELEASE + + + + javax.servlet + servlet-api + 3.0-alpha-1 + provided + + + + + + + + org.apache.maven.plugins + maven-war-plugin + 2.4 + + false + + + + + \ No newline at end of file diff --git a/mvc/springmvc-annotation/src/main/java/cn/lastwhisper/MyWebAppInitializer.java b/mvc/springmvc-annotation/src/main/java/cn/lastwhisper/MyWebAppInitializer.java new file mode 100644 index 00000000..bb38819b --- /dev/null +++ b/mvc/springmvc-annotation/src/main/java/cn/lastwhisper/MyWebAppInitializer.java @@ -0,0 +1,33 @@ +package cn.lastwhisper; + +import cn.lastwhisper.config.AppConfig; +import cn.lastwhisper.config.RootConfig; +import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; + +//webʱ򴴽󣻵÷ʼǰǰ˿ +public class MyWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { + + //ȡࣻSpringļ + @Override + protected Class[] getRootConfigClasses() { + // TODO Auto-generated method stub + return new Class[]{RootConfig.class}; + } + + //ȡwebࣨSpringMVCļ + @Override + protected Class[] getServletConfigClasses() { + // TODO Auto-generated method stub + return new Class[]{AppConfig.class}; + } + + //ȡDispatcherServletӳϢ + // /󣨰̬Դxx.js,xx.pngDz*.jsp + // /**.jspҳ涼أjspҳtomcatjspģ + @Override + protected String[] getServletMappings() { + // TODO Auto-generated method stub + return new String[]{"/"}; + } + +} diff --git a/mvc/springmvc-annotation/src/main/java/cn/lastwhisper/config/AppConfig.java b/mvc/springmvc-annotation/src/main/java/cn/lastwhisper/config/AppConfig.java new file mode 100644 index 00000000..5c6783a4 --- /dev/null +++ b/mvc/springmvc-annotation/src/main/java/cn/lastwhisper/config/AppConfig.java @@ -0,0 +1,45 @@ +package cn.lastwhisper.config; + + +import cn.lastwhisper.controller.MyFirstInterceptor; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.ComponentScan.Filter; +import org.springframework.context.annotation.FilterType; +import org.springframework.stereotype.Controller; +import org.springframework.web.servlet.config.annotation.*; + +//SpringMVCֻɨController +//useDefaultFilters=false ĬϵĹ˹ +@ComponentScan(value = "com.atguigu", includeFilters = { + @Filter(type = FilterType.ANNOTATION, classes = {Controller.class}) +}, useDefaultFilters = false) +@EnableWebMvc +public class AppConfig extends WebMvcConfigurerAdapter { + + // + + //ͼ + @Override + public void configureViewResolvers(ViewResolverRegistry registry) { + // TODO Auto-generated method stub + //Ĭеҳ涼 /WEB-INF/ xxx .jsp + //registry.jsp(); + registry.jsp("/WEB-INF/views/", ".jsp"); + } + + //̬Դ + @Override + public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { + // TODO Auto-generated method stub + configurer.enable(); + } + + // + @Override + public void addInterceptors(InterceptorRegistry registry) { + // TODO Auto-generated method stub + //super.addInterceptors(registry); + registry.addInterceptor(new MyFirstInterceptor()).addPathPatterns("/**"); + } + +} diff --git a/mvc/springmvc-annotation/src/main/java/cn/lastwhisper/config/RootConfig.java b/mvc/springmvc-annotation/src/main/java/cn/lastwhisper/config/RootConfig.java new file mode 100644 index 00000000..8e1bf4da --- /dev/null +++ b/mvc/springmvc-annotation/src/main/java/cn/lastwhisper/config/RootConfig.java @@ -0,0 +1,14 @@ +package cn.lastwhisper.config; + +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.ComponentScan.Filter; +import org.springframework.context.annotation.FilterType; +import org.springframework.stereotype.Controller; + +//Springɨcontroller; +@ComponentScan(value="cn.lastwhisper",excludeFilters={ + @Filter(type=FilterType.ANNOTATION,classes={Controller.class}) +}) +public class RootConfig { + +} diff --git a/mvc/springmvc-annotation/src/main/java/cn/lastwhisper/controller/AsyncController.java b/mvc/springmvc-annotation/src/main/java/cn/lastwhisper/controller/AsyncController.java new file mode 100644 index 00000000..8f61b576 --- /dev/null +++ b/mvc/springmvc-annotation/src/main/java/cn/lastwhisper/controller/AsyncController.java @@ -0,0 +1,84 @@ +package cn.lastwhisper.controller; + +import cn.lastwhisper.service.DeferredResultQueue; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.context.request.async.DeferredResult; + +import java.util.UUID; +import java.util.concurrent.Callable; + + +@Controller +public class AsyncController { + + + @ResponseBody + @RequestMapping("/createOrder") + public DeferredResult createOrder(){ + DeferredResult deferredResult = new DeferredResult<>((long)3000, "create fail..."); + + DeferredResultQueue.save(deferredResult); + + return deferredResult; + } + + + @ResponseBody + @RequestMapping("/create") + public String create(){ + // + String order = UUID.randomUUID().toString(); + DeferredResult deferredResult = DeferredResultQueue.get(); + deferredResult.setResult(order); + return "success===>"+order; + } + + /** + * 1Callable + * 2Spring첽Callable ύ TaskExecutor ʹһִ߳̽ + * 3DispatcherServletеFilter˳weḅ߳response ִ״̬ + * 4CallableؽSpringMVCɷָ֮ǰĴ + * 5CallableصĽSpringMVCͼȾ̵ȣ-ͼȾ + * + * preHandle.../springmvc-annotation/async01 + * ߳̿ʼ...Thread[http-bio-8081-exec-3,5,main]==>1513932494700 + * ߳̽...Thread[http-bio-8081-exec-3,5,main]==>1513932494700 + * =========DispatcherServletеFilter˳߳============================ + * + * ================ȴCallableִ========== + * ߳̿ʼ...Thread[MvcAsync1,5,main]==>1513932494707 + * ߳̿ʼ...Thread[MvcAsync1,5,main]==>1513932496708 + * ================Callableִ========== + * + * ================ٴյ֮ǰط======== + * preHandle.../springmvc-annotation/async01 + * postHandle...Callable֮ǰķֵĿ귽ķֵ + * afterCompletion... + * + * 첽: + * 1ԭAPIAsyncListener + * 2SpringMVCʵAsyncHandlerInterceptor + * + */ + @ResponseBody + @RequestMapping("/async01") + public Callable async01(){ + System.out.println("߳̿ʼ..."+ Thread.currentThread()+"==>"+ System.currentTimeMillis()); + + Callable callable = new Callable() { + @Override + public String call() throws Exception { + System.out.println("߳̿ʼ..."+ Thread.currentThread()+"==>"+ System.currentTimeMillis()); + Thread.sleep(2000); + System.out.println("߳̿ʼ..."+ Thread.currentThread()+"==>"+ System.currentTimeMillis()); + return "Callable async01()"; + } + }; + + System.out.println("߳̽..."+ Thread.currentThread()+"==>"+ System.currentTimeMillis()); + return callable; + } + +} diff --git a/mvc/springmvc-annotation/src/main/java/cn/lastwhisper/controller/HelloController.java b/mvc/springmvc-annotation/src/main/java/cn/lastwhisper/controller/HelloController.java new file mode 100644 index 00000000..f4fbcf03 --- /dev/null +++ b/mvc/springmvc-annotation/src/main/java/cn/lastwhisper/controller/HelloController.java @@ -0,0 +1,30 @@ +package cn.lastwhisper.controller; + + +import cn.lastwhisper.service.HelloService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +@Controller +public class HelloController { + + @Autowired + HelloService helloService; + + + @ResponseBody + @RequestMapping("/hello") + public String hello() { + return helloService.sayHello("tomcat.."); + } + + // /WEB-INF/views/success.jsp + @RequestMapping("/suc") + public String success() { + return "success"; + } + + +} diff --git a/mvc/springmvc-annotation/src/main/java/cn/lastwhisper/controller/MyFirstInterceptor.java b/mvc/springmvc-annotation/src/main/java/cn/lastwhisper/controller/MyFirstInterceptor.java new file mode 100644 index 00000000..632d0a56 --- /dev/null +++ b/mvc/springmvc-annotation/src/main/java/cn/lastwhisper/controller/MyFirstInterceptor.java @@ -0,0 +1,37 @@ +package cn.lastwhisper.controller; + +import org.springframework.web.servlet.HandlerInterceptor; +import org.springframework.web.servlet.ModelAndView; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +public class MyFirstInterceptor implements HandlerInterceptor { + + //Ŀ귽֮ǰִ + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) + throws Exception { + // TODO Auto-generated method stub + System.out.println("preHandle..."+request.getRequestURI()); + return true; + } + + //Ŀ귽ִȷԺִ + @Override + public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, + ModelAndView modelAndView) throws Exception { + // TODO Auto-generated method stub + System.out.println("postHandle..."); + + } + + //ҳӦԺִ + @Override + public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) + throws Exception { + // TODO Auto-generated method stub + System.out.println("afterCompletion..."); + } + +} diff --git a/mvc/springmvc-annotation/src/main/java/cn/lastwhisper/service/DeferredResultQueue.java b/mvc/springmvc-annotation/src/main/java/cn/lastwhisper/service/DeferredResultQueue.java new file mode 100644 index 00000000..0e5fe690 --- /dev/null +++ b/mvc/springmvc-annotation/src/main/java/cn/lastwhisper/service/DeferredResultQueue.java @@ -0,0 +1,20 @@ +package cn.lastwhisper.service; + +import org.springframework.web.context.request.async.DeferredResult; + +import java.util.Queue; +import java.util.concurrent.ConcurrentLinkedQueue; + +public class DeferredResultQueue { + + private static Queue> queue = new ConcurrentLinkedQueue>(); + + public static void save(DeferredResult deferredResult){ + queue.add(deferredResult); + } + + public static DeferredResult get( ){ + return queue.poll(); + } + +} diff --git a/mvc/springmvc-annotation/src/main/java/cn/lastwhisper/service/HelloService.java b/mvc/springmvc-annotation/src/main/java/cn/lastwhisper/service/HelloService.java new file mode 100644 index 00000000..1e1ca96a --- /dev/null +++ b/mvc/springmvc-annotation/src/main/java/cn/lastwhisper/service/HelloService.java @@ -0,0 +1,13 @@ +package cn.lastwhisper.service; + +import org.springframework.stereotype.Service; + +@Service +public class HelloService { + + public String sayHello(String name){ + + return "Hello "+name; + } + +} diff --git a/mvc/springmvc-annotation/src/main/resources/mvc.xml b/mvc/springmvc-annotation/src/main/resources/mvc.xml new file mode 100644 index 00000000..21477033 --- /dev/null +++ b/mvc/springmvc-annotation/src/main/resources/mvc.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + diff --git a/mvc/springmvc-annotation/src/main/resources/note.txt b/mvc/springmvc-annotation/src/main/resources/note.txt new file mode 100644 index 00000000..238b68ad --- /dev/null +++ b/mvc/springmvc-annotation/src/main/resources/note.txt @@ -0,0 +1,32 @@ +1、web容器在启动的时候,会扫描每个jar包下的META-INF/services/javax.servlet.ServletContainerInitializer +2、加载这个文件指定的类SpringServletContainerInitializer +3、spring的应用一启动会加载感兴趣的WebApplicationInitializer接口的下的所有组件; +4、并且为WebApplicationInitializer组件创建对象(组件不是接口,不是抽象类) + 1)、AbstractContextLoaderInitializer:创建根容器;createRootApplicationContext(); + 2)、AbstractDispatcherServletInitializer: + 创建一个web的ioc容器;createServletApplicationContext(); + 创建了DispatcherServlet;createDispatcherServlet(); + 将创建的DispatcherServlet添加到ServletContext中; + getServletMappings(); + 3)、AbstractAnnotationConfigDispatcherServletInitializer:注解方式配置的DispatcherServlet初始化器 + 创建根容器:createRootApplicationContext() + getRootConfigClasses();传入一个配置类 + 创建web的ioc容器: createServletApplicationContext(); + 获取配置类;getServletConfigClasses(); + +总结: + 以注解方式来启动SpringMVC;继承AbstractAnnotationConfigDispatcherServletInitializer; +实现抽象方法指定DispatcherServlet的配置信息; + +=========================== +定制SpringMVC; +1)、@EnableWebMvc:开启SpringMVC定制配置功能; + ; + +2)、配置组件(视图解析器、视图映射、静态资源映射、拦截器。。。) + extends WebMvcConfigurerAdapter + + + + + \ No newline at end of file diff --git a/mvc/springmvc-annotation/src/main/webapp/WEB-INF/views/success.jsp b/mvc/springmvc-annotation/src/main/webapp/WEB-INF/views/success.jsp new file mode 100644 index 00000000..d58a60e0 --- /dev/null +++ b/mvc/springmvc-annotation/src/main/webapp/WEB-INF/views/success.jsp @@ -0,0 +1,12 @@ +<%@ page language="java" contentType="text/html; charset=UTF-8" + pageEncoding="UTF-8" %> + + + + + Insert title here + + +

success!

+ + \ No newline at end of file diff --git a/mvc/springmvc-annotation/src/main/webapp/index.jsp b/mvc/springmvc-annotation/src/main/webapp/index.jsp new file mode 100644 index 00000000..a9d42636 --- /dev/null +++ b/mvc/springmvc-annotation/src/main/webapp/index.jsp @@ -0,0 +1,12 @@ +<%@ page language="java" contentType="text/html; charset=UTF-8" + pageEncoding="UTF-8"%> + + + + +Insert title here + + + + + \ No newline at end of file diff --git a/mvc/springmvc-annotation/src/main/webapp/upload_3.jpg b/mvc/springmvc-annotation/src/main/webapp/upload_3.jpg new file mode 100644 index 00000000..e70eacb2 Binary files /dev/null and b/mvc/springmvc-annotation/src/main/webapp/upload_3.jpg differ diff --git a/mvc/springmvc/pom.xml b/mvc/springmvc/pom.xml index f6580e7c..5be68def 100644 --- a/mvc/springmvc/pom.xml +++ b/mvc/springmvc/pom.xml @@ -9,7 +9,6 @@ 4.0.0 - cn.lastwhisper springmvc war @@ -33,13 +32,14 @@ org.springframework - spring-context - 5.0.4.RELEASE + spring-webmvc + 4.3.11.RELEASE + org.springframework spring-webmvc - 5.0.4.RELEASE + 4.3.11.RELEASE javax.servlet diff --git a/mvc/springmvc/src/main/java/cn/lastwhisper/bean/User.java b/mvc/springmvc/src/main/java/cn/lastwhisper/bean/User.java new file mode 100644 index 00000000..1f704a6d --- /dev/null +++ b/mvc/springmvc/src/main/java/cn/lastwhisper/bean/User.java @@ -0,0 +1,33 @@ +package cn.lastwhisper.bean; + +/** + * + * @author lastwhisper + * @date 2020/6/3 + */ +public class User { + + private String username; + private String password; + + public User(String username, String password) { + this.username = username; + this.password = password; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } +} diff --git a/mvc/springmvc/src/main/java/cn/lastwhisper/controller/ControllerDemo4.java b/mvc/springmvc/src/main/java/cn/lastwhisper/controller/ControllerDemo4.java index 2bab1d9f..2aa07481 100644 --- a/mvc/springmvc/src/main/java/cn/lastwhisper/controller/ControllerDemo4.java +++ b/mvc/springmvc/src/main/java/cn/lastwhisper/controller/ControllerDemo4.java @@ -21,7 +21,7 @@ public class ControllerDemo4 { public void sayHello(HttpServletResponse response) throws Exception { System.out.println("接收到了请求"); response.setContentType("text/html;charset=UTF-8"); - response.getWriter().write(" {\"id\":\"1\",\"username\":\"泰斯特\",\"age\":18}"); + response.getWriter().write("{\"id\":\"1\",\"username\":\"泰斯特\",\"age\":18}"); } } diff --git a/mvc/springmvc/src/main/java/cn/lastwhisper/controller/DownLoadFileController.java b/mvc/springmvc/src/main/java/cn/lastwhisper/controller/DownLoadFileController.java new file mode 100644 index 00000000..5d65a008 --- /dev/null +++ b/mvc/springmvc/src/main/java/cn/lastwhisper/controller/DownLoadFileController.java @@ -0,0 +1,40 @@ +package cn.lastwhisper.controller; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.OutputStream; + +/** + * 文件下载测试 + * @author lastwhisper + * @date 2019/12/20 + */ +@Controller +public class DownLoadFileController { + + @RequestMapping("/download") + @ResponseBody + public String download(HttpServletRequest request, HttpServletResponse response) { + + response.setCharacterEncoding("UTF-8"); + response.setContentType("application/force-download"); + response.addHeader("Content-Disposition", "attachment;filename=stock.txt"); + String content = "Hello,Txt World"; + //ServletOutputStream outputStream = response.getOutputStream(); + try { + OutputStream os = response.getOutputStream(); + os.write(content.getBytes()); + os.close(); + } catch (IOException e) { + e.printStackTrace(); + } + return "{\"id\":\"1\",\"username\":\"tomcat\",\"age\":18}"; + //return null; + } + +} diff --git a/mvc/springmvc/src/main/java/cn/lastwhisper/controller/ParameterController1.java b/mvc/springmvc/src/main/java/cn/lastwhisper/controller/ParameterController1.java index 8267cb0d..c82364a1 100644 --- a/mvc/springmvc/src/main/java/cn/lastwhisper/controller/ParameterController1.java +++ b/mvc/springmvc/src/main/java/cn/lastwhisper/controller/ParameterController1.java @@ -68,4 +68,6 @@ public void testParam4(@PathVariable("username") String username, @PathVariable System.out.println(username+","+age); } + + } \ No newline at end of file diff --git a/mvc/springmvc/src/main/java/cn/lastwhisper/controller/ParameterController2.java b/mvc/springmvc/src/main/java/cn/lastwhisper/controller/ParameterController2.java new file mode 100644 index 00000000..c5c61963 --- /dev/null +++ b/mvc/springmvc/src/main/java/cn/lastwhisper/controller/ParameterController2.java @@ -0,0 +1,39 @@ +package cn.lastwhisper.controller; + +import cn.lastwhisper.bean.User; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +import java.util.List; + +/** + * + * @author lastwhisper + * @date 2020/6/3 + */ +@Controller +@RequestMapping("param2") +public class ParameterController2 { + + @RequestMapping("test1") + @ResponseBody + public String testParam1(List list) { + for (Object o : list) { + System.out.println(o); + } + return "success"; + } + + @RequestMapping("test2") + @ResponseBody + public String testParam2(@RequestBody List list) { + for (Object o : list) { + System.out.println(o); + } + return "success"; + } +} + + diff --git a/mvc/springmvc/src/main/resources/springmvc.xml b/mvc/springmvc/src/main/resources/springmvc.xml index e7f76671..a3dd1939 100644 --- a/mvc/springmvc/src/main/resources/springmvc.xml +++ b/mvc/springmvc/src/main/resources/springmvc.xml @@ -9,19 +9,19 @@ http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> - + - - - + + + - + diff --git a/mvc/springmvc/src/main/webapp/index.jsp b/mvc/springmvc/src/main/webapp/index.jsp index 5f0249c0..f8ba8431 100644 --- a/mvc/springmvc/src/main/webapp/index.jsp +++ b/mvc/springmvc/src/main/webapp/index.jsp @@ -22,12 +22,12 @@ $("#testAjaxParam").click(function () { $.ajax({ - type:"POST", - url:"testParam3", - data:'{"id":"1","username":"泰斯特","age":22}', - dataType:"text", - contentType:"application/json",//发生数据的格式 - success:function (data) { + type: "POST", + url: "testParam3", + data: '{"id":"1","username":"泰斯特","age":22}', + dataType: "text", + contentType: "application/json",//发生数据的格式 + success: function (data) { alert(data); } }); @@ -48,5 +48,9 @@ RequestBody分析
PathVariable分析 +
+

文件下载分析

+文件下载分析 +
diff --git a/mvc/src/main/webapp/WEB-INF/web.xml b/mvc/src/main/webapp/WEB-INF/web.xml deleted file mode 100644 index 9f88c1f9..00000000 --- a/mvc/src/main/webapp/WEB-INF/web.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - Archetype Created Web Application - diff --git a/mvc/src/main/webapp/index.jsp b/mvc/src/main/webapp/index.jsp deleted file mode 100644 index c38169bb..00000000 --- a/mvc/src/main/webapp/index.jsp +++ /dev/null @@ -1,5 +0,0 @@ - - -

Hello World!

- - diff --git "a/notes/leetcode/LeetCode \347\254\254 39 \351\242\230\357\274\232\342\200\234\347\273\204\345\220\210\346\200\273\345\222\214\342\200\235\351\242\230\350\247\243\351\205\215\345\233\276.pptx" "b/notes/leetcode/LeetCode \347\254\254 39 \351\242\230\357\274\232\342\200\234\347\273\204\345\220\210\346\200\273\345\222\214\342\200\235\351\242\230\350\247\243\351\205\215\345\233\276.pptx" new file mode 100644 index 00000000..a272ec10 Binary files /dev/null and "b/notes/leetcode/LeetCode \347\254\254 39 \351\242\230\357\274\232\342\200\234\347\273\204\345\220\210\346\200\273\345\222\214\342\200\235\351\242\230\350\247\243\351\205\215\345\233\276.pptx" differ diff --git a/notes/leetcode/Leetcode.mmap b/notes/leetcode/Leetcode.mmap new file mode 100644 index 00000000..4ad8d276 Binary files /dev/null and b/notes/leetcode/Leetcode.mmap differ diff --git a/notes/leetcode/leetcode-39.vsdx b/notes/leetcode/leetcode-39.vsdx new file mode 100644 index 00000000..a7b87898 Binary files /dev/null and b/notes/leetcode/leetcode-39.vsdx differ diff --git a/notes/leetcode/leetcode-46.vsdx b/notes/leetcode/leetcode-46.vsdx new file mode 100644 index 00000000..9f87245e Binary files /dev/null and b/notes/leetcode/leetcode-46.vsdx differ diff --git a/notes/leetcode/leetcode-47.vsdx b/notes/leetcode/leetcode-47.vsdx new file mode 100644 index 00000000..0ef684c7 Binary files /dev/null and b/notes/leetcode/leetcode-47.vsdx differ diff --git a/notes/leetcode/leetcode-56.vsdx b/notes/leetcode/leetcode-56.vsdx new file mode 100644 index 00000000..7fd62ba0 Binary files /dev/null and b/notes/leetcode/leetcode-56.vsdx differ diff --git a/notes/leetcode/leetcode-77.vsdx b/notes/leetcode/leetcode-77.vsdx new file mode 100644 index 00000000..30cd8ce3 Binary files /dev/null and b/notes/leetcode/leetcode-77.vsdx differ diff --git a/notes/leetcode/leetcode-92.vsdx b/notes/leetcode/leetcode-92.vsdx new file mode 100644 index 00000000..7156ce81 Binary files /dev/null and b/notes/leetcode/leetcode-92.vsdx differ diff --git "a/notes/orm/jpa/SpringDataJPA\347\254\254\344\270\200\345\244\251\350\256\262\344\271\211.doc" "b/notes/orm/jpa/SpringDataJPA\347\254\254\344\270\200\345\244\251\350\256\262\344\271\211.doc" new file mode 100644 index 00000000..4302567f Binary files /dev/null and "b/notes/orm/jpa/SpringDataJPA\347\254\254\344\270\200\345\244\251\350\256\262\344\271\211.doc" differ diff --git "a/notes/orm/jpa/SpringDataJPA\347\254\254\344\270\211\345\244\251\350\256\262\344\271\211.doc" "b/notes/orm/jpa/SpringDataJPA\347\254\254\344\270\211\345\244\251\350\256\262\344\271\211.doc" new file mode 100644 index 00000000..7876c79b Binary files /dev/null and "b/notes/orm/jpa/SpringDataJPA\347\254\254\344\270\211\345\244\251\350\256\262\344\271\211.doc" differ diff --git "a/notes/orm/jpa/SpringDataJPA\347\254\254\344\272\214\345\244\251\350\256\262\344\271\211.doc" "b/notes/orm/jpa/SpringDataJPA\347\254\254\344\272\214\345\244\251\350\256\262\344\271\211.doc" new file mode 100644 index 00000000..cb121e7c Binary files /dev/null and "b/notes/orm/jpa/SpringDataJPA\347\254\254\344\272\214\345\244\251\350\256\262\344\271\211.doc" differ diff --git a/notes/orm/jpa/jpa01.txt b/notes/orm/jpa/jpa01.txt new file mode 100644 index 00000000..d32c902c --- /dev/null +++ b/notes/orm/jpa/jpa01.txt @@ -0,0 +1,90 @@ +springdatajpa + day1:orm思想和hibernate以及jpa的概述和jpa的基本操作 + day2:springdatajpa的运行原理以及基本操作 + day3:多表操作,复杂查询 + +第一 orm思想 + 主要目的:操作实体类就相当于操作数据库表 + 建立两个映射关系: + 实体类和表的映射关系 + 实体类中属性和表中字段的映射关系 + 不再重点关注:sql语句 + + 实现了ORM思想的框架:mybatis,hibernate + +第二 hibernate框架介绍 + Hibernate是一个开放源代码的对象关系映射框架, + 它对JDBC进行了非常轻量级的对象封装, + 它将POJO与数据库表建立映射关系,是一个全自动的orm框架 + +第三 JPA规范 + jpa规范,实现jpa规范,内部是由接口和抽象类组成 + +第四 jpa的基本操作 + 案例:是客户的相关操作(增删改查) + 客户:就是一家公司 + 客户表: + + jpa操作的操作步骤 + 1.加载配置文件创建实体管理器工厂 + Persisitence:静态方法(根据持久化单元名称创建实体管理器工厂) + createEntityMnagerFactory(持久化单元名称) + 作用:创建实体管理器工厂 + + 2.根据实体管理器工厂,创建实体管理器 + EntityManagerFactory :获取EntityManager对象 + 方法:createEntityManager + * 内部维护的很多的内容 + 内部维护了数据库信息, + 维护了缓存信息 + 维护了所有的实体管理器对象 + 再创建EntityManagerFactory的过程中会根据配置创建数据库表 + * EntityManagerFactory的创建过程比较浪费资源 + 特点:线程安全的对象 + 多个线程访问同一个EntityManagerFactory不会有线程安全问题 + * 如何解决EntityManagerFactory的创建过程浪费资源(耗时)的问题? + 思路:创建一个公共的EntityManagerFactory的对象 + * 静态代码块的形式创建EntityManagerFactory + + 3.创建事务对象,开启事务 + EntityManager对象:实体类管理器 + beginTransaction : 创建事务对象 + presist : 保存 + merge : 更新 + remove : 删除 + find/getRefrence : 根据id查询 + + Transaction 对象 : 事务 + begin:开启事务 + commit:提交事务 + rollback:回滚 + 4.增删改查操作 + 5.提交事务 + 6.释放资源 + + i.搭建环境的过程 + 1.创建maven工程导入坐标 + 2.需要配置jpa的核心配置文件 + *位置:配置到类路径下的一个叫做 META-INF 的文件夹下 + *命名:persistence.xml + 3.编写客户的实体类 + 4.配置实体类和表,类中属性和表中字段的映射关系 + 5.保存客户到数据库中 + ii.完成基本CRUD案例 + persist : 保存 + merge : 更新 + remove : 删除 + find/getRefrence : 根据id查询 + + iii.jpql查询 + sql:查询的是表和表中的字段 + jpql:查询的是实体类和类中的属性 + * jpql和sql语句的语法相似 + + 1.查询全部 + 2.分页查询 + 3.统计查询 + 4.条件查询 + 5.排序 + + \ No newline at end of file diff --git a/notes/orm/jpa/jpa02.txt b/notes/orm/jpa/jpa02.txt new file mode 100644 index 00000000..146ff87e --- /dev/null +++ b/notes/orm/jpa/jpa02.txt @@ -0,0 +1,68 @@ +SpringDataJpa第二天 + orm思想,hibernate,JPA的相关操作 + +* SpringDataJpa + +第一 springDataJpa的概述 + +第二 springDataJpa的入门操作 + 案例:客户的基本CRUD + i.搭建环境 + 创建工程导入坐标 + 配置spring的配置文件(配置spring Data jpa的整合) + 编写实体类(Customer),使用jpa注解配置映射关系 + ii.编写一个符合springDataJpa的dao层接口 + * 只需要编写dao层接口,不需要编写dao层接口的实现类 + * dao层接口规范 + 1.需要继承两个接口(JpaRepository,JpaSpecificationExecutor) + 2.需要提供响应的泛型 + + * + findOne(id) :根据id查询 + save(customer):保存或者更新(依据:传递的实体类对象中,是否包含id属性) + delete(id) :根据id删除 + findAll() : 查询全部 + +第三 springDataJpa的运行过程和原理剖析 + 1.通过JdkDynamicAopProxy的invoke方法创建了一个动态代理对象 + 2.SimpleJpaRepository当中封装了JPA的操作(借助JPA的api完成数据库的CRUD) + 3.通过hibernate完成数据库操作(封装了jdbc) + + +第四 复杂查询 + i.借助接口中的定义好的方法完成查询 + findOne(id):根据id查询 + ii.jpql的查询方式 + jpql : jpa query language (jpq查询语言) + 特点:语法或关键字和sql语句类似 + 查询的是类和类中的属性 + + * 需要将JPQL语句配置到接口方法上 + 1.特有的查询:需要在dao接口上配置方法 + 2.在新添加的方法上,使用注解的形式配置jpql查询语句 + 3.注解 : @Query + + iii.sql语句的查询 + 1.特有的查询:需要在dao接口上配置方法 + 2.在新添加的方法上,使用注解的形式配置sql查询语句 + 3.注解 : @Query + value :jpql语句 | sql语句 + nativeQuery :false(使用jpql查询) | true(使用本地查询:sql查询) + 是否使用本地查询 + + iiii.方法名称规则查询 + + + + + + + + + + + + + + + diff --git a/notes/orm/jpa/jpa03.txt b/notes/orm/jpa/jpa03.txt new file mode 100644 index 00000000..097fe254 --- /dev/null +++ b/notes/orm/jpa/jpa03.txt @@ -0,0 +1,129 @@ +回顾 + i.springDatajpa,jpa规范,hibernate三者之间的关系 + code -- > springDatajpa --> jpa规范的API --> hibernate + ii.符合springDataJpa规范的dao层接口的编写规则 + 1.需要实现两个接口(JpaRepository,JapSpecificationExecutor) + 2.提供响应的泛型 + iii.运行过程 + * 动态代理的方式:动态代理对象 + iiii.查询 + +第一 Specifications动态查询 + + JpaSpecificationExecutor 方法列表 + + T findOne(Specification spec); //查询单个对象 + + List findAll(Specification spec); //查询列表 + + //查询全部,分页 + //pageable:分页参数 + //返回值:分页pageBean(page:是springdatajpa提供的) + Page findAll(Specification spec, Pageable pageable); + + //查询列表 + //Sort:排序参数 + List findAll(Specification spec, Sort sort); + + long count(Specification spec);//统计查询 + + * Specification :查询条件 + 自定义我们自己的Specification实现类 + 实现 + //root:查询的根对象(查询的任何属性都可以从根对象中获取) + //CriteriaQuery:顶层查询对象,自定义查询方式(了解:一般不用) + //CriteriaBuilder:查询的构造器,封装了很多的查询条件 + Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder cb); //封装查询条件 + +第二 多表之间的关系和操作多表的操作步骤 + + 表关系 + 一对一 + 一对多: + 一的一方:主表 + 多的一方:从表 + 外键:需要再从表上新建一列作为外键,他的取值来源于主表的主键 + 多对多: + 中间表:中间表中最少应该由两个字段组成,这两个字段做为外键指向两张表的主键,又组成了联合主键 + + 讲师对学员:一对多关系 + + 实体类中的关系 + 包含关系:可以通过实体类中的包含关系描述表关系 + 继承关系 + + 分析步骤 + 1.明确表关系 + 2.确定表关系(描述 外键|中间表) + 3.编写实体类,再实体类中描述表关系(包含关系) + 4.配置映射关系 + +第三 完成多表操作 + + i.一对多操作 + 案例:客户和联系人的案例(一对多关系) + 客户:一家公司 + 联系人:这家公司的员工 + + 一个客户可以具有多个联系人 + 一个联系人从属于一家公司 + + 分析步骤 + 1.明确表关系 + 一对多关系 + 2.确定表关系(描述 外键|中间表) + 主表:客户表 + 从表:联系人表 + * 再从表上添加外键 + 3.编写实体类,再实体类中描述表关系(包含关系) + 客户:再客户的实体类中包含一个联系人的集合 + 联系人:在联系人的实体类中包含一个客户的对象 + 4.配置映射关系 + * 使用jpa注解配置一对多映射关系 + + 级联: + 操作一个对象的同时操作他的关联对象 + + 级联操作: + 1.需要区分操作主体 + 2.需要在操作主体的实体类上,添加级联属性(需要添加到多表映射关系的注解上) + 3.cascade(配置级联) + + 级联添加, + 案例:当我保存一个客户的同时保存联系人 + 级联删除 + 案例:当我删除一个客户的同时删除此客户的所有联系人 + + ii.多对多操作 + 案例:用户和角色(多对多关系) + 用户: + 角色: + + 分析步骤 + 1.明确表关系 + 多对多关系 + 2.确定表关系(描述 外键|中间表) + 中间间表 + 3.编写实体类,再实体类中描述表关系(包含关系) + 用户:包含角色的集合 + 角色:包含用户的集合 + 4.配置映射关系 + + iii.多表的查询 + 1.对象导航查询 + 查询一个对象的同时,通过此对象查询他的关联对象 + + 案例:客户和联系人 + + 从一方查询多方 + * 默认:使用延迟加载(****) + + 从多方查询一方 + * 默认:使用立即加载 + + + + + + + \ No newline at end of file diff --git "a/notes/orm/mybatis/Mybatis\347\254\254\344\270\200\345\244\251\350\256\262\344\271\211.pdf" "b/notes/orm/mybatis/Mybatis\347\254\254\344\270\200\345\244\251\350\256\262\344\271\211.pdf" new file mode 100644 index 00000000..0afc32e4 Binary files /dev/null and "b/notes/orm/mybatis/Mybatis\347\254\254\344\270\200\345\244\251\350\256\262\344\271\211.pdf" differ diff --git "a/notes/orm/mybatis/Mybatis\347\254\254\344\270\211\345\244\251\350\256\262\344\271\211.pdf" "b/notes/orm/mybatis/Mybatis\347\254\254\344\270\211\345\244\251\350\256\262\344\271\211.pdf" new file mode 100644 index 00000000..dceb2acb Binary files /dev/null and "b/notes/orm/mybatis/Mybatis\347\254\254\344\270\211\345\244\251\350\256\262\344\271\211.pdf" differ diff --git "a/notes/orm/mybatis/Mybatis\347\254\254\344\272\214\345\244\251\350\256\262\344\271\211.pdf" "b/notes/orm/mybatis/Mybatis\347\254\254\344\272\214\345\244\251\350\256\262\344\271\211.pdf" new file mode 100644 index 00000000..de81578e Binary files /dev/null and "b/notes/orm/mybatis/Mybatis\347\254\254\344\272\214\345\244\251\350\256\262\344\271\211.pdf" differ diff --git "a/notes/orm/mybatis/Mybatis\347\254\254\345\233\233\345\244\251\350\256\262\344\271\211.pdf" "b/notes/orm/mybatis/Mybatis\347\254\254\345\233\233\345\244\251\350\256\262\344\271\211.pdf" new file mode 100644 index 00000000..7f2399cb Binary files /dev/null and "b/notes/orm/mybatis/Mybatis\347\254\254\345\233\233\345\244\251\350\256\262\344\271\211.pdf" differ diff --git a/notes/orm/mybatis/Noname1.txt b/notes/orm/mybatis/Noname1.txt new file mode 100644 index 00000000..c1dd955c --- /dev/null +++ b/notes/orm/mybatis/Noname1.txt @@ -0,0 +1,121 @@ +mybatis + +һ죺mybatis + mybatisĸ + mybatisĻ + mybatisŰ + ԶmybatisܣҪĿΪô˽mybatisִϸڣ +ڶ죺mybatisʹ + mybatisĵcrud + mybatisIJͷֵ + mybatisdaoд + mybatisõϸ + ǩʹ +죺mybatisͶ + mybatisӳ + mybatisƼƵķ + mybatisĶѯ + һԶࣨһ + Զ +죺mybatisĻע⿪ + mybatisеļʱѯʱ + mybatisеһͶ + mybatisע⿪ + CRUD + ѯ +----------------------------------------------------------- +1ʲôǿܣ + еһ׽ͬĿܽDzͬ⡣ + ʹÿܵĺô + ܷװ˺ܶϸڣʹ߿ʹüķʽʵֹܡ߿Чʡ +2ܹ + ֲ㣺 + չʾݵ + ҵ㣺 + Ǵҵ + ־ò㣺 + Ǻݿ⽻ +3־ò㼼 + JDBC + Connection + PreparedStatement + ResultSet + SpringJdbcTemplate + Springжjdbcļ򵥷װ + ApacheDBUtils + SpringJdbcTemplateҲǶJdbcļ򵥷װ + + Щǿ + JDBCǹ淶 + SpringJdbcTemplateApacheDBUtilsֻǹ + +4mybatisĸ + mybatisһ־òܣjavaдġ + װjdbcĺܶϸڣʹֻҪעsql䱾עעӵȷӹ + ʹORM˼ʵ˽ķװ + + ORM + Object Relational Mappging ϵӳ + 򵥵˵ + ǰݿʵ༰ʵԶӦ + ǿԲʵʵֲݿ + + user User + id userId + user_name userName + Ҫ + ʵеԺݿֶƱһ¡ + user User + id id + user_name user_name +5mybatis + mybatisĻ + һmaven̲ + ڶʵdaoĽӿ + Mybatisļ + SqlMapConifg.xml + IJӳļ + IUserDao.xml + ע + һIUserDao.xml IUserDao.javaʱΪ˺֮ǰ֪ʶһ¡ + Mybatisѳ־òIJӿƺӳļҲMapper + ԣIUserDao IUserMapperһ + ڶideaдĿ¼ʱͰDzһ + ڴʱcom.itheima.daoṹ + Ŀ¼ڴʱcom.itheima.daoһĿ¼ + mybatisӳļλñdaoӿڵİṹͬ + ĸӳļmapperǩnamespaceԵȡֵdaoӿڵȫ޶ + ӳļIJãselectidԵȡֵdaoӿڵķ + + ˵ģ֮ڿодdaoʵࡣ + mybatisŰ + һȡļ + ڶSqlSessionFactory + SqlSession + IJDaoӿڵĴ + 岽ִdaoеķ + ͷԴ + + ע + Ҫӳи֪mybatisҪװĸʵ + õķʽָʵȫ޶ + + mybatisעŰ + IUserDao.xmlƳdaoӿڵķʹ@Selectע⣬ָSQL + ͬʱҪSqlMapConfig.xmlеmapperʱʹclassָdaoӿڵȫ޶ + ȷ + ʵʿУԽԽãԶDzòдdaoʵķʽ + ʹXMLעá + Mybatis֧дdaoʵġ + +6ԶMybatisķ + mybatisʹôdaoķʽʵɾIJʱʲôأ + ֻ£ + һ + ڶڴеselectList + + ԶmybatisͨŰ + class Resources + class SqlSessionFactoryBuilder + interface SqlSessionFactory + interface SqlSession \ No newline at end of file diff --git a/notes/orm/mybatis/Noname2.txt b/notes/orm/mybatis/Noname2.txt new file mode 100644 index 00000000..feb6ff1b --- /dev/null +++ b/notes/orm/mybatis/Noname2.txt @@ -0,0 +1,20 @@ +1عmybatisԶͻ+ԶMybatisע⿪ +2MybatisڴDaoCRUD ص +3CRUDп⣺ĴԼֵķװ +4MybatisڴͳdaoʽʹãԼдdaoʵࣩ ˽ +5mybatisļеij + propertiesǩ + typeAliasesǩ ---Integerд + mappersǩӱǩpackage + +----------------------------------------- +OGNLʽ + Object Graphic Navigation Language + ͼ + + ͨȡֵȡݡдϰgetʡˡ + 磺ǻȡû + едuser.getUsername(); + OGNLʽдuser.username + mybatisΪʲôֱдusername,user.أ + ΪparameterTypeѾṩ࣬ԴʱҪд \ No newline at end of file diff --git a/notes/orm/mybatis/Noname3.txt b/notes/orm/mybatis/Noname3.txt new file mode 100644 index 00000000..0bb629d2 --- /dev/null +++ b/notes/orm/mybatis/Noname3.txt @@ -0,0 +1,88 @@ +1mybatisеӳԼ ԭ˽⣬Ӧòֻ + mybatisӳʹü + mybatisƵķ +2mybatisXMLõĶ̬SQLʹ ü + mappersļеļǩ + + + + +3mybatisеĶ Ӧ + һԶ + һһ + Զ +-------------------------------------------------------------------------------- +1ӳأ + ʵʿжʹӳء + ΪԼǻȡĵʱ䡣 +2mybatisеӳ + mybatisӳṩ3ַʽã + õλã + ļSqlMapConfig.xmlеdataSourceǩtypeԾDZʾúӳطʽ + typeԵȡֵ + POOLED ôͳjavax.sql.DataSource淶еӳأmybatisԹ淶ʵ + UNPOOLED ôͳĻȡӵķʽȻҲʵJavax.sql.DataSourceӿڣDzûʹóص˼롣 + JNDI ÷ṩJNDIʵ֣ȡDataSource󣬲ͬķõDataSourceDzһ + ע⣺webmavenwaṛDzʹõġ + ǿγʹõtomcatӳؾdbcpӳء +3mybatisе + ʲô + ĴACID + ǸԻ3 + 취ָ뼶 + + ͨsqlsessioncommitrollbackʵύͻع +4mybatisеĶѯ + ֮Ĺϵм֣ + һԶ + һ + һһ + Զ + + ûͶһԶ + ûǶһ + һû¶ + ͬһû + + ˺֤žһһ + һֻһ֤ + һֻ֤һ + + ʦѧ֮ǶԶ + һѧԱʦ̹ + һʦԽѧ + + óÿһֻһû + MybatisͰѶһһһ + + mybatisеĶѯ + ʾû˻ + һûж˻ + һ˻ֻһû˻Ҳͬһû + 裺 + 1űû˻ + û˻֮߱һԶĹϵҪʹ˻ + 2ʵࣺûʵ˻ʵ + û˻ʵֳһԶĹϵ + 3ļ + ûļ + ˻ļ + 4ʵã + Dzѯûʱͬʱõû˻Ϣ + Dzѯ˻ʱͬʱõ˻ûϢ + + ʾûͽɫ + һûжɫ + һɫԸû + 裺 + 1űûɫ + ûͽɫжԶĹϵҪʹммаԵм + 2ʵࣺûʵͽɫʵ + ûͽɫʵֳԶĹϵ + ԰Էһ + 3ļ + ûļ + ɫļ + 4ʵã + DzѯûʱͬʱõûĽɫϢ + DzѯɫʱͬʱõɫûϢ \ No newline at end of file diff --git a/notes/orm/mybatis/Noname4.txt b/notes/orm/mybatis/Noname4.txt new file mode 100644 index 00000000..803e56e0 --- /dev/null +++ b/notes/orm/mybatis/Noname4.txt @@ -0,0 +1,49 @@ +1Mybatisеӳټ + ⣺һԶУһû100˻ + ڲѯûʱҪҪѹ˻ + ڲѯ˻ʱҪҪѹû + + ڲѯûʱûµ˻ϢӦǣʲôʱʹãʲôʱѯġ + ڲѯ˻ʱ˻ûϢӦ˻ѯʱһѯ + + ʲôӳټ + ʹʱŷѯõʱ򲻲ѯأأ + ʲô + òãֻҪһ÷Ϸѯ + + ڶӦֱϵУһԶ࣬һһһԶ + һԶ࣬ԶࣺͨǶDzӳټء + һһһͨǶDzء + +2MybatisеĻ + ʲôǻ + ڴеʱݡ + Ϊʲôʹû + ٺݿĽִЧʡ + ʲôʹû棬ʲôݲʹ + ڻ棺 + ѯҲıġ + ݵȷսӰ첻ġ + ڻ棺 + ı + ݵȷսӰܴġ + 磺ƷĿ棬еĻʣеƼۡ + MybatisеһͶ + һ棺 + ָMybatisSqlSessionĻ档 + ִвѯ֮󣬲ѯĽͬʱ뵽SqlSessionΪṩһС + ĽṹһMapٴβѯͬݣmybatisȥsqlsession + ѯǷУеĻֱóá + SqlSessionʧʱmybatisһҲʧˡ + + : + ָMybatisSqlSessionFactoryĻ档ͬһSqlSessionFactory󴴽SqlSession仺档 + ʹò裺 + һMybatisֶ֧棨SqlMapConfig.xmlã + ڶõǰӳļֶ֧棨IUserDao.xmlã + õǰIJֶ֧棨selectǩã +3Mybatisеע⿪ +  + CRUDDaoʽ + ѯ + \ No newline at end of file diff --git a/orm/jdbc/README.md b/orm/jdbc/README.md new file mode 100644 index 00000000..e375d947 --- /dev/null +++ b/orm/jdbc/README.md @@ -0,0 +1,144 @@ +# JDBC开发步骤 + +创建一个以JDBC连接数据库的程序,包含7个步骤: + +## 1、加载JDBC驱动程序: + +在连接数据库之前,首先要加载想要连接的数据库的驱动到JVM(Java虚拟机),这通过java.lang.Class.forName(String className)实现。 例如: + +```Java +try{ + //加载MySql的驱动类 + Class.forName("com.mysql.jdbc.Driver") ; +}catch(ClassNotFoundException e){ + System.out.println("找不到驱动程序类 ,加载驱动失败!"); + e.printStackTrace() ; +} +``` + +成功加载后,会将Driver类的实例注册到DriverManager类中。 + +## 2、提供JDBC连接的URL + +连接URL定义了连接数据库时的协议、子协议、数据源标识。 + +- 书写形式:协议:子协议:数据源标识 +- 协议:在JDBC中总是以jdbc开始 +- 子协议:是桥连接的驱动程序或是数据库管理系统名称。 +- 数据源标识:标记找到数据库来源的地址与连接端口。 + +例如:(MySql的连接URL) + +jdbc:mysql:[//localhost:3306/test?useUnicode=true&characterEncoding=gbk](//localhost:3306/test?useUnicode=true&characterEncoding=gbk); + +useUnicode=true:表示使用Unicode字符集。如果characterEncoding设置为gb2312或GBK,本参数必须设置为true 。characterEncoding=gbk:字符编码方式。 + +## 3、创建数据库的连接 + +要连接数据库,需要向java.sql.DriverManager请求并获得Connection对象,该对象就代表一个数据库的连接。Mysql Connection接口实现类com.mysql.cj.jdbc.ConnectionImpl + +例如: + +```Java +//连接MySql数据库,用户名和密码都是root +String url = "jdbc:mysql://localhost:3306/test" ; +String username = "root" ; +String password = "gg" ; +try{ + Connection con = DriverManager.getConnection(url , username , password); +}catch(SQLException se){ + System.out.println("数据库连接失败!"); + se.printStackTrace() ; +} +``` + +## 4、创建一个Statement + +要执行SQL语句,必须获得java.sql.Statement实例,Statement实例分为以下3 种类型: + +1、执行静态SQL语句。通常通过Statement实例实现。 + +2、执行动态SQL语句。通常通过PreparedStatement实例实现。 + +3、执行数据库存储过程。通常通过CallableStatement实例实现。 + +具体的实现方式: + +```Java +Statement stmt = con.createStatement() ; +ResultSet rs = stmt.executeQuery("SELECT firstname,lastname FROM people"); + +PreparedStatement pstmt = con.prepareStatement("update people set firstname=? , lastname=? where id=?") ; +CallableStatement cstmt = con.prepareCall("{CALL demoSp(? , ?)}") ; +``` + +## 5、执行SQL语句 + +Statement接口提供了三种执行SQL语句的方法:executeQuery 、executeUpdate 和execute + +1、ResultSet executeQuery(String sqlString):执行查询数据库的SQL语句,返回一个结果集(ResultSet)对象。 + +2、int executeUpdate(String sqlString):用于执行INSERT、UPDATE或DELETE语句以及SQL DDL语句,如:CREATE TABLE和DROP TABLE等 + +3、execute(sqlString):用于执行返回多个结果集、多个更新计数或二者组合的语句。 + +具体实现的代码: + +```java +ResultSet rs = stmt.executeQuery("SELECT * FROM ...") ; +int rows = stmt.executeUpdate("INSERT INTO ...") ; +boolean flag = stmt.execute(String sql) ; +``` + +## 6、处理结果 + +两种情况: + +1、执行更新返回的是本次操作影响到的记录数。 + +2、执行查询返回的结果是一个ResultSet对象。 + +ResultSet包含符合SQL语句中条件的所有行,并且它通过一套get方法提供了对这些行中数据的访问。 使用结果集(ResultSet)对象的访问方法获取数据: + +```java +while(rs.next()){ + String name = rs.getString("name") ; + String pass = rs.getString(1) ; // 此方法比较高效(列是从左到右编号的,并且从列1开始) +} +``` + +## 7、关闭JDBC对象 + +操作完成以后要把所有使用的JDBC对象全都关闭,以释放JDBC资源,关闭顺序和声明顺序相反: + +1、关闭记录集 + +2、关闭声明 + +3、关闭连接对象 + +```java +if(rs != null){ // 关闭记录集 + try{ + rs.close() ; + }catch(SQLException e){ + e.printStackTrace() ; + } +} + +if(stmt != null){ // 关闭声明 + try{ + stmt.close() ; + }catch(SQLException e){ + e.printStackTrace() ; + } +} +if(conn != null){ // 关闭连接对象 + try{ + conn.close() ; + }catch(SQLException e){ + e.printStackTrace() ; + } +} +``` + diff --git a/orm/jdbc/pom.xml b/orm/jdbc/pom.xml new file mode 100644 index 00000000..d15daba6 --- /dev/null +++ b/orm/jdbc/pom.xml @@ -0,0 +1,34 @@ + + + + + + + + 4.0.0 + + cn.lastwhisper--> + jdbc + 1.0-SNAPSHOT--> + + + + + + mysql + mysql-connector-java + 5.1.6 + + + + + junit + junit + 4.12 + test + + + + \ No newline at end of file diff --git a/orm/jdbc/sql/batchtable.sql b/orm/jdbc/sql/batchtable.sql new file mode 100644 index 00000000..2b36ac6a --- /dev/null +++ b/orm/jdbc/sql/batchtable.sql @@ -0,0 +1,31 @@ +/* + Navicat Premium Data Transfer + + Source Server : mysql5.7 + Source Server Type : MySQL + Source Server Version : 50724 + Source Host : localhost:3306 + Source Schema : mysqlstudy + + Target Server Type : MySQL + Target Server Version : 50724 + File Encoding : 65001 + + Date: 05/02/2020 13:38:49 +*/ + +SET NAMES utf8mb4; +SET FOREIGN_KEY_CHECKS = 0; + +-- ---------------------------- +-- Table structure for batchtable +-- ---------------------------- +DROP TABLE IF EXISTS `batchtable`; +CREATE TABLE `batchtable` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `column1` int(11) NULL DEFAULT NULL, + `column2` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; + +SET FOREIGN_KEY_CHECKS = 1; diff --git a/orm/jdbc/src/main/java/cn/lastwhisper/jdbc/Main1.java b/orm/jdbc/src/main/java/cn/lastwhisper/jdbc/Main1.java new file mode 100644 index 00000000..f5ac1a5f --- /dev/null +++ b/orm/jdbc/src/main/java/cn/lastwhisper/jdbc/Main1.java @@ -0,0 +1,56 @@ +package cn.lastwhisper.jdbc; + + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.SQLException; + +public class Main1 { + public static void main(String[] args) { + Connection conn = null; + PreparedStatement pst = null; + + try { + Class.forName("com.mysql.jdbc.Driver"); + conn = DriverManager.getConnection("jdbc:mysql://********:3306/****", "****", "****"); + + String sql = "insert into employees (user_id, age, first_name, second_name, date) values(?,?,?,?,?)"; + + pst = conn.prepareStatement(sql); + + int loop = 0; + for(loop = 0; loop < 1000; loop++) { + pst.setInt(1, loop); + pst.setInt(2, 18); + pst.setString(3, "roger"); + pst.setString(4, "zhang"); + pst.setString(5, "2017-01-17"); + pst.addBatch(); + } + + pst.executeBatch(); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } catch (SQLException e) { + e.printStackTrace(); + } finally { + if(pst != null) { + try { + pst.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + + if(conn != null) { + try { + conn.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + } + } +} + \ No newline at end of file diff --git a/orm/jdbc/src/main/java/cn/lastwhisper/jdbc/Main2.java b/orm/jdbc/src/main/java/cn/lastwhisper/jdbc/Main2.java new file mode 100644 index 00000000..9ea899b7 --- /dev/null +++ b/orm/jdbc/src/main/java/cn/lastwhisper/jdbc/Main2.java @@ -0,0 +1,66 @@ +package cn.lastwhisper.jdbc; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.SQLException; + + +public class Main2 { + + public static void main(String[] args) { + Connection conn = null; + PreparedStatement pst = null; + + //执行sql=insert into employees (user_id, age, first_name, second_name, date) values(?,?,?,?,?) ||用时=12752 + try { + Class.forName("com.mysql.jdbc.Driver"); + conn = DriverManager.getConnection("jdbc:mysql://47.100.54.177:3637/mysqlstudy?rewriteBatchedStatements=true", "root", "4710054177.gg"); + long startTime = System.currentTimeMillis(); + + String sql = "insert into employees (user_id, age, first_name, second_name, date) values(?,?,?,?,?)"; + + conn.setAutoCommit(false); + pst = conn.prepareStatement(sql); + + for(int loop = 0; loop < 1000; loop++) { + pst.setInt(1, loop); + pst.setInt(2, 18); + pst.setString(3, "roger"); + pst.setString(4, "zhang"); + pst.setString(5, "2017-01-17"); + pst.addBatch(); + } + + pst.executeBatch(); + conn.commit(); + + System.out.println("执行sql=" + sql + " ||用时=" + (System.currentTimeMillis() - startTime)); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } catch (SQLException e) { + e.printStackTrace(); + try { + conn.rollback(); + } catch (SQLException e1) { + e1.printStackTrace(); + } + } finally { + if(pst != null) { + try { + pst.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + + if(conn != null) { + try { + conn.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + } + } +} \ No newline at end of file diff --git a/orm/jdbc/src/main/java/cn/lastwhisper/jdbc/Main3.java b/orm/jdbc/src/main/java/cn/lastwhisper/jdbc/Main3.java new file mode 100644 index 00000000..530985e8 --- /dev/null +++ b/orm/jdbc/src/main/java/cn/lastwhisper/jdbc/Main3.java @@ -0,0 +1,55 @@ +package cn.lastwhisper.jdbc; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.SQLException; + +public class Main3 { + + public static void main(String[] args) { + Connection conn = null; + PreparedStatement pst = null; + + try { + Class.forName("com.mysql.jdbc.Driver"); + conn = DriverManager.getConnection("jdbc:mysql://********:3306/****?rewriteBatchedStatements=true", "****", "****"); + + String sql = "insert into employees (user_id, age, first_name, second_name, date) values(?,?,?,?,?)"; + + pst = conn.prepareStatement(sql); + + int loop = 0; + for(loop = 0; loop < 1000; loop++) { + pst.setInt(1, loop); + pst.setInt(2, 18); + pst.setString(3, "roger"); + pst.setString(4, "zhang"); + pst.setString(5, "2017-01-17"); + pst.addBatch(); + } + + pst.executeBatch(); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } catch (SQLException e) { + e.printStackTrace(); + } finally { + if(pst != null) { + try { + pst.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + + if(conn != null) { + try { + conn.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + } + } +} \ No newline at end of file diff --git a/orm/jdbc/src/main/java/cn/lastwhisper/jdbc/Main4.java b/orm/jdbc/src/main/java/cn/lastwhisper/jdbc/Main4.java new file mode 100644 index 00000000..0c7fd744 --- /dev/null +++ b/orm/jdbc/src/main/java/cn/lastwhisper/jdbc/Main4.java @@ -0,0 +1,66 @@ +package cn.lastwhisper.jdbc; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.SQLException; + +public class Main4 { + + public static void main(String[] args) { + Connection conn = null; + PreparedStatement pst = null; + // 执行sql=insert into employees (user_id, age, first_name, second_name, date) values(?,?,?,?,?) ||用时=8297 + try { + Class.forName("com.mysql.jdbc.Driver"); + conn = DriverManager.getConnection("jdbc:mysql://47.100.54.177:3637/mysqlstudy?rewriteBatchedStatements=true", "root", "4710054177.gg"); + + long startTime = System.currentTimeMillis(); + + String sql = "insert into employees (user_id, age, first_name, second_name, date) values(?,?,?,?,?)"; + + conn.setAutoCommit(false); + pst = conn.prepareStatement(sql); + + int loop = 0; + for(loop = 0; loop < 1000; loop++) { + pst.setInt(1, loop); + pst.setInt(2, 18); + pst.setString(3, "roger"); + pst.setString(4, "zhang"); + pst.setString(5, "2017-01-17"); + pst.addBatch(); + } + + pst.executeBatch(); + conn.commit(); + + System.out.println("执行sql=" + sql + " ||用时=" + (System.currentTimeMillis() - startTime)); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } catch (SQLException e) { + e.printStackTrace(); + try { + conn.rollback(); + } catch (SQLException e1) { + e1.printStackTrace(); + } + } finally { + if(pst != null) { + try { + pst.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + + if(conn != null) { + try { + conn.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + } + } +} \ No newline at end of file diff --git a/orm/jdbc/src/main/java/cn/lastwhisper/jdbc/util/Callback.java b/orm/jdbc/src/main/java/cn/lastwhisper/jdbc/util/Callback.java new file mode 100644 index 00000000..b281f6ae --- /dev/null +++ b/orm/jdbc/src/main/java/cn/lastwhisper/jdbc/util/Callback.java @@ -0,0 +1,17 @@ +package cn.lastwhisper.jdbc.util; + + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; + +/** + * @author lastwhisper + */ +@FunctionalInterface +public interface Callback { + /** + * 模板方法的回调方法 + */ + void execute(PreparedStatement pstm) throws SQLException; +} \ No newline at end of file diff --git a/orm/jdbc/src/main/java/cn/lastwhisper/jdbc/util/JdbcUtil.java b/orm/jdbc/src/main/java/cn/lastwhisper/jdbc/util/JdbcUtil.java new file mode 100644 index 00000000..f24b2fa5 --- /dev/null +++ b/orm/jdbc/src/main/java/cn/lastwhisper/jdbc/util/JdbcUtil.java @@ -0,0 +1,121 @@ +package cn.lastwhisper.jdbc.util; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.SQLException; + +/** + * https://blog.csdn.net/zhangw1236/article/details/54583192 + * @author lastwhisper + * @date 2020/2/5 + */ +public class JdbcUtil { + + static { + try { + Class.forName("com.mysql.jdbc.Driver"); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + } + + public static Connection getConnection() { + try { + String user = "root"; + //String password = "root"; + String password = "4710054177.gg"; + //String url = "jdbc:mysql://localhost:3306/mysqlstudy?characterEnconding=UTF-8"; + String url = "jdbc:mysql://47.100.54.177:3637/mysqlstudy?characterEnconding=UTF-8"; + return DriverManager.getConnection(url, user, password); + } catch (SQLException e) { + e.printStackTrace(); + } + return null; + } + + public static Connection getBatchConnection() { + try { + String user = "root"; + //String password = "root"; + String password = "4710054177.gg"; + + //String url = "jdbc:mysql://localhost:3306/mysqlstudy?characterEnconding=UTF-8&rewriteBatchedStatements=true"; + String url = "jdbc:mysql://47.100.54.177:3637/mysqlstudy?characterEnconding=UTF-8&rewriteBatchedStatements=true"; + return DriverManager.getConnection(url, user, password); + } catch (SQLException e) { + e.printStackTrace(); + } + return null; + } + + /** + * 增删改模板 + * + */ + public static void executeUpdate(Callback callback, String sql) { + Connection conn = getConnection(); + PreparedStatement pstm = null; + try { + assert conn != null; + pstm = conn.prepareStatement(sql); + Long startTime = System.currentTimeMillis(); + + callback.execute(pstm); + + Long endTime = System.currentTimeMillis(); + System.out.println("执行sql=" + sql + " ||用时=" + (endTime - startTime)); + } catch (Exception e) { + e.printStackTrace(); + } finally { + close(conn); + close(pstm); + } + + } + + public static void executeBatchUpdate(Callback callback, String sql) { + Connection conn = getBatchConnection(); + PreparedStatement pstm = null; + try { + assert conn != null; + conn.setAutoCommit(false); + pstm = conn.prepareStatement(sql); + Long startTime = System.currentTimeMillis(); + + callback.execute(pstm); + + conn.commit(); + Long endTime = System.currentTimeMillis(); + System.out.println("执行sql=" + sql + " ||用时=" + (endTime - startTime)); + } catch (Exception e) { + e.printStackTrace(); + } finally { + close(conn); + close(pstm); + } + + } + + private static void close(PreparedStatement pstm) { + if (pstm != null) { + try { + pstm.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + + } + + private static void close(Connection conn) { + if (conn != null) { + try { + conn.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + } + +} diff --git a/orm/jdbc/src/test/java/cn/lastwhisper/jdbc/test/JdbcTest.java b/orm/jdbc/src/test/java/cn/lastwhisper/jdbc/test/JdbcTest.java new file mode 100644 index 00000000..cd53ec0c --- /dev/null +++ b/orm/jdbc/src/test/java/cn/lastwhisper/jdbc/test/JdbcTest.java @@ -0,0 +1,74 @@ +package cn.lastwhisper.jdbc.test; + +import cn.lastwhisper.jdbc.util.JdbcUtil; +import org.junit.Test; + +import java.util.Random; + +/** + * + * @author lastwhisper + * @date 2020/2/5 + */ +public class JdbcTest { + + // 插入一条,执行一条 + @Test + public void TestInsert() { + // 执行sql=INSERT INTO batchtable(account,name,area,title,motto) values(?,?,?,?,?) ||用时=12771 + JdbcUtil.executeUpdate(pstm -> { + for (int i = 1; i <= 1000; i++) { + pstm.setString(1, generateRandomString(10)); + pstm.setString(2, generateRandomString(20)); + pstm.setString(3, generateRandomString(20)); + pstm.setString(4, generateRandomString(20)); + pstm.setString(5, generateRandomString(50)); + pstm.executeUpdate(); + } + }, "INSERT INTO batchtable(account,name,area,title,motto) values(?,?,?,?,?)"); + } + + // 批量插入 + @Test + public void TestBatchInsert() { + // 执行sql=INSERT INTO batchtable(account,name,area,title,motto) values(?,?,?,?,?) ||用时=12210 + JdbcUtil.executeBatchUpdate(pstm -> { + for (int i = 1; i <= 1000; i++) { + pstm.setString(1, generateRandomString(10)); + pstm.setString(2, generateRandomString(20)); + pstm.setString(3, generateRandomString(20)); + pstm.setString(4, generateRandomString(20)); + pstm.setString(5, generateRandomString(50)); + pstm.addBatch(); + // 每1000条记录插入一次 + //if (i % 1000 == 0){ + // pstm.executeBatch(); + // conn.commit(); + // pstm.clearBatch(); + //} + } + pstm.executeBatch(); + //conn.commit(); + pstm.clearBatch(); + }, "INSERT INTO batchtable(account,name,area,title,motto) values(?,?,?,?,?)"); + } + + + //生成指定length的随机字符串(A-Z,a-z,0-9) + public static String generateRandomString(int length) { + String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + Random random = new Random(); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < length; i++) { + int number = random.nextInt(str.length()); + sb.append(str.charAt(number)); + } + return sb.toString(); + } + + public static void main(String[] args) { + System.out.println(generateRandomString(10).length() == 10); + System.out.println(generateRandomString(20).length() == 20); + System.out.println(generateRandomString(50).length() == 50); + } +} diff --git a/orm/jpa/jpa-onetomany/src/main/java/cn/lastwhisper/jpaonetomany/domain/Customer.java b/orm/jpa/jpa-onetomany/src/main/java/cn/lastwhisper/jpaonetomany/domain/Customer.java index a86e3931..1a8ebe7b 100644 --- a/orm/jpa/jpa-onetomany/src/main/java/cn/lastwhisper/jpaonetomany/domain/Customer.java +++ b/orm/jpa/jpa-onetomany/src/main/java/cn/lastwhisper/jpaonetomany/domain/Customer.java @@ -1,6 +1,8 @@ package cn.lastwhisper.jpaonetomany.domain; import lombok.*; +import org.hibernate.annotations.Fetch; +import org.hibernate.annotations.FetchMode; import javax.persistence.*; import java.io.Serializable; diff --git a/orm/mongodb/pom.xml b/orm/mongodb/pom.xml new file mode 100644 index 00000000..4b4ab923 --- /dev/null +++ b/orm/mongodb/pom.xml @@ -0,0 +1,64 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.2.1.RELEASE + + + cn.cunchang + mongodb + 0.0.1-SNAPSHOT + mongodb + Demo project for Spring Boot Data MongoDB + + 1.8 + + + + org.springframework.boot + spring-boot-starter-data-mongodb + + + org.springframework.boot + spring-boot-starter-web + + + + org.projectlombok + lombok + true + + + org.springframework.boot + spring-boot-starter-test + test + + + + junit + junit + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.projectlombok + lombok + + + + + + + + diff --git a/orm/mongodb/src/main/java/cn/cunchang/Application.java b/orm/mongodb/src/main/java/cn/cunchang/Application.java new file mode 100644 index 00000000..2ba8082d --- /dev/null +++ b/orm/mongodb/src/main/java/cn/cunchang/Application.java @@ -0,0 +1,13 @@ +package cn.cunchang; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + +} diff --git a/orm/mongodb/src/main/java/cn/cunchang/domain/Comment.java b/orm/mongodb/src/main/java/cn/cunchang/domain/Comment.java new file mode 100644 index 00000000..5ae35add --- /dev/null +++ b/orm/mongodb/src/main/java/cn/cunchang/domain/Comment.java @@ -0,0 +1,147 @@ +package cn.cunchang.domain; + +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.index.CompoundIndex; +import org.springframework.data.mongodb.core.index.Indexed; +import org.springframework.data.mongodb.core.mapping.Document; +import org.springframework.data.mongodb.core.mapping.Field; + +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.Date; + +/** + * 文章评论实体类 + */ +//把一个java类声明为mongodb的文档,可以通过collection参数指定这个类对应的文档。 +//@Document(collection="mongodb 对应 collection 名") +// 若未加 @Document ,该 bean save 到 mongo 的 comment collection +// 若添加 @Document ,则 save 到 comment collection +@Document(collection="comment")//可以省略,如果省略,则默认使用类名小写映射集合 +//复合索引 +@CompoundIndex( def = "{'userid': 1, 'nickname': -1}") +public class Comment implements Serializable { + //主键标识,该属性的值会自动对应mongodb的主键字段"_id",如果该属性名就叫“id”,则该注解可以省略,否则必须写 + @Id + private String id;//主键 + //该属性对应mongodb的字段的名字,如果一致,则无需该注解 + @Field("content") + private String content;//吐槽内容 + private Date publishtime;//发布日期 + //添加了一个单字段的索引 + @Indexed + private String userid;//发布人ID + private String nickname;//昵称 + private LocalDateTime createdatetime;//评论的日期时间 + private Integer likenum;//点赞数 + private Integer replynum;//回复数 + private String state;//状态 + private String parentid;//上级ID + private String articleid; + //getter and setter..... + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public Date getPublishtime() { + return publishtime; + } + + public void setPublishtime(Date publishtime) { + this.publishtime = publishtime; + } + + public String getUserid() { + return userid; + } + + public void setUserid(String userid) { + this.userid = userid; + } + + public String getNickname() { + return nickname; + } + + public void setNickname(String nickname) { + this.nickname = nickname; + } + + public LocalDateTime getCreatedatetime() { + return createdatetime; + } + + public void setCreatedatetime(LocalDateTime createdatetime) { + this.createdatetime = createdatetime; + } + + public Integer getLikenum() { + return likenum; + } + + public void setLikenum(Integer likenum) { + this.likenum = likenum; + } + + public Integer getReplynum() { + return replynum; + } + + public void setReplynum(Integer replynum) { + this.replynum = replynum; + } + + public String getState() { + return state; + } + + public void setState(String state) { + this.state = state; + } + + public String getParentid() { + return parentid; + } + + public void setParentid(String parentid) { + this.parentid = parentid; + } + + public String getArticleid() { + return articleid; + } + + public void setArticleid(String articleid) { + this.articleid = articleid; + } + + @Override + public String toString() { + return "Comment{" + + "id='" + id + '\'' + + ", content='" + content + '\'' + + ", publishtime=" + publishtime + + ", userid='" + userid + '\'' + + ", nickname='" + nickname + '\'' + + ", createdatetime=" + createdatetime + + ", likenum=" + likenum + + ", replynum=" + replynum + + ", state='" + state + '\'' + + ", parentid='" + parentid + '\'' + + ", articleid='" + articleid + '\'' + + '}'; + } +} \ No newline at end of file diff --git a/orm/mongodb/src/main/java/cn/cunchang/repository/CommentRepository.java b/orm/mongodb/src/main/java/cn/cunchang/repository/CommentRepository.java new file mode 100644 index 00000000..fa39100b --- /dev/null +++ b/orm/mongodb/src/main/java/cn/cunchang/repository/CommentRepository.java @@ -0,0 +1,12 @@ +package cn.cunchang.repository; + +import cn.cunchang.domain.Comment; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.mongodb.repository.MongoRepository; + +public interface CommentRepository extends MongoRepository { + + Page findByParentid(String parentid, Pageable pageable); + +} diff --git a/orm/mongodb/src/main/java/cn/cunchang/service/CommentService.java b/orm/mongodb/src/main/java/cn/cunchang/service/CommentService.java new file mode 100644 index 00000000..ebbd3b3c --- /dev/null +++ b/orm/mongodb/src/main/java/cn/cunchang/service/CommentService.java @@ -0,0 +1,90 @@ +package cn.cunchang.service; + +import cn.cunchang.domain.Comment; +import cn.cunchang.repository.CommentRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.query.Criteria; +import org.springframework.data.mongodb.core.query.Query; +import org.springframework.data.mongodb.core.query.Update; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class CommentService { + + @Autowired + private CommentRepository commentRepository; + @Autowired + private MongoTemplate mongoTemplate; + + + + /** + * 保存一个评论 + * @param comment + */ + public void saveComment(Comment comment){ + //如果需要自定义主键,可以在这里指定主键;如果不指定主键,MongoDB会自动生成主键 + //设置一些默认初始值。。。 + //调用dao + commentRepository.save(comment); + } + + /** + * 更新评论 + * @param comment + */ + public void updateComment(Comment comment){ + //调用dao + commentRepository.save(comment); + } + + /** + * 根据id删除评论 + * @param id + */ + public void deleteCommentById(String id){ + //调用dao + commentRepository.deleteById(id); + } + + /** + * 查询所有评论 + * @return + */ + public List findCommentList(){ + //调用dao + return commentRepository.findAll(); + } + + /** + * 根据id查询评论 + * @param id + * @return + */ + public Comment findCommentById(String id){ + //调用dao + return commentRepository.findById(id).get(); + } + + + public Page findCommentListByParentid(String parentid,int page,int size) { + return commentRepository.findByParentid(parentid,PageRequest.of(page-1,size)); + } + + public void updateCommentLikenum(String id){ + + // 查询条件 + Query query = Query.query(Criteria.where("_id").is(id)); + // 更新条件 + Update update = new Update(); + update.inc("likenum"); + mongoTemplate.updateFirst(query,update,Comment.class); + } + +} \ No newline at end of file diff --git a/orm/mongodb/src/main/resources/application.yml b/orm/mongodb/src/main/resources/application.yml new file mode 100644 index 00000000..eece65c8 --- /dev/null +++ b/orm/mongodb/src/main/resources/application.yml @@ -0,0 +1,13 @@ +spring: + #数据源配置 + data: + mongodb: + # 主机地址 + host: 127.0.0.1 + # 数据库 + database: articledb + # 默认端口是27017 + port: 27017 + # 也可以使用uri连接 + # bobo:123456 账号密码 +# uri: mongodb://bobo:123456@180.76.159.126:27017,180.76.159.126:27018,180.76.159.126:27019/articledb?connect=replicaSet&slaveOk=true&replicaSet=myrs \ No newline at end of file diff --git a/orm/mongodb/src/test/java/cn/cunchang/ApplicationTests.java b/orm/mongodb/src/test/java/cn/cunchang/ApplicationTests.java new file mode 100644 index 00000000..c13144bc --- /dev/null +++ b/orm/mongodb/src/test/java/cn/cunchang/ApplicationTests.java @@ -0,0 +1,13 @@ +package cn.cunchang; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class ApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/orm/mongodb/src/test/java/cn/cunchang/service/CommentServiceTest.java b/orm/mongodb/src/test/java/cn/cunchang/service/CommentServiceTest.java new file mode 100644 index 00000000..d6af5098 --- /dev/null +++ b/orm/mongodb/src/test/java/cn/cunchang/service/CommentServiceTest.java @@ -0,0 +1,66 @@ +package cn.cunchang.service; + +import cn.cunchang.domain.Comment; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.data.domain.Page; +import org.springframework.test.context.junit4.SpringRunner; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * @author cunchang + * @date 2021/4/5 1:43 下午 + */ +@RunWith(SpringRunner.class) +@SpringBootTest +public class CommentServiceTest { + + @Autowired + private CommentService commentService; + + + @Test + public void testFindCommentList() { + List commentList = commentService.findCommentList(); + System.out.println(commentList); + } + + @Test + public void testFindCommentById() { + Comment commentById = commentService.findCommentById("606aa5b81cc0086e2eedd0d5"); + System.out.println(commentById); + } + + @Test + public void testSaveComment(){ + Comment comment=new Comment(); + // 不设置 id,MongoDB 会帮我们生成一个 ObjectId + comment.setArticleid("100000"); + comment.setContent("测试添加的数据的评论"); + comment.setCreatedatetime(LocalDateTime.now()); + comment.setUserid("1004"); + comment.setNickname("tomcat"); + comment.setState("1"); + comment.setLikenum(0); + comment.setReplynum(0); + comment.setParentid("606aa5b81cc0086e2eedd0d5"); + commentService.saveComment(comment); + } + + @Test + public void testFindCommentListByParentid() { + Page page = commentService.findCommentListByParentid("606aa5b81cc0086e2eedd0d5", 1, 2); + System.out.println(page.getTotalElements()); + System.out.println(page.getContent()); + } + + @Test + public void testUpdateCommentLikenum() { + commentService.updateCommentLikenum("606aa6ece3f00c7ab1909598"); + } + +} \ No newline at end of file diff --git a/orm/mybatis/README.MD b/orm/mybatis/README.MD new file mode 100644 index 00000000..ed323bb0 --- /dev/null +++ b/orm/mybatis/README.MD @@ -0,0 +1,15 @@ +# 一、mybatis入门与基础使用 +- mybatis-basic +- mybatis-crud +- mybatis-dynamicsql +# 二、mybatis多表 +- mybatis-datasource-tx +- mybatis-onetoone +- mybatis-onetomany +- mybatis-manytomany +# 三、mybatis缓存与注解 +- mybatis-lazy +- mybatis-cache +- mybatis-annotation-crud +- mybatis-annotation-manytable +# 四、mybatis拦截器 diff --git a/orm/mybatis/mybatis-action/dirty-read/README.md b/orm/mybatis/mybatis-action/dirty-read/README.md new file mode 100644 index 00000000..0c116c34 --- /dev/null +++ b/orm/mybatis/mybatis-action/dirty-read/README.md @@ -0,0 +1,18 @@ +# mybatis一级缓存导致的脏读 + + + +## mybatis下读已提交测试 + +| 步骤 | thread A | thread B | +| ---- | -------------------------------------------------- | ------------------------- | +| 1 | 开启事务 | | +| 2 | User user1 = userMapper.selectById(1L);user1不为空 | 开启事务 | +| 3 | Thread.sleep(10s); | userMapper.deleteById(1L) | +| 4 | | 提交事务 | +| 5 | User user2= userMapper.selectById(1L);user2不为空 | | +| 6 | 提交事务 | | + +- 按照mysql`读已提交`的规则,第5步应该返回空 +- 第2步有sql打印,第5步无sql打印,且user1==user2,说明user2是mybatis的缓存 + diff --git a/orm/mybatis/mybatis-action/dirty-read/init.sql b/orm/mybatis/mybatis-action/dirty-read/init.sql new file mode 100644 index 00000000..d6b0d180 --- /dev/null +++ b/orm/mybatis/mybatis-action/dirty-read/init.sql @@ -0,0 +1,12 @@ +CREATE TABLE `user` +( + `id` int NOT NULL AUTO_INCREMENT, + `username` varchar(32) NOT NULL COMMENT '用户名称', + `birthday` datetime DEFAULT NULL COMMENT '生日', + `sex` char(1) DEFAULT NULL COMMENT '性别', + `address` varchar(256) DEFAULT NULL COMMENT '地址', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +INSERT INTO `user` (`id`, `username`, `birthday`, `sex`, `address`) VALUES +('1', 'tomcat1', '2021-03-16 22:37:51', '男', '北京市顺义区1'); diff --git a/orm/mybatis/mybatis-action/dirty-read/pom.xml b/orm/mybatis/mybatis-action/dirty-read/pom.xml new file mode 100644 index 00000000..c30b92f6 --- /dev/null +++ b/orm/mybatis/mybatis-action/dirty-read/pom.xml @@ -0,0 +1,96 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.2.0.RELEASE + + + cn.cunchang + dirty-read + 0.0.1-SNAPSHOT + springboot-ssm + Demo project for Spring Boot mybatis-xml + + + 1.8 + + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-devtools + runtime + true + + + + org.springframework.boot + spring-boot-starter-test + test + + + + org.mybatis.spring.boot + mybatis-spring-boot-starter + 2.1.2 + + + + com.alibaba + druid-spring-boot-starter + 1.1.21 + + + + mysql + mysql-connector-java + + + + + io.springfox + springfox-swagger2 + 2.9.2 + + + io.springfox + springfox-swagger-ui + 2.9.2 + + + io.swagger + swagger-models + 1.5.22 + + + io.swagger + swagger-annotations + 1.5.22 + + + + org.projectlombok + lombok + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/orm/mybatis/mybatis-action/dirty-read/src/main/java/cn/cunchang/Application.java b/orm/mybatis/mybatis-action/dirty-read/src/main/java/cn/cunchang/Application.java new file mode 100644 index 00000000..372d4b71 --- /dev/null +++ b/orm/mybatis/mybatis-action/dirty-read/src/main/java/cn/cunchang/Application.java @@ -0,0 +1,14 @@ +package cn.cunchang; + +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + +} diff --git a/orm/mybatis/mybatis-action/dirty-read/src/main/java/cn/cunchang/config/RdsDataSourceConfiguration.java b/orm/mybatis/mybatis-action/dirty-read/src/main/java/cn/cunchang/config/RdsDataSourceConfiguration.java new file mode 100644 index 00000000..56887c7a --- /dev/null +++ b/orm/mybatis/mybatis-action/dirty-read/src/main/java/cn/cunchang/config/RdsDataSourceConfiguration.java @@ -0,0 +1,58 @@ +package cn.cunchang.config; + +import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder; +import lombok.extern.slf4j.Slf4j; +import org.apache.ibatis.session.SqlSessionFactory; +import org.mybatis.spring.SqlSessionFactoryBean; +import org.mybatis.spring.SqlSessionTemplate; +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; +import org.springframework.core.io.support.ResourcePatternResolver; +import org.springframework.jdbc.datasource.DataSourceTransactionManager; + +import javax.sql.DataSource; +import java.util.Properties; + +@Configuration +@MapperScan(basePackages = "cn.cunchang.mapper", sqlSessionFactoryRef = "sqlSessionFactory") +@Slf4j +public class RdsDataSourceConfiguration { + + @Bean(name = "dataSource") + @ConfigurationProperties(prefix = "spring.datasource.rds") + public DataSource dataSource() { + return DruidDataSourceBuilder.create().build(); + } + + @Bean(name = "sqlSessionFactory") + public SqlSessionFactory sqlSessionFactory(@Qualifier("dataSource") DataSource dataSource) { + final SqlSessionFactoryBean bean = new SqlSessionFactoryBean(); + bean.setDataSource(dataSource); + ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); + try { + bean.setConfigLocation(resolver.getResource("classpath:mybatis/mybatis-config.xml")); + bean.setMapperLocations(resolver.getResources("classpath:mybatis/mapper/*.xml")); + Properties prop = new Properties(); + bean.setConfigurationProperties(prop); + return bean.getObject(); + } catch (Exception e) { + log.error("初始化数据库异常", e); + throw new RuntimeException(e); + } + } + + @Bean(name = "transactionManager") + public DataSourceTransactionManager transactionManager(@Qualifier("dataSource") DataSource dataSource) { + return new DataSourceTransactionManager(dataSource); + } + + @Bean(name = "sqlSessionTemplate") + public SqlSessionTemplate sqlSessionTemplate(@Qualifier("sqlSessionFactory") SqlSessionFactory sqlSessionFactory) { + return new SqlSessionTemplate(sqlSessionFactory); + } + +} \ No newline at end of file diff --git a/orm/mybatis/mybatis-action/dirty-read/src/main/java/cn/cunchang/config/SwaggerConfig.java b/orm/mybatis/mybatis-action/dirty-read/src/main/java/cn/cunchang/config/SwaggerConfig.java new file mode 100644 index 00000000..062dc691 --- /dev/null +++ b/orm/mybatis/mybatis-action/dirty-read/src/main/java/cn/cunchang/config/SwaggerConfig.java @@ -0,0 +1,29 @@ +package cn.cunchang.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import springfox.documentation.builders.ApiInfoBuilder; +import springfox.documentation.builders.PathSelectors; +import springfox.documentation.builders.RequestHandlerSelectors; +import springfox.documentation.spi.DocumentationType; +import springfox.documentation.spring.web.plugins.Docket; +import springfox.documentation.swagger2.annotations.EnableSwagger2; + +/** + * @author cunchang + */ +@Configuration +@EnableSwagger2 +public class SwaggerConfig { + @Bean + public Docket createRestApi() { + return new Docket(DocumentationType.SWAGGER_2) + .pathMapping("/") + .select() + .apis(RequestHandlerSelectors.basePackage("cn.cunchang")) + .paths(PathSelectors.any()) + .build().apiInfo(new ApiInfoBuilder() + .version("1.0") + .build()); + } +} diff --git a/orm/mybatis/mybatis-action/dirty-read/src/main/java/cn/cunchang/controller/UserController.java b/orm/mybatis/mybatis-action/dirty-read/src/main/java/cn/cunchang/controller/UserController.java new file mode 100644 index 00000000..0efa2032 --- /dev/null +++ b/orm/mybatis/mybatis-action/dirty-read/src/main/java/cn/cunchang/controller/UserController.java @@ -0,0 +1,68 @@ +package cn.cunchang.controller; + +import cn.cunchang.mapper.UserMapper; +import cn.cunchang.model.User; +import io.swagger.annotations.Api; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.transaction.annotation.Isolation; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Date; +import java.util.concurrent.TimeUnit; + +/** + * @author cunchang + * @date 2020/5/31 + */ +@Api(value = "UserController", description = "") +@RestController +@RequestMapping("") +public class UserController { + + @Autowired + private UserMapper userMapper; + + @GetMapping("/init") + @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED, + rollbackFor = Exception.class) + public String init() { + User user = new User(); + user.setId(1L); + user.setUsername("tomcat1"); + user.setBirthday(new Date()); + user.setSex("男"); + user.setAddress("北京市顺义区1"); + + int row = userMapper.insert(user); + return "succes"+row; + } + + @GetMapping("/rctx1") + @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED, + rollbackFor = Exception.class) + public String rctx1() throws InterruptedException { + User user1 = userMapper.selectById(1L); + System.err.println("delete前,用户id=1的信息:"+user1); + // 睡10s,等delete执行完 + TimeUnit.SECONDS.sleep(10L); + + User user2 = userMapper.selectById(1L); + System.err.println("delete后,用户id=1的信息:"+user2); + System.err.println("user1==user2?:"+(user1==user2)); + return "succes"; + } + + @GetMapping("/rctx2") + @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED, + rollbackFor = Exception.class) + public String rctx2() { + int row = userMapper.deleteById(1L); + return "succes"; + } + + +} diff --git a/orm/mybatis/mybatis-action/dirty-read/src/main/java/cn/cunchang/mapper/UserMapper.java b/orm/mybatis/mybatis-action/dirty-read/src/main/java/cn/cunchang/mapper/UserMapper.java new file mode 100644 index 00000000..50f26cdd --- /dev/null +++ b/orm/mybatis/mybatis-action/dirty-read/src/main/java/cn/cunchang/mapper/UserMapper.java @@ -0,0 +1,48 @@ +package cn.cunchang.mapper; + +import cn.cunchang.model.User; +import org.apache.ibatis.annotations.Options; +import org.apache.ibatis.mapping.StatementType; + +/** + * 用户数据层 + * + * @author cunchang + * @date 2020/5/31 + */ +public interface UserMapper { + + /** + * 根据用户 id 查询单个用户 + * + * @param userId 用户 id + * @return 用户 + */ + @Options(flushCache= Options.FlushCachePolicy.TRUE,statementType = StatementType.PREPARED) + User selectById(Long id); + + /** + * 保存用户 + * + * @param user 用户 + * @return int 更新行数量 + */ + int insert(User user); + + /** + * 更新用户 + * + * @param user 用户 + * @return int 更新行数量 + */ + int updateById(User user); + + /** + * 根据用户 id 删除用户 + * + * @param userId 用户 id + * @return int 更新行数量 + */ + int deleteById(Long id); + +} diff --git a/orm/mybatis/mybatis-action/dirty-read/src/main/java/cn/cunchang/model/User.java b/orm/mybatis/mybatis-action/dirty-read/src/main/java/cn/cunchang/model/User.java new file mode 100644 index 00000000..10d4a644 --- /dev/null +++ b/orm/mybatis/mybatis-action/dirty-read/src/main/java/cn/cunchang/model/User.java @@ -0,0 +1,40 @@ +package cn.cunchang.model; + +import lombok.Data; +import lombok.ToString; + +import java.util.Date; + +/** + * @author cunchang + * @date 2020/5/30 + */ +@Data +@ToString +public class User { + + private Long id; + + /** + * 用户名称 + */ + private String username; + + /** + * 生日 + */ + private Date birthday; + + /** + * 性别 + */ + private String sex; + + /** + * 地址 + */ + private String address; + + + +} diff --git a/orm/mybatis/mybatis-action/dirty-read/src/main/resources/application.yml b/orm/mybatis/mybatis-action/dirty-read/src/main/resources/application.yml new file mode 100644 index 00000000..17eef61e --- /dev/null +++ b/orm/mybatis/mybatis-action/dirty-read/src/main/resources/application.yml @@ -0,0 +1,28 @@ +logging: + level: + cn: + cunchang: + mapper: debug +spring: + datasource: + rds: + url: jdbc:mysql://localhost:3306/orm?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true + driver-class-name: com.mysql.jdbc.Driver + username: root + password: 123456 + initialSize: 10 + maxActive: 30 + minIdle: 10 + #获取连接等待超时时间 + maxWait: 60000 + #间隔多久进行一次检测,检测需要关闭的空闲连接 + timeBetweenEvictionRunsMillis: 60000 + #一个连接在池中最小生存的时间 + minEvictableIdleTimeMillis: 300000 + validationQuery: SELECT 'x' + testWhileIdle: true + testOnBorrow: false + testOnReturn: false + #打开PSCache,并指定每个连接上PSCache的大小。oracle设为true,mysql设为false。分库分表较多推荐设置为false + poolPreparedStatements: false + maxPoolPreparedStatementPerConnectionSize: 20 diff --git a/orm/mybatis/mybatis-action/dirty-read/src/main/resources/mybatis/mapper/UserMapper.xml b/orm/mybatis/mybatis-action/dirty-read/src/main/resources/mybatis/mapper/UserMapper.xml new file mode 100644 index 00000000..46f275fb --- /dev/null +++ b/orm/mybatis/mybatis-action/dirty-read/src/main/resources/mybatis/mapper/UserMapper.xml @@ -0,0 +1,39 @@ + + + + + + + + id, username,birthday, sex , address + + + + + + INSERT INTO user (id,username, birthday, sex, address) + VALUES (#{id},#{username}, #{birthday}, #{sex}, #{address}) + + + + UPDATE user + + username = #{username}, + birthday = #{birthday}, + sex = #{sex}, + address = #{address}, + + WHERE + id = #{id} + + + + DELETE FROM `user` + WHERE `id` = #{id} + + + \ No newline at end of file diff --git a/orm/mybatis/mybatis-action/dirty-read/src/main/resources/mybatis/mybatis-config.xml b/orm/mybatis/mybatis-action/dirty-read/src/main/resources/mybatis/mybatis-config.xml new file mode 100644 index 00000000..1efddd51 --- /dev/null +++ b/orm/mybatis/mybatis-action/dirty-read/src/main/resources/mybatis/mybatis-config.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/orm/mybatis/mybatis-action/insert-fetch-id/pom.xml b/orm/mybatis/mybatis-action/insert-fetch-id/pom.xml new file mode 100644 index 00000000..50c2d861 --- /dev/null +++ b/orm/mybatis/mybatis-action/insert-fetch-id/pom.xml @@ -0,0 +1,43 @@ + + + + 4.0.0 + mybatis-crud + cn.lastwhisper + 1.0-SNAPSHOT + + + + org.mybatis + mybatis + 3.4.5 + + + + mysql + mysql-connector-java + 8.0.21 + + + + log4j + log4j + 1.2.12 + + + + junit + junit + 4.10 + + + + org.projectlombok + lombok + 1.18.10 + + + + \ No newline at end of file diff --git a/orm/mybatis/mybatis-action/insert-fetch-id/sql/rt.sql b/orm/mybatis/mybatis-action/insert-fetch-id/sql/rt.sql new file mode 100644 index 00000000..8c1eed69 --- /dev/null +++ b/orm/mybatis/mybatis-action/insert-fetch-id/sql/rt.sql @@ -0,0 +1,13 @@ +CREATE DATABASE orm; +USE orm; +DROP TABLE IF EXISTS `user`; + +CREATE TABLE `user` +( + `id` int(11) NOT NULL auto_increment, + `username` varchar(32) NOT NULL COMMENT '用户名称', + `birthday` datetime default NULL COMMENT '生日', + `sex` char(1) default NULL COMMENT '性别', + `address` varchar(256) default NULL COMMENT '地址', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; \ No newline at end of file diff --git a/orm/mybatis/mybatis-action/insert-fetch-id/src/main/java/cn/cunchang/dao/UserMapper.java b/orm/mybatis/mybatis-action/insert-fetch-id/src/main/java/cn/cunchang/dao/UserMapper.java new file mode 100644 index 00000000..efe6b792 --- /dev/null +++ b/orm/mybatis/mybatis-action/insert-fetch-id/src/main/java/cn/cunchang/dao/UserMapper.java @@ -0,0 +1,86 @@ +package cn.cunchang.dao; + +import cn.cunchang.domain.User; +import org.apache.ibatis.annotations.Insert; +import org.apache.ibatis.annotations.Options; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.SelectKey; + +import java.util.List; + +/** + * @author Administrator + */ +public interface UserMapper { + + /** + * 普通新增 + * @param user + * @return + */ + int insert(User user); + + /** + * xml配置标签获取id + * @param user + * @return + */ + int insert1(User user); + + /** + * xml配置useGeneratedKeys + * @param user + * @return + */ + int insert2(User user); + + /** + * 结合@Param注解 + * @param user + * @return + */ + int insert3(@Param("do") User user); + + /** + * 注解配置 + * @param user + * @return + */ + @Insert("insert into user(username,sex,birthday,address) values(#{username},#{sex},#{birthday},#{address})") + @SelectKey(keyColumn = "id", keyProperty = "id", resultType = Integer.class, before = + false, statement = {"select last_insert_id()"}) + int insert4(User user); + + /** + * 普通批量插入 + * @param list + * @return + */ + int insertBatch(@Param("list") List list); + + /** + * 批量插入xml配置 + * @param list + * @return + */ + int insertBatch1(@Param("list") List list); + + /** + * 批量插入注解配置 + * @param list + * @return + */ + @Insert("") + @Options(useGeneratedKeys = true, keyProperty = "id") + int insertBatch2(@Param("list") List list); + + + + /*************ExecutorType.BATCH模式************/ + + + +} diff --git a/orm/mybatis/mybatis-action/insert-fetch-id/src/main/java/cn/cunchang/domain/User.java b/orm/mybatis/mybatis-action/insert-fetch-id/src/main/java/cn/cunchang/domain/User.java new file mode 100644 index 00000000..aa3680d0 --- /dev/null +++ b/orm/mybatis/mybatis-action/insert-fetch-id/src/main/java/cn/cunchang/domain/User.java @@ -0,0 +1,24 @@ +package cn.cunchang.domain; + +import lombok.*; + +import java.io.Serializable; +import java.util.Date; + +/** + * @author Administrator + */ +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +@ToString +public class User implements Serializable { + + private Integer id; + private String username; + private Date birthday; + private String sex; + private String address; + +} \ No newline at end of file diff --git a/orm/mybatis/mybatis-action/insert-fetch-id/src/main/resources/SqlMapConfig.xml b/orm/mybatis/mybatis-action/insert-fetch-id/src/main/resources/SqlMapConfig.xml new file mode 100644 index 00000000..2e4b5dac --- /dev/null +++ b/orm/mybatis/mybatis-action/insert-fetch-id/src/main/resources/SqlMapConfig.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/orm/mybatis/mybatis-action/insert-fetch-id/src/main/resources/cn/cunchang/dao/UserMapper.xml b/orm/mybatis/mybatis-action/insert-fetch-id/src/main/resources/cn/cunchang/dao/UserMapper.xml new file mode 100644 index 00000000..f18232e2 --- /dev/null +++ b/orm/mybatis/mybatis-action/insert-fetch-id/src/main/resources/cn/cunchang/dao/UserMapper.xml @@ -0,0 +1,46 @@ + + + + + + insert into user(username,birthday,sex,address) + values(#{username},#{birthday},#{sex},#{address}) + + + + + select last_insert_id(); + + insert into user(username,birthday,sex,address) + values(#{username},#{birthday},#{sex},#{address}) + + + + insert into user(username,birthday,sex,address) + values(#{username},#{birthday},#{sex},#{address}) + + + + insert into user(username,birthday,sex,address) + values(#{do.username},#{do.birthday},#{do.sex},#{do.address}) + + + + insert into user(username,birthday,sex,address) + values + + (#{do.username},#{do.birthday},#{do.sex},#{do.address}) + + + + + insert into user(username,birthday,sex,address) + values + + (#{do.username},#{do.birthday},#{do.sex},#{do.address}) + + + + \ No newline at end of file diff --git a/orm/mybatis/mybatis-action/insert-fetch-id/src/main/resources/log4j.properties b/orm/mybatis/mybatis-action/insert-fetch-id/src/main/resources/log4j.properties new file mode 100644 index 00000000..ad1a14eb --- /dev/null +++ b/orm/mybatis/mybatis-action/insert-fetch-id/src/main/resources/log4j.properties @@ -0,0 +1,12 @@ +# Set root category priority to INFO and its only appender to CONSOLE. +#log4j.rootCategory=INFO, CONSOLE debug info warn error fatal +log4j.rootCategory=debug, CONSOLE, LOGFILE + +# Set the enterprise logger category to FATAL and its only appender to CONSOLE. +log4j.logger.cn.cunchang=CONSOLE + +# CONSOLE is set to be a ConsoleAppender using a PatternLayout. +log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender +log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout +log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n + diff --git a/orm/mybatis/mybatis-action/insert-fetch-id/src/test/java/cn/lastwhisper/test/ExecutorTypeBatch.java b/orm/mybatis/mybatis-action/insert-fetch-id/src/test/java/cn/lastwhisper/test/ExecutorTypeBatch.java new file mode 100644 index 00000000..28bb5ddb --- /dev/null +++ b/orm/mybatis/mybatis-action/insert-fetch-id/src/test/java/cn/lastwhisper/test/ExecutorTypeBatch.java @@ -0,0 +1,62 @@ +package cn.lastwhisper.test; + +import cn.cunchang.dao.UserMapper; +import cn.cunchang.domain.User; +import org.apache.ibatis.io.Resources; +import org.apache.ibatis.session.ExecutorType; +import org.apache.ibatis.session.SqlSession; +import org.apache.ibatis.session.SqlSessionFactory; +import org.apache.ibatis.session.SqlSessionFactoryBuilder; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.io.InputStream; +import java.sql.PreparedStatement; +import java.util.ArrayList; +import java.util.List; + +/** + * @author cunchang + * @date 2021/11/25 11:12 下午 + */ +public class ExecutorTypeBatch { + + private InputStream in; + SqlSessionFactory sqlSessionFactory; + + + @Test + public void testInsertBatch1(List userList) { + // 创建 SqlSession 对象 + SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH,false); + // 创建 Dao 的代理对象 + UserMapper userMapper = session.getMapper(UserMapper.class); + + for (User user : userList) { + userMapper.insert(user); + } + + session.commit(); + //7.释放资源 + session.close(); + } + + + @Before//在测试方法执行之前执行 + public void init() throws Exception { + //1.读取配置文件 + in = Resources.getResourceAsStream("SqlMapConfig.xml"); + //2.创建构建者对象 + SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); + //3.创建 SqlSession 工厂对象 + SqlSessionFactory factory = builder.build(in); + + } + + @After//在测试方法执行完成之后执行 + public void destroy() throws Exception { + in.close(); + } + +} diff --git a/orm/mybatis/mybatis-action/insert-fetch-id/src/test/java/cn/lastwhisper/test/InsertFetchIdTest.java b/orm/mybatis/mybatis-action/insert-fetch-id/src/test/java/cn/lastwhisper/test/InsertFetchIdTest.java new file mode 100644 index 00000000..6d49b993 --- /dev/null +++ b/orm/mybatis/mybatis-action/insert-fetch-id/src/test/java/cn/lastwhisper/test/InsertFetchIdTest.java @@ -0,0 +1,90 @@ +package cn.lastwhisper.test; + +import cn.cunchang.dao.UserMapper; +import cn.cunchang.domain.User; +import org.apache.ibatis.io.Resources; +import org.apache.ibatis.session.SqlSession; +import org.apache.ibatis.session.SqlSessionFactory; +import org.apache.ibatis.session.SqlSessionFactoryBuilder; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +/** + * 增删改查 + */ +public class InsertFetchIdTest { + private InputStream in; + private SqlSession session; + private UserMapper userMapper; + + @Test + public void testInsert1() { + User user = new User(); + user.setUsername("tomcat"); + user.setAddress("北京市顺义区"); + user.setSex("男"); + user.setBirthday(new Date()); + System.out.println("保存操作之前:" + user); + Assert.assertEquals(1, userMapper.insert(user)); +// Assert.assertEquals(1, userMapper.insert1(user)); +// Assert.assertEquals(1, userMapper.insert2(user)); +// Assert.assertEquals(1, userMapper.insert3(user)); +// Assert.assertEquals(1, userMapper.insert4(user)); + System.out.println("保存操作之后:" + user); + } + + @Test + public void testInsertBatch1() { + User user1 = new User(); + user1.setUsername("tomcat1"); + user1.setAddress("北京市顺义区1"); + user1.setSex("男"); + user1.setBirthday(new Date()); + + User user2 = new User(); + user2.setUsername("tomcat2"); + user2.setAddress("北京市顺义区2"); + user2.setSex("男"); + user2.setBirthday(new Date()); + List list = new ArrayList<>(); + list.add(user1); + list.add(user2); + + System.out.println("保存操作之前:" + list); + Assert.assertEquals(list.size(), userMapper.insertBatch(list)); +// Assert.assertEquals(list.size(), userMapper.insertBatch1(list)); +// Assert.assertEquals(list.size(), userMapper.insertBatch2(list)); + System.out.println("保存操作之后:" + list); + } + + + @Before//在测试方法执行之前执行 + public void init() throws Exception { + //1.读取配置文件 + in = Resources.getResourceAsStream("SqlMapConfig.xml"); + //2.创建构建者对象 + SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); + //3.创建 SqlSession 工厂对象 + SqlSessionFactory factory = builder.build(in); + //4.创建 SqlSession 对象 + session = factory.openSession(); + //5.创建 Dao 的代理对象 + userMapper = session.getMapper(UserMapper.class); + } + + @After//在测试方法执行完成之后执行 + public void destroy() throws Exception { + session.commit(); + //7.释放资源 + session.close(); + in.close(); + } + +} \ No newline at end of file diff --git a/orm/mybatis/mybatis-annotation-crud/pom.xml b/orm/mybatis/mybatis-annotation-crud/pom.xml index a5c0cd98..b60231fe 100644 --- a/orm/mybatis/mybatis-annotation-crud/pom.xml +++ b/orm/mybatis/mybatis-annotation-crud/pom.xml @@ -2,14 +2,11 @@ - - mybatis - cn.lastwhisper - 1.0-SNAPSHOT - - 4.0.0 + 4.0.0 mybatis-annotation-crud + cn.lastwhisper + 1.0-SNAPSHOT @@ -21,7 +18,7 @@ mysql mysql-connector-java - 5.1.6 + 8.0.21 @@ -43,4 +40,5 @@ + \ No newline at end of file diff --git a/orm/mybatis/mybatis-annotation-manytable/pom.xml b/orm/mybatis/mybatis-annotation-manytable/pom.xml index efdbb6c0..eb5825b8 100644 --- a/orm/mybatis/mybatis-annotation-manytable/pom.xml +++ b/orm/mybatis/mybatis-annotation-manytable/pom.xml @@ -11,36 +11,4 @@ mybatis-annotation-manytable - - - org.mybatis - mybatis - 3.4.5 - - - - mysql - mysql-connector-java - 5.1.6 - - - - log4j - log4j - 1.2.12 - - - - junit - junit - 4.10 - - - - org.projectlombok - lombok - 1.18.10 - - - \ No newline at end of file diff --git a/orm/mybatis/mybatis-basic/pom.xml b/orm/mybatis/mybatis-basic/pom.xml index 49fb9625..54d616f6 100644 --- a/orm/mybatis/mybatis-basic/pom.xml +++ b/orm/mybatis/mybatis-basic/pom.xml @@ -10,34 +10,4 @@ 4.0.0 mybatis-basic - - - - org.mybatis - mybatis - 3.4.5 - - - junit - junit - 4.10 - test - - - mysql - mysql-connector-java - 5.1.6 - runtime - - - log4j - log4j - 1.2.12 - - - org.projectlombok - lombok - 1.18.10 - - \ No newline at end of file diff --git a/orm/mybatis/mybatis-basic/src/main/resources/SqlMapConfig.xml b/orm/mybatis/mybatis-basic/src/main/resources/SqlMapConfig.xml index 46ab9b2e..c9595ccc 100644 --- a/orm/mybatis/mybatis-basic/src/main/resources/SqlMapConfig.xml +++ b/orm/mybatis/mybatis-basic/src/main/resources/SqlMapConfig.xml @@ -8,7 +8,7 @@ - + diff --git a/orm/mybatis/mybatis-cache/pom.xml b/orm/mybatis/mybatis-cache/pom.xml index 9cdc5200..71d12b2c 100644 --- a/orm/mybatis/mybatis-cache/pom.xml +++ b/orm/mybatis/mybatis-cache/pom.xml @@ -11,37 +11,4 @@ mybatis-cache - - - - org.mybatis - mybatis - 3.4.5 - - - - mysql - mysql-connector-java - 5.1.6 - - - - log4j - log4j - 1.2.12 - - - - junit - junit - 4.10 - - - - org.projectlombok - lombok - 1.18.10 - - - \ No newline at end of file diff --git a/orm/mybatis/mybatis-cache/readme.md b/orm/mybatis/mybatis-cache/readme.md index 8c6f1ced..6779cdda 100644 --- a/orm/mybatis/mybatis-cache/readme.md +++ b/orm/mybatis/mybatis-cache/readme.md @@ -4,3 +4,4 @@ mybatis一级缓存和二级缓存 当我们在使用二级缓存时,所缓存的类一定要实现 java.io.Serializable 接口,这种就可以使用序列化 方式来保存对象。 + diff --git a/orm/mybatis/mybatis-crud/pom.xml b/orm/mybatis/mybatis-crud/pom.xml index c8d520e0..50c2d861 100644 --- a/orm/mybatis/mybatis-crud/pom.xml +++ b/orm/mybatis/mybatis-crud/pom.xml @@ -2,14 +2,12 @@ - - mybatis - cn.lastwhisper - 1.0-SNAPSHOT - - 4.0.0 + 4.0.0 mybatis-crud + cn.lastwhisper + 1.0-SNAPSHOT + org.mybatis @@ -20,7 +18,7 @@ mysql mysql-connector-java - 5.1.6 + 8.0.21 @@ -34,6 +32,7 @@ junit 4.10 + org.projectlombok lombok @@ -41,5 +40,4 @@ - \ No newline at end of file diff --git a/orm/mybatis/mybatis-crud/sql/rt.sql b/orm/mybatis/mybatis-crud/sql/rt.sql new file mode 100644 index 00000000..8c1eed69 --- /dev/null +++ b/orm/mybatis/mybatis-crud/sql/rt.sql @@ -0,0 +1,13 @@ +CREATE DATABASE orm; +USE orm; +DROP TABLE IF EXISTS `user`; + +CREATE TABLE `user` +( + `id` int(11) NOT NULL auto_increment, + `username` varchar(32) NOT NULL COMMENT '用户名称', + `birthday` datetime default NULL COMMENT '生日', + `sex` char(1) default NULL COMMENT '性别', + `address` varchar(256) default NULL COMMENT '地址', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; \ No newline at end of file diff --git a/orm/mybatis/mybatis-crud/src/main/java/cn/lastwhisper/mybatiscrud/domain/User.java b/orm/mybatis/mybatis-crud/src/main/java/cn/lastwhisper/mybatiscrud/domain/User.java index 3706bb70..64d398d5 100644 --- a/orm/mybatis/mybatis-crud/src/main/java/cn/lastwhisper/mybatiscrud/domain/User.java +++ b/orm/mybatis/mybatis-crud/src/main/java/cn/lastwhisper/mybatiscrud/domain/User.java @@ -14,9 +14,16 @@ @Setter @ToString public class User implements Serializable { - private Integer userId; - private String userName; - private Date userBirthday; - private String userSex; - private String userAddress; + +// private Integer userId; +// private String userName; +// private Date userBirthday; +// private String userSex; +// private String userAddress; + + private Integer id; + private String username; + private Date birthday; + private String sex; + private String address; } \ No newline at end of file diff --git a/orm/mybatis/mybatis-crud/src/main/resources/SqlMapConfig.xml b/orm/mybatis/mybatis-crud/src/main/resources/SqlMapConfig.xml index 4bcf6b39..2d8a5b97 100644 --- a/orm/mybatis/mybatis-crud/src/main/resources/SqlMapConfig.xml +++ b/orm/mybatis/mybatis-crud/src/main/resources/SqlMapConfig.xml @@ -11,7 +11,7 @@ - + @@ -19,13 +19,13 @@ - + - + diff --git a/orm/mybatis/mybatis-crud/src/test/java/cn/lastwhisper/test/MybatisCRUDTest.java b/orm/mybatis/mybatis-crud/src/test/java/cn/lastwhisper/test/MybatisCRUDTest.java index 837619c8..e1a89a72 100644 --- a/orm/mybatis/mybatis-crud/src/test/java/cn/lastwhisper/test/MybatisCRUDTest.java +++ b/orm/mybatis/mybatis-crud/src/test/java/cn/lastwhisper/test/MybatisCRUDTest.java @@ -35,13 +35,14 @@ public void testFindOne() { @Test public void testSave() { User user = new User(); - user.setUserName("modify User property"); - user.setUserAddress("北京市顺义区"); - user.setUserSex("男"); - user.setUserBirthday(new Date()); + user.setUsername("modify User property"); + user.setAddress("北京市顺义区"); + user.setSex("男"); + user.setBirthday(new Date()); System.out.println("保存操作之前: " + user); //5.执行保存方法 - userMapper.saveUser(user); + int row = userMapper.saveUser(user); + System.out.println("更新行数:"+row); System.out.println("保存操作之后: " + user);//出现id值 } @@ -50,7 +51,7 @@ public void testUpdateUser()throws Exception{ // 根据 id 查询 User user = userMapper.findById(52); //6.执行操作 - user.setUserAddress("北京市顺义区"); + user.setAddress("北京市顺义区"); int res = userMapper.updateUser(user); System.out.println(res); } diff --git a/orm/mybatis/mybatis-crud/src/test/java/cn/lastwhisper/test/MybatisSelectTest.java b/orm/mybatis/mybatis-crud/src/test/java/cn/lastwhisper/test/MybatisSelectTest.java index 39b7e1a6..46666088 100644 --- a/orm/mybatis/mybatis-crud/src/test/java/cn/lastwhisper/test/MybatisSelectTest.java +++ b/orm/mybatis/mybatis-crud/src/test/java/cn/lastwhisper/test/MybatisSelectTest.java @@ -62,7 +62,7 @@ public void testFindTotal() throws Exception { public void testFindByQueryVo() { QueryVo vo = new QueryVo(); User user = new User(); - user.setUserName("%王%"); + user.setUsername("%王%"); vo.setUser(user); List users = userMapper.findUserByVo(vo); for(User u : users) { diff --git a/orm/mybatis/mybatis-datasource-tx/pom.xml b/orm/mybatis/mybatis-datasource-tx/pom.xml deleted file mode 100644 index 6d314f3a..00000000 --- a/orm/mybatis/mybatis-datasource-tx/pom.xml +++ /dev/null @@ -1,46 +0,0 @@ - - - - mybatis - cn.lastwhisper - 1.0-SNAPSHOT - - 4.0.0 - - mybatis-datasource-tx - - - - org.mybatis - mybatis - 3.4.5 - - - - mysql - mysql-connector-java - 5.1.6 - - - - log4j - log4j - 1.2.12 - - - - junit - junit - 4.10 - - - - org.projectlombok - lombok - 1.18.10 - - - - \ No newline at end of file diff --git a/orm/mybatis/mybatis-datasource-tx/src/main/java/cn/lastwhisper/mybatis/datasource/dao/UserMapper.java b/orm/mybatis/mybatis-datasource-tx/src/main/java/cn/lastwhisper/mybatis/datasource/dao/UserMapper.java deleted file mode 100644 index f5db06be..00000000 --- a/orm/mybatis/mybatis-datasource-tx/src/main/java/cn/lastwhisper/mybatis/datasource/dao/UserMapper.java +++ /dev/null @@ -1,18 +0,0 @@ -package cn.lastwhisper.mybatis.datasource.dao; - - -import cn.lastwhisper.mybatis.datasource.domain.User; - -/** - * @author Administrator - */ -public interface UserMapper { - - /** - * 根据 id 查询 - * @param userId - * @return - */ - User findUserById(Integer userId); - -} diff --git a/orm/mybatis/mybatis-datasource-tx/src/main/java/cn/lastwhisper/mybatis/datasource/domain/QueryVo.java b/orm/mybatis/mybatis-datasource-tx/src/main/java/cn/lastwhisper/mybatis/datasource/domain/QueryVo.java deleted file mode 100644 index 899bd3ba..00000000 --- a/orm/mybatis/mybatis-datasource-tx/src/main/java/cn/lastwhisper/mybatis/datasource/domain/QueryVo.java +++ /dev/null @@ -1,18 +0,0 @@ -package cn.lastwhisper.mybatis.datasource.domain; - -import java.io.Serializable; - -/** - * @author Administrator - */ -public class QueryVo implements Serializable { - private User user; - - public User getUser() { - return user; - } - - public void setUser(User user) { - this.user = user; - } -} \ No newline at end of file diff --git a/orm/mybatis/mybatis-datasource-tx/src/main/java/cn/lastwhisper/mybatis/datasource/domain/User.java b/orm/mybatis/mybatis-datasource-tx/src/main/java/cn/lastwhisper/mybatis/datasource/domain/User.java deleted file mode 100644 index 421fb839..00000000 --- a/orm/mybatis/mybatis-datasource-tx/src/main/java/cn/lastwhisper/mybatis/datasource/domain/User.java +++ /dev/null @@ -1,22 +0,0 @@ -package cn.lastwhisper.mybatis.datasource.domain; - -import lombok.*; - -import java.io.Serializable; -import java.util.Date; - -/** - * @author Administrator - */ -@AllArgsConstructor -@NoArgsConstructor -@Getter -@Setter -@ToString -public class User implements Serializable { - private Integer userid; - private String username; - private Date userbirthday; - private String usersex; - private String useraddress; -} \ No newline at end of file diff --git a/orm/mybatis/mybatis-datasource-tx/src/main/resources/SqlMapConfig.xml b/orm/mybatis/mybatis-datasource-tx/src/main/resources/SqlMapConfig.xml deleted file mode 100644 index a53a6654..00000000 --- a/orm/mybatis/mybatis-datasource-tx/src/main/resources/SqlMapConfig.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/orm/mybatis/mybatis-datasource-tx/src/main/resources/cn/lastwhisper/mybatis/datasource/dao/UserMapper.xml b/orm/mybatis/mybatis-datasource-tx/src/main/resources/cn/lastwhisper/mybatis/datasource/dao/UserMapper.xml deleted file mode 100644 index 4d0de673..00000000 --- a/orm/mybatis/mybatis-datasource-tx/src/main/resources/cn/lastwhisper/mybatis/datasource/dao/UserMapper.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/orm/mybatis/mybatis-datasource-tx/src/test/java/cn/lastwhisper/test/MybatisCRUDTest.java b/orm/mybatis/mybatis-datasource-tx/src/test/java/cn/lastwhisper/test/MybatisCRUDTest.java deleted file mode 100644 index 9f514376..00000000 --- a/orm/mybatis/mybatis-datasource-tx/src/test/java/cn/lastwhisper/test/MybatisCRUDTest.java +++ /dev/null @@ -1,41 +0,0 @@ -package cn.lastwhisper.test; - -import cn.lastwhisper.mybatis.datasource.dao.UserMapper; -import cn.lastwhisper.mybatis.datasource.domain.User; -import org.apache.ibatis.io.Resources; -import org.apache.ibatis.session.SqlSession; -import org.apache.ibatis.session.SqlSessionFactory; -import org.apache.ibatis.session.SqlSessionFactoryBuilder; -import org.junit.Test; - -import java.io.InputStream; - -/** - * 增删改查 - */ -public class MybatisCRUDTest { - private InputStream in; - private SqlSession session; - private UserMapper userMapper; - - - /** - * mybatis数据源 - * PooledDataSource中找到popConnection()方法 - */ - @Test - public void testSql() throws Exception { - InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml"); - SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in); - SqlSession sqlSession = factory.openSession(); - UserMapper userMapper = sqlSession.getMapper(UserMapper.class); - User user = userMapper.findUserById(42); - System.out.println(user); - - // 释放资源 - sqlSession.close(); - in.close(); - } - - -} \ No newline at end of file diff --git a/orm/mybatis/mybatis-design/pom.xml b/orm/mybatis/mybatis-design/pom.xml deleted file mode 100644 index d824f953..00000000 --- a/orm/mybatis/mybatis-design/pom.xml +++ /dev/null @@ -1,46 +0,0 @@ - - - - mybatis - cn.lastwhisper - 1.0-SNAPSHOT - - 4.0.0 - - mybatis-design - - - - - log4j - log4j - 1.2.12 - - - - dom4j - dom4j - 1.6.1 - - - - mysql - mysql-connector-java - 5.1.6 - - - - jaxen - jaxen - 1.1.6 - - - junit - junit - 4.10 - - - - \ No newline at end of file diff --git a/orm/mybatis/mybatis-design/readme.md b/orm/mybatis/mybatis-design/readme.md deleted file mode 100644 index 617f3b10..00000000 --- a/orm/mybatis/mybatis-design/readme.md +++ /dev/null @@ -1 +0,0 @@ -手写 Mybatis 框架 \ No newline at end of file diff --git a/orm/mybatis/mybatis-design/src/main/java/cn/lastwhisper/dao/IUserDao.java b/orm/mybatis/mybatis-design/src/main/java/cn/lastwhisper/dao/IUserDao.java deleted file mode 100644 index f17b67d0..00000000 --- a/orm/mybatis/mybatis-design/src/main/java/cn/lastwhisper/dao/IUserDao.java +++ /dev/null @@ -1,22 +0,0 @@ -package cn.lastwhisper.dao; - -import cn.lastwhisper.domain.User; -import cn.lastwhisper.mybatis.annotations.Select; - -import java.util.List; - -/** - * @author 黑马程序员 - * @Company http://www.ithiema.com - * - * 用户的持久层接口 - */ -public interface IUserDao { - - /** - * 查询所有操作 - * @return - */ - @Select("select * from user") - List findAll(); -} diff --git a/orm/mybatis/mybatis-design/src/main/java/cn/lastwhisper/domain/User.java b/orm/mybatis/mybatis-design/src/main/java/cn/lastwhisper/domain/User.java deleted file mode 100644 index 7a2feb43..00000000 --- a/orm/mybatis/mybatis-design/src/main/java/cn/lastwhisper/domain/User.java +++ /dev/null @@ -1,68 +0,0 @@ -package cn.lastwhisper.domain; - -import java.io.Serializable; -import java.util.Date; - -/** - * @author 黑马程序员 - * @Company http://www.ithiema.com - */ -public class User implements Serializable{ - - private Integer id; - private String username; - private Date birthday; - private String sex; - private String address; - - public Integer getId() { - return id; - } - - public void setId(Integer id) { - this.id = id; - } - - public String getUsername() { - return username; - } - - public void setUsername(String username) { - this.username = username; - } - - public Date getBirthday() { - return birthday; - } - - public void setBirthday(Date birthday) { - this.birthday = birthday; - } - - public String getSex() { - return sex; - } - - public void setSex(String sex) { - this.sex = sex; - } - - public String getAddress() { - return address; - } - - public void setAddress(String address) { - this.address = address; - } - - @Override - public String toString() { - return "User{" + - "id=" + id + - ", username='" + username + '\'' + - ", birthday=" + birthday + - ", sex='" + sex + '\'' + - ", address='" + address + '\'' + - '}'; - } -} diff --git a/orm/mybatis/mybatis-design/src/main/java/cn/lastwhisper/mybatis/annotations/Select.java b/orm/mybatis/mybatis-design/src/main/java/cn/lastwhisper/mybatis/annotations/Select.java deleted file mode 100644 index a1506862..00000000 --- a/orm/mybatis/mybatis-design/src/main/java/cn/lastwhisper/mybatis/annotations/Select.java +++ /dev/null @@ -1,22 +0,0 @@ -package cn.lastwhisper.mybatis.annotations; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * @author 黑马程序员 - * @Company http://www.ithiema.com - * 查询的注解 - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.METHOD) -public @interface Select { - - /** - * 配置SQL语句的 - * @return - */ - String value(); -} diff --git a/orm/mybatis/mybatis-design/src/main/java/cn/lastwhisper/mybatis/cfg/Configuration.java b/orm/mybatis/mybatis-design/src/main/java/cn/lastwhisper/mybatis/cfg/Configuration.java deleted file mode 100644 index 9c3a8e75..00000000 --- a/orm/mybatis/mybatis-design/src/main/java/cn/lastwhisper/mybatis/cfg/Configuration.java +++ /dev/null @@ -1,59 +0,0 @@ -package cn.lastwhisper.mybatis.cfg; - -import java.util.HashMap; -import java.util.Map; - -/** - * @author 黑马程序员 - * @Company http://www.ithiema.com - * 自定义mybatis的配置类 - */ -public class Configuration { - - private String driver; - private String url; - private String username; - private String password; - - private Map mappers = new HashMap(); - - public Map getMappers() { - return mappers; - } - - public void setMappers(Map mappers) { - this.mappers.putAll(mappers);//此处需要使用追加的方式 - } - - public String getDriver() { - return driver; - } - - public void setDriver(String driver) { - this.driver = driver; - } - - public String getUrl() { - return url; - } - - public void setUrl(String url) { - this.url = url; - } - - public String getUsername() { - return username; - } - - public void setUsername(String username) { - this.username = username; - } - - public String getPassword() { - return password; - } - - public void setPassword(String password) { - this.password = password; - } -} diff --git a/orm/mybatis/mybatis-design/src/main/java/cn/lastwhisper/mybatis/cfg/Mapper.java b/orm/mybatis/mybatis-design/src/main/java/cn/lastwhisper/mybatis/cfg/Mapper.java deleted file mode 100644 index b1bcd9e0..00000000 --- a/orm/mybatis/mybatis-design/src/main/java/cn/lastwhisper/mybatis/cfg/Mapper.java +++ /dev/null @@ -1,28 +0,0 @@ -package cn.lastwhisper.mybatis.cfg; - -/** - * @author 黑马程序员 - * @Company http://www.ithiema.com - * 用于封装执行的SQL语句和结果类型的全限定类名 - */ -public class Mapper { - - private String queryString;//SQL - private String resultType;//实体类的全限定类名 - - public String getQueryString() { - return queryString; - } - - public void setQueryString(String queryString) { - this.queryString = queryString; - } - - public String getResultType() { - return resultType; - } - - public void setResultType(String resultType) { - this.resultType = resultType; - } -} diff --git a/orm/mybatis/mybatis-design/src/main/java/cn/lastwhisper/mybatis/io/Resources.java b/orm/mybatis/mybatis-design/src/main/java/cn/lastwhisper/mybatis/io/Resources.java deleted file mode 100644 index 541331b7..00000000 --- a/orm/mybatis/mybatis-design/src/main/java/cn/lastwhisper/mybatis/io/Resources.java +++ /dev/null @@ -1,20 +0,0 @@ -package cn.lastwhisper.mybatis.io; - -import java.io.InputStream; - -/** - * @author 黑马程序员 - * @Company http://www.ithiema.com - * 使用类加载器读取配置文件的类 - */ -public class Resources { - - /** - * 根据传入的参数,获取一个字节输入流 - * @param filePath - * @return - */ - public static InputStream getResourceAsStream(String filePath){ - return Resources.class.getClassLoader().getResourceAsStream(filePath); - } -} diff --git a/orm/mybatis/mybatis-design/src/main/java/cn/lastwhisper/mybatis/sqlsession/SqlSession.java b/orm/mybatis/mybatis-design/src/main/java/cn/lastwhisper/mybatis/sqlsession/SqlSession.java deleted file mode 100644 index 1e9754a6..00000000 --- a/orm/mybatis/mybatis-design/src/main/java/cn/lastwhisper/mybatis/sqlsession/SqlSession.java +++ /dev/null @@ -1,23 +0,0 @@ -package cn.lastwhisper.mybatis.sqlsession; - -/** - * @author 黑马程序员 - * @Company http://www.ithiema.com - * 自定义Mybatis中和数据库交互的核心类 - * 它里面可以创建dao接口的代理对象 - */ -public interface SqlSession { - - /** - * 根据参数创建一个代理对象 - * @param daoInterfaceClass dao的接口字节码 - * @param - * @return - */ - T getMapper(Class daoInterfaceClass); - - /** - * 释放资源 - */ - void close(); -} diff --git a/orm/mybatis/mybatis-design/src/main/java/cn/lastwhisper/mybatis/sqlsession/SqlSessionFactory.java b/orm/mybatis/mybatis-design/src/main/java/cn/lastwhisper/mybatis/sqlsession/SqlSessionFactory.java deleted file mode 100644 index d3c20e75..00000000 --- a/orm/mybatis/mybatis-design/src/main/java/cn/lastwhisper/mybatis/sqlsession/SqlSessionFactory.java +++ /dev/null @@ -1,14 +0,0 @@ -package cn.lastwhisper.mybatis.sqlsession; - -/** - * @author 黑马程序员 - * @Company http://www.ithiema.com - */ -public interface SqlSessionFactory { - - /** - * 用于打开一个新的SqlSession对象 - * @return - */ - SqlSession openSession(); -} diff --git a/orm/mybatis/mybatis-design/src/main/java/cn/lastwhisper/mybatis/sqlsession/SqlSessionFactoryBuilder.java b/orm/mybatis/mybatis-design/src/main/java/cn/lastwhisper/mybatis/sqlsession/SqlSessionFactoryBuilder.java deleted file mode 100644 index 23ec39ed..00000000 --- a/orm/mybatis/mybatis-design/src/main/java/cn/lastwhisper/mybatis/sqlsession/SqlSessionFactoryBuilder.java +++ /dev/null @@ -1,25 +0,0 @@ -package cn.lastwhisper.mybatis.sqlsession; - -import cn.lastwhisper.mybatis.cfg.Configuration; -import cn.lastwhisper.mybatis.sqlsession.defaults.DefaultSqlSessionFactory; -import cn.lastwhisper.mybatis.utils.XMLConfigBuilder; - -import java.io.InputStream; - -/** - * @author 黑马程序员 - * @Company http://www.ithiema.com - * 用于创建一个SqlSessionFactory对象 - */ -public class SqlSessionFactoryBuilder { - - /** - * 根据参数的字节输入流来构建一个SqlSessionFactory工厂 - * @param config - * @return - */ - public SqlSessionFactory build(InputStream config) { - Configuration cfg = XMLConfigBuilder.loadConfiguration(config); - return new DefaultSqlSessionFactory(cfg); - } -} diff --git a/orm/mybatis/mybatis-design/src/main/java/cn/lastwhisper/mybatis/sqlsession/defaults/DefaultSqlSession.java b/orm/mybatis/mybatis-design/src/main/java/cn/lastwhisper/mybatis/sqlsession/defaults/DefaultSqlSession.java deleted file mode 100644 index 16fe42e8..00000000 --- a/orm/mybatis/mybatis-design/src/main/java/cn/lastwhisper/mybatis/sqlsession/defaults/DefaultSqlSession.java +++ /dev/null @@ -1,52 +0,0 @@ -package cn.lastwhisper.mybatis.sqlsession.defaults; - - -import cn.lastwhisper.mybatis.cfg.Configuration; -import cn.lastwhisper.mybatis.sqlsession.SqlSession; -import cn.lastwhisper.mybatis.sqlsession.proxy.MapperProxy; -import cn.lastwhisper.mybatis.utils.DataSourceUtil; - -import java.lang.reflect.Proxy; -import java.sql.Connection; - -/** - * @author 黑马程序员 - * @Company http://www.ithiema.com - * SqlSession接口的实现类 - */ -public class DefaultSqlSession implements SqlSession { - - private Configuration cfg; - private Connection connection; - - public DefaultSqlSession(Configuration cfg){ - this.cfg = cfg; - connection = DataSourceUtil.getConnection(cfg); - } - - /** - * 用于创建代理对象 - * @param daoInterfaceClass dao的接口字节码 - * @param - * @return - */ - @Override - public T getMapper(Class daoInterfaceClass) { - return (T) Proxy.newProxyInstance(daoInterfaceClass.getClassLoader(), - new Class[]{daoInterfaceClass},new MapperProxy(cfg.getMappers(),connection)); - } - - /** - * 用于释放资源 - */ - @Override - public void close() { - if(connection != null) { - try { - connection.close(); - } catch (Exception e) { - e.printStackTrace(); - } - } - } -} diff --git a/orm/mybatis/mybatis-design/src/main/java/cn/lastwhisper/mybatis/sqlsession/defaults/DefaultSqlSessionFactory.java b/orm/mybatis/mybatis-design/src/main/java/cn/lastwhisper/mybatis/sqlsession/defaults/DefaultSqlSessionFactory.java deleted file mode 100644 index 3c8cb400..00000000 --- a/orm/mybatis/mybatis-design/src/main/java/cn/lastwhisper/mybatis/sqlsession/defaults/DefaultSqlSessionFactory.java +++ /dev/null @@ -1,29 +0,0 @@ -package cn.lastwhisper.mybatis.sqlsession.defaults; - - -import cn.lastwhisper.mybatis.cfg.Configuration; -import cn.lastwhisper.mybatis.sqlsession.SqlSession; -import cn.lastwhisper.mybatis.sqlsession.SqlSessionFactory; - -/** - * @author 黑马程序员 - * @Company http://www.ithiema.com - * SqlSessionFactory接口的实现类 - */ -public class DefaultSqlSessionFactory implements SqlSessionFactory { - - private Configuration cfg; - - public DefaultSqlSessionFactory(Configuration cfg) { - this.cfg = cfg; - } - - /** - * 用于创建一个新的操作数据库对象 - * @return - */ - @Override - public SqlSession openSession() { - return new DefaultSqlSession(cfg); - } -} diff --git a/orm/mybatis/mybatis-design/src/main/java/cn/lastwhisper/mybatis/sqlsession/proxy/MapperProxy.java b/orm/mybatis/mybatis-design/src/main/java/cn/lastwhisper/mybatis/sqlsession/proxy/MapperProxy.java deleted file mode 100644 index b0754fee..00000000 --- a/orm/mybatis/mybatis-design/src/main/java/cn/lastwhisper/mybatis/sqlsession/proxy/MapperProxy.java +++ /dev/null @@ -1,52 +0,0 @@ -package cn.lastwhisper.mybatis.sqlsession.proxy; - - -import cn.lastwhisper.mybatis.cfg.Mapper; -import cn.lastwhisper.mybatis.utils.Executor; - -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Method; -import java.sql.Connection; -import java.util.Map; - -/** - * @author 黑马程序员 - * @Company http://www.ithiema.com - */ -public class MapperProxy implements InvocationHandler { - - //map的key是全限定类名+方法名 - private Map mappers; - private Connection conn; - - public MapperProxy(Map mappers,Connection conn){ - this.mappers = mappers; - this.conn = conn; - } - - /** - * 用于对方法进行增强的,我们的增强其实就是调用selectList方法 - * @param proxy - * @param method - * @param args - * @return - * @throws Throwable - */ - @Override - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - //1.获取方法名 - String methodName = method.getName(); - //2.获取方法所在类的名称 - String className = method.getDeclaringClass().getName(); - //3.组合key - String key = className+"."+methodName; - //4.获取mappers中的Mapper对象 - Mapper mapper = mappers.get(key); - //5.判断是否有mapper - if(mapper == null){ - throw new IllegalArgumentException("传入的参数有误"); - } - //6.调用工具类执行查询所有 - return new Executor().selectList(mapper,conn); - } -} diff --git a/orm/mybatis/mybatis-design/src/main/java/cn/lastwhisper/mybatis/utils/DataSourceUtil.java b/orm/mybatis/mybatis-design/src/main/java/cn/lastwhisper/mybatis/utils/DataSourceUtil.java deleted file mode 100644 index bf62c05f..00000000 --- a/orm/mybatis/mybatis-design/src/main/java/cn/lastwhisper/mybatis/utils/DataSourceUtil.java +++ /dev/null @@ -1,28 +0,0 @@ -package cn.lastwhisper.mybatis.utils; - -import cn.lastwhisper.mybatis.cfg.Configuration; - -import java.sql.Connection; -import java.sql.DriverManager; - -/** - * @author 黑马程序员 - * @Company http://www.ithiema.com - * 用于创建数据源的工具类 - */ -public class DataSourceUtil { - - /** - * 用于获取一个连接 - * @param cfg - * @return - */ - public static Connection getConnection(Configuration cfg){ - try { - Class.forName(cfg.getDriver()); - return DriverManager.getConnection(cfg.getUrl(), cfg.getUsername(), cfg.getPassword()); - }catch(Exception e){ - throw new RuntimeException(e); - } - } -} diff --git a/orm/mybatis/mybatis-design/src/main/java/cn/lastwhisper/mybatis/utils/Executor.java b/orm/mybatis/mybatis-design/src/main/java/cn/lastwhisper/mybatis/utils/Executor.java deleted file mode 100644 index 359014e8..00000000 --- a/orm/mybatis/mybatis-design/src/main/java/cn/lastwhisper/mybatis/utils/Executor.java +++ /dev/null @@ -1,86 +0,0 @@ -package cn.lastwhisper.mybatis.utils; - - -import cn.lastwhisper.mybatis.cfg.Mapper; - -import java.beans.PropertyDescriptor; -import java.lang.reflect.Method; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.ResultSetMetaData; -import java.util.ArrayList; -import java.util.List; - -/** - * @author 黑马程序员 - * @Company http://www.ithiema.com - * 负责执行SQL语句,并且封装结果集 - */ -public class Executor { - - public List selectList(Mapper mapper, Connection conn) { - PreparedStatement pstm = null; - ResultSet rs = null; - try { - //1.取出mapper中的数据 - String queryString = mapper.getQueryString();//select * from user - String resultType = mapper.getResultType();//com.itheima.domain.User - Class domainClass = Class.forName(resultType); - //2.获取PreparedStatement对象 - pstm = conn.prepareStatement(queryString); - //3.执行SQL语句,获取结果集 - rs = pstm.executeQuery(); - //4.封装结果集 - List list = new ArrayList();//定义返回值 - while (rs.next()) { - //实例化要封装的实体类对象 - E obj = (E) domainClass.newInstance(); - - //取出结果集的元信息:ResultSetMetaData - ResultSetMetaData rsmd = rs.getMetaData(); - //取出总列数 - int columnCount = rsmd.getColumnCount(); - //遍历总列数 - for (int i = 1; i <= columnCount; i++) { - //获取每列的名称,列名的序号是从1开始的 - String columnName = rsmd.getColumnName(i); - //根据得到列名,获取每列的值 - Object columnValue = rs.getObject(columnName); - //给obj赋值:使用Java内省机制(借助PropertyDescriptor实现属性的封装) - PropertyDescriptor pd = new PropertyDescriptor(columnName, domainClass);//要求:实体类的属性和数据库表的列名保持一种 - //获取它的写入方法 - Method writeMethod = pd.getWriteMethod(); - //把获取的列的值,给对象赋值 - writeMethod.invoke(obj, columnValue); - } - //把赋好值的对象加入到集合中 - list.add(obj); - } - return list; - } catch (Exception e) { - throw new RuntimeException(e); - } finally { - release(pstm, rs); - } - } - - - private void release(PreparedStatement pstm, ResultSet rs) { - if (rs != null) { - try { - rs.close(); - } catch (Exception e) { - e.printStackTrace(); - } - } - - if (pstm != null) { - try { - pstm.close(); - } catch (Exception e) { - e.printStackTrace(); - } - } - } -} diff --git a/orm/mybatis/mybatis-design/src/main/java/cn/lastwhisper/mybatis/utils/XMLConfigBuilder.java b/orm/mybatis/mybatis-design/src/main/java/cn/lastwhisper/mybatis/utils/XMLConfigBuilder.java deleted file mode 100644 index 87b60ce6..00000000 --- a/orm/mybatis/mybatis-design/src/main/java/cn/lastwhisper/mybatis/utils/XMLConfigBuilder.java +++ /dev/null @@ -1,219 +0,0 @@ -package cn.lastwhisper.mybatis.utils; - -//import com.itheima.mybatis.annotations.Select; - -import cn.lastwhisper.mybatis.annotations.Select; -import cn.lastwhisper.mybatis.cfg.Configuration; -import cn.lastwhisper.mybatis.cfg.Mapper; -import cn.lastwhisper.mybatis.io.Resources; -import org.dom4j.Attribute; -import org.dom4j.Document; -import org.dom4j.Element; -import org.dom4j.io.SAXReader; - -import java.io.IOException; -import java.io.InputStream; -import java.lang.reflect.Method; -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * @author 黑马程序员 - * @Company http://www.ithiema.com - * 用于解析配置文件 - */ -public class XMLConfigBuilder { - - - /** - * 解析主配置文件,把里面的内容填充到DefaultSqlSession所需要的地方 - * 使用的技术: - * dom4j+xpath - */ - public static Configuration loadConfiguration(InputStream config) { - try { - //定义封装连接信息的配置对象(mybatis的配置对象) - Configuration cfg = new Configuration(); - - //1.获取SAXReader对象 - SAXReader reader = new SAXReader(); - //2.根据字节输入流获取Document对象 - Document document = reader.read(config); - //3.获取根节点 - Element root = document.getRootElement(); - //4.使用xpath中选择指定节点的方式,获取所有property节点 - List propertyElements = root.selectNodes("//property"); - //5.遍历节点 - for (Element propertyElement : propertyElements) { - //判断节点是连接数据库的哪部分信息 - //取出name属性的值 - String name = propertyElement.attributeValue("name"); - if ("driver".equals(name)) { - //表示驱动 - //获取property标签value属性的值 - String driver = propertyElement.attributeValue("value"); - cfg.setDriver(driver); - } - if ("url".equals(name)) { - //表示连接字符串 - //获取property标签value属性的值 - String url = propertyElement.attributeValue("value"); - cfg.setUrl(url); - } - if ("username".equals(name)) { - //表示用户名 - //获取property标签value属性的值 - String username = propertyElement.attributeValue("value"); - cfg.setUsername(username); - } - if ("password".equals(name)) { - //表示密码 - //获取property标签value属性的值 - String password = propertyElement.attributeValue("value"); - cfg.setPassword(password); - } - } - //取出mappers中的所有mapper标签,判断他们使用了resource还是class属性 - List mapperElements = root.selectNodes("//mappers/mapper"); - //遍历集合 - for (Element mapperElement : mapperElements) { - //判断mapperElement使用的是哪个属性 - Attribute attribute = mapperElement.attribute("resource"); - if (attribute != null) { - System.out.println("使用的是XML"); - //表示有resource属性,用的是XML - //取出属性的值 - String mapperPath = attribute.getValue();//获取属性的值"com/itheima/dao/IUserDao.xml" - //把映射配置文件的内容获取出来,封装成一个map - Map mappers = loadMapperConfiguration(mapperPath); - //给configuration中的mappers赋值 - cfg.setMappers(mappers); - } else { - System.out.println("使用的是注解"); - //表示没有resource属性,用的是注解 - //获取class属性的值 - String daoClassPath = mapperElement.attributeValue("class"); - //根据daoClassPath获取封装的必要信息 - Map mappers = loadMapperAnnotation(daoClassPath); - //给configuration中的mappers赋值 - cfg.setMappers(mappers); - } - } - //返回Configuration - return cfg; - } catch (Exception e) { - throw new RuntimeException(e); - } finally { - try { - config.close(); - } catch (Exception e) { - e.printStackTrace(); - } - } - - } - - /** - * 根据传入的参数,解析XML,并且封装到Map中 - * @param mapperPath 映射配置文件的位置 - * @return map中包含了获取的唯一标识(key是由dao的全限定类名和方法名组成) - * 以及执行所需的必要信息(value是一个Mapper对象,里面存放的是执行的SQL语句和要封装的实体类全限定类名) - */ - private static Map loadMapperConfiguration(String mapperPath) throws IOException { - InputStream in = null; - try { - //定义返回值对象 - Map mappers = new HashMap(); - //1.根据路径获取字节输入流 - in = Resources.getResourceAsStream(mapperPath); - //2.根据字节输入流获取Document对象 - SAXReader reader = new SAXReader(); - Document document = reader.read(in); - //3.获取根节点 - Element root = document.getRootElement(); - //4.获取根节点的namespace属性取值 - String namespace = root.attributeValue("namespace");//是组成map中key的部分 - //5.获取所有的select节点 - List selectElements = root.selectNodes("//select"); - //6.遍历select节点集合 - for (Element selectElement : selectElements) { - //取出id属性的值 组成map中key的部分 - String id = selectElement.attributeValue("id"); - //取出resultType属性的值 组成map中value的部分 - String resultType = selectElement.attributeValue("resultType"); - //取出文本内容 组成map中value的部分 - String queryString = selectElement.getText(); - //创建Key - String key = namespace + "." + id; - //创建Value - Mapper mapper = new Mapper(); - mapper.setQueryString(queryString); - mapper.setResultType(resultType); - //把key和value存入mappers中 - mappers.put(key, mapper); - } - return mappers; - } catch (Exception e) { - throw new RuntimeException(e); - } finally { - in.close(); - } - } - - /** - * 根据传入的参数,得到dao中所有被select注解标注的方法。 - * 根据方法名称和类名,以及方法上注解value属性的值,组成Mapper的必要信息 - * @param daoClassPath - * @return - */ - private static Map loadMapperAnnotation(String daoClassPath) throws Exception { - //定义返回值对象 - Map mappers = new HashMap(); - - //1.得到dao接口的字节码对象 - Class daoClass = Class.forName(daoClassPath); - //2.得到dao接口中的方法数组 - Method[] methods = daoClass.getMethods(); - //3.遍历Method数组 - for (Method method : methods) { - //取出每一个方法,判断是否有select注解 - boolean isAnnotated = method.isAnnotationPresent(Select.class); - if (isAnnotated) { - //创建Mapper对象 - Mapper mapper = new Mapper(); - //取出注解的value属性值 - Select selectAnno = method.getAnnotation(Select.class); - String queryString = selectAnno.value(); - mapper.setQueryString(queryString); - //获取当前方法的返回值,还要求必须带有泛型信息 - Type type = method.getGenericReturnType();//List - //判断type是不是参数化的类型 - if (type instanceof ParameterizedType) { - //强转 - ParameterizedType ptype = (ParameterizedType) type; - //得到参数化类型中的实际类型参数 - Type[] types = ptype.getActualTypeArguments(); - //取出第一个 - Class domainClass = (Class) types[0]; - //获取domainClass的类名 - String resultType = domainClass.getName(); - //给Mapper赋值 - mapper.setResultType(resultType); - } - //组装key的信息 - //获取方法的名称 - String methodName = method.getName(); - String className = method.getDeclaringClass().getName(); - String key = className + "." + methodName; - //给map赋值 - mappers.put(key, mapper); - } - } - return mappers; - } - - -} diff --git a/orm/mybatis/mybatis-design/src/main/resources/SqlMapConfig.xml b/orm/mybatis/mybatis-design/src/main/resources/SqlMapConfig.xml deleted file mode 100644 index 088013e6..00000000 --- a/orm/mybatis/mybatis-design/src/main/resources/SqlMapConfig.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/orm/mybatis/mybatis-design/src/main/resources/com/itheima/dao/IUserDao.xml b/orm/mybatis/mybatis-design/src/main/resources/com/itheima/dao/IUserDao.xml deleted file mode 100644 index 6905b083..00000000 --- a/orm/mybatis/mybatis-design/src/main/resources/com/itheima/dao/IUserDao.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - \ No newline at end of file diff --git a/orm/mybatis/mybatis-design/src/test/java/cn/lastwhisper/test/MybatisTest.java b/orm/mybatis/mybatis-design/src/test/java/cn/lastwhisper/test/MybatisTest.java deleted file mode 100644 index e81d322e..00000000 --- a/orm/mybatis/mybatis-design/src/test/java/cn/lastwhisper/test/MybatisTest.java +++ /dev/null @@ -1,43 +0,0 @@ -package cn.lastwhisper.test; - -import cn.lastwhisper.dao.IUserDao; -import cn.lastwhisper.domain.User; -import cn.lastwhisper.mybatis.io.Resources; -import cn.lastwhisper.mybatis.sqlsession.SqlSession; -import cn.lastwhisper.mybatis.sqlsession.SqlSessionFactory; -import cn.lastwhisper.mybatis.sqlsession.SqlSessionFactoryBuilder; - -import java.io.InputStream; -import java.util.List; - -/** - * @author 黑马程序员 - * @Company http://www.ithiema.com - * mybatis的入门案例 - */ -public class MybatisTest { - - /** - * 入门案例 - * @param args - */ - public static void main(String[] args) throws Exception { - //1.读取配置文件 - InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml"); - //2.创建SqlSessionFactory工厂 - SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); - SqlSessionFactory factory = builder.build(in); - //3.使用工厂生产SqlSession对象 - SqlSession session = factory.openSession(); - //4.使用SqlSession创建Dao接口的代理对象 - IUserDao userDao = session.getMapper(IUserDao.class); - //5.使用代理对象执行方法 - List users = userDao.findAll(); - for (User user : users) { - System.out.println(user); - } - //6.释放资源 - session.close(); - in.close(); - } -} diff --git a/orm/mybatis/mybatis-dynamicsql/pom.xml b/orm/mybatis/mybatis-dynamicsql/pom.xml index c8b52e51..33c67ef1 100644 --- a/orm/mybatis/mybatis-dynamicsql/pom.xml +++ b/orm/mybatis/mybatis-dynamicsql/pom.xml @@ -11,36 +11,4 @@ mybatis-dynamicsql - - - org.mybatis - mybatis - 3.4.5 - - - - mysql - mysql-connector-java - 5.1.6 - - - - log4j - log4j - 1.2.12 - - - - junit - junit - 4.10 - - - - org.projectlombok - lombok - 1.18.10 - - - \ No newline at end of file diff --git a/orm/mybatis/mybatis-dynamicsql/src/main/resources/cn/lastwhisper/mybatis/dynamicsql/dao/UserMapper.xml b/orm/mybatis/mybatis-dynamicsql/src/main/resources/cn/lastwhisper/mybatis/dynamicsql/dao/UserMapper.xml index bd58eacf..e0ba2683 100644 --- a/orm/mybatis/mybatis-dynamicsql/src/main/resources/cn/lastwhisper/mybatis/dynamicsql/dao/UserMapper.xml +++ b/orm/mybatis/mybatis-dynamicsql/src/main/resources/cn/lastwhisper/mybatis/dynamicsql/dao/UserMapper.xml @@ -23,9 +23,9 @@ select 字段 from user where id in (?) 标签用于遍历集合,它的属性: collection:代表要遍历的集合元素,注意编写时不要写#{} + item:代表遍历集合的每个元素,生成的变量名 open:代表语句的开始部分 close:代表结束部分 - item:代表遍历集合的每个元素,生成的变量名 separator:代表分隔符 --> diff --git a/orm/mybatis/mybatis-interceptor/pom.xml b/orm/mybatis/mybatis-interceptor/pom.xml new file mode 100644 index 00000000..a7ec3788 --- /dev/null +++ b/orm/mybatis/mybatis-interceptor/pom.xml @@ -0,0 +1,14 @@ + + + + mybatis + cn.lastwhisper + 1.0-SNAPSHOT + + 4.0.0 + + mybatis-interceptor-datascope + + \ No newline at end of file diff --git a/orm/mybatis/mybatis-interceptor/src/main/java/cn/lastwhisper/mybatis/interceptor/CameHumpInterceptor.java b/orm/mybatis/mybatis-interceptor/src/main/java/cn/lastwhisper/mybatis/interceptor/CameHumpInterceptor.java new file mode 100644 index 00000000..8bb30fb7 --- /dev/null +++ b/orm/mybatis/mybatis-interceptor/src/main/java/cn/lastwhisper/mybatis/interceptor/CameHumpInterceptor.java @@ -0,0 +1,90 @@ +package cn.lastwhisper.mybatis.interceptor; + +import org.apache.ibatis.executor.resultset.ResultSetHandler; +import org.apache.ibatis.plugin.*; + +import java.sql.Statement; +import java.util.*; + +/** + * MyBatis Map 类型下划线 Key 转小写驼峰形式 + * + * @author liuzenghui + */ +@Intercepts( + @Signature(type = ResultSetHandler.class,//定位一个方法 + method = "handleResultSets", + args = {Statement.class}) +)//配置拦截器要拦截的接口方法 +@SuppressWarnings({"unchecked", "rawtypes"}) +public class CameHumpInterceptor implements Interceptor { + + @Override + public Object intercept(Invocation invocation) throws Throwable { + //先执行得到结果,再对结果进行处理 + List list = (List) invocation.proceed(); + for (Object object : list) { + //如果结果是 Map 类型,就对 Map 的 Key 进行转换 + if (object instanceof Map) { + processMap((Map) object); + } else { + break; + } + } + return list; + } + + /** + * 处理 Map 类型 + * + * @param map + */ + private void processMap(Map map) { + Set keySet = new HashSet(map.keySet()); + for (String key : keySet) { + //大写开头的会将整个字符串转换为小写,如果包含下划线也会处理为驼峰 + if ((key.charAt(0) >= 'A' && key.charAt(0) <= 'Z') || key.contains("_")) {// key.indexOf("_") >= 0 + Object value = map.get(key); + map.remove(key); + map.put(underlineToCamelhump(key), value); + } + } + } + + /** + * 将下划线风格替换为驼峰风格 + * + * @param inputString + * @return + */ + public static String underlineToCamelhump(String inputString) { + StringBuilder sb = new StringBuilder(); + + boolean nextUpperCase = false; + for (int i = 0; i < inputString.length(); i++) { + char c = inputString.charAt(i); + if (c == '_') { + if (sb.length() > 0) { + nextUpperCase = true; + } + } else { + if (nextUpperCase) { + sb.append(Character.toUpperCase(c)); + nextUpperCase = false; + } else { + sb.append(Character.toLowerCase(c)); + } + } + } + return sb.toString(); + } + + @Override + public Object plugin(Object target) { + return Plugin.wrap(target, this); + } + + @Override + public void setProperties(Properties properties) { + } +} \ No newline at end of file diff --git a/orm/mybatis/mybatis-interceptor/src/main/java/cn/lastwhisper/mybatis/interceptor/dao/UserMapper.java b/orm/mybatis/mybatis-interceptor/src/main/java/cn/lastwhisper/mybatis/interceptor/dao/UserMapper.java new file mode 100644 index 00000000..7844158a --- /dev/null +++ b/orm/mybatis/mybatis-interceptor/src/main/java/cn/lastwhisper/mybatis/interceptor/dao/UserMapper.java @@ -0,0 +1,20 @@ +package cn.lastwhisper.mybatis.interceptor.dao; + +import cn.lastwhisper.mybatis.interceptor.datascope.DataScope; +import cn.lastwhisper.mybatis.interceptor.domain.User; +import org.apache.ibatis.annotations.Param; + +import java.util.List; +import java.util.Map; + +/** + * @author Administrator + */ +public interface UserMapper { + + List> selectUsers(@Param("dataScope") DataScope dataScope); + + + List findUser(); + +} diff --git a/orm/mybatis/mybatis-interceptor/src/main/java/cn/lastwhisper/mybatis/interceptor/datascope/DataScope.java b/orm/mybatis/mybatis-interceptor/src/main/java/cn/lastwhisper/mybatis/interceptor/datascope/DataScope.java new file mode 100644 index 00000000..e9a9692a --- /dev/null +++ b/orm/mybatis/mybatis-interceptor/src/main/java/cn/lastwhisper/mybatis/interceptor/datascope/DataScope.java @@ -0,0 +1,50 @@ +package cn.lastwhisper.mybatis.interceptor.datascope; + +import java.util.List; + +/** + * 数据范围 + * + * @author fengshuonan + * @date 2017-07-23 22:19 + */ +public class DataScope { + + /** + * 限制范围的字段名称 + */ + private String scopeName = "deptid"; + + /** + * 限制范围的 + */ + private List deptIds; + + public DataScope() { + } + + public DataScope(List deptIds) { + this.deptIds = deptIds; + } + + public DataScope(String scopeName, List deptIds) { + this.scopeName = scopeName; + this.deptIds = deptIds; + } + + public List getDeptIds() { + return deptIds; + } + + public void setDeptIds(List deptIds) { + this.deptIds = deptIds; + } + + public String getScopeName() { + return scopeName; + } + + public void setScopeName(String scopeName) { + this.scopeName = scopeName; + } +} diff --git a/orm/mybatis/mybatis-interceptor/src/main/java/cn/lastwhisper/mybatis/interceptor/datascope/DataScopeInterceptor.java b/orm/mybatis/mybatis-interceptor/src/main/java/cn/lastwhisper/mybatis/interceptor/datascope/DataScopeInterceptor.java new file mode 100644 index 00000000..e2eee9b3 --- /dev/null +++ b/orm/mybatis/mybatis-interceptor/src/main/java/cn/lastwhisper/mybatis/interceptor/datascope/DataScopeInterceptor.java @@ -0,0 +1,114 @@ +package cn.lastwhisper.mybatis.interceptor.datascope; + + +import org.apache.ibatis.executor.statement.StatementHandler; +import org.apache.ibatis.mapping.BoundSql; +import org.apache.ibatis.mapping.MappedStatement; +import org.apache.ibatis.mapping.SqlCommandType; +import org.apache.ibatis.plugin.*; +import org.apache.ibatis.reflection.MetaObject; +import org.apache.ibatis.reflection.SystemMetaObject; + +import java.lang.reflect.Proxy; +import java.sql.Connection; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +/** + * 数据范围的拦截器 + * + * @author fengshuonan + * @date 2017-07-23 21:26 + */ +@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})}) +public class DataScopeInterceptor implements Interceptor { + + @Override + public Object intercept(Invocation invocation) throws Throwable { + StatementHandler statementHandler = (StatementHandler) realTarget(invocation.getTarget()); + MetaObject metaStatementHandler = SystemMetaObject.forObject(statementHandler); + MappedStatement mappedStatement = (MappedStatement) metaStatementHandler.getValue("delegate.mappedStatement"); + + if (!SqlCommandType.SELECT.equals(mappedStatement.getSqlCommandType())) { + return invocation.proceed(); + } + + BoundSql boundSql = (BoundSql) metaStatementHandler.getValue("delegate.boundSql"); + String originalSql = boundSql.getSql(); + Object parameterObject = boundSql.getParameterObject(); + + //查找参数中包含DataScope类型的参数 + DataScope dataScope = findDataScopeObject(parameterObject); + + if (dataScope == null) { + return invocation.proceed(); + } else { + String scopeName = dataScope.getScopeName(); + List deptIds = dataScope.getDeptIds(); + String join = join(deptIds, ","); + originalSql = "select * from (" + originalSql + ") temp_data_scope where temp_data_scope." + scopeName + " in (" + join + ")"; + + metaStatementHandler.setValue("delegate.boundSql.sql", originalSql); + return invocation.proceed(); + } + } + + /** + * 查找对象是否包括DataScope类 + */ + public DataScope findDataScopeObject(Object parameterObj) { + if (parameterObj instanceof DataScope) { + return (DataScope) parameterObj; + } else if (parameterObj instanceof Map) { + for (Object val : ((Map) parameterObj).values()) { + if (val instanceof DataScope) { + return (DataScope) val; + } + } + } + return null; + } + + + /** + * 以 conjunction 为分隔符将集合转换为字符串 + * + * @param 被处理的集合 + * @param collection 集合 + * @param conjunction 分隔符 + * @return 连接后的字符串 + */ + private static String join(Iterable collection, String conjunction) { + StringBuilder sb = new StringBuilder(); + boolean isFirst = true; + for (T item : collection) { + if (isFirst) { + isFirst = false; + } else { + sb.append(conjunction); + } + sb.append(item); + } + return sb.toString(); + } + + private static Object realTarget(Object target) { + if (Proxy.isProxyClass(target.getClass())) { + MetaObject metaObject = SystemMetaObject.forObject(target); + return realTarget(metaObject.getValue("h.target")); + } else { + return target; + } + } + + @Override + public Object plugin(Object target) { + return Plugin.wrap(target, this); + } + + @Override + public void setProperties(Properties properties) { + + } +} diff --git a/orm/mybatis/mybatis-interceptor/src/main/java/cn/lastwhisper/mybatis/interceptor/domain/Dept.java b/orm/mybatis/mybatis-interceptor/src/main/java/cn/lastwhisper/mybatis/interceptor/domain/Dept.java new file mode 100644 index 00000000..6b7539c5 --- /dev/null +++ b/orm/mybatis/mybatis-interceptor/src/main/java/cn/lastwhisper/mybatis/interceptor/domain/Dept.java @@ -0,0 +1,126 @@ +package cn.lastwhisper.mybatis.interceptor.domain; + +/** + *

+ * 部门表 + *

+ * + * @author stylefeng + * @since 2017-07-11 + */ +public class Dept { + + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + private Integer id; + /** + * 排序 + */ + private Integer num; + /** + * 父部门id + */ + private Integer pid; + /** + * 父级ids + */ + private String pids; + /** + * 简称 + */ + private String simplename; + /** + * 全称 + */ + private String fullname; + /** + * 提示 + */ + private String tips; + /** + * 版本(乐观锁保留字段) + */ + private Integer version; + + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getNum() { + return num; + } + + public void setNum(Integer num) { + this.num = num; + } + + public Integer getPid() { + return pid; + } + + public void setPid(Integer pid) { + this.pid = pid; + } + + public String getPids() { + return pids; + } + + public void setPids(String pids) { + this.pids = pids; + } + + public String getSimplename() { + return simplename; + } + + public void setSimplename(String simplename) { + this.simplename = simplename; + } + + public String getFullname() { + return fullname; + } + + public void setFullname(String fullname) { + this.fullname = fullname; + } + + public String getTips() { + return tips; + } + + public void setTips(String tips) { + this.tips = tips; + } + + public Integer getVersion() { + return version; + } + + public void setVersion(Integer version) { + this.version = version; + } + + @Override + public String toString() { + return "Dept{" + + "id=" + id + + ", num=" + num + + ", pid=" + pid + + ", pids=" + pids + + ", simplename=" + simplename + + ", fullname=" + fullname + + ", tips=" + tips + + ", version=" + version + + "}"; + } +} diff --git a/orm/mybatis/mybatis-interceptor/src/main/java/cn/lastwhisper/mybatis/interceptor/domain/User.java b/orm/mybatis/mybatis-interceptor/src/main/java/cn/lastwhisper/mybatis/interceptor/domain/User.java new file mode 100644 index 00000000..c760f89f --- /dev/null +++ b/orm/mybatis/mybatis-interceptor/src/main/java/cn/lastwhisper/mybatis/interceptor/domain/User.java @@ -0,0 +1,219 @@ +package cn.lastwhisper.mybatis.interceptor.domain; + +import java.util.Date; + +/** + *

+ * 管理员表 + *

+ * + * @author stylefeng + * @since 2017-07-11 + */ +public class User { + + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + private Integer id; + /** + * 头像 + */ + private String avatar; + /** + * 账号 + */ + private String account; + /** + * 密码 + */ + private String password; + /** + * md5密码盐 + */ + private String salt; + /** + * 名字 + */ + private String name; + /** + * 生日 + */ + private Date birthday; + /** + * 性别(1:男 2:女) + */ + private Integer sex; + /** + * 电子邮件 + */ + private String email; + /** + * 电话 + */ + private String phone; + /** + * 角色id + */ + private String roleid; + /** + * 部门id + */ + private Integer deptid; + /** + * 状态(1:启用 2:冻结 3:删除) + */ + private Integer status; + /** + * 创建时间 + */ + private Date createtime; + /** + * 保留字段 + */ + private Integer version; + + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getAvatar() { + return avatar; + } + + public void setAvatar(String avatar) { + this.avatar = avatar; + } + + public String getAccount() { + return account; + } + + public void setAccount(String account) { + this.account = account; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getSalt() { + return salt; + } + + public void setSalt(String salt) { + this.salt = salt; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Date getBirthday() { + return birthday; + } + + public void setBirthday(Date birthday) { + this.birthday = birthday; + } + + public Integer getSex() { + return sex; + } + + public void setSex(Integer sex) { + this.sex = sex; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } + + public String getRoleid() { + return roleid; + } + + public void setRoleid(String roleid) { + this.roleid = roleid; + } + + public Integer getDeptid() { + return deptid; + } + + public void setDeptid(Integer deptid) { + this.deptid = deptid; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public Date getCreatetime() { + return createtime; + } + + public void setCreatetime(Date createtime) { + this.createtime = createtime; + } + + public Integer getVersion() { + return version; + } + + public void setVersion(Integer version) { + this.version = version; + } + + @Override + public String toString() { + return "User{" + + "id=" + id + + ", avatar=" + avatar + + ", account=" + account + + ", password=" + password + + ", salt=" + salt + + ", name=" + name + + ", birthday=" + birthday + + ", sex=" + sex + + ", email=" + email + + ", phone=" + phone + + ", roleid=" + roleid + + ", deptid=" + deptid + + ", status=" + status + + ", createtime=" + createtime + + ", version=" + version + + "}"; + } +} diff --git a/orm/mybatis/mybatis-interceptor/src/main/resources/SqlMapConfig.xml b/orm/mybatis/mybatis-interceptor/src/main/resources/SqlMapConfig.xml new file mode 100644 index 00000000..b18e8529 --- /dev/null +++ b/orm/mybatis/mybatis-interceptor/src/main/resources/SqlMapConfig.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/orm/mybatis/mybatis-interceptor/src/main/resources/cn/lastwhisper/mybatis/interceptor/dao/UserMapper.xml b/orm/mybatis/mybatis-interceptor/src/main/resources/cn/lastwhisper/mybatis/interceptor/dao/UserMapper.xml new file mode 100644 index 00000000..f4a100e6 --- /dev/null +++ b/orm/mybatis/mybatis-interceptor/src/main/resources/cn/lastwhisper/mybatis/interceptor/dao/UserMapper.xml @@ -0,0 +1,24 @@ + + + + + + + + + id, account, name, birthday, sex, email, avatar, + phone, roleid, + deptid, status, + createtime, version + + + + \ No newline at end of file diff --git a/orm/mybatis/mybatis-datasource-tx/src/main/resources/log4j.properties b/orm/mybatis/mybatis-interceptor/src/main/resources/log4j.properties similarity index 100% rename from orm/mybatis/mybatis-datasource-tx/src/main/resources/log4j.properties rename to orm/mybatis/mybatis-interceptor/src/main/resources/log4j.properties diff --git a/orm/mybatis/mybatis-interceptor/src/test/java/cn/lastwhisper/test/MybatisSelectTest.java b/orm/mybatis/mybatis-interceptor/src/test/java/cn/lastwhisper/test/MybatisSelectTest.java new file mode 100644 index 00000000..b3019909 --- /dev/null +++ b/orm/mybatis/mybatis-interceptor/src/test/java/cn/lastwhisper/test/MybatisSelectTest.java @@ -0,0 +1,78 @@ +package cn.lastwhisper.test; + +import cn.lastwhisper.mybatis.interceptor.dao.UserMapper; +import cn.lastwhisper.mybatis.interceptor.datascope.DataScope; +import cn.lastwhisper.mybatis.interceptor.domain.User; +import org.apache.ibatis.io.Resources; +import org.apache.ibatis.session.SqlSession; +import org.apache.ibatis.session.SqlSessionFactory; +import org.apache.ibatis.session.SqlSessionFactoryBuilder; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +/** + * 高级查询 + * @author lastwhisper + * @date 2019/10/17 + */ +public class MybatisSelectTest { + private InputStream in; + private SqlSession session; + private UserMapper userMapper; + + @Test + public void testDataPermission() { + DataScope dataScope = new DataScope(getCurrentUserDept()); + dataScope.setScopeName("deptid"); + // deptId是指你想查询用户所在的部门,0表示所有 + // 但是你自己能看的用户所在的部门范围在DataScope里面 + List> maps = userMapper.selectUsers(dataScope); + + System.out.println(Optional.ofNullable(maps).orElse(new ArrayList<>()).size()); + } + + + public List getCurrentUserDept() { + // 获取当前用户所属的部门 + List list = new ArrayList<>(); + list.add(24); + return list; + } + + @Test + public void testFindUser() { + //5.执行查询一个方法 + List user = userMapper.findUser(); + user.forEach(System.out::println); + } + + + @Before//在测试方法执行之前执行 + public void init() throws Exception { + //1.读取配置文件 + in = Resources.getResourceAsStream("SqlMapConfig.xml"); + //2.创建构建者对象 + SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); + //3.创建 SqlSession 工厂对象 + SqlSessionFactory factory = builder.build(in); + //4.创建 SqlSession 对象 + session = factory.openSession(); + //5.创建 Dao 的代理对象 + userMapper = session.getMapper(UserMapper.class); + } + + @After//在测试方法执行完成之后执行 + public void destroy() throws Exception { + session.commit(); + //7.释放资源 + session.close(); + in.close(); + } +} diff --git a/orm/mybatis/mybatis-lazy/pom.xml b/orm/mybatis/mybatis-lazy/pom.xml index 4d1ca3fa..66a69bce 100644 --- a/orm/mybatis/mybatis-lazy/pom.xml +++ b/orm/mybatis/mybatis-lazy/pom.xml @@ -11,36 +11,4 @@ mybatis-lazy - - - org.mybatis - mybatis - 3.4.5 - - - - mysql - mysql-connector-java - 5.1.6 - - - - log4j - log4j - 1.2.12 - - - - junit - junit - 4.10 - - - - org.projectlombok - lombok - 1.18.10 - - - \ No newline at end of file diff --git a/orm/mybatis/mybatis-lazy/src/main/resources/SqlMapConfig.xml b/orm/mybatis/mybatis-lazy/src/main/resources/SqlMapConfig.xml index df1fb7d4..178ab376 100644 --- a/orm/mybatis/mybatis-lazy/src/main/resources/SqlMapConfig.xml +++ b/orm/mybatis/mybatis-lazy/src/main/resources/SqlMapConfig.xml @@ -28,7 +28,7 @@ - + diff --git a/orm/mybatis/mybatis-lazy/src/test/java/cn/lastwhisper/test/UserTest.java b/orm/mybatis/mybatis-lazy/src/test/java/cn/lastwhisper/test/UserTest.java index 49eb92c6..adfded7f 100644 --- a/orm/mybatis/mybatis-lazy/src/test/java/cn/lastwhisper/test/UserTest.java +++ b/orm/mybatis/mybatis-lazy/src/test/java/cn/lastwhisper/test/UserTest.java @@ -27,11 +27,11 @@ public void testFindAll() { //6.执行操作 List users = userMapper.findAll(); // 延迟加载不使用,不加载Account的查询语句 - //for (User user : users) { - // System.out.println("-------每个用户的内容---------"); - // System.out.println(user); - // System.out.println(user.getAccounts()); - //} + for (User user : users) { + System.out.println("-------每个用户的内容---------"); +// System.out.println(user); + System.out.println(user.getAccounts()); + } } @Before//在测试方法执行之前执行 diff --git a/orm/mybatis/mybatis-manytomany/pom.xml b/orm/mybatis/mybatis-manytomany/pom.xml index ec0d8c0e..e61feee8 100644 --- a/orm/mybatis/mybatis-manytomany/pom.xml +++ b/orm/mybatis/mybatis-manytomany/pom.xml @@ -11,36 +11,4 @@ mybatis-manytomany - - - org.mybatis - mybatis - 3.4.5 - - - - mysql - mysql-connector-java - 5.1.6 - - - - log4j - log4j - 1.2.12 - - - - junit - junit - 4.10 - - - - org.projectlombok - lombok - 1.18.10 - - - \ No newline at end of file diff --git a/orm/mybatis/mybatis-onetomany/pom.xml b/orm/mybatis/mybatis-onetomany/pom.xml index 49848fd1..fea8f45f 100644 --- a/orm/mybatis/mybatis-onetomany/pom.xml +++ b/orm/mybatis/mybatis-onetomany/pom.xml @@ -11,36 +11,4 @@ mybatis-onetomany - - - org.mybatis - mybatis - 3.4.5 - - - - mysql - mysql-connector-java - 5.1.6 - - - - log4j - log4j - 1.2.12 - - - - junit - junit - 4.10 - - - - org.projectlombok - lombok - 1.18.10 - - - \ No newline at end of file diff --git a/orm/mybatis/mybatis-onetomany/src/main/resources/cn/lastwhisper/mybatis/onetomany/dao/UserMapper.xml b/orm/mybatis/mybatis-onetomany/src/main/resources/cn/lastwhisper/mybatis/onetomany/dao/UserMapper.xml index b57eef3c..5fdc7e7c 100644 --- a/orm/mybatis/mybatis-onetomany/src/main/resources/cn/lastwhisper/mybatis/onetomany/dao/UserMapper.xml +++ b/orm/mybatis/mybatis-onetomany/src/main/resources/cn/lastwhisper/mybatis/onetomany/dao/UserMapper.xml @@ -24,13 +24,11 @@ \ No newline at end of file diff --git a/orm/mybatis/mybatis-onetoone/pom.xml b/orm/mybatis/mybatis-onetoone/pom.xml index 43ee500b..0eed8ca8 100644 --- a/orm/mybatis/mybatis-onetoone/pom.xml +++ b/orm/mybatis/mybatis-onetoone/pom.xml @@ -11,36 +11,4 @@ mybatis-onetoone - - - org.mybatis - mybatis - 3.4.5 - - - - mysql - mysql-connector-java - 5.1.6 - - - - log4j - log4j - 1.2.12 - - - - junit - junit - 4.10 - - - - org.projectlombok - lombok - 1.18.10 - - - \ No newline at end of file diff --git a/orm/orm.sql b/orm/mybatis/orm.sql similarity index 100% rename from orm/orm.sql rename to orm/mybatis/orm.sql diff --git a/orm/mybatis/pom.xml b/orm/mybatis/pom.xml index 97fc70a9..7e28da99 100644 --- a/orm/mybatis/pom.xml +++ b/orm/mybatis/pom.xml @@ -2,21 +2,61 @@ - - orm - cn.lastwhisper - 1.0-SNAPSHOT - 4.0.0 + cn.lastwhisper mybatis + 1.0-SNAPSHOT + pom mybatis-basic - mybatis-design mybatis-crud - mybatis-datasource-tx + mybatis-dynamicsql + + mybatis-onetoone + mybatis-onetomany + mybatis-manytomany + + mybatis-cache + mybatis-lazy + mybatis-annotation-crud + mybatis-annotation-manytable + mybatis-Interceptor + + + + org.mybatis + mybatis + 3.4.5 + + + + mysql + mysql-connector-java + 5.1.6 + + + + log4j + log4j + 1.2.12 + + + + junit + junit + 4.10 + + + + org.projectlombok + lombok + 1.18.10 + + + \ No newline at end of file diff --git a/orm/pom.xml b/orm/pom.xml deleted file mode 100644 index 7f3ab77d..00000000 --- a/orm/pom.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - 4.0.0 - - cn.lastwhisper - orm - pom - 1.0-SNAPSHOT - - mybatis - jpa - jpa - - - - \ No newline at end of file diff --git a/spring-annotation/README.md b/spring-annotation/README.md new file mode 100644 index 00000000..e4cc3ce8 --- /dev/null +++ b/spring-annotation/README.md @@ -0,0 +1,29 @@ +顺序 +1.componentregister 组件注册 +2.lifecycle 生命周期 +3.propertyvalue 属性赋值 +4.autowired 自动装配 +5.profile profile +6.aop aop原理 +7.transaction 声明式事务原理 +8.ext 扩展 + +比较重要的模块 +componentregister 组件注册 +lifecycle2 生命周期 +aop aop原理 +transaction 声明式事务原理 +ext 扩展 + + +spring官网 +https://docs.spring.io/spring-framework/docs/current/reference/html/core.html + +课程注释 + +https://www.cnblogs.com/wjqhuaxia/p/12261814.html +https://www.cnblogs.com/zhulibin2012/p/11106112.html + +别人写的源码分析 + +https://segmentfault.com/a/1190000022694615 \ No newline at end of file diff --git a/spring-annotation/aop-@Aspect/pom.xml b/spring-annotation/aop-@Aspect/pom.xml new file mode 100644 index 00000000..48010efa --- /dev/null +++ b/spring-annotation/aop-@Aspect/pom.xml @@ -0,0 +1,34 @@ + + + + 4.0.0 + + cn.lastwhisper + aop-Aspect + 1.0-SNAPSHOT + + + + + org.springframework + spring-aspects + 4.3.12.RELEASE + + + + org.springframework + spring-context + 4.3.12.RELEASE + + + + junit + junit + 4.12 + test + + + + \ No newline at end of file diff --git a/spring-annotation/aop/src/main/java/cn/lastwhisper/aop/LogAspects.java b/spring-annotation/aop-@Aspect/src/main/java/cn/lastwhisper/aop/LogAspects.java similarity index 89% rename from spring-annotation/aop/src/main/java/cn/lastwhisper/aop/LogAspects.java rename to spring-annotation/aop-@Aspect/src/main/java/cn/lastwhisper/aop/LogAspects.java index 25dca16c..224b2b65 100644 --- a/spring-annotation/aop/src/main/java/cn/lastwhisper/aop/LogAspects.java +++ b/spring-annotation/aop-@Aspect/src/main/java/cn/lastwhisper/aop/LogAspects.java @@ -1,8 +1,11 @@ package cn.lastwhisper.aop; + import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.*; +import java.util.Arrays; + /** * 切面类 * @author lastwhisper @@ -19,13 +22,13 @@ public void pointCut() { // 前置通知:在目标方法运行之前运行 @Before(value = "pointCut()") public void logStart(JoinPoint joinPoint) { - System.out.println(joinPoint.getSignature().getName() + "开始...参数列表是:{" + joinPoint.getArgs() + "}"); + System.out.println(joinPoint.getSignature().getName() + "开始...参数列表是:{" + Arrays.toString(joinPoint.getArgs()) + "}"); } // 后置通知:在目标方法运行之后运行 @After(value = "pointCut()") public void logEnd(JoinPoint joinPoint) { - System.out.println(joinPoint.getSignature().getName() + "结束...参数列表是:{" + joinPoint.getArgs() + "}"); + System.out.println(joinPoint.getSignature().getName() + "结束...参数列表是:{" + Arrays.toString(joinPoint.getArgs()) + "}"); } // JoinPoint一定要放到方法参数列表第一位 diff --git a/spring-annotation/aop/src/main/java/cn/lastwhisper/aop/MathCalculator.java b/spring-annotation/aop-@Aspect/src/main/java/cn/lastwhisper/aop/MathCalculator.java similarity index 100% rename from spring-annotation/aop/src/main/java/cn/lastwhisper/aop/MathCalculator.java rename to spring-annotation/aop-@Aspect/src/main/java/cn/lastwhisper/aop/MathCalculator.java diff --git a/spring-annotation/aop-@Aspect/src/main/java/cn/lastwhisper/aop/TestClient.java b/spring-annotation/aop-@Aspect/src/main/java/cn/lastwhisper/aop/TestClient.java new file mode 100644 index 00000000..eeec9c31 --- /dev/null +++ b/spring-annotation/aop-@Aspect/src/main/java/cn/lastwhisper/aop/TestClient.java @@ -0,0 +1,16 @@ +package cn.lastwhisper.aop; + +import cn.lastwhisper.aop.config.MainConfigOfAop; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; + +public class TestClient { + + public static void main(String[] args) { + AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfAop.class); + MathCalculator mathCalculator = applicationContext.getBean(MathCalculator.class); + + mathCalculator.div(2, 1); + + } + +} \ No newline at end of file diff --git a/spring-annotation/aop-@Aspect/src/main/java/cn/lastwhisper/aop/config/MainConfigOfAop.java b/spring-annotation/aop-@Aspect/src/main/java/cn/lastwhisper/aop/config/MainConfigOfAop.java new file mode 100644 index 00000000..63fbad01 --- /dev/null +++ b/spring-annotation/aop-@Aspect/src/main/java/cn/lastwhisper/aop/config/MainConfigOfAop.java @@ -0,0 +1,194 @@ +package cn.lastwhisper.aop.config; + +import cn.lastwhisper.aop.LogAspects; +import cn.lastwhisper.aop.MathCalculator; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.EnableAspectJAutoProxy; + +/** + * AOP:面向切面编程,指在程序运行期间动态的将某段代码切入到指定方法指定位置进行运行的编程方式。 + * + * 1)导入AOP依赖:spring-aspects + * 2)准备一个业务处理类(MathCalculator):在业务处理时将日志进行打印(方法执行前、方法执行后、方法出现异常时...) + * 3)准备一个日志切面类(LogAspects):在业务处理类运行的不同时期执行不同的通知 + * 通知方法: + * (1)前置通知(@Before):logStart,在目标方法(div)执行之前运行 + * (2)后置通知(@After):logEnd,在目标方法(div)执行之后运行 + * (3)返回通知(@AfterReturning):logReturn,在目标方法(div)执行返回之后运行 + * (4)异常通知(@AfterThrowing):logException,在目标方法(div)执行时出现异常之后运行 + * (5)环绕通知(@Around):动态代理,手动推进目标方法运行(joinPoint.procced()) + * 4)通知注解:给切面类的方法标注何时运行(@Before、@After...) + * 5)将业务处理类和日志切面类都加入到容器中,并告诉Spring那个是切面类(@Aspect) + * 6)给配置类中加 @EnableAspectJAutoProxy(开启基于注解的aop模式) + * + * AOP原理:看给容器中注册了什么组件,这个组件什么时候工作,这个组件的功能是什么? + * 1)@EnableAspectJAutoProxy注解的功能(看给容器中注册了什么组件) + * 导入组件@Import(AspectJAutoProxyRegistrar.class) + * AspectJAutoProxyRegistrar实现了ImportBeanDefinitionRegistrar接口 + * 利用AspectJAutoProxyRegistrar自定义给容器注册bean + * 给容器中注册了一个AnnotationAwareAspectJAutoProxyCreator组件,组件名称叫做org.springframework.aop.config.internalAutoProxyCreator + * + * 2)AnnotationAwareAspectJAutoProxyCreator(这个组件什么时候工作) + * AnnotationAwareAspectJAutoProxyCreator + * ——》父类 AspectJAwareAdvisorAutoProxyCreator + * ——》父类 AbstractAdvisorAutoProxyCreator + * ——》父类 AbstractAutoProxyCreator + * implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware + * 重点关注后置处理器(在bean初始化完成前后做事情)、获取BeanFactory + * + * 在整个继承结构中,给关注点设置断点 + * AbstractAutoProxyCreator.setBeanFactory();因为它获取了BeanFactory + * AbstractAutoProxyCreator.postProcessAfterInitialization、postProcessBeforeInstantiation;因为它有后置处理器的逻辑 + * + * AbstractAdvisorAutoProxyCreator.setBeanFactory();重写了setBeanFactory(),执行自己的initBeanFactory() + * + * AspectJAwareAdvisorAutoProxyCreator没有需要关注的点 + * + * AnnotationAwareAspectJAutoProxyCreator.initBeanFactory;重新父类initBeanFactory()方法 + * + * 3)AnnotationAwareAspectJAutoProxyCreator创建和注册的过程(这个组件什么时候工作) + * 1)传入配置类,创建IOC容器 + * 2)注册配置类,AbstractApplicationContext.refresh()刷新容器 + * 3) + * // Register bean processors that intercept bean creation. + * registerBeanPostProcessors(beanFactory); + * PostProcessorRegistrationDelegate.registerBeanPostProcessors():注册bean的后置处理器,用于拦截bean的创建 + * *注册bean的后置处理器的流程: + * 1)获取IOC容器中已经定义的(还未创建),需要创建对象的所有BeanPostProcessor + * 2)给容器中加入别的BeanPostProcessor + * 3)分离BeanPostProcessor,分别注册BeanPostProcessor + * 1.First, register the BeanPostProcessors that implement PriorityOrdered + * 2.Next, register the BeanPostProcessors that implement Ordered. + * 3.Now, register all regular BeanPostProcessors. + * 4)注册BeanPostProcessor,实际上就是创建BeanPostProcessor对象,保存在容器中 + * 由于AnnotationAwareAspectJAutoProxyCreator实现了Ordered与xxxBeanPostProcessor接口在(3)的2步骤开始注册 + * *AnnotationAwareAspectJAutoProxyCreator注册流程(225行:BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);) + * 1.创建名称为internalAutoProxyCreator的BeanPostProcessor(AnnotationAwareAspectJAutoProxyCreator)实例 + * 504行:doCreateBean() + * internalAutoProxyCreator——》513行:instanceWrapper = createBeanInstance(beanName, mbd, args) + * AnnotationAwareAspectJAutoProxyCreator——》515行:final Object bean = instanceWrapper.getWrappedInstance() + * 2.populateBean:给bean的属性赋值 + * 3.initializeBean:初始化bean + * *初始化bean的流程: + * 1.invokeAwareMethods:处理Aware接口的回调 + * 2.applyBeanPostProcessorsBeforeInitialization:后置处理器的Before的回调 + * 3.invokeInitMethods:执行初始化方法 + * 4.applyBeanPostProcessorsAfterInitialization:后置处理器的After的回调 + * 4.BeanPostProcessor(AnnotationAwareAspectJAutoProxyCreator)创建成功 + * AnnotationAwareAspectJAutoProxyCreator调用父类的setBeanFactory(AbstractAdvisorAutoProxyCreator.setBeanFactory) + * 父类的setBeanFactory调用自身的initBeanFactory + * 5)registerBeanPostProcessors 把BeanPostProcessor注册到BeanFactory中(PostProcessorRegistrationDelegate.addBeanPostProcessor(postProcessor))——————————————注册 + * =======以上是注册AnnotationAwareAspectJAutoProxyCreator的过程======== + * + * AnnotationAwareAspectJAutoProxyCreator的后置处理器类型:InstantiationAwareBeanPostProcessor + * 下面看看InstantiationAwareBeanPostProcessor的调用时机 + * 4)finishBeanFactoryInitialization(beanFactory):完成BeanFactory初始化,创建剩下的单实例bean + * 1) + * // Instantiate all remaining (non-lazy-init) singletons. + * finishBeanFactoryInitialization——》beanFactory.preInstantiateSingletons(); + * 遍历获取容器中的所有的beanDefinitionNames,依次创建FactoryBean和普通Bean + * getBean——》doGetBean——》getSingleton + * 2)getSingleton() 创建bean + * 1)先从缓存中检查手动注册的单例对象 + * AbstractBeanFactory.doGetBean——》getSingleton(beanName); + * 2)缓存没有就走createBean()创建Bean + * [BeanPostProcessor在Bean实例创建前后调用] + * [InstantiationAwareBeanPostProcessor在Bean实例创建前先获取代理对象]//AnnotationAwareAspectJAutoProxyCreator + * 1)、resolveBeforeInstantiation解析BeforeInstantiation,创建代理对象 + * bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName); + * 在这里会处理InstantiationAwareBeanPostProcessor,回调AbstractAutoProxyCreator.postProcessBeforeInstantiation方法 + * if (bean != null) { + * bean = applyBeanPostProcessorsAfterInitialization(bean, beanName); + * } + * 2)、代理对象创建失败的话,doCreateBean(3.3.4流程),创建普通对象 + * =======以上是InstantiationAwareBeanPostProcessor的调用时机======== + * + * 下面看看InstantiationAwareBeanPostProcessor被调用时主要干什么事情(创建代理对象,将通知方法,包装成拦截器) + * 5)AnnotationAwareAspectJAutoProxyCreator[InstantiationAwareBeanPostProcessor]的作用: + * 1)Bean创建之前,调用postProcessBeforeInstantiation() + * 1)判断当前Bean是否在advisedBeans(保存了所有需要增强的Bean)中 + * 2)判断当前Bean是否是基础类(Advice、Pointcut、Advisor、AopInfrastructureBean)或者是切面(是否有@Aspect,有就是切面) + * 3)是否需要跳过 + * 1)拿到候选的增强器,就是切面里面的通知方法 [List candidateAdvisors],增强器类型 InstantiationModelAwarePointcutAdvisor + * 如果是AspectJPointcutAdvisor返回true + * 2)父类返回false + * 2)、Bean创建之后,调用postProcessAfterInitialization() + * 关注mathCalculator、LogAspects创建 + * wrapIfNecessary方法会创建代理对象,返回给spring: + * 1)、getAdvicesAndAdvisorsForBean获取当前Bean可应用的通知方法 + * 关注findEligibleAdvisors + * 1)、找到候选的所有通知方法。findCandidateAdvisors();所有切面都在这里面 + * 2)、获取可应用到当前Bean的通知方法。findAdvisorsThatCanApply(); + * AopUtils.findAdvisorsThatCanApply这里面有切点表达式的匹配代码 + * 3)、sortAdvisors(eligibleAdvisors)对通知方法进行排序,根据这排序器AnnotationAwareOrderComparator + * 2)、保存当前Bean到advisedBeans(保存了所有需要增强的Bean)中——有待商议 + * 3)、createProxy()如果当前Bean需要增强,创建当前Bean的代理对象 + * 1)、将通知方法Advisor保存到ProxyFactory中,默认会添加一个ExposeInvocationInterceptor,用于记录当前调用的MethodInvocation + * 2)、proxyFactory.getProxy()创建代理对象 + * createAopProxy()创建JdkDynamicAopProxy或者ObjenesisCglibAopProxy + * 然后JdkDynamicAopProxy.getProxy()获取代理类 + * 3)、将代理类放到proxyTypes(key:Bean,value:代理类)中 + * 3)、以后从容器中获取到的就是这个Bean的代理对象,执行目标方法的时候,代理对象会执行通知方法 + * + * =======以上是InstantiationAwareBeanPostProcessor被调用时干什么事情======== + * 下面看看代理对象创建好了,我们在Spring获取Bean组件,并且调用方法时,增强方法是怎么工作的 + * + * 6)目标方法执行时的拦截器链(将每一个通知方法包装成拦截器) + * 断点放到Bean调用方法的地方,强制步入-步出,强制步入-步出,强制步入-步出,就会进入下面的方法 + * 1)、CglibAopProxy.intercept()拦截目标方法执行 + * 2)、根据ProxyFactory获取将要执行的目标方法拦截器链 + * this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass) + * this.advised的实现类是ProxyFactory + * 1)、创建interceptorList保存拦截器链 + * 2)、遍历所有通知方法,转成Interceptor,registry.getInterceptors(advisor) + * 如果是MethodInterceptor直接加入集合 + * 如果不是,使用AdvisorAdapter将通知方法转为MethodInterceptor加入集合 + * 3)、没有拦截器链,执行目标方法 + * 4)、有拦截器链,CglibMethodInvocation.proceed()执行拦截器链 + * 5)、proceed()拦截器链的触发过程 + * 1)、如果拦截器的索引等于拦截器数组-1(最后一个拦截器调用完成或者一开始就没有拦截器),直接执行目标方法 + * 2)、如果jdk动态代理 + * 3)、如果cglib动态代理,MethodInterceptor.invoke(this); + * 这里的MethodInterceptor是所有的通知方法,this是CglibMethodInvocation + * + * ExposeInvocationInterceptor,用于记录当前调用的MethodInvocation + * + * + * 总结: + * 1)、@EnableAspectJAutoProxy 开启AOP功能 + * 2)、@EnableAspectJAutoProxy 会给容器中注册一个组件AnnotationAwareAspectJAutoProxyCreator + * 3)、AnnotationAwareAspectJAutoProxyCreator是一个后置处理器(InstantiationAwareBeanPostProcessor) + * 4)、容器的创建流程: + * 1)、registerBeanPostProcessors()注册后置处理器,创建AnnotationAwareAspectJAutoProxyCreator + * 2)、finishBeanFactoryInitialization()初始化剩下的单实例Bean + * 1)、创建业务逻辑组件和切面组件 + * 2)、resolveBeforeInstantiation->wrapIfNecessary + * 给业务组件创建代理类,将通知方法包装成增强器(Advisor) + * 5)、执行目标方法 + * 1)、代理类执行目标方法 + * 2)、CglibAopProxy.intercept()拦截方法的执行 + * 1)、将目标方法的增强器(Advice),包装成截器链(MethodInterceptor) + * 2)、利用拦截器的链式机制,依次进入每个拦截器执行 + * 3)、效果: + * 正常执行:前置通知-》目标方法-》后置通知-》返回通知 + * 异常执行:前置通知-》目标方法-》后置通知-》异常通知 + * + * + * + * @author lastwhisper + */ +@EnableAspectJAutoProxy // 开启基于注解的aop模式 +@Configuration +public class MainConfigOfAop { + + @Bean + public MathCalculator mathCalculator() { + return new MathCalculator(); + } + + @Bean + public LogAspects logAspects() { + return new LogAspects(); + } +} diff --git a/spring-annotation/aop-@Aspect/src/main/resources/Bean.xml b/spring-annotation/aop-@Aspect/src/main/resources/Bean.xml new file mode 100644 index 00000000..26af0a5a --- /dev/null +++ b/spring-annotation/aop-@Aspect/src/main/resources/Bean.xml @@ -0,0 +1,11 @@ + + + + + + + + \ No newline at end of file diff --git a/spring-annotation/aop-interface/README.md b/spring-annotation/aop-interface/README.md new file mode 100644 index 00000000..f48ba1ab --- /dev/null +++ b/spring-annotation/aop-interface/README.md @@ -0,0 +1 @@ +1111 diff --git a/spring-annotation/aop-interface/pom.xml b/spring-annotation/aop-interface/pom.xml new file mode 100644 index 00000000..cf5a5702 --- /dev/null +++ b/spring-annotation/aop-interface/pom.xml @@ -0,0 +1,39 @@ + + + 4.0.0 + + cn.lastwhisper + aop-interface + 0.0.1-SNAPSHOT + + + 8 + 8 + + + + + + org.springframework + spring-aspects + 4.3.12.RELEASE + + + + org.springframework + spring-context + 4.3.12.RELEASE + + + + junit + junit + 4.12 + test + + + + + \ No newline at end of file diff --git a/spring-annotation/aop-interface/src/main/java/cn/cunchang/Calculate.java b/spring-annotation/aop-interface/src/main/java/cn/cunchang/Calculate.java new file mode 100644 index 00000000..e775328a --- /dev/null +++ b/spring-annotation/aop-interface/src/main/java/cn/cunchang/Calculate.java @@ -0,0 +1,45 @@ +package cn.cunchang; + +/** + * 计算类接口 + */ +public interface Calculate { + + /** + * 加法 + * + * @param numA + * @param numB + * @return + */ + int add(int numA, int numB); + + /** + * 减法 + * + * @param numA + * @param numB + * @return + */ + int sub(int numA, int numB); + + /** + * 除法 + * + * @param numA + * @param numB + * @return + */ + int div(int numA, int numB); + + /** + * 乘法 + * + * @param numA + * @param numB + * @return + */ + int multi(int numA, int numB); + + int mod(int numA, int numB); +} \ No newline at end of file diff --git a/spring-annotation/aop-interface/src/main/java/cn/cunchang/TestClient.java b/spring-annotation/aop-interface/src/main/java/cn/cunchang/TestClient.java new file mode 100644 index 00000000..85e88091 --- /dev/null +++ b/spring-annotation/aop-interface/src/main/java/cn/cunchang/TestClient.java @@ -0,0 +1,21 @@ +package cn.cunchang; + +import cn.cunchang.aop.EalyAopMainConfig; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; + +/** + * @author cunchang + * @date 2022/7/2 10:11 PM + */ +public class TestClient { + public static void main(String[] args) { + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(EalyAopMainConfig.class); + // 1、ProxyFactoryBean方式 +// Calculate calculateProxy = ctx.getBean("calculateProxy", Calculate.class); +// calculateProxy.div(1, 1); + + // 2、AutoProxyCreator 后置处理器方式 + Calculate calculateProxy = ctx.getBean(Calculate.class); + calculateProxy.div(1, 1); + } +} diff --git a/spring-annotation/aop-interface/src/main/java/cn/cunchang/TulingCalculate.java b/spring-annotation/aop-interface/src/main/java/cn/cunchang/TulingCalculate.java new file mode 100644 index 00000000..3463a205 --- /dev/null +++ b/spring-annotation/aop-interface/src/main/java/cn/cunchang/TulingCalculate.java @@ -0,0 +1,47 @@ +package cn.cunchang; + +import org.springframework.aop.framework.AopContext; +import org.springframework.stereotype.Component; + +@Component +public class TulingCalculate implements Calculate { + + @Override + public int add(int numA, int numB) { + + System.out.println("执行目标方法:add"); + System.out.println(1 / 0); + return numA + numB; + } + + @Override + public int sub(int numA, int numB) { + System.out.println("执行目标方法:reduce"); + return numA - numB; + } + + @Override + public int div(int numA, int numB) { + System.out.println("执行目标方法:div"); + return numA / numB; + } + + @Override + public int multi(int numA, int numB) { + System.out.println("执行目标方法:multi"); + + return numA * numB; + } + + @Override + public int mod(int numA, int numB) { + System.out.println("执行目标方法:mod"); + + int retVal = ((Calculate) AopContext.currentProxy()).add(numA, numB); + //int retVal = this.add(numA,numB); + + return retVal % numA; + + //return numA%numB; + } +} \ No newline at end of file diff --git a/spring-annotation/aop-interface/src/main/java/cn/cunchang/aop/EalyAopMainConfig.java b/spring-annotation/aop-interface/src/main/java/cn/cunchang/aop/EalyAopMainConfig.java new file mode 100644 index 00000000..d1c0c776 --- /dev/null +++ b/spring-annotation/aop-interface/src/main/java/cn/cunchang/aop/EalyAopMainConfig.java @@ -0,0 +1,146 @@ +package cn.cunchang.aop; + +import cn.cunchang.Calculate; +import cn.cunchang.TulingCalculate; +import org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator; +import org.springframework.aop.support.NameMatchMethodPointcutAdvisor; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * * Spring常见代理创建方式 + * * FactoryBean方式,创建单个动态代理: ProxyFactoryBean 1.指定续增强的接口:proxyInterfaces 2.指定需增强的实现类target 3.指定Advice、Advisor、Interceptor都行 + * * autoProxy方式:批量根据advisor自动创建 + * * BeanPostProcessor手动指定Advice方式 BeanNameAutoProxyCreator 1.指定Advice 2.可以使用正则来匹配 bean 的名字 + * * BeanPostProcessor自动扫描Advisor方式 DefaultAdvisorAutoProxyCreator (不支持注解)、 + * * AnnotationAwareAspectJAutoProxyCreator(注解)、 + * * AspectJAwareAdvisorAutoProxyCreator(XML) + * + * @author cunchang + * @date 2022/7/2 10:10 PM + */ +@Configuration +public class EalyAopMainConfig { + + // 被代理对象 + @Bean + public Calculate tulingCalculate() { + return new TulingCalculate(); + } + + // Advice 方式 + @Bean + public TulingLogAdvice tulingLogAdvice() { + return new TulingLogAdvice(); + } + + // Interceptor方式 , 类似环绕通知 + @Bean + public TulingLogInterceptor tulingLogInterceptor() { + return new TulingLogInterceptor(); + } + + /**************************1、ProxyFactoryBean******************************/ + + /** + * FactoryBean方式单个: ProxyFactoryBean + *

+ * 此中方法有个致命的问题,如果我们只能指定单一的Bean的AOP, + * 如果多个Bean需要创建多个ProxyFactoryBean 。 + * 而且,我们看到,我们的拦截器的粒度只控制到了类级别,类中所有的方法都进行了拦截。 + * 接下来,我们看看怎么样只拦截特定的方法。 + */ +// @Bean +// public ProxyFactoryBean calculateProxy() { +// ProxyFactoryBean userService = new ProxyFactoryBean(); +// userService.setInterceptorNames("tulingLogAdvice", "tulingLogInterceptor"); // 根据指定的顺序执行 +// userService.setTarget(tulingCalculate()); +// return userService; +// } + + /**************************1、ProxyFactoryBean******************************/ + + + /**************************2、ProxyFactoryBean+Advisor******************************/ + /** + * Advisor 种类很多: + * RegexpMethodPointcutAdvisor 按正则匹配类 + * NameMatchMethodPointcutAdvisor 按方法名匹配 + * DefaultBeanFactoryPointcutAdvisor xml解析的Advisor ,入参" + Arrays.asList(args)); + } +} \ No newline at end of file diff --git a/spring-annotation/aop-interface/src/main/java/cn/cunchang/aop/TulingLogInterceptor.java b/spring-annotation/aop-interface/src/main/java/cn/cunchang/aop/TulingLogInterceptor.java new file mode 100644 index 00000000..5c31d665 --- /dev/null +++ b/spring-annotation/aop-interface/src/main/java/cn/cunchang/aop/TulingLogInterceptor.java @@ -0,0 +1,19 @@ +package cn.cunchang.aop; + +import org.aopalliance.intercept.MethodInterceptor; +import org.aopalliance.intercept.MethodInvocation; + +import java.util.Arrays; + +public class TulingLogInterceptor implements MethodInterceptor { + @Override + public Object invoke(MethodInvocation invocation) throws Throwable { +// System.out.println(getClass() + "调用方法前"); + System.out.println("执行目标方法【" + invocation.getMethod().getName() + "】的<环绕通知-前>,入参" + Arrays.asList(invocation.getArguments())); + Object ret = invocation.proceed(); +// System.out.println(getClass() + "调用方法后"); + System.out.println("执行目标方法【" + invocation.getMethod().getName() + "】的<环绕通知-后>,入参" + Arrays.asList(invocation.getArguments())); + return ret; + } + +} \ No newline at end of file diff --git a/spring-annotation/aop-schema-based/README.md b/spring-annotation/aop-schema-based/README.md new file mode 100644 index 00000000..32ecb215 --- /dev/null +++ b/spring-annotation/aop-schema-based/README.md @@ -0,0 +1,3 @@ +参考 +https://www.cnblogs.com/HigginCui/p/6323131.html + diff --git a/spring-annotation/aop-schema-based/pom.xml b/spring-annotation/aop-schema-based/pom.xml new file mode 100644 index 00000000..21717038 --- /dev/null +++ b/spring-annotation/aop-schema-based/pom.xml @@ -0,0 +1,37 @@ + + + + 4.0.0 + + cn.lastwhisper + aop-schema-based + 1.0-SNAPSHOT + jar + spring aop低级api xml配置 + + + + + org.springframework + spring-aspects + 4.3.12.RELEASE + + + + org.springframework + spring-context + 4.3.12.RELEASE + + + + junit + junit + 4.12 + test + + + + + \ No newline at end of file diff --git a/spring-annotation/aop-schema-based/src/main/java/cn/cunchang/aop/CarAdvisor.java b/spring-annotation/aop-schema-based/src/main/java/cn/cunchang/aop/CarAdvisor.java new file mode 100644 index 00000000..4c5a4229 --- /dev/null +++ b/spring-annotation/aop-schema-based/src/main/java/cn/cunchang/aop/CarAdvisor.java @@ -0,0 +1,44 @@ +package cn.cunchang.aop; + +import java.lang.reflect.Method; + +import cn.cunchang.domain.BenzCar; +import org.springframework.aop.ClassFilter; +import org.springframework.aop.support.StaticMethodMatcherPointcutAdvisor; + +/** + * 汽车类的切面CarAdvisor类 + * 实现接口:StaticMethodMatcherPointcutAdvisor + * 实现StaticMethodMatcherPointcutAdvisor接口唯一需要定义的是matches()方法, + * + */ +public class CarAdvisor extends StaticMethodMatcherPointcutAdvisor{ + + /** + * 切点方法 匹配 + * 匹配规则:方法名为driving + * 默认情况下,匹配所有的类 + */ + @Override + public boolean matches(Method method, Class clazz) { + return "driving".equals(method.getName()); + } + + /** + * 通过覆盖getClassFilter()方法,让它仅匹配BenzCar类及其子类 + */ + @Override + public ClassFilter getClassFilter(){ + return new ClassFilter() { + /** + * 切点类 匹配 + * 匹配规则:为BenzCar类或其子类 + */ + @Override + public boolean matches(Class clazz) { + return BenzCar.class.isAssignableFrom(clazz); + } + }; + } + +} \ No newline at end of file diff --git a/spring-annotation/aop-schema-based/src/main/java/cn/cunchang/aop/CarAdvisor2.java b/spring-annotation/aop-schema-based/src/main/java/cn/cunchang/aop/CarAdvisor2.java new file mode 100644 index 00000000..4510a4b8 --- /dev/null +++ b/spring-annotation/aop-schema-based/src/main/java/cn/cunchang/aop/CarAdvisor2.java @@ -0,0 +1,45 @@ +package cn.cunchang.aop; + +import cn.cunchang.domain.BenzCar; +import cn.cunchang.domain.Car; +import org.springframework.aop.ClassFilter; +import org.springframework.aop.support.StaticMethodMatcherPointcutAdvisor; + +import java.lang.reflect.Method; + +/** + * 汽车类的切面CarAdvisor类 + * 实现接口:StaticMethodMatcherPointcutAdvisor + * 实现StaticMethodMatcherPointcutAdvisor接口唯一需要定义的是matches()方法, + * + */ +public class CarAdvisor2 extends StaticMethodMatcherPointcutAdvisor{ + + /** + * 切点方法 匹配 + * 匹配规则:方法名为driving + * 默认情况下,匹配所有的类 + */ + @Override + public boolean matches(Method method, Class clazz) { + return "driving".equals(method.getName()); + } + + /** + * 通过覆盖getClassFilter()方法,让它仅匹配BenzCar类及其子类 + */ + @Override + public ClassFilter getClassFilter(){ + return new ClassFilter() { + /** + * 切点类 匹配 + * 匹配规则:为BenzCar类或其子类 + */ + @Override + public boolean matches(Class clazz) { + return Car.class.isAssignableFrom(clazz); + } + }; + } + +} \ No newline at end of file diff --git a/spring-annotation/aop-schema-based/src/main/java/cn/cunchang/aop/DrivingBeforeAdvice.java b/spring-annotation/aop-schema-based/src/main/java/cn/cunchang/aop/DrivingBeforeAdvice.java new file mode 100644 index 00000000..a84f044c --- /dev/null +++ b/spring-annotation/aop-schema-based/src/main/java/cn/cunchang/aop/DrivingBeforeAdvice.java @@ -0,0 +1,18 @@ +package cn.cunchang.aop; + +import java.lang.reflect.Method; +import org.springframework.aop.MethodBeforeAdvice; + +/** + * Driving的前置增强类 + */ +public class DrivingBeforeAdvice implements MethodBeforeAdvice{ + + @Override + public void before(Method method, Object[] args, Object obj) throws Throwable { + //得到切点的信息 + System.out.println("要增强的是:"+obj.getClass()+"类 ---"+method.getName()+"方法"); + System.out.println("【前置增强】做好行驶前的准备工作..."); + } + +} \ No newline at end of file diff --git a/spring-annotation/aop-schema-based/src/main/java/cn/cunchang/aop/DrivingInterceptor.java b/spring-annotation/aop-schema-based/src/main/java/cn/cunchang/aop/DrivingInterceptor.java new file mode 100644 index 00000000..05614d36 --- /dev/null +++ b/spring-annotation/aop-schema-based/src/main/java/cn/cunchang/aop/DrivingInterceptor.java @@ -0,0 +1,30 @@ +package cn.cunchang.aop; + +import org.aopalliance.intercept.MethodInterceptor; +import org.aopalliance.intercept.MethodInvocation; +import org.springframework.aop.MethodBeforeAdvice; +import org.springframework.aop.aspectj.AspectJAroundAdvice; +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; + +import java.lang.reflect.Method; + +/** + * Driving的方法拦截器 + */ + +public class DrivingInterceptor implements MethodInterceptor{ + + @Override + public Object invoke(MethodInvocation invocation) throws Throwable { + Object result = null; + + System.out.println("车辆放行前..."); + result= invocation.proceed(); + System.out.println("车辆放行后..."); + + return result; + } + +} \ No newline at end of file diff --git a/spring-annotation/aop-schema-based/src/main/java/cn/cunchang/domain/BenzCar.java b/spring-annotation/aop-schema-based/src/main/java/cn/cunchang/domain/BenzCar.java new file mode 100644 index 00000000..a3c361e1 --- /dev/null +++ b/spring-annotation/aop-schema-based/src/main/java/cn/cunchang/domain/BenzCar.java @@ -0,0 +1,10 @@ +package cn.cunchang.domain; + +public class BenzCar implements Car{ + + @Override + public void driving() { + System.out.println("奔驰车在行驶..."); + } + +} \ No newline at end of file diff --git a/spring-annotation/aop-schema-based/src/main/java/cn/cunchang/domain/BmwCar.java b/spring-annotation/aop-schema-based/src/main/java/cn/cunchang/domain/BmwCar.java new file mode 100644 index 00000000..f6af10e7 --- /dev/null +++ b/spring-annotation/aop-schema-based/src/main/java/cn/cunchang/domain/BmwCar.java @@ -0,0 +1,10 @@ +package cn.cunchang.domain; + +public class BmwCar implements Car{ + + @Override + public void driving(){ + System.out.println("五菱宏光在行驶..."); + } + +} \ No newline at end of file diff --git a/spring-annotation/aop-schema-based/src/main/java/cn/cunchang/domain/Car.java b/spring-annotation/aop-schema-based/src/main/java/cn/cunchang/domain/Car.java new file mode 100644 index 00000000..6bf57ea2 --- /dev/null +++ b/spring-annotation/aop-schema-based/src/main/java/cn/cunchang/domain/Car.java @@ -0,0 +1,11 @@ +package cn.cunchang.domain; + +/** + * @author cunchang + * @date 2021/8/29 11:21 上午 + */ +public interface Car { + + public void driving(); + +} diff --git a/spring-annotation/aop-schema-based/src/main/resources/aop-low-api.xml b/spring-annotation/aop-schema-based/src/main/resources/aop-low-api.xml new file mode 100644 index 00000000..c0abd1fe --- /dev/null +++ b/spring-annotation/aop-schema-based/src/main/resources/aop-low-api.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/spring-annotation/aop-schema-based/src/test/java/cn/lastwhisper/aop/test/AOP_LowApiTest.java b/spring-annotation/aop-schema-based/src/test/java/cn/lastwhisper/aop/test/AOP_LowApiTest.java new file mode 100644 index 00000000..aba84379 --- /dev/null +++ b/spring-annotation/aop-schema-based/src/test/java/cn/lastwhisper/aop/test/AOP_LowApiTest.java @@ -0,0 +1,26 @@ +package cn.lastwhisper.aop.test; + +import cn.cunchang.domain.BmwCar; +import cn.cunchang.domain.BenzCar; +import org.junit.Test; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +/** + * @author lastwhisper + */ +public class AOP_LowApiTest { + + @Test + public void test01() { + ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("aop-low-api.xml"); + + BenzCar benz = (BenzCar) applicationContext.getBean("benz"); + BmwCar bmw = (BmwCar) applicationContext.getBean("bmw"); + + benz.driving(); //奔驰车的driving方法 + System.out.println("==========================="); + bmw.driving(); //宝马车的driving方法 + + } + +} diff --git a/spring-annotation/aop/pom.xml b/spring-annotation/aop/pom.xml deleted file mode 100644 index 1a3bc778..00000000 --- a/spring-annotation/aop/pom.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - spring-annotation - cn.lastwhisper - 1.0-SNAPSHOT - - 4.0.0 - - cn.lastwhisper - aop - - - - - org.springframework - spring-aspects - 5.1.5.RELEASE - - - - - \ No newline at end of file diff --git a/spring-annotation/aop/src/main/java/cn/lastwhisper/aop/config/MainConfigOfAop.java b/spring-annotation/aop/src/main/java/cn/lastwhisper/aop/config/MainConfigOfAop.java deleted file mode 100644 index 76baf359..00000000 --- a/spring-annotation/aop/src/main/java/cn/lastwhisper/aop/config/MainConfigOfAop.java +++ /dev/null @@ -1,101 +0,0 @@ -package cn.lastwhisper.aop.config; - -import cn.lastwhisper.aop.LogAspects; -import cn.lastwhisper.aop.MathCalculator; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.EnableAspectJAutoProxy; - -/** - * AOP:面向切面编程,指在程序运行期间动态的将某段代码切入到指定方法指定位置进行运行的编程方式。 - * - * 1)导入AOP依赖:spring-aspects - * 2)准备一个业务处理类(MathCalculator):在业务处理时将日志进行打印(方法执行前、方法执行后、方法出现异常时...) - * 3)准备一个日志切面类(LogAspects):在业务处理类运行的不同时期执行不同的通知 - * 通知方法: - * (1)前置通知(@Before):logStart,在目标方法(div)执行之前运行 - * (2)后置通知(@After):logEnd,在目标方法(div)执行之后运行 - * (3)返回通知(@AfterReturning):logReturn,在目标方法(div)执行返回之后运行 - * (4)异常通知(@AfterThrowing):logException,在目标方法(div)执行时出现异常之后运行 - * (5)环绕通知(@Around):动态代理,手动推进目标方法运行(joinPoint.procced()) - * 4)通知注解:给切面类的方法标注何时运行(@Before、@After...) - * 5)将业务处理类和日志切面类都加入到容器中,并告诉Spring那个是切面类(@Aspect) - * 6)给配置类中加 @EnableAspectJAutoProxy(开启基于注解的aop模式) - * - * AOP原理:看给容器中注册了什么组件,这个组件什么时候工作,这个组件的功能是什么? - * 1)@EnableAspectJAutoProxy - * 导入组件@Import(AspectJAutoProxyRegistrar.class) - * AspectJAutoProxyRegistrar实现了ImportBeanDefinitionRegistrar接口 - * 利用AspectJAutoProxyRegistrar自定义给容器注册bean(BeanDefinetion) - * internalAutoProxyCreator=AnnotationAwareAspectJAutoProxyCreator - * 给容器中注册了一个AnnotationAwareAspectJAutoProxyCreator - * - * 2)AnnotationAwareAspectJAutoProxyCreator: - * AnnotationAwareAspectJAutoProxyCreator - * ——》AspectJAwareAdvisorAutoProxyCreator - * ——》AbstractAdvisorAutoProxyCreator - * ——》AbstractAutoProxyCreator - * ——》implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware - * 关注后置处理器(在bean初始化完成前后做事情)、自动装配BeanFactory - * - * AbstractAutoProxyCreator.setBeanFactory - * AbstractAutoProxyCreator.postProcessAfterInitialization、postProcessBeforeInstantiation等有后置处理器的逻辑 - * - * AbstractAdvisorAutoProxyCreator.setBeanFactory()——》initBeanFactory - * - * AnnotationAwareAspectJAutoProxyCreator.initBeanFactory - * - * 流程: - * 1)传入配置类,创建IOC容器 - * 2)注册配置类,AbstractApplicationContext.refresh()刷新容器 - * 3)PostProcessorRegistrationDelegate.registerBeanPostProcessors:注册bean的后置处理器来方便拦截bean的创建 - * *注册bean的后置处理器的流程: - * (1)获取IOC容器中已经定义的需要创建对象的所有BeanPostProcessor - * (2)给容器中加入别的BeanPostProcessor - * (3)分离BeanPostProcessor,分别注册BeanPostProcessor - * 1.First, register the BeanPostProcessors that implement PriorityOrdered - * 2.Next, register the BeanPostProcessors that implement Ordered. - * 3.Now, register all regular BeanPostProcessors. - * (4)注册BeanPostProcessor,实际上就是创建BeanPostProcessor对象,保存在容器中——————————————创建 - * 由于AnnotationAwareAspectJAutoProxyCreator实现了Ordered与xxxBeanPostProcessor接口在(3)的2步骤开始注册 - * *AnnotationAwareAspectJAutoProxyCreator注册流程(AbstractAutowireCapableBeanFactory.doCreateBean()) - * 1.创建internalAutoProxyCreator的BeanPostProcessor(AnnotationAwareAspectJAutoProxyCreator)实例 - * internalAutoProxyCreator——》instanceWrapper = createBeanInstance(beanName, mbd, args) - * AnnotationAwareAspectJAutoProxyCreator——》final Object bean = instanceWrapper.getWrappedInstance() - * 2.populateBean:给bean的属性赋值 - * 3.initializeBean:初始化bean - * *初始化bean的流程: - * 1.invokeAwareMethods:处理Aware接口的回调 - * 2.applyBeanPostProcessorsBeforeInitialization:后置处理器的Before调用 - * 3.invokeInitMethods:执行初始化方法 - * 4.applyBeanPostProcessorsAfterInitialization:后置处理器的After调用 - * 4. BeanPostProcessor(AnnotationAwareAspectJAutoProxyCreator)创建成功 - * AnnotationAwareAspectJAutoProxyCreator调用父类的setBeanFactory(AbstractAdvisorAutoProxyCreator.setBeanFactory) - * 父类的setBeanFactory调用自身的initBeanFactory - * (5)把BeanPostProcessor注册到BeanFactory中(beanFactory.addBeanPostProcessor(postProcessor))——————————————注册 - * =======以上是创建和注册AnnotationAwareAspectJAutoProxyCreator的过程======== - * - * AnnotationAwareAspectJAutoProxyCreator的后置处理器类型:InstantiationAwareBeanPostProcessor - * 4)finishBeanFactoryInitialization(beanFactory):完成BeanFactory初始化,创建剩下的单实例bean - * (1)遍历获取容器中的所有的Bean,依次创建对象getBean(beanName); - * getBean——》doGetBean——》getSingleton - * (2)创建bean - * 1.先从缓存中获取 - * AbstractBeanFactory.doGetBean——》Object sharedInstance = getSingleton(beanName); - * - * @author lastwhisper - */ -@EnableAspectJAutoProxy // 开启基于注解的aop模式 -@Configuration -public class MainConfigOfAop { - - @Bean - public MathCalculator mathCalculator() { - return new MathCalculator(); - } - - @Bean - public LogAspects logAspects() { - return new LogAspects(); - } -} diff --git a/spring-annotation/aop/src/test/java/cn/lastwhisper/aop/test/IOCTest_AOP.java b/spring-annotation/aop/src/test/java/cn/lastwhisper/aop/test/IOCTest_AOP.java deleted file mode 100644 index d57687f6..00000000 --- a/spring-annotation/aop/src/test/java/cn/lastwhisper/aop/test/IOCTest_AOP.java +++ /dev/null @@ -1,22 +0,0 @@ -package cn.lastwhisper.aop.test; - -import cn.lastwhisper.aop.MathCalculator; -import cn.lastwhisper.aop.config.MainConfigOfAop; -import org.junit.Test; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; - -/** - * @author lastwhisper - */ -public class IOCTest_AOP { - - @Test - public void test01() { - AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfAop.class); - - MathCalculator mathCalculator = applicationContext.getBean(MathCalculator.class); - mathCalculator.div(2, 1); - - } - -} diff --git a/spring-annotation/autowired/pom.xml b/spring-annotation/autowired/pom.xml index da57b039..38f3d623 100644 --- a/spring-annotation/autowired/pom.xml +++ b/spring-annotation/autowired/pom.xml @@ -2,22 +2,34 @@ - - spring-annotation - cn.lastwhisper - 1.0-SNAPSHOT - + 4.0.0 cn.lastwhisper autowired + 1.0-SNAPSHOT + + + org.springframework + spring-context + 4.3.12.RELEASE + + + + junit + junit + 4.12 + test + + javax.inject javax.inject 1 + \ No newline at end of file diff --git a/spring-annotation/autowired/src/main/java/cn/lastwhisper/autowired/bean/Red.java b/spring-annotation/autowired/src/main/java/cn/lastwhisper/autowired/bean/Red.java index 66f1e6e6..f2527a27 100644 --- a/spring-annotation/autowired/src/main/java/cn/lastwhisper/autowired/bean/Red.java +++ b/spring-annotation/autowired/src/main/java/cn/lastwhisper/autowired/bean/Red.java @@ -14,14 +14,17 @@ @Component public class Red implements ApplicationContextAware, BeanNameAware, EmbeddedValueResolverAware { + @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { System.out.println("applicationContext:" + applicationContext); } + @Override public void setBeanName(String name) { System.out.println("name:" + name); } + @Override public void setEmbeddedValueResolver(StringValueResolver resolver) { String stringValue = resolver.resolveStringValue("操作系统:${os.name},#{2019710+1}"); System.out.println(stringValue); diff --git a/spring-annotation/autowired/src/main/java/cn/lastwhisper/autowired/config/MainConfigOfAutoWired.java b/spring-annotation/autowired/src/main/java/cn/lastwhisper/autowired/config/MainConfigOfAutoWired.java index ce9a614b..46d86fca 100644 --- a/spring-annotation/autowired/src/main/java/cn/lastwhisper/autowired/config/MainConfigOfAutoWired.java +++ b/spring-annotation/autowired/src/main/java/cn/lastwhisper/autowired/config/MainConfigOfAutoWired.java @@ -39,8 +39,7 @@ * @author lastwhisper */ @Configuration -@ComponentScan({"cn.lastwhisper.autowired.controller", "cn.lastwhisper.autowired.service", - "cn.lastwhisper.autowired.dao", "cn.lastwhisper.autowired.bean"}) +@ComponentScan({"cn.lastwhisper"}) public class MainConfigOfAutoWired { // @Primary() Antowired多个bean时首选bean @Primary() diff --git a/spring-annotation/componentregister/pom.xml b/spring-annotation/componentregister/pom.xml index dd88a86d..6a75993c 100644 --- a/spring-annotation/componentregister/pom.xml +++ b/spring-annotation/componentregister/pom.xml @@ -2,15 +2,26 @@ - - spring-annotation - cn.lastwhisper - 1.0-SNAPSHOT - + 4.0.0 cn.lastwhisper componentregister + 1.0-SNAPSHOT + + + + + org.springframework + spring-context + 4.3.12.RELEASE + + + junit + junit + 4.12 + + \ No newline at end of file diff --git a/spring-annotation/componentregister/src/main/java/cn/lastwhisper/componentregister/MainTest.java b/spring-annotation/componentregister/src/main/java/cn/lastwhisper/componentregister/MainTest.java index 2bfa5024..4ab18524 100644 --- a/spring-annotation/componentregister/src/main/java/cn/lastwhisper/componentregister/MainTest.java +++ b/spring-annotation/componentregister/src/main/java/cn/lastwhisper/componentregister/MainTest.java @@ -1,25 +1,40 @@ package cn.lastwhisper.componentregister; import cn.lastwhisper.componentregister.bean.Person; -import cn.lastwhisper.componentregister.config.MainConfig; +import cn.lastwhisper.componentregister.config.MainConfigScan; +import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; public class MainTest { - public static void main(String[] args) { - // 1.读取xml - //ApplicationContext applicationContext = new ClassPathXmlApplicationContext("Bean.xml"); - //Person person = (Person) applicationContext.getBean("person"); - //System.out.println(person); + + /** + * 测试读取配置类 + */ + @Test + public void test2(){ // 2.读取配置类 - ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class); + ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigScan.class); Person person = applicationContext.getBean(Person.class); System.out.println(person); + // 找到Person Bean组件的名字 String[] namesForType = applicationContext.getBeanNamesForType(Person.class); - for (int i = 0; i < namesForType.length; i++) { - String s = namesForType[i]; + for (String s : namesForType) { System.out.println(s); } } + + /** + * 测试读取配置文件 + */ + @Test + public void test1(){ + // 1.读取xml + ApplicationContext applicationContext = new ClassPathXmlApplicationContext("Bean.xml"); + Person person = (Person) applicationContext.getBean("person"); + System.out.println(person); + } + } \ No newline at end of file diff --git a/spring-annotation/componentregister/src/main/java/cn/lastwhisper/componentregister/bean/Blue.java b/spring-annotation/componentregister/src/main/java/cn/lastwhisper/componentregister/bean/Blue.java index 3e7e3638..ae7f1c0f 100644 --- a/spring-annotation/componentregister/src/main/java/cn/lastwhisper/componentregister/bean/Blue.java +++ b/spring-annotation/componentregister/src/main/java/cn/lastwhisper/componentregister/bean/Blue.java @@ -5,3 +5,4 @@ */ public class Blue { } + diff --git a/spring-annotation/componentregister/src/main/java/cn/lastwhisper/componentregister/bean/ColorFactoryBean.java b/spring-annotation/componentregister/src/main/java/cn/lastwhisper/componentregister/bean/ColorFactoryBean.java index c323a592..9c12b143 100644 --- a/spring-annotation/componentregister/src/main/java/cn/lastwhisper/componentregister/bean/ColorFactoryBean.java +++ b/spring-annotation/componentregister/src/main/java/cn/lastwhisper/componentregister/bean/ColorFactoryBean.java @@ -3,26 +3,26 @@ import org.springframework.beans.factory.FactoryBean; /** + * FactoryBean有啥用? + * 与其他框架进行整合 + * + * * @author lastwhisper */ public class ColorFactoryBean implements FactoryBean { /** * 返回需要注册的对象 - * - * @param - * @return cn.lastwhisper.cn.lastwhisper.componentregister.bean.Color */ + @Override public Color getObject() throws Exception { - System.out.println("ColorFactoryBean.getObject"); + System.out.println("ColorFactoryBean.getObject方法执行"); return new Color(); } /** * 返回需要注册对象的class - * - * @param - * @return java.lang.Class */ + @Override public Class getObjectType() { return Color.class; } @@ -31,10 +31,8 @@ public Class getObjectType() { * 是否单例 * true:单实例,在容器中保存一份 * false:多实例,每次获取都会创建一个新的bean - * - * @param - * @return boolean */ + @Override public boolean isSingleton() { return true; } diff --git a/spring-annotation/componentregister/src/main/java/cn/lastwhisper/componentregister/condition/LinuxCondition.java b/spring-annotation/componentregister/src/main/java/cn/lastwhisper/componentregister/condition/LinuxCondition.java index ea348966..06724ccf 100644 --- a/spring-annotation/componentregister/src/main/java/cn/lastwhisper/componentregister/condition/LinuxCondition.java +++ b/spring-annotation/componentregister/src/main/java/cn/lastwhisper/componentregister/condition/LinuxCondition.java @@ -17,6 +17,7 @@ public class LinuxCondition implements Condition { * @param metadata * @return boolean */ + @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { // 获取运行时环境 Environment environment = context.getEnvironment(); diff --git a/spring-annotation/componentregister/src/main/java/cn/lastwhisper/componentregister/condition/MacCondition.java b/spring-annotation/componentregister/src/main/java/cn/lastwhisper/componentregister/condition/MacCondition.java new file mode 100644 index 00000000..0da1f4a6 --- /dev/null +++ b/spring-annotation/componentregister/src/main/java/cn/lastwhisper/componentregister/condition/MacCondition.java @@ -0,0 +1,49 @@ +package cn.lastwhisper.componentregister.condition; + +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.context.annotation.Condition; +import org.springframework.context.annotation.ConditionContext; +import org.springframework.core.env.Environment; +import org.springframework.core.type.AnnotatedTypeMetadata; + +/** + * bean加载条件 + * @author lastwhisper + */ +public class MacCondition implements Condition { + /** + * 匹配mac操作系统 + * + * @param context 上下文 + * @param metadata 注解信息 + * @return boolean + */ + @Override + public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { + // 获取到的是app classLoader,跟this获取的一样啊,好奇怪,有什么用呢? + ClassLoader appClassLoader = context.getClassLoader(); + ClassLoader classLoader = this.getClass().getClassLoader(); + + // ioc BeanFactory + ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); + // BeanDefinitionRegistry增删改查Bean注册信息 + BeanDefinitionRegistry registry = context.getRegistry(); + + // 获取运行时环境 + Environment environment = context.getEnvironment(); + // 获取操作系统 + String property = environment.getProperty("os.name"); + + if (property.toLowerCase().contains("mac os x")) { + return true; + } + return false; + } + + + public static void main(String[] args) { + System.out.println(System.getProperty("os.name").toLowerCase()); + } + +} diff --git a/spring-annotation/componentregister/src/main/java/cn/lastwhisper/componentregister/condition/WindowsCondition.java b/spring-annotation/componentregister/src/main/java/cn/lastwhisper/componentregister/condition/WindowsCondition.java index 2cb6ed05..60df75ef 100644 --- a/spring-annotation/componentregister/src/main/java/cn/lastwhisper/componentregister/condition/WindowsCondition.java +++ b/spring-annotation/componentregister/src/main/java/cn/lastwhisper/componentregister/condition/WindowsCondition.java @@ -14,10 +14,11 @@ public class WindowsCondition implements Condition { /** * 匹配windows操作系统 * - * @param context - * @param metadata + * @param context 上下文 + * @param metadata 注解信息 * @return boolean */ + @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { // 获取运行时环境 Environment environment = context.getEnvironment(); @@ -31,4 +32,6 @@ public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) } return false; } + + } diff --git a/spring-annotation/componentregister/src/main/java/cn/lastwhisper/componentregister/config/MainConfig.java b/spring-annotation/componentregister/src/main/java/cn/lastwhisper/componentregister/config/MainConfig.java deleted file mode 100644 index a59ea476..00000000 --- a/spring-annotation/componentregister/src/main/java/cn/lastwhisper/componentregister/config/MainConfig.java +++ /dev/null @@ -1,37 +0,0 @@ -package cn.lastwhisper.componentregister.config; - -import cn.lastwhisper.componentregister.bean.Person; -import cn.lastwhisper.componentregister.filter.MyTypeFilter; -import org.springframework.context.annotation.*; - -/** - * 配置类相当于是配置文件 - * @author lastwhisper - */ -@Configuration // 告诉Spring这是一个配置类 -//excludeFilters = Filter[];指定在扫描的时候按照什么规则来排除脑哪些组件 -//includeFilters = Filter[];指定在扫描的时候,只需要包含哪些组件 -@ComponentScans(value = { - @ComponentScan(value = "cn.lastwhisper", includeFilters = { - // 这里面是一个@Filter注解数组,FilterType.ANNOTATION表示的排除的规则 :按照注解来进行匹配 - // classes = {Controller.class}表示的是标有这些注解的类给纳入到IOC容器中 - //@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class}), - // FilterType.ASSIGNABLE_TYPE 按照给定类型进行匹配 - //@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {BookService.class}) - // FilterType.ASPECTJ 表达式 - // FilterType.REGEX 正则表达式 - @ComponentScan.Filter(type = FilterType.CUSTOM, classes = {MyTypeFilter.class}) - }, useDefaultFilters = false) -}) -public class MainConfig { - /** - * 在Spring的IOC容器中,默认名称为:person222,如果设置Bean的value值,则按value值 - * - * @param - * @return cn.lastwhisper.cn.lastwhisper.componentregister.bean.Person - */ - @Bean("personName") - public Person person222() { - return new Person("lastwhisper", 21); - } -} diff --git a/spring-annotation/componentregister/src/main/java/cn/lastwhisper/componentregister/config/MainConfig2.java b/spring-annotation/componentregister/src/main/java/cn/lastwhisper/componentregister/config/MainConfig2.java deleted file mode 100644 index d3f5dfef..00000000 --- a/spring-annotation/componentregister/src/main/java/cn/lastwhisper/componentregister/config/MainConfig2.java +++ /dev/null @@ -1,85 +0,0 @@ -package cn.lastwhisper.componentregister.config; - -import cn.lastwhisper.componentregister.bean.Color; -import cn.lastwhisper.componentregister.bean.ColorFactoryBean; -import cn.lastwhisper.componentregister.bean.Person; -import cn.lastwhisper.componentregister.bean.Red; -import cn.lastwhisper.componentregister.condition.LinuxCondition; -import cn.lastwhisper.componentregister.condition.WindowsCondition; -import cn.lastwhisper.componentregister.filter.MyTypeFilter; -import cn.lastwhisper.componentregister.register.MyImportBeanDefinitionRegistrar; -import cn.lastwhisper.componentregister.selector.MyImportSelector; -import org.springframework.context.annotation.*; - -/** - * @author lastwhisper - */ - -@Configuration -@ComponentScan(excludeFilters = { - @ComponentScan.Filter(type = FilterType.CUSTOM, classes = {MyTypeFilter.class}) -}) -//@Import({Color.class, Red.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class}) -public class MainConfig2 { - /** - * Scope取值:prototype、singleton、request、session。默认是singleton - * prototype:多实例,IOC容器启动时并不会创建对象,只有获取时才会创建。懒加载 - * singleton:单实例,IOC容器启动时创建对象放入IOC容器中。 - * request:一次请求创建一个实例 - * session:一个session创建一个实例 - * - * 懒加载: 当IOC容器启动时不创建对象,第一次使用时才创建。 - * singleton默认在IOC容器启动时创建对象,加上@Lazy变成懒加载。 - * - * @param - * @return cn.lastwhisper.cn.lastwhisper.componentregister.bean.Person - */ - @Scope("singleton") - @Lazy - @Bean("person") - public Person person() { - System.out.println("Person对象创建完毕"); - return new Person("tom", 22); - } - - /** - * * @Conditional({Condition.class}): 按条件判断,满足条件给容器注册bean - * 现在下面的两个bean注册到IOC容器是要条件的: - * 1.如果系统是windows,给容器注册("bill") - * 2.如果系统是linux,给容器注册("linus") - * @param - * @return cn.lastwhisper.cn.lastwhisper.componentregister.bean.Person - */ - @Conditional({WindowsCondition.class}) - @Bean("bill") - public Person windows() { - return new Person("Bill Gates", 66); - } - - @Conditional({LinuxCondition.class}) - @Bean("linus") - public Person linux() { - return new Person("linus", 45); - } - - /** - * 给容器中注册组件的几种方式: - * 1)、组件扫描+组件注册注解 @Controller、@Service、@Repository、@Component(自己写的类) - * - * 2)、@Bean(注册第三方包里面的组件,如连接池等) - * 3)、@Import(快速给容器中注册一个组件) - * (1)、@Import(要注册到容器的组件):容器会自动注册这个组件,id是全限定名 - * (2)、ImportSelector:返回需要注册的组件的全限定名 - * (3)、ImportBeanDefinitionRegistrar:手动注册bean到容器 - * - * 4)、使用Spring提供的FactoryBean(工厂bean) - * (1)、默认获取的是getObject返回的对象 - * (2)、要获取FactoryBean本身,我们需要给id前面加上一个“&”符号:&colorFactoryBean - */ - - @Bean - public ColorFactoryBean colorFactoryBean() { - return new ColorFactoryBean(); - } - -} diff --git a/spring-annotation/componentregister/src/main/java/cn/lastwhisper/componentregister/config/MainConfigRegister.java b/spring-annotation/componentregister/src/main/java/cn/lastwhisper/componentregister/config/MainConfigRegister.java new file mode 100644 index 00000000..f3fd1040 --- /dev/null +++ b/spring-annotation/componentregister/src/main/java/cn/lastwhisper/componentregister/config/MainConfigRegister.java @@ -0,0 +1,102 @@ +package cn.lastwhisper.componentregister.config; + +import cn.lastwhisper.componentregister.bean.Color; +import cn.lastwhisper.componentregister.bean.ColorFactoryBean; +import cn.lastwhisper.componentregister.bean.Person; +import cn.lastwhisper.componentregister.bean.Red; +import cn.lastwhisper.componentregister.condition.LinuxCondition; +import cn.lastwhisper.componentregister.condition.MacCondition; +import cn.lastwhisper.componentregister.condition.WindowsCondition; +import cn.lastwhisper.componentregister.filter.MyTypeFilter; +import cn.lastwhisper.componentregister.register.MyImportBeanDefinitionRegistrar; +import cn.lastwhisper.componentregister.selector.MyImportSelector; +import org.springframework.context.annotation.*; + +/** + * @author lastwhisper + */ + +//@Configuration +//@ComponentScan(excludeFilters = { +// @ComponentScan.Filter(type = FilterType.CUSTOM, classes = {MyTypeFilter.class}) +//}) +@ComponentScan(value = "cn.lastwhisper") +//@Conditional({WindowsCondition.class}) +@Import({Color.class, Red.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class}) +public class MainConfigRegister { + /** + * Scope取值:prototype、singleton、request、session。默认是singleton + * prototype:多实例,IOC容器启动时并不会创建对象,只有获取时才会创建。懒加载 + * singleton:单实例,IOC容器启动时创建对象放入IOC容器中。 + * request:一次请求创建一个实例(需要web环境) + * session:一个session创建一个实例(需要web环境) + * + * 懒加载:当IOC容器启动时不创建对象,第一次使用时才创建。 + * singleton默认不是懒加载,加上@Lazy变成懒加载。 + * prototype是懒加载 + */ + @Scope("singleton") +// @Scope("prototype") +// @Lazy // 通过初始化容器,查看是否输出"Person对象创建完毕" + @Bean("person") + public Person person() { +// System.out.println("Person对象创建完毕"); + return new Person("tom", 22); + } + + /** + * 注解@Conditional({Condition.class}): 按条件判断,满足条件给容器注册bean + * + * System.out.println(System.getProperty("os.name").toLowerCase()); + * + * 现在下面的两个bean注册到IOC容器是要条件的: + * 1.如果系统是windows,给容器注册("bill") + * 2.如果系统是linux,给容器注册("linus") + * 3.如果系统是mac,给容器注册("jobs") + */ + @Conditional({WindowsCondition.class}) + @Bean("bill") + public Person windows() { + return new Person("Bill Gates", 66); + } + + /** + * -Dos.name 变成linux + */ + @Conditional({LinuxCondition.class}) + @Bean("linus") + public Person linux() { + return new Person("linus", 45); + } + + + @Conditional({MacCondition.class}) + @Bean("jobs") + public Person jobs() { + return new Person("Steve Jobs", 45); + } + + /** + * 给容器中注册组件的几种方式: + * 1)、组件扫描+组件注册注解 @Controller、@Service、@Repository、@Component(自己写的类) + * + * 2)、@Bean(应用场景:注册第三方包里面的组件,如连接池等) + * + * 3)、@Import(快速给容器中注册一个组件;应用场景:注册第三方包里面的组件,如连接池等) + * (1)、@Import(要注册到容器的组件):容器会自动注册这个组件,id是全限定名 + * (2)、ImportSelector:返回需要注册的组件的全限定名 + * (3)、ImportBeanDefinitionRegistrar:手动注册bean到容器 + * + * 4)、使用Spring提供的FactoryBean(应用场景:与其他框架整合使用,比如mybatis的SqlSessionFactoryBean) + * Spring 中有两种类型的Bean,一种是普通Bean,另一种是工厂Bean 即 FactoryBean + * (1)、默认获取的是getObject返回的对象 + * (2)、要获取FactoryBean本身,我们需要给id前面加上一个“&”符号:&colorFactoryBean + * + * + */ + @Bean + public ColorFactoryBean colorFactoryBean() { + return new ColorFactoryBean(); + } + +} diff --git a/spring-annotation/componentregister/src/main/java/cn/lastwhisper/componentregister/config/MainConfigScan.java b/spring-annotation/componentregister/src/main/java/cn/lastwhisper/componentregister/config/MainConfigScan.java new file mode 100644 index 00000000..b56ef71c --- /dev/null +++ b/spring-annotation/componentregister/src/main/java/cn/lastwhisper/componentregister/config/MainConfigScan.java @@ -0,0 +1,55 @@ +package cn.lastwhisper.componentregister.config; + +import cn.lastwhisper.componentregister.bean.Person; +import cn.lastwhisper.componentregister.filter.MyTypeFilter; +import cn.lastwhisper.componentregister.service.BookService; +import org.springframework.context.annotation.*; +import org.springframework.stereotype.Controller; + +/** + * 配置类相当于是配置文件 + * @author lastwhisper + */ +@Configuration // 告诉Spring这是一个配置类 +@ComponentScans(value = { + @ComponentScan( + value = "cn.lastwhisper", + includeFilters = { + // 这里面是一个@Filter注解数组,FilterType.ANNOTATION表示的排除的规则 :按照注解来进行匹配 + // classes = {Controller.class}表示的是标有这些注解的类给纳入到IOC容器中 + @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class}), + // FilterType.ASSIGNABLE_TYPE 按照给定类型进行匹配 +// @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {BookService.class}), + // FilterType.ASPECTJ 表达式 + // FilterType.REGEX 正则表达式 + // FilterType.CUSTOM 自定义过滤规则 +// @ComponentScan.Filter(type = FilterType.CUSTOM, classes = {MyTypeFilter.class}) + }, + // useDefaultFilters = true默认include @Controller、@Service、@Repository、@Component + useDefaultFilters = false), + @ComponentScan( + value = "cn.lastwhisper", + excludeFilters = { + // FilterType.ASSIGNABLE_TYPE 按照给定类型进行匹配 +// @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {BookService.class}), + }, + useDefaultFilters = false) +}) +/* + * 注解@ComponentScan对应 + * + * excludeFilters = Filter[];指定在扫描的时候按照什么规则来排除脑哪些组件 + * includeFilters = Filter[];指定在扫描的时候,只需要包含哪些组件,想让包扫描的includeFilters生效,必须声明useDefaultFilters = false + * + * @ComponentScan在jdk8是可重复声明注解,不是jdk8,可以使用@ComponentScans进行重复声明 + */ +public class MainConfigScan { + /** + * 在Spring的IOC容器中,默认名称为:person222,如果设置Bean的value值,则按value值 + * 给容器中注册一个Bean + */ + @Bean("personName") + public Person person222() { + return new Person("lastwhisper", 21); + } +} diff --git a/spring-annotation/componentregister/src/main/java/cn/lastwhisper/componentregister/controller/BookController.java b/spring-annotation/componentregister/src/main/java/cn/lastwhisper/componentregister/controller/BookController.java index 2bd334cd..5b079626 100644 --- a/spring-annotation/componentregister/src/main/java/cn/lastwhisper/componentregister/controller/BookController.java +++ b/spring-annotation/componentregister/src/main/java/cn/lastwhisper/componentregister/controller/BookController.java @@ -1,7 +1,15 @@ package cn.lastwhisper.componentregister.controller; +import cn.lastwhisper.componentregister.bean.Red; +import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Controller; @Controller public class BookController { + + @Bean("myRed") + public Red red(){ + return new Red(); + } + } diff --git a/spring-annotation/componentregister/src/main/java/cn/lastwhisper/componentregister/filter/MyTypeFilter.java b/spring-annotation/componentregister/src/main/java/cn/lastwhisper/componentregister/filter/MyTypeFilter.java index 92e2c513..b8576fd9 100644 --- a/spring-annotation/componentregister/src/main/java/cn/lastwhisper/componentregister/filter/MyTypeFilter.java +++ b/spring-annotation/componentregister/src/main/java/cn/lastwhisper/componentregister/filter/MyTypeFilter.java @@ -1,6 +1,5 @@ package cn.lastwhisper.componentregister.filter; -import org.springframework.context.annotation.Conditional; import org.springframework.core.type.AnnotationMetadata; import org.springframework.core.type.ClassMetadata; import org.springframework.core.type.classreading.MetadataReader; @@ -8,7 +7,6 @@ import org.springframework.core.type.filter.TypeFilter; import java.io.IOException; -import java.lang.annotation.Annotation; /** * 自定义ComponentScan过滤器 @@ -23,6 +21,7 @@ public class MyTypeFilter implements TypeFilter { * @param metadataReaderFactory 获取其他任何类型 * @return boolean */ + @Override public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException { // 获取当前正在扫描的类注解的信息 AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata(); @@ -30,7 +29,7 @@ public boolean match(MetadataReader metadataReader, MetadataReaderFactory metada ClassMetadata classMetadata = metadataReader.getClassMetadata(); // 获取类名 String className = classMetadata.getClassName(); - System.out.println("扫描的类——》" + className); + System.out.println(this.getClass().getSimpleName()+ " 扫描的类——》" + className); // 根据类名进行过滤 if (className.contains("Book")) { return true; diff --git a/spring-annotation/componentregister/src/main/java/cn/lastwhisper/componentregister/register/MyImportBeanDefinitionRegistrar.java b/spring-annotation/componentregister/src/main/java/cn/lastwhisper/componentregister/register/MyImportBeanDefinitionRegistrar.java index a666f4ea..31a66b4e 100644 --- a/spring-annotation/componentregister/src/main/java/cn/lastwhisper/componentregister/register/MyImportBeanDefinitionRegistrar.java +++ b/spring-annotation/componentregister/src/main/java/cn/lastwhisper/componentregister/register/MyImportBeanDefinitionRegistrar.java @@ -10,17 +10,19 @@ * @author lastwhisper */ public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { + /** - * 把所有需要添加到容器中的bean通过BeanDefinitionRegistry里面的registerBeanDefinition方法来手动的进行注册 + * 把所有需要添加到容器中的bean,通过BeanDefinitionRegistry来手动的进行注册 * - * @param importingClassMetadata 当前类的注解信息 + * @param importingClassMetadata 使用MyImportSelector类的所有注解(MainConfigRegister类的注解) * @param registry BeanDefinition注册类 * @return void */ + @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { - boolean blueb = registry.containsBeanDefinition("cn.lastwhisper.cn.lastwhisper.componentregister.bean.Blue"); - boolean redb = registry.containsBeanDefinition("cn.lastwhisper.cn.lastwhisper.componentregister.bean.Red"); + boolean blueb = registry.containsBeanDefinition("cn.lastwhisper.componentregister.bean.Blue"); + boolean redb = registry.containsBeanDefinition("cn.lastwhisper.componentregister.bean.Red"); // 模拟注册条件 if (blueb && redb) { // bean定义信息 diff --git a/spring-annotation/componentregister/src/main/java/cn/lastwhisper/componentregister/selector/MyImportSelector.java b/spring-annotation/componentregister/src/main/java/cn/lastwhisper/componentregister/selector/MyImportSelector.java index ad366551..61d23def 100644 --- a/spring-annotation/componentregister/src/main/java/cn/lastwhisper/componentregister/selector/MyImportSelector.java +++ b/spring-annotation/componentregister/src/main/java/cn/lastwhisper/componentregister/selector/MyImportSelector.java @@ -8,12 +8,15 @@ * @author lastwhisper */ public class MyImportSelector implements ImportSelector { + /** * - * @param importingClassMetadata 使用MyImportSelector类的所有注解 + * @param importingClassMetadata 使用MyImportSelector类的所有注解(MainConfigRegister类的注解) * @return java.lang.String[] 导入组件的全类名 */ + @Override public String[] selectImports(AnnotationMetadata importingClassMetadata) { return new String[]{"cn.lastwhisper.componentregister.bean.Blue", "cn.lastwhisper.componentregister.bean.Yellow"}; } + } diff --git a/spring-annotation/componentregister/src/main/resources/Bean.xml b/spring-annotation/componentregister/src/main/resources/Bean.xml index a2ff2f7d..094df6b9 100644 --- a/spring-annotation/componentregister/src/main/resources/Bean.xml +++ b/spring-annotation/componentregister/src/main/resources/Bean.xml @@ -1,15 +1,27 @@ + xmlns:context="http://www.springframework.org/schema/context" + xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> - - - - - - + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/spring-annotation/componentregister/src/test/java/cn/lastwhisper/componentregister/test/IOCTest.java b/spring-annotation/componentregister/src/test/java/cn/lastwhisper/componentregister/test/IOCTest.java index 489c23ef..76ead8aa 100644 --- a/spring-annotation/componentregister/src/test/java/cn/lastwhisper/componentregister/test/IOCTest.java +++ b/spring-annotation/componentregister/src/test/java/cn/lastwhisper/componentregister/test/IOCTest.java @@ -1,11 +1,17 @@ package cn.lastwhisper.componentregister.test; -import cn.lastwhisper.componentregister.config.MainConfig; -import cn.lastwhisper.componentregister.config.MainConfig2; +import cn.lastwhisper.componentregister.bean.Blue; +import cn.lastwhisper.componentregister.bean.Person; +import cn.lastwhisper.componentregister.bean.RainBow; +import cn.lastwhisper.componentregister.config.MainConfigScan; +import cn.lastwhisper.componentregister.config.MainConfigRegister; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import java.nio.Buffer; +import java.util.Map; + /** * @author lastwhisper */ @@ -19,12 +25,12 @@ public class IOCTest { */ @Test public void test05() { - ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class); - + ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigRegister.class); + // 获取的是FactoryBean.getObject创建的对象 Object factoryBean = applicationContext.getBean("colorFactoryBean"); Object factoryBean2 = applicationContext.getBean("colorFactoryBean"); System.out.println("bean的类型:" + factoryBean.getClass()); - System.out.println(factoryBean == factoryBean2); + System.out.println(factoryBean == factoryBean2? "单实例" : "多实例"); Object factoryBean3 = applicationContext.getBean("&colorFactoryBean"); System.out.println("bean的类型:" + factoryBean3.getClass()); @@ -32,17 +38,15 @@ public void test05() { /** * 测试Import - * - * @param - * @return void */ @Test public void test04() { - ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class); + ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigRegister.class); String[] definitionNames = applicationContext.getBeanDefinitionNames(); for (String name : definitionNames) { System.out.println(name); } + System.out.println(applicationContext.getBean(RainBow.class)); } /** @@ -53,26 +57,27 @@ public void test04() { */ @Test public void test03() { - ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class); - String[] definitionNames = applicationContext.getBeanDefinitionNames(); - for (String name : definitionNames) { - System.out.println(name); + AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigRegister.class); +// String[] definitionNames = applicationContext.getBeanDefinitionNames(); +// for (String name : definitionNames) { +// System.out.println(name); +// } + Map personMap = applicationContext.getBeansOfType(Person.class); + for (Map.Entry entry : personMap.entrySet()) { + System.out.println(entry); } } /** * 测试组件作用域与懒加载 - * - * @param - * @return void */ @Test public void test02() { - ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class); + ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigRegister.class); System.out.println("IOC容器启动完毕"); - Object person = applicationContext.getBean("person"); - Object person2 = applicationContext.getBean("person"); - System.out.println(person == person2); +// Object person = applicationContext.getBean("person"); +// Object person2 = applicationContext.getBean("person"); +// System.out.println(person == person2 ? "单实例" : "多实例"); } /** @@ -83,10 +88,10 @@ public void test02() { */ @Test public void test01() { - ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class); + ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigScan.class); String[] definitionNames = applicationContext.getBeanDefinitionNames(); for (String name : definitionNames) { - System.out.println(name); + System.out.printf("definitionName:%s\n",name); } } diff --git a/spring-annotation/event/pom.xml b/spring-annotation/event/pom.xml new file mode 100644 index 00000000..07ff4095 --- /dev/null +++ b/spring-annotation/event/pom.xml @@ -0,0 +1,28 @@ + + + + 4.0.0 + + event + cn.lastwhisper + 1.0-SNAPSHOT + + + + + org.springframework + spring-context + 4.3.12.RELEASE + + + + junit + junit + 4.12 + test + + + + \ No newline at end of file diff --git a/spring-annotation/event/src/main/java/cn/lastwhisper/spring/event/BlackListEvent.java b/spring-annotation/event/src/main/java/cn/lastwhisper/spring/event/BlackListEvent.java new file mode 100644 index 00000000..45b4660c --- /dev/null +++ b/spring-annotation/event/src/main/java/cn/lastwhisper/spring/event/BlackListEvent.java @@ -0,0 +1,36 @@ +package cn.lastwhisper.spring.event; + +import org.springframework.context.ApplicationEvent; + +/** + * 事件体 + */ +public class BlackListEvent extends ApplicationEvent { + + private final String address; + private final String content; + + public BlackListEvent(Object source, String address, String content) { + super(source); + this.address = address; + this.content = content; + } + + // accessor and other methods... + + public String getAddress() { + return address; + } + + public String getContent() { + return content; + } + + @Override + public String toString() { + return "BlackListEvent{" + + "address='" + address + '\'' + + ", content='" + content + '\'' + + '}'; + } +} \ No newline at end of file diff --git a/spring-annotation/event/src/main/java/cn/lastwhisper/spring/event/BlackListNotifier.java b/spring-annotation/event/src/main/java/cn/lastwhisper/spring/event/BlackListNotifier.java new file mode 100644 index 00000000..5ec70e19 --- /dev/null +++ b/spring-annotation/event/src/main/java/cn/lastwhisper/spring/event/BlackListNotifier.java @@ -0,0 +1,21 @@ +package cn.lastwhisper.spring.event; + +import org.springframework.context.event.EventListener; + +/** + * 事件接收者 + */ +public class BlackListNotifier { + + private String notificationAddress; + + public void setNotificationAddress(String notificationAddress) { + this.notificationAddress = notificationAddress; + } + + @EventListener + public void processBlackListEvent(BlackListEvent event) { + System.out.println("接收到消息:" + event); + // notify appropriate parties via notificationAddress... + } +} \ No newline at end of file diff --git a/spring-annotation/event/src/main/java/cn/lastwhisper/spring/event/EmailService.java b/spring-annotation/event/src/main/java/cn/lastwhisper/spring/event/EmailService.java new file mode 100644 index 00000000..9954611c --- /dev/null +++ b/spring-annotation/event/src/main/java/cn/lastwhisper/spring/event/EmailService.java @@ -0,0 +1,32 @@ +package cn.lastwhisper.spring.event; + +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.context.ApplicationEventPublisherAware; + +import java.util.List; + +/** + * 事件发送者 + */ +public class EmailService implements ApplicationEventPublisherAware { + + private List blackList; + + private ApplicationEventPublisher publisher; + + public void setBlackList(List blackList) { + this.blackList = blackList; + } + + public void setApplicationEventPublisher(ApplicationEventPublisher publisher) { + this.publisher = publisher; + } + + public void sendEmail(String address, String content) { + if (blackList.contains(address)) { + publisher.publishEvent(new BlackListEvent(this, address, content)); + return; + } + // send email... + } +} \ No newline at end of file diff --git a/spring-annotation/event/src/main/java/cn/lastwhisper/spring/event/EventConfig.java b/spring-annotation/event/src/main/java/cn/lastwhisper/spring/event/EventConfig.java new file mode 100644 index 00000000..e3e3fe49 --- /dev/null +++ b/spring-annotation/event/src/main/java/cn/lastwhisper/spring/event/EventConfig.java @@ -0,0 +1,41 @@ +package cn.lastwhisper.spring.event; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author lastwhisper + * @date 2020/2/18 + */ +@Configuration +@ComponentScan("cn.lastwhisper.spring.event") +public class EventConfig { + + @Bean + public BlackListNotifier blackListNotifier() { + BlackListNotifier blackListNotifier = new BlackListNotifier(); + blackListNotifier.setNotificationAddress("blacklist@example.org"); + return blackListNotifier; + } + + @Bean + public EmailService emailService() { + EmailService emailService = new EmailService(); + emailService.setBlackList(blackList()); + return emailService; + } + + @Bean + public List blackList() { + List blackList = new ArrayList<>(); + blackList.add("known.spammer@example.org"); + blackList.add("known.hacker@example.org"); + blackList.add("john.doe@example.org"); + return blackList; + } + +} diff --git a/spring-annotation/event/src/test/java/cn/lastwhisper/spring/event/IOCTest_Event.java b/spring-annotation/event/src/test/java/cn/lastwhisper/spring/event/IOCTest_Event.java new file mode 100644 index 00000000..b9dd6dec --- /dev/null +++ b/spring-annotation/event/src/test/java/cn/lastwhisper/spring/event/IOCTest_Event.java @@ -0,0 +1,26 @@ +package cn.lastwhisper.spring.event; + +import org.junit.Test; +import org.springframework.context.ApplicationEvent; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; + +/** + * @author lastwhisper + */ +public class IOCTest_Event { + + /** + * 测试Spring事件 + */ + @Test + public void test01() { + AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(EventConfig.class); + System.out.println("容器初始化..."); + EmailService emailService = applicationContext.getBean(EmailService.class); + emailService.sendEmail("john.doe@example.org","hello world"); + emailService.sendEmail("blacklist@example.org","hello world"); + + applicationContext.close(); + } + +} diff --git a/spring-annotation/ext/README.md b/spring-annotation/ext/README.md new file mode 100644 index 00000000..3cc07379 --- /dev/null +++ b/spring-annotation/ext/README.md @@ -0,0 +1,3 @@ +1. event +2. BeanDefinitionRegistryPostProcessor +3. BeanFactoryPostProcessor \ No newline at end of file diff --git a/spring-annotation/ext/pom.xml b/spring-annotation/ext/pom.xml new file mode 100644 index 00000000..a382dcfd --- /dev/null +++ b/spring-annotation/ext/pom.xml @@ -0,0 +1,27 @@ + + + + 4.0.0 + cn.lastwhisper + ext + 1.0-SNAPSHOT + + + + + org.springframework + spring-context + 4.3.12.RELEASE + + + + junit + junit + 4.12 + test + + + + \ No newline at end of file diff --git a/spring-annotation/ext/src/main/java/cn/lastwhisper/spring/ext/ExtConfig.java b/spring-annotation/ext/src/main/java/cn/lastwhisper/spring/ext/ExtConfig.java new file mode 100644 index 00000000..9a8bdbfe --- /dev/null +++ b/spring-annotation/ext/src/main/java/cn/lastwhisper/spring/ext/ExtConfig.java @@ -0,0 +1,116 @@ +package cn.lastwhisper.spring.ext; + +import cn.lastwhisper.spring.ext.bean.Blue; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; + +/** + * 扩展原理: + * BeanPostProcessor:bean后置处理器,bean创建对象初始化前后进行拦截工作的 + * + * 1、BeanFactoryPostProcessor:beanFactory的后置处理器; + * 在BeanFactory标准初始化之后调用,来定制和修改BeanFactory的内容; + * 所有的bean定义(BeanDefinition)已经保存加载到beanFactory,但是bean的实例还未创建 + * + * BeanFactoryPostProcessor原理: 先根据BeanFactory找到当前Class的组件id,然后排序,然后根据组件id找到组件对象,然后进行回调 + * 1)、ioc容器创建对象 + * 2)、invokeBeanFactoryPostProcessors(beanFactory); + * 如何找到所有的BeanFactoryPostProcessor并执行他们的方法; + * 1)、直接在BeanFactory中找到所有类型是BeanFactoryPostProcessor的组件,并执行他们的方法 + * 2)、在onRefresh() 初始化创建其他组件前面执行 + * + * 2、BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor + * postProcessBeanDefinitionRegistry(); + * 在所有bean定义(BeanDefinition)将要被加载,bean实例还未创建的; + * + * 优先于BeanFactoryPostProcessor执行; + * 利用BeanDefinitionRegistryPostProcessor给容器中再额外添加一些组件; + * + * 原理: 先根据BeanFactory找到当前Class的组件id,然后排序,然后根据组件id找到组件对象,然后进行回调 + * 1)、ioc创建对象 + * 2)、refresh()-》invokeBeanFactoryPostProcessors(beanFactory); + * 3)、从容器中获取到所有的BeanDefinitionRegistryPostProcessor组件。 + * 1、依次触发所有的postProcessBeanDefinitionRegistry()方法 + * 2、再来触发postProcessBeanFactory()方法BeanFactoryPostProcessor; + * + * 4)、再来从容器中找到BeanFactoryPostProcessor组件;然后依次触发postProcessBeanFactory()方法 + * + * 3、ApplicationListener:监听容器中发布的事件。事件驱动模型开发; + * public interface ApplicationListener + * 监听 ApplicationEvent 及其下面的子事件; + * + * 事件监听开发步骤: + * 1)、监听类 + * 1)、一个监听器(ApplicationListener实现类)来监听某个事件(ApplicationEvent及其子类) + * 2)、@EventListener 注解 + * 原理:使用EventListenerMethodProcessor处理器来解析方法上的@EventListener; + * 2)、把监听器加入到容器; + * 3)、只要容器中有相关事件的发布,我们就能监听到这个事件; + * ContextRefreshedEvent:容器刷新完成(所有bean都完全创建)会发布这个事件; + * ContextClosedEvent:关闭容器会发布这个事件; + * 4)、发布一个事件: + * applicationContext.publishEvent(); + * + * 4、ApplicationListener原理: + * ContextRefreshedEvent、IOCTest_Ext$1[source=我发布的事件]、ContextClosedEvent; + * 1)、ContextRefreshedEvent事件: + * 1)、容器创建对象:refresh(); + * 2)、finishRefresh();容器刷新完成会发布ContextRefreshedEvent事件 + * 3)、publishEvent【事件发布流程】 + * 【事件发布流程】: + * 1)、publishEvent(new ContextRefreshedEvent(this)); + * 1)、获取事件的多播器(派发器):getApplicationEventMulticaster() + * 2)、multicastEvent()派发事件: + * 3)、获取到所有的ApplicationListener; + * for (final ApplicationListener listener : getApplicationListeners(event, type)) { + * 1)、如果有Executor,可以支持使用Executor进行异步派发; + * Executor executor = getTaskExecutor(); + * 2)、否则,同步的方式直接执行listener方法;invokeListener(listener, event); + * 拿到listener回调onApplicationEvent方法; + * 2)、自己发布事件; + * 3)、容器关闭会发布ContextClosedEvent事件 + * + * + * 【事件多播器(派发器)怎么拿到的?】: + * getApplicationEventMulticaster() + * 1)、容器创建对象:refresh(); + * 2)、初始化派发器:initApplicationEventMulticaster();初始化ApplicationEventMulticaster; + * 1)、先去容器中找有没有id=“applicationEventMulticaster”的组件; + * 2)、如果没有this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory); + * 并且加入到容器中,我们就可以在其他组件要派发事件,自动注入这个applicationEventMulticaster; + * + * 【容器中有哪些监听器】 + * 1)、容器创建对象:refresh(); + * 2)、注册监听器:registerListeners(); + * 从容器中拿到所有的监听器,把他们注册到applicationEventMulticaster中; + * String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false); + * //将listener注册到ApplicationEventMulticaster中 + * getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName); + * + * 为什么加上@EventListener注解就可以监听到事件?看注解里面的注释 + * 主要是EventListenerMethodProcessor搞事,在afterSingletonsInstantiated()里面会将支持直接监听的方法, + * 转成ApplicationListenerMethodAdapter,并且adapter记录了监听类(UserService)和方法(listen) + * 事件推送时,会先掉ApplicationListenerMethodAdapter,再反射调用监听类的方法 + * 5)、SmartInitializingSingleton 原理:->afterSingletonsInstantiated(); + * 1)、ioc容器创建对象并refresh(); + * 2)、finishBeanFactoryInitialization(beanFactory);初始化剩下的单实例bean; + * 1)、先创建所有的单实例bean;getBean(); + * 2)、获取所有创建好的单实例bean,判断是否是SmartInitializingSingleton类型的; + * 如果是就调用afterSingletonsInstantiated(); + * + * + * + * @author lastwhisper + * @date 2020/2/18 + */ +@Configuration +@ComponentScan("cn.lastwhisper.spring.ext") +public class ExtConfig { + + @Bean + public Blue blue() { + return new Blue(); + } + +} diff --git a/spring-annotation/ext/src/main/java/cn/lastwhisper/spring/ext/MyApplicationListener.java b/spring-annotation/ext/src/main/java/cn/lastwhisper/spring/ext/MyApplicationListener.java new file mode 100644 index 00000000..f25bf024 --- /dev/null +++ b/spring-annotation/ext/src/main/java/cn/lastwhisper/spring/ext/MyApplicationListener.java @@ -0,0 +1,20 @@ +package cn.lastwhisper.spring.ext; + +import org.springframework.context.ApplicationEvent; +import org.springframework.context.ApplicationListener; +import org.springframework.stereotype.Component; + +@Component +public class MyApplicationListener implements ApplicationListener { + + /** + * 当容器中发布此事件以后,方法触发 + * @param event 事件 + */ + @Override + public void onApplicationEvent(ApplicationEvent event) { + // TODO Auto-generated method stub + System.out.println("收到事件:"+event); + } + +} \ No newline at end of file diff --git a/spring-annotation/ext/src/main/java/cn/lastwhisper/spring/ext/MyBeanDefinitionRegistryPostProcessor.java b/spring-annotation/ext/src/main/java/cn/lastwhisper/spring/ext/MyBeanDefinitionRegistryPostProcessor.java new file mode 100644 index 00000000..022e91c9 --- /dev/null +++ b/spring-annotation/ext/src/main/java/cn/lastwhisper/spring/ext/MyBeanDefinitionRegistryPostProcessor.java @@ -0,0 +1,47 @@ +package cn.lastwhisper.spring.ext; + +import cn.lastwhisper.spring.ext.bean.Blue; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.BeanDefinitionHolder; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.support.*; +import org.springframework.stereotype.Component; + +import static org.springframework.beans.factory.config.AutowireCapableBeanFactory.AUTOWIRE_BY_NAME; + + +@Component +public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor { + + @Override + public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { + + System.out.println("MyBeanDefinitionRegistryPostProcessor...bean的数量:" + beanFactory.getBeanDefinitionCount()); + } + + /** + * BeanDefinitionRegistry Bean定义信息的保存中心,以后BeanFactory就是按照BeanDefinitionRegistry里面保存的每一个bean定义信息创建bean实例 + */ + @Override + public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { + + System.out.println("postProcessBeanDefinitionRegistry...bean的数量:" + registry.getBeanDefinitionCount()); + //RootBeanDefinition beanDefinition = new RootBeanDefinition(Blue.class); + BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(Blue.class); + + //设置属性值 + builder.addPropertyValue("name","i am blue"); + //设置可通过@Autowire注解引用 + builder.setAutowireMode(AUTOWIRE_BY_NAME); + + AbstractBeanDefinition beanDefinition = builder.getBeanDefinition(); + +// registry.registerBeanDefinition("hello", beanDefinition); + + // 看springcloud openfeign源码,feign接口怎么在容器中声明的 + BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, Blue.class.getName(), + new String[] { "hello" }); + BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry); + } + +} \ No newline at end of file diff --git a/spring-annotation/ext/src/main/java/cn/lastwhisper/spring/ext/MyBeanFactoryPostProcessor.java b/spring-annotation/ext/src/main/java/cn/lastwhisper/spring/ext/MyBeanFactoryPostProcessor.java new file mode 100644 index 00000000..4b166bc0 --- /dev/null +++ b/spring-annotation/ext/src/main/java/cn/lastwhisper/spring/ext/MyBeanFactoryPostProcessor.java @@ -0,0 +1,27 @@ +package cn.lastwhisper.spring.ext; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.BeanFactoryPostProcessor; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.stereotype.Component; + +import java.util.Arrays; + +/** + * @author lastwhisper + * @date 2020/2/18 + */ +@Component +public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor { + + @Override + public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { + System.out.println("MyBeanFactoryPostProcessor...postProcessBeanFactory..."); + int count = beanFactory.getBeanDefinitionCount(); + String[] names = beanFactory.getBeanDefinitionNames(); + System.out.println("当前BeanFactory中有" + count + " 个Bean。" + " Names:" + Arrays.asList(names)); + + + } + +} \ No newline at end of file diff --git a/spring-annotation/ext/src/main/java/cn/lastwhisper/spring/ext/UserService.java b/spring-annotation/ext/src/main/java/cn/lastwhisper/spring/ext/UserService.java new file mode 100644 index 00000000..ca009639 --- /dev/null +++ b/spring-annotation/ext/src/main/java/cn/lastwhisper/spring/ext/UserService.java @@ -0,0 +1,21 @@ +package cn.lastwhisper.spring.ext; + +import org.springframework.context.ApplicationEvent; +import org.springframework.context.event.EventListener; +import org.springframework.stereotype.Service; + +@Service +public class UserService { + + /** + * https://docs.spring.io/spring/docs/5.1.8.RELEASE/spring-framework-reference/core.html#context-functionality-events + * 使用@EventListener注解ApplicationListener实现 + * + * + */ + @EventListener(classes = {ApplicationEvent.class}) + public void listen(ApplicationEvent event) { + System.out.println("UserService。。监听到的事件:" + event); + } + +} \ No newline at end of file diff --git a/spring-annotation/ext/src/main/java/cn/lastwhisper/spring/ext/bean/Blue.java b/spring-annotation/ext/src/main/java/cn/lastwhisper/spring/ext/bean/Blue.java new file mode 100644 index 00000000..5e897338 --- /dev/null +++ b/spring-annotation/ext/src/main/java/cn/lastwhisper/spring/ext/bean/Blue.java @@ -0,0 +1,18 @@ +package cn.lastwhisper.spring.ext.bean; + +public class Blue { + + private String name; + + public Blue() { + System.out.println("blue...constructor"); + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} \ No newline at end of file diff --git a/spring-annotation/ext/src/main/resources/note.txt b/spring-annotation/ext/src/main/resources/note.txt new file mode 100644 index 00000000..4f8874ed --- /dev/null +++ b/spring-annotation/ext/src/main/resources/note.txt @@ -0,0 +1,200 @@ +Spring容器的refresh()【创建刷新】; +1、prepareRefresh()刷新前的预处理; + 1)、initPropertySources()初始化一些属性设置;子容器(子类)自定义个性化的属性设置方法; + 2)、getEnvironment().validateRequiredProperties();检验属性的合法等 + 3)、earlyApplicationEvents= new LinkedHashSet();保存容器中的一些早期的事件; +2、obtainFreshBeanFactory();获取一个初始化的BeanFactory; + 1)、refreshBeanFactory();刷新【创建】BeanFactory; + 创建了一个this.beanFactory = new DefaultListableBeanFactory(); + 设置SerializationId; + 2)、getBeanFactory();返回刚才refreshBeanFactory()(GenericApplicationContext)创建的BeanFactory对象; + 3)、将创建的BeanFactory【DefaultListableBeanFactory】返回; +3、prepareBeanFactory(beanFactory);BeanFactory的预准备工作(对BeanFactory进行一些默认设置); + 1)、设置BeanFactory的类加载器、表达式解析器... + 2)、添加部分BeanPostProcessor【ApplicationContextAwareProcessor】 + 3)、设置忽略的自动装配的接口EnvironmentAware、EmbeddedValueResolverAware; + 接口ASrv,Aimpl实现ASrv,Aimpl忽略自动注入和ASrv中的setter方法入参相同的类 + 4)、注册可以解析的自动装配;我们能直接在任何组件中自动注入: + BeanFactory、ResourceLoader、ApplicationEventPublisher、ApplicationContext + 5)、添加ApplicationListener检测后置处理器【ApplicationListenerDetector】, + 6)、添加类加载时期织入后置处理器【LoadTimeWeaverAwareProcessor】, + 7)、给BeanFactory中注册一些默认的组件; + environment【ConfigurableEnvironment】、 + systemProperties【Map】、 + systemEnvironment【Map】 +4、postProcessBeanFactory(beanFactory);BeanFactory准备工作完成后进行的后置处理工作; + 1)、允许AbstractApplicationContext的子类通过重写这个方法来在BeanFactory创建并预准备完成以后做进一步的设置 +======================以上是BeanFactory的创建及预准备工作================================== +5、invokeBeanFactoryPostProcessors(beanFactory);执行BeanFactoryPostProcessor及其接口的方法; + BeanFactoryPostProcessor:BeanFactory的后置处理器。在BeanFactory标准初始化之后执行的; + 两个接口:BeanFactoryPostProcessor、BeanDefinitionRegistryPostProcessor + 1)、执行BeanFactoryPostProcessor的方法; + 先执行BeanDefinitionRegistryPostProcessor + 1)、获取所有的BeanDefinitionRegistryPostProcessor; + 2)、先执行实现了PriorityOrdered优先级接口的BeanDefinitionRegistryPostProcessor、 + postProcessor.postProcessBeanDefinitionRegistry(registry) + 3)、再执行实现了Ordered顺序接口的BeanDefinitionRegistryPostProcessor; + postProcessor.postProcessBeanDefinitionRegistry(registry) + 4)、最后执行没有实现任何优先级或者是顺序接口的BeanDefinitionRegistryPostProcessors; + postProcessor.postProcessBeanDefinitionRegistry(registry) + + 再执行BeanFactoryPostProcessor的方法 + 1)、获取所有的BeanFactoryPostProcessor + 2)、先执行实现了PriorityOrdered优先级接口的BeanFactoryPostProcessor、 + postProcessor.postProcessBeanFactory() + 3)、再执行实现了Ordered顺序接口的BeanFactoryPostProcessor; + postProcessor.postProcessBeanFactory() + 4)、最后执行没有实现任何优先级或者是顺序接口的BeanFactoryPostProcessor; + postProcessor.postProcessBeanFactory() +6、registerBeanPostProcessors(beanFactory);注册BeanPostProcessor拦截bean的创建过程 + 不同接口类型的BeanPostProcessor;在Bean创建前后的执行时机是不一样的 + BeanPostProcessor、 + DestructionAwareBeanPostProcessor、 + InstantiationAwareBeanPostProcessor、 + SmartInstantiationAwareBeanPostProcessor、 + MergedBeanDefinitionPostProcessor【internalPostProcessors】、 + + 1)、获取所有的 BeanPostProcessor;后置处理器都默认可以通过PriorityOrdered、Ordered接口来执行优先级 + 2)、先注册PriorityOrdered优先级接口的BeanPostProcessor; + 把每一个BeanPostProcessor添加到BeanFactory中 + 3)、再注册Ordered接口的BeanPostProcessor + 4)、最后注册没有实现任何优先级接口的BeanPostProcessor + 5)、最终注册MergedBeanDefinitionPostProcessor; + 6)、注册一个ApplicationListenerDetector;来在Bean创建完成后检查是否是ApplicationListener,如果是 + applicationContext.addApplicationListener((ApplicationListener) bean); + + 疑惑点 + int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length; + +7、initMessageSource();初始化MessageSource组件(做国际化功能,消息绑定,消息解析); + 1)、获取BeanFactory + 2)、看容器中是否有id为messageSource的,类型是MessageSource的组件 + 如果有赋值给messageSource,如果没有自己创建一个DelegatingMessageSource; + MessageSource:取出国际化配置文件中的某个key的值;能按照区域信息获取; + 3)、把创建好的MessageSource注册在容器中,以后获取国际化配置文件的值的时候,可以自动注入MessageSource; + beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource); + MessageSource.getMessage(String code, Object[] args, String defaultMessage, Locale locale); +8、initApplicationEventMulticaster();初始化事件派发器; + 1)、获取BeanFactory + 2)、从BeanFactory中获取applicationEventMulticaster的ApplicationEventMulticaster; + 3)、如果上一步没有配置;创建一个SimpleApplicationEventMulticaster + 4)、将创建的ApplicationEventMulticaster添加到BeanFactory中,以后其他组件直接自动注入 +9、onRefresh();留给子容器(子类) + 1、bstractApplicationContext的子类重写这个方法,在容器刷新的时候可以自定义逻辑; +10、registerListeners();给容器中将所有项目里面的ApplicationListener注册进来; + 1、从容器中拿到所有的ApplicationListener + 2、将每个监听器添加到事件派发器中; + getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName); + 3、派发之前步骤产生的事件this.earlyApplicationEvents; +11、finishBeanFactoryInitialization(beanFactory);主要功能:初始化所有剩下的单实例bean; + beanFactory.preInstantiateSingletons();初始化后剩下的单实例bean + 1、第一个for循环 + // Trigger initialization of all non-lazy singleton beans... + 1)、获取容器中的所有Bean,依次进行初始化和创建对象 + 2)、获取Bean的定义信息;RootBeanDefinition + 3)、Bean不是抽象的,是单实例的,不是懒加载; + 1)、判断是否实现FactoryBean接口,利用getObject创建对象 + 2)、不是FactoryBean,利用getBean(beanName)创建对象 + 使用条件断点beanName.equals("blue") + 0、getBean(beanName); ioc.getBean(); + 1、doGetBean(name, null, null, false); + 2、先获取缓存中保存的单实例Bean。如果能获取到说明这个Bean之前被创建过(所有创建过的单实例Bean都会被缓存起来) + 从private final Map singletonObjects = new ConcurrentHashMap(256);获取的 + 3、缓存中获取不到,开始Bean的创建对象流程; + 4、标记当前bean已经被创建(markBeanAsCreated(beanName)),帮助BeanFactory优化其缓存,以重复创建指定的Bean + 5、获取Bean的定义信息(getMergedLocalBeanDefinition(beanName)) + 6、循环依赖的解决应该就在这里————【获取当前Bean依赖的其他Bean(mbd.getDependsOn());如果有按照getBean()把依赖的Bean先创建出来;】 + 7、启动单实例Bean的创建流程; + 1)、createBean(beanName, mbd, args); + 2)、Object bean = resolveBeforeInstantiation(beanName, mbdToUse);给BeanPostProcessor返回代理对象的机会; + 【InstantiationAwareBeanPostProcessor】:提前执行,在Bean创建之前执行; + 先触发:postProcessBeforeInstantiation(); + 如果有返回值:触发postProcessAfterInitialization(); + 3)、如果前面的InstantiationAwareBeanPostProcessor没有返回代理对象;调用4) + 4)、Object beanInstance = doCreateBean(beanName, mbdToUse, args);创建Bean + 1)、【创建Bean实例】;createBeanInstance(beanName, mbd, args); + 利用工厂方法或者对象的构造器创建出Bean实例; + 2)、applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName); + 调用MergedBeanDefinitionPostProcessor的postProcessMergedBeanDefinition(mbd, beanType, beanName); + 3)、【Bean属性赋值】populateBean(beanName, mbd, instanceWrapper); + 赋值之前: + 1)、拿到InstantiationAwareBeanPostProcessor后置处理器; + postProcessAfterInstantiation(); + 2)、拿到InstantiationAwareBeanPostProcessor后置处理器; + postProcessPropertyValues(); + =====赋值之前:=== + 3)、应用Bean属性的值;为属性利用setter方法等进行赋值; + applyPropertyValues(beanName, mbd, bw, pvs); + 4)、【Bean初始化】initializeBean(beanName, exposedObject, mbd); + 1)、【执行Aware接口方法】invokeAwareMethods(beanName, bean);执行xxxAware接口的方法 + BeanNameAware\BeanClassLoaderAware\BeanFactoryAware + 2)、【执行后置处理器初始化之前】applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); + BeanPostProcessor.postProcessBeforeInitialization(); + 3)、【执行初始化方法】invokeInitMethods(beanName, wrappedBean, mbd); + 1)、是否是InitializingBean接口的实现;执行接口规定的初始化; + 2)、是否有自定义初始化方法; + 4)、【执行后置处理器初始化之后】applyBeanPostProcessorsAfterInitialization + BeanPostProcessor.postProcessAfterInitialization(); + 5)、注册Bean的销毁方法; + registerDisposableBeanIfNecessary(beanName, bean, mbd); + 5)、将创建的Bean添加到缓存中(addSingleton(String beanName, Object singletonObject)) + ioc容器就是这些Map;很多的Map里面保存了单实例Bean,环境信息。。。。; + 2、第二个for循环 + 所有Bean都利用getBean创建完成以后; + 检查所有的Bean是否是SmartInitializingSingleton接口的;如果是;就执行afterSingletonsInstantiated(); + +12、finishRefresh();完成BeanFactory的初始化创建工作;IOC容器就创建完成; + 1)、initLifecycleProcessor();初始化和生命周期有关的后置处理器;LifecycleProcessor + 默认从容器中找是否有lifecycleProcessor的组件【LifecycleProcessor】; + 如果没有new DefaultLifecycleProcessor()加入到容器; + + 写一个LifecycleProcessor的实现类,可以在BeanFactory + void onRefresh(); + void onClose(); + 2)、getLifecycleProcessor().onRefresh(); + 拿到前面定义的生命周期处理器(BeanFactory);回调onRefresh(); + 3)、publishEvent(new ContextRefreshedEvent(this));发布容器刷新完成事件; + 4)、LiveBeansView.registerApplicationContext(this); + + ======总结=========== + 1)、Spring容器在启动的时候,先会保存所有注册进来的Bean的定义信息; + 1)、xml注册bean; + 2)、注解注册Bean;@Service、@Component、@Bean、xxx + 2)、Spring容器会合适的时机创建这些Bean + 1)、用到这个bean的时候;利用getBean创建bean;创建好以后保存在容器中; + 2)、统一创建剩下所有的bean的时候;finishBeanFactoryInitialization(); + 3)、后置处理器;BeanPostProcessor + 1)、每一个bean创建完成,都会使用各种后置处理器进行处理;来增强bean的功能; + AutowiredAnnotationBeanPostProcessor:处理自动注入 + AnnotationAwareAspectJAutoProxyCreator:来做AOP功能; + xxx.... + 增强的功能注解: + AsyncAnnotationBeanPostProcessor + .... + 4)、事件驱动模型; + ApplicationListener;事件监听; + ApplicationEventMulticaster;事件派发: + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spring-annotation/ext/src/test/java/cn/lastwhisper/spring/ext/test/IOCTest_EXT.java b/spring-annotation/ext/src/test/java/cn/lastwhisper/spring/ext/test/IOCTest_EXT.java new file mode 100644 index 00000000..af4b6bfc --- /dev/null +++ b/spring-annotation/ext/src/test/java/cn/lastwhisper/spring/ext/test/IOCTest_EXT.java @@ -0,0 +1,34 @@ +package cn.lastwhisper.spring.ext.test; + +import cn.lastwhisper.spring.ext.ExtConfig; +import cn.lastwhisper.spring.ext.bean.Blue; +import org.junit.Test; +import org.springframework.context.ApplicationEvent; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; + +/** + * @author lastwhisper + */ +public class IOCTest_EXT { + + /** + * 测试Spring事件 + * 查询Spring容器启动流程 + * + * @param + * @return void + */ + @Test + public void test01() { + AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(ExtConfig.class); + System.out.println("容器初始化..."); + + applicationContext.publishEvent(new ApplicationEvent("发布事件"){}); + + Blue blue = (Blue) applicationContext.getBean("hello"); + System.out.println("blue:"+blue); + + applicationContext.close(); + } + +} diff --git a/spring-annotation/lifecycle/pom.xml b/spring-annotation/lifecycle/pom.xml deleted file mode 100644 index e6fb7f03..00000000 --- a/spring-annotation/lifecycle/pom.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - spring-annotation - cn.lastwhisper - 1.0-SNAPSHOT - - 4.0.0 - - cn.lastwhisper - lifecycle - - - \ No newline at end of file diff --git a/spring-annotation/lifecycle/src/main/java/cn/lastwhisper/lifecycle/bean/Car.java b/spring-annotation/lifecycle/src/main/java/cn/lastwhisper/lifecycle/bean/Car.java deleted file mode 100644 index fd8b4712..00000000 --- a/spring-annotation/lifecycle/src/main/java/cn/lastwhisper/lifecycle/bean/Car.java +++ /dev/null @@ -1,19 +0,0 @@ -package cn.lastwhisper.lifecycle.bean; - -/** - * @author lastwhisper - */ -public class Car { - - public Car() { - System.out.println("car constructor..."); - } - // 初始化资源线程池、连接池等 - public void init() { - System.out.println("car init..."); - } - // 释放资源 - public void destroy() { - System.out.println("car destroy..."); - } -} diff --git a/spring-annotation/lifecycle/src/main/java/cn/lastwhisper/lifecycle/bean/Cat.java b/spring-annotation/lifecycle/src/main/java/cn/lastwhisper/lifecycle/bean/Cat.java deleted file mode 100644 index 9316efac..00000000 --- a/spring-annotation/lifecycle/src/main/java/cn/lastwhisper/lifecycle/bean/Cat.java +++ /dev/null @@ -1,26 +0,0 @@ -package cn.lastwhisper.lifecycle.bean; - -import org.springframework.beans.factory.DisposableBean; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.stereotype.Component; - -/** - * @author lastwhisper - */ -@Component -public class Cat implements InitializingBean, DisposableBean { - - public Cat() { - System.out.println("cat constructor..."); - } - // 对象创建完成,并赋值之后调用 - public void afterPropertiesSet() throws Exception { - System.out.println("cat afterPropertiesSet..."); - } - // 容器销毁bean时调用 - public void destroy() throws Exception { - System.out.println("cat destroy..."); - } - - -} diff --git a/spring-annotation/lifecycle/src/main/java/cn/lastwhisper/lifecycle/bean/Dog.java b/spring-annotation/lifecycle/src/main/java/cn/lastwhisper/lifecycle/bean/Dog.java deleted file mode 100644 index 1f73b040..00000000 --- a/spring-annotation/lifecycle/src/main/java/cn/lastwhisper/lifecycle/bean/Dog.java +++ /dev/null @@ -1,38 +0,0 @@ -package cn.lastwhisper.lifecycle.bean; - -import org.springframework.beans.BeansException; -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationContextAware; -import org.springframework.stereotype.Component; - -import javax.annotation.PostConstruct; -import javax.annotation.PreDestroy; - -/** - * @author lastwhisper - */ -@Component -public class Dog implements ApplicationContextAware { - private ApplicationContext applicationContext; - - public Dog() { - System.out.println("dog constructor..."); - } - - // 对象创建完成,并赋值之后调用 - @PostConstruct - public void init() throws Exception { - System.out.println("dog @PostConstruct..."); - } - - // 容器销毁bean时调用 - @PreDestroy - public void destroy() throws Exception { - System.out.println("dog @PreDestroy..."); - } - - public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { - this.applicationContext = applicationContext; - } - -} diff --git a/spring-annotation/lifecycle/src/main/java/cn/lastwhisper/lifecycle/bean/MyBeanPostProcessor.java b/spring-annotation/lifecycle/src/main/java/cn/lastwhisper/lifecycle/bean/MyBeanPostProcessor.java deleted file mode 100644 index 12841c41..00000000 --- a/spring-annotation/lifecycle/src/main/java/cn/lastwhisper/lifecycle/bean/MyBeanPostProcessor.java +++ /dev/null @@ -1,35 +0,0 @@ -package cn.lastwhisper.lifecycle.bean; - -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.config.BeanPostProcessor; -import org.springframework.stereotype.Component; - -/** - * @author lastwhisper - */ -@Component -public class MyBeanPostProcessor implements BeanPostProcessor { - /** - * 在对象任何初始化之前调用 - * - * @param bean - * @param beanName - * @return java.lang.Object - */ - public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { - System.out.println("postProcessBeforeInitialization..." + beanName + "..." + bean); - return bean; - } - - /** - * 在对象初始化之后调用 - * - * @param bean - * @param beanName - * @return java.lang.Object - */ - public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { - System.out.println("postProcessAfterInitialization..." + beanName + "..." + bean); - return bean; - } -} diff --git a/spring-annotation/lifecycle/src/main/java/cn/lastwhisper/lifecycle/config/MainConfigOfLifeCycle.java b/spring-annotation/lifecycle/src/main/java/cn/lastwhisper/lifecycle/config/MainConfigOfLifeCycle.java deleted file mode 100644 index 6fab747c..00000000 --- a/spring-annotation/lifecycle/src/main/java/cn/lastwhisper/lifecycle/config/MainConfigOfLifeCycle.java +++ /dev/null @@ -1,54 +0,0 @@ -package cn.lastwhisper.lifecycle.config; - -import cn.lastwhisper.lifecycle.bean.Car; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Scope; - -/** - * 容器管理bean的生命周期,容器在bean进行到当前生命周期时,调用自定义的初始化与销毁方法。 - * - * bean的生命周期:创建——》初始化——》销毁 - * 创建(构造器): - * 单实例:容器启动时进行创建对象 - * 多实例:容器启动时并不会创建对象,使用时才会创建 - * 初始化: - * 对象创建完成,并赋值好,进行初始化 - * 销毁 - * 单实例:容器关闭时进行销毁 - * 多实例:容器不会管理多实例bean,不会调用销毁方法 - * - * 1)指定初始化和销毁方法 - * 通过@Bean(initMethod = "init", destroyMethod = "destroy")指定初始化和销毁方法 - * 相当于xml中的配置:init-method="init" destroy-method="destroy" - * 2)通过bean实现InitializingBean(定义初始化逻辑)、DisposableBean(定义销毁逻辑) - * 3)JSR250规范 - * *@PostConstruct:在bean创建完成并且属性赋值完成,来执行初始化方法 - * *@PreDestroy:在容器销毁bean之前调用 - * 4)BeanPostProcessor:bean的后置处理器,在bean初始化前后进行处理 - * postProcessBeforeInitialization:在对象任何初始化(initMethod、afterPropertiesSet)之前调用 - * postProcessAfterInitialization:在对象初始化之后调用 - * BeanPostProcessor原理: - * AbstractAutowireCapableBeanFactory.doCreateBean{ - * populateBean(beanName, mbd, instanceWrapper); // 给对象中的字段赋值 - * initializeBean{ - * applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);// 调用postProcessBeforeInitialization处理器 - * invokeInitMethods(beanName, wrappedBean, mbd); // 调用对象的初始化方法 - * applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);//调用postProcessAfterInitialization处理器 - * } - * } - * - * @author lastwhisper - */ -@ComponentScan("cn.lastwhisper.lifecycle.bean") -@Configuration -public class MainConfigOfLifeCycle { - - @Scope("singleton") - //@Scope("prototype") - @Bean(initMethod = "init", destroyMethod = "destroy") - public Car car() { - return new Car(); - } -} diff --git a/spring-annotation/lifecycle/src/test/java/cn/lastwhisper/lifecycle/test/IOCTest_LifeCycle.java b/spring-annotation/lifecycle/src/test/java/cn/lastwhisper/lifecycle/test/IOCTest_LifeCycle.java deleted file mode 100644 index ac07e9ae..00000000 --- a/spring-annotation/lifecycle/src/test/java/cn/lastwhisper/lifecycle/test/IOCTest_LifeCycle.java +++ /dev/null @@ -1,22 +0,0 @@ -package cn.lastwhisper.lifecycle.test; - -import cn.lastwhisper.lifecycle.config.MainConfigOfLifeCycle; -import org.junit.Test; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; - -/** - * @author lastwhisper - */ -public class IOCTest_LifeCycle { - @Test - public void test01() { - // 初始化容器 - AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class); - System.out.println("bean容器初始化..."); - //applicationContext.getBean("car"); - //applicationContext.getBean("cat"); - //applicationContext.getBean("dog"); - // 关闭容器 - applicationContext.close(); - } -} diff --git a/spring-annotation/liftcycle/pom.xml b/spring-annotation/liftcycle/pom.xml new file mode 100644 index 00000000..b75828be --- /dev/null +++ b/spring-annotation/liftcycle/pom.xml @@ -0,0 +1,33 @@ + + + 4.0.0 + + liftcycle + cn.lastwhisper + 0.0.1-SNAPSHOT + + + 8 + 8 + + + + + + org.springframework + spring-context + 4.3.12.RELEASE + + + + junit + junit + 4.12 + test + + + + + \ No newline at end of file diff --git a/spring-annotation/liftcycle/src/main/java/cn/cunchang/LifeCycleBean.java b/spring-annotation/liftcycle/src/main/java/cn/cunchang/LifeCycleBean.java new file mode 100644 index 00000000..c516a783 --- /dev/null +++ b/spring-annotation/liftcycle/src/main/java/cn/cunchang/LifeCycleBean.java @@ -0,0 +1,72 @@ +package cn.cunchang; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.BeanFactoryAware; +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; + +/** + * @author cunchang + * @date 2022/5/23 11:25 AM + */ +public class LifeCycleBean implements BeanFactoryAware, ApplicationContextAware, InitializingBean, DisposableBean { + + @Override + public void setBeanFactory(BeanFactory beanFactory) throws BeansException { + System.out.println("==== 1.BeanFactoryAware.setBeanFactory: " + beanFactory); + } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + System.out.println("==== 2.ApplicationContextAware.setApplicationContext: " + applicationContext); + } + + // ==== 4.BeanPostProcessor.postProcessBeforeInitialization + + /** + * 对象创建完成,并赋值之后调用 + * 由CommonAnnotationBeanPostProcessor处理, 相当于xml中的init-method配置 + */ + @PostConstruct + public void initBean() { + System.out.println("==== 4.CommonAnnotationBeanPostProcessor.postConstruct"); + } + + // 对象创建完成,并赋值之后调用 + @Override + public void afterPropertiesSet() throws Exception { + System.out.println("==== 5.InitializingBean.afterPropertiesSet"); + } + + public void initMethod() { + System.out.println("==== 6.init-method"); + } + + // ==== 8.BeanPostProcessor.postProcessAfterInitialization + + /** + * 容器销毁bean时调用 + * 由CommonAnnotationBeanPostProcessor处理, 相当于xml中的destroy-method配置 + */ + @PreDestroy + public void destroyBean() { + System.out.println("==== 8.CommonAnnotationBeanPostProcessor.preDestroy"); + } + + // 容器销毁bean时调用 + @Override + public void destroy() throws Exception { + System.out.println("==== 9.DisposableBean.destroy"); + } + + public void destroyMethod() { + System.out.println("==== 10.destroy-method"); + } + +} \ No newline at end of file diff --git a/spring-annotation/liftcycle/src/main/java/cn/cunchang/MyBeanPostProcessor.java b/spring-annotation/liftcycle/src/main/java/cn/cunchang/MyBeanPostProcessor.java new file mode 100644 index 00000000..49b8605e --- /dev/null +++ b/spring-annotation/liftcycle/src/main/java/cn/cunchang/MyBeanPostProcessor.java @@ -0,0 +1,44 @@ +package cn.cunchang; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.stereotype.Service; + +/** + * @author cunchang + * @date 2022/5/23 11:25 AM + */ +@Service +public class MyBeanPostProcessor implements BeanPostProcessor { + + /** + * 在对象任何初始化之前调用 + * @param bean ioc容器中的每一个Bean对象 + * @param beanName Bean对象对应的name + * @return java.lang.Object + * @throws BeansException + */ + @Override + public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { + if (bean instanceof LifeCycleBean) { + System.out.println("==== 3.BeanPostProcessor.postProcessBeforeInitialization: " + beanName); + } + return bean; + } + + /** + * 在对象初始化之后调用 + * + * @param bean ioc容器中的每一个Bean对象 + * @param beanName Bean对象对应的name + * @return java.lang.Object + */ + @Override + public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { + if (bean instanceof LifeCycleBean) { + System.out.println("==== 7.BeanPostProcessor.postProcessAfterInitialization: " + beanName); + } + return bean; + } + +} \ No newline at end of file diff --git a/spring-annotation/liftcycle/src/main/java/cn/cunchang/config/MainConfigOfLifeCycle.java b/spring-annotation/liftcycle/src/main/java/cn/cunchang/config/MainConfigOfLifeCycle.java new file mode 100644 index 00000000..c8e39afa --- /dev/null +++ b/spring-annotation/liftcycle/src/main/java/cn/cunchang/config/MainConfigOfLifeCycle.java @@ -0,0 +1,67 @@ +package cn.cunchang.config; + +import cn.cunchang.LifeCycleBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Scope; + +/** + * 容器管理bean的生命周期,容器在bean进行到当前生命周期时,调用自定义的初始化与销毁方法。 + * + * bean的生命周期:创建——》初始化——》销毁 + * 创建(构造器): + * 单实例:容器启动时进行创建对象 + * 多实例:容器启动时并不会创建对象,使用时才会创建 + * 初始化: + * 对象创建完成,并赋值好,进行初始化 + * 销毁 + * 单实例:容器关闭时进行销毁 + * 多实例:容器不会管理多实例bean,不会调用销毁方法 + * + * 1)指定初始化和销毁方法 + * 通过@Bean(initMethod = "init", destroyMethod = "destroy")指定初始化和销毁方法 + * 相当于xml中的配置:init-method="init" destroy-method="destroy" + * 2)通过bean实现InitializingBean(定义初始化逻辑)、DisposableBean(定义销毁逻辑) + * + * 3)JSR250规 + * *@PostConstruct:在bean创建完成并且属性赋值完成,来执行初始化方法 + * *@PreDestroy:在容器销毁bean之前调用 + * 4)BeanPostProcessor:对所有bean的后置处理器,在bean初始化前后进行处理 + * 该接口有两个方法: + * postProcessBeforeInitialization:在对象创建之后,任何初始化(initMethod、afterPropertiesSet)之前调用 + * postProcessAfterInitialization:在对象初始化之后调用 + * + * BeanPostProcessor原理: + * AbstractAutowireCapableBeanFactory.doCreateBean{ + * populateBean(beanName, mbd, instanceWrapper); // 给Bean对象中的成员变量赋值 + * initializeBean{ + * applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);// 调用postProcessBeforeInitialization处理器,一旦返回null就结束 + * invokeInitMethods(beanName, wrappedBean, mbd); // 调用对象的初始化方法 + * applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);//调用postProcessAfterInitialization处理器,一旦返回null就结束 + * } + * } + * + * Spring底层BeanPostProcessor的使用: + * AsyncAnnotationBeanPostProcessor 处理@Async注解的方法 + * ApplicationContextAwareProcessor 处理实现ApplicationContextAware的类 + * BeanValidationPostProcessor 处理JSR-303数据校验 + * InitDestroyAnnotationBeanPostProcessor 处理@PostConstruct和@PreDestroy注解 + * CommonAnnotationBeanPostProcessor 初始化时,设置@PostConstruct和@PreDestroy为初始化和销毁注解 + * AutowiredAnnotationBeanPostProcessor 处理@Autowire注解 + * + * @author lastwhisper + */ +@ComponentScan("cn.cunchang") +@Configuration +public class MainConfigOfLifeCycle { + + + //@Scope("prototype") + @Scope("singleton") + @Bean(initMethod = "initMethod", destroyMethod = "destroyMethod") + public LifeCycleBean lifeCycleBean() { + return new LifeCycleBean(); + } + +} diff --git a/spring-annotation/liftcycle/src/test/java/cn/cunchang/IOCTest_LifeCycle2.java b/spring-annotation/liftcycle/src/test/java/cn/cunchang/IOCTest_LifeCycle2.java new file mode 100644 index 00000000..416b9891 --- /dev/null +++ b/spring-annotation/liftcycle/src/test/java/cn/cunchang/IOCTest_LifeCycle2.java @@ -0,0 +1,23 @@ +package cn.cunchang; + +import cn.cunchang.config.MainConfigOfLifeCycle; +import org.junit.Test; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; + +/** + * @author lastwhisper + */ +public class IOCTest_LifeCycle2 { + + @Test + public void test01() { + // 初始化容器 + AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class); + System.out.println("bean容器初始化..."); + LifeCycleBean lifeCycleBean = applicationContext.getBean(LifeCycleBean.class); + + // 关闭容器 + applicationContext.close(); + } + +} diff --git a/spring-annotation/pom.xml b/spring-annotation/pom.xml index 6195d8d3..4534f311 100644 --- a/spring-annotation/pom.xml +++ b/spring-annotation/pom.xml @@ -1,36 +1,25 @@ - + 4.0.0 - cn.lastwhisper spring-annotation pom - 1.0-SNAPSHOT + 0.0.1-SNAPSHOT - propertyvalue - lifecycle - componentregister - autowired - profile - aop + aop-interface + spring-annotation + Spring Annotation + + + 1.8 + - - - org.springframework - spring-context - 5.1.5.RELEASE - + - - junit - junit - 4.12 - test - + + - - \ No newline at end of file + diff --git a/spring-annotation/profile/pom.xml b/spring-annotation/profile/pom.xml index 629d5c7d..63986ebd 100644 --- a/spring-annotation/profile/pom.xml +++ b/spring-annotation/profile/pom.xml @@ -2,15 +2,12 @@ - - spring-annotation - cn.lastwhisper - 1.0-SNAPSHOT - + 4.0.0 cn.lastwhisper profile + 1.0-SNAPSHOT @@ -25,5 +22,19 @@ mysql-connector-java 5.1.38 + + + + org.springframework + spring-context + 4.3.12.RELEASE + + + + junit + junit + 4.12 + test + \ No newline at end of file diff --git a/spring-annotation/profile/src/main/java/cn/lastwhisper/profile/config/MainConfigofProfile.java b/spring-annotation/profile/src/main/java/cn/lastwhisper/profile/config/MainConfigofProfile.java index 13e79b34..74f83552 100644 --- a/spring-annotation/profile/src/main/java/cn/lastwhisper/profile/config/MainConfigofProfile.java +++ b/spring-annotation/profile/src/main/java/cn/lastwhisper/profile/config/MainConfigofProfile.java @@ -72,6 +72,7 @@ public DataSource dataSourceProd(@Value("${db.password}") String pwd) throws Pro return dataSource; } + @Override public void setEmbeddedValueResolver(StringValueResolver resolver) { driverClass = resolver.resolveStringValue("${db.driverClass}"); } diff --git a/spring-annotation/profile/src/test/java/cn/lastwhisper/profile/test/IOCTest_Profile.java b/spring-annotation/profile/src/test/java/cn/lastwhisper/profile/test/IOCTest_Profile.java index 809843bd..fd2dd6d3 100644 --- a/spring-annotation/profile/src/test/java/cn/lastwhisper/profile/test/IOCTest_Profile.java +++ b/spring-annotation/profile/src/test/java/cn/lastwhisper/profile/test/IOCTest_Profile.java @@ -18,9 +18,6 @@ public class IOCTest_Profile { * 1)使用命令参数加载profile * -Dspring.profiles.active=test * 2)使用AnnotationConfigApplicationContext无参构造器 - * - * @param - * @return void */ @Test public void test01() { diff --git a/spring-annotation/propertyvalue/pom.xml b/spring-annotation/propertyvalue/pom.xml index b1352e34..982b21e7 100644 --- a/spring-annotation/propertyvalue/pom.xml +++ b/spring-annotation/propertyvalue/pom.xml @@ -2,15 +2,27 @@ - - spring-annotation - cn.lastwhisper - 1.0-SNAPSHOT - + 4.0.0 - cn.lastwhisper propertyvalue + cn.lastwhisper + 1.0-SNAPSHOT + + + + + org.springframework + spring-context + 4.3.12.RELEASE + + + junit + junit + 4.12 + test + + \ No newline at end of file diff --git a/spring-annotation/propertyvalue/src/main/java/cn/lastwhisper/propertyvalue/bean/Person.java b/spring-annotation/propertyvalue/src/main/java/cn/lastwhisper/propertyvalue/bean/Person.java index 886ee0ba..3051fd2c 100644 --- a/spring-annotation/propertyvalue/src/main/java/cn/lastwhisper/propertyvalue/bean/Person.java +++ b/spring-annotation/propertyvalue/src/main/java/cn/lastwhisper/propertyvalue/bean/Person.java @@ -3,6 +3,9 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; +import java.util.List; +import java.util.Set; + /** * @author lastwhisper */ @@ -20,12 +23,15 @@ public class Person { @Value("${person.nickname}") private String nickname; - public Person() { - } + // 支付宝、微信、银行卡各有多少钱 + @Value("#{'${person.moneyList}'.split(',')}") + private List moneyList; - public Person(String name, Integer age) { - this.name = name; - this.age = age; + @Value("#{'${person.moneyList}'.split(',')}") + private Set moneySet; + + + public Person() { } public String getName() { @@ -52,12 +58,30 @@ public void setNickname(String nickname) { this.nickname = nickname; } + public List getMoneyList() { + return moneyList; + } + + public void setMoneyList(List moneyList) { + this.moneyList = moneyList; + } + + public Set getMoneySet() { + return moneySet; + } + + public void setMoneySet(Set moneySet) { + this.moneySet = moneySet; + } + @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + ", nickname='" + nickname + '\'' + + ", moneyList=" + moneyList + + ", moneySet=" + moneySet + '}'; } } diff --git a/spring-annotation/propertyvalue/src/main/resources/Bean.xml b/spring-annotation/propertyvalue/src/main/resources/Bean.xml index e612e1c2..c615f286 100644 --- a/spring-annotation/propertyvalue/src/main/resources/Bean.xml +++ b/spring-annotation/propertyvalue/src/main/resources/Bean.xml @@ -10,8 +10,8 @@ - - + + diff --git a/spring-annotation/propertyvalue/src/main/resources/person.properties b/spring-annotation/propertyvalue/src/main/resources/person.properties index cb56670a..1a40a850 100644 --- a/spring-annotation/propertyvalue/src/main/resources/person.properties +++ b/spring-annotation/propertyvalue/src/main/resources/person.properties @@ -1 +1,2 @@ -person.nickname=nike \ No newline at end of file +person.nickname=nike +person.moneyList=100,200,300 \ No newline at end of file diff --git a/spring-annotation/propertyvalue/src/test/java/cn/lastwhisper/propertyvalue/test/IOCTest_PropertyValue.java b/spring-annotation/propertyvalue/src/test/java/cn/lastwhisper/propertyvalue/test/IOCTest_PropertyValue.java index 6700aa6a..0deb59ef 100644 --- a/spring-annotation/propertyvalue/src/test/java/cn/lastwhisper/propertyvalue/test/IOCTest_PropertyValue.java +++ b/spring-annotation/propertyvalue/src/test/java/cn/lastwhisper/propertyvalue/test/IOCTest_PropertyValue.java @@ -1,4 +1,4 @@ -package cn.lastwhisper.lifecycle.test; +package cn.lastwhisper.propertyvalue.test; import cn.lastwhisper.propertyvalue.bean.Person; import cn.lastwhisper.propertyvalue.config.MainConfigOfPropertyValues; @@ -18,14 +18,16 @@ public void test01() { ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfPropertyValues.class); System.out.println("容器初始化..."); +// printBeans(applicationContext); + + Person person = (Person) applicationContext.getBean("person"); System.out.println(person); - Environment environment = applicationContext.getEnvironment(); - String property = environment.getProperty("person.nickname"); - System.out.println(property); +// Environment environment = applicationContext.getEnvironment(); +// String property = environment.getProperty("person.nickname"); +// System.out.println(property); - //printBeans(applicationContext); } private void printBeans(ApplicationContext applicationContext) { diff --git a/spring-annotation/readme.md b/spring-annotation/readme.md deleted file mode 100644 index 326711a8..00000000 --- a/spring-annotation/readme.md +++ /dev/null @@ -1,5 +0,0 @@ -1.组件注册 componentregister -2.生命周期 lifecycle -3.属性赋值 propertyvalue -4.自动装配 autowired -5.aop aop \ No newline at end of file diff --git a/spring-annotation/transaction/README.md b/spring-annotation/transaction/README.md new file mode 100644 index 00000000..8c6c4fd3 --- /dev/null +++ b/spring-annotation/transaction/README.md @@ -0,0 +1,4 @@ +注解事务实现原理 + + + diff --git a/spring-annotation/transaction/pom.xml b/spring-annotation/transaction/pom.xml new file mode 100644 index 00000000..46b1beaa --- /dev/null +++ b/spring-annotation/transaction/pom.xml @@ -0,0 +1,46 @@ + + + + 4.0.0 + + transaction + cn.lastwhisper + 1.0-SNAPSHOT + + + + org.springframework + spring-jdbc + 4.3.12.RELEASE + + + + + org.springframework + spring-context + 4.3.12.RELEASE + + + + junit + junit + 4.12 + test + + + + mysql + mysql-connector-java + 8.0.25 + + + + c3p0 + c3p0 + 0.9.1.2 + + + + \ No newline at end of file diff --git a/spring-annotation/transaction/src/main/java/cn/lastwhisper/tx/TxConfig.java b/spring-annotation/transaction/src/main/java/cn/lastwhisper/tx/TxConfig.java new file mode 100644 index 00000000..963bf9d9 --- /dev/null +++ b/spring-annotation/transaction/src/main/java/cn/lastwhisper/tx/TxConfig.java @@ -0,0 +1,97 @@ +package cn.lastwhisper.tx; + +import com.mchange.v2.c3p0.ComboPooledDataSource; +import org.springframework.context.annotation.AdviceMode; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.datasource.DataSourceTransactionManager; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +import javax.sql.DataSource; +import java.beans.PropertyVetoException; + +/** + * 声明式事务: + * + * 环境搭建: + * 1、导入相关依赖 + * 数据源、数据库驱动、Spring-jdbc模块 + * 2、配置数据源、JdbcTemplate(Spring提供的简化数据库操作的工具)操作数据 + * 3、给方法上标注 @Transactional 表示当前方法是一个事务方法; + * 4、 @EnableTransactionManagement 开启基于注解的事务管理功能; + * @EnableXXX + * 5、配置事务管理器来控制事务; + * @Bean + * public PlatformTransactionManager transactionManager() + * + * 原理: + * 1)、@EnableTransactionManagement + * 利用TransactionManagementConfigurationSelector给容器中会导入组件 + * 默认导入两个组件 + * AutoProxyRegistrar + * ProxyTransactionManagementConfiguration + * 2)、AutoProxyRegistrar: + * 给容器中注册一个 InfrastructureAdvisorAutoProxyCreator 组件; + * InfrastructureAdvisorAutoProxyCreator:? + * 利用后置处理器机制在对象创建以后,包装对象,返回一个代理对象(增强器),代理对象执行方法利用拦截器链进行调用; + * + * 3)、ProxyTransactionManagementConfiguration 做了什么? + * 1、给容器中注册事务增强器 transactionAdvisor() + * 1)、事务增强器要用事务注解的信息,AnnotationTransactionAttributeSource解析事务注解 + * 2)、事务拦截器: + * TransactionInterceptor;保存了事务属性信息,事务管理器; + * 它是一个 MethodInterceptor; + * 在目标方法执行的时候; + * 执行拦截器链; + * 事务拦截器: + * 看(MethodInterceptor.invoke(this)里面的invokeWithinTransaction方法 + * 1)、先获取事务相关的属性 + * 2)、再获取PlatformTransactionManager,如果事先没有添加指定任何transactionmanger + * 最终会从容器中按照类型获取一个PlatformTransactionManager; + * 3)、执行目标方法 + * 如果异常,获取到事务管理器,利用事务管理回滚操作; + * 如果正常,利用事务管理器,提交事务 + * + * + * + * + * @author lastwhisper + * @date 2020/2/17 + */ +@EnableTransactionManagement +@ComponentScan("cn.lastwhisper.tx") +@Configuration +public class TxConfig { + + // 数据源 + @Bean("dataSource") + public DataSource dataSource() throws PropertyVetoException { + ComboPooledDataSource dataSource = new ComboPooledDataSource(); + dataSource.setUser("root"); + dataSource.setPassword("123456"); + dataSource.setDriverClass("com.mysql.cj.jdbc.Driver"); + dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test?useSSL=false"); + return dataSource; + } + + /** + * Spring对@Configuration类会特殊处理,多次调用方法都是从容器中找组件 + */ + @Bean + public JdbcTemplate jdbcTemplate() throws PropertyVetoException { + return new JdbcTemplate(dataSource()); + } + + /** + * No qualifying bean of type 'org.springframework.transaction.PlatformTransactionManager' available + * + * 事务管理器 + */ + @Bean + public PlatformTransactionManager transactionManager() throws PropertyVetoException { + return new DataSourceTransactionManager(dataSource()); + } +} diff --git a/spring-annotation/transaction/src/main/java/cn/lastwhisper/tx/UserDao.java b/spring-annotation/transaction/src/main/java/cn/lastwhisper/tx/UserDao.java new file mode 100644 index 00000000..bd11bc37 --- /dev/null +++ b/spring-annotation/transaction/src/main/java/cn/lastwhisper/tx/UserDao.java @@ -0,0 +1,28 @@ +package cn.lastwhisper.tx; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Repository; + +import java.util.UUID; + +/** + * + * @author lastwhisper + * @date 2020/2/17 + */ +@Repository +public class UserDao { + + @Autowired + JdbcTemplate jdbcTemplate; + + public void insert() { + String sql = "INSERT INTO tbl_user(username,age) VALUES(?,?)"; + String username = UUID.randomUUID().toString().substring(0, 5); + Integer age = 19; + jdbcTemplate.update(sql, username, age); + } + + +} diff --git a/spring-annotation/transaction/src/main/java/cn/lastwhisper/tx/UserService.java b/spring-annotation/transaction/src/main/java/cn/lastwhisper/tx/UserService.java new file mode 100644 index 00000000..b9768a4c --- /dev/null +++ b/spring-annotation/transaction/src/main/java/cn/lastwhisper/tx/UserService.java @@ -0,0 +1,25 @@ +package cn.lastwhisper.tx; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +/** + * + * @author lastwhisper + * @date 2020/2/17 + */ +@Service +public class UserService { + + @Autowired + private UserDao userDao; + + @Transactional + public void insertUser() { + userDao.insert(); + System.out.println("插入完成"); + int i = 10 / 0; + } + +} diff --git a/spring-annotation/transaction/src/main/resources/Bean.xml b/spring-annotation/transaction/src/main/resources/Bean.xml new file mode 100644 index 00000000..6c676469 --- /dev/null +++ b/spring-annotation/transaction/src/main/resources/Bean.xml @@ -0,0 +1,10 @@ + + + + + + + \ No newline at end of file diff --git a/spring-annotation/transaction/src/main/resources/test.sql b/spring-annotation/transaction/src/main/resources/test.sql new file mode 100644 index 00000000..ac93d122 --- /dev/null +++ b/spring-annotation/transaction/src/main/resources/test.sql @@ -0,0 +1,39 @@ +/* + Navicat Premium Data Transfer + + Source Server : mysql5.7 + Source Server Type : MySQL + Source Server Version : 50724 + Source Host : localhost:3306 + Source Schema : test + + Target Server Type : MySQL + Target Server Version : 50724 + File Encoding : 65001 + + Date: 25/02/2020 16:38:21 +*/ + +SET NAMES utf8mb4; +SET FOREIGN_KEY_CHECKS = 0; + +-- ---------------------------- +-- Table structure for tbl_user +-- ---------------------------- +DROP TABLE IF EXISTS `tbl_user`; +CREATE TABLE `tbl_user` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `username` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `age` int(11) NULL DEFAULT NULL, + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of tbl_user +-- ---------------------------- +INSERT INTO `tbl_user` VALUES (1, 'admin', 18); +INSERT INTO `tbl_user` VALUES (2, '836d9', 19); +INSERT INTO `tbl_user` VALUES (3, '9504c', 19); +INSERT INTO `tbl_user` VALUES (4, '75a1f', 19); + +SET FOREIGN_KEY_CHECKS = 1; diff --git a/spring-annotation/transaction/src/test/java/cn/lastwhisper/tx/test/IOCTest_TX.java b/spring-annotation/transaction/src/test/java/cn/lastwhisper/tx/test/IOCTest_TX.java new file mode 100644 index 00000000..8c1f28df --- /dev/null +++ b/spring-annotation/transaction/src/test/java/cn/lastwhisper/tx/test/IOCTest_TX.java @@ -0,0 +1,40 @@ +package cn.lastwhisper.tx.test; + +import cn.lastwhisper.tx.TxConfig; +import cn.lastwhisper.tx.UserService; +import org.junit.Test; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; + +/** + * @author lastwhisper + */ +public class IOCTest_TX { + + + /** + * 测试事务 + * + * @param + * @return void + */ + @Test + public void test01() { + AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(TxConfig.class); + System.out.println("容器初始化..."); + + UserService userService = applicationContext.getBean(UserService.class); + userService.insertUser(); + + applicationContext.close(); + //printBeans(applicationContext); + } + + private void printBeans(ApplicationContext applicationContext) { + String[] definitionNames = applicationContext.getBeanDefinitionNames(); + for (String name : definitionNames) { + System.out.println(name); + } + } + +} diff --git a/spring-batch/spring-batch/pom.xml b/spring-batch/spring-batch/pom.xml new file mode 100644 index 00000000..3dd045d5 --- /dev/null +++ b/spring-batch/spring-batch/pom.xml @@ -0,0 +1,99 @@ + + + 4.0.0 + cn.cunchang + spring-batch + 0.0.1-SNAPSHOT + spring-batch + spring-batch + + + 1.8 + 1.8 + 2.2.4.RELEASE + Hoxton.SR1 + 2.2.0.RELEASE + + + + + org.springframework.boot + spring-boot-starter-web + + + + + org.springframework.boot + spring-boot-starter-batch + + + org.springframework.batch + spring-batch-integration + + + + + com.alibaba.cloud + spring-cloud-starter-stream-rocketmq + + + + org.hsqldb + hsqldb + runtime + + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.batch + spring-batch-test + test + + + + + + + + org.springframework.boot + spring-boot-starter-parent + ${spring.boot.version} + pom + import + + + org.springframework.cloud + spring-cloud-dependencies + ${spring.cloud.version} + pom + import + + + com.alibaba.cloud + spring-cloud-alibaba-dependencies + ${spring.cloud.alibaba.version} + pom + import + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/spring-batch/spring-batch/src/main/java/cn/cunchang/SpringBatchApplication.java b/spring-batch/spring-batch/src/main/java/cn/cunchang/SpringBatchApplication.java new file mode 100644 index 00000000..905f278d --- /dev/null +++ b/spring-batch/spring-batch/src/main/java/cn/cunchang/SpringBatchApplication.java @@ -0,0 +1,14 @@ +package cn.cunchang; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class SpringBatchApplication { + + public static void main(String[] args) { +// System.exit(SpringApplication.exit(SpringApplication.run(SpringBatchApplication.class, args))); + SpringApplication.run(SpringBatchApplication.class, args); + } + +} diff --git a/spring-batch/spring-batch/src/main/java/cn/cunchang/batch/BatchConfiguration.java b/spring-batch/spring-batch/src/main/java/cn/cunchang/batch/BatchConfiguration.java new file mode 100644 index 00000000..e3ffd39f --- /dev/null +++ b/spring-batch/spring-batch/src/main/java/cn/cunchang/batch/BatchConfiguration.java @@ -0,0 +1,21 @@ +package cn.cunchang.batch; + +import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing; +import org.springframework.batch.integration.config.annotation.EnableBatchIntegration; +import org.springframework.cloud.stream.annotation.EnableBinding; +import org.springframework.context.annotation.Configuration; + +/** + * @EnableBatchProcessing 自动注册springbatch的关键组件 + * 比如 JobBuilderFactory、StepBuilderFactory + * + */ +@Configuration +@EnableBatchProcessing +@EnableBatchIntegration +@EnableBinding(BatchMessageChannel.class) +public class BatchConfiguration { + + + +} \ No newline at end of file diff --git a/spring-batch/spring-batch/src/main/java/cn/cunchang/batch/BatchMessageChannel.java b/spring-batch/spring-batch/src/main/java/cn/cunchang/batch/BatchMessageChannel.java new file mode 100644 index 00000000..2341a625 --- /dev/null +++ b/spring-batch/spring-batch/src/main/java/cn/cunchang/batch/BatchMessageChannel.java @@ -0,0 +1,46 @@ +package cn.cunchang.batch; + +import org.springframework.cloud.stream.annotation.Input; +import org.springframework.cloud.stream.annotation.Output; +import org.springframework.messaging.MessageChannel; +import org.springframework.messaging.SubscribableChannel; + +/** + * BatchMessageChannel + * + * @author jianzhu + * @date 2021/3/19 18:47 + */ +public interface BatchMessageChannel { + + /** + * ================================================== Manager + */ + + // 输出型消息通道,发送消息:Manager -> Workers + String DAILY_ORDER_MANAGER_OUTPUT = "daily-order-manager-output"; + + @Output(DAILY_ORDER_MANAGER_OUTPUT) + MessageChannel dailyOrderOutgoingRequestsToWorkers(); + + String CHECK_MANAGER_OUTPUT = "check-manager-output"; + + @Output(CHECK_MANAGER_OUTPUT) + MessageChannel checkOutgoingRequestsToWorkers(); + + /** + * ================================================== Worker + */ + + // 输入型消息通道,接收 Manager 消息 + String DAILY_ORDER_WORKER_INPUT = "daily-order-worker-input"; + + @Input(DAILY_ORDER_WORKER_INPUT) + SubscribableChannel dailyOrderIncomingRequestsFromManager(); + + String CHECK_WORKER_INPUT = "check-worker-input"; + + @Input(CHECK_WORKER_INPUT) + SubscribableChannel checkIncomingRequestsFromManager(); + +} diff --git a/spring-batch/spring-batch/src/main/java/cn/cunchang/batch/job/BatchConfiguration.java b/spring-batch/spring-batch/src/main/java/cn/cunchang/batch/job/BatchConfiguration.java new file mode 100644 index 00000000..43b96687 --- /dev/null +++ b/spring-batch/spring-batch/src/main/java/cn/cunchang/batch/job/BatchConfiguration.java @@ -0,0 +1,112 @@ +package cn.cunchang.batch.job; + +import cn.cunchang.batch.listener.JobCompletionNotificationListener; +import cn.cunchang.pojo.Person; +import cn.cunchang.batch.processor.PersonItemProcessor; +import org.springframework.batch.core.Job; +import org.springframework.batch.core.Step; +import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing; +import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; +import org.springframework.batch.core.configuration.annotation.StepBuilderFactory; +import org.springframework.batch.core.launch.support.RunIdIncrementer; +import org.springframework.batch.item.database.BeanPropertyItemSqlParameterSourceProvider; +import org.springframework.batch.item.database.JdbcBatchItemWriter; +import org.springframework.batch.item.database.builder.JdbcBatchItemWriterBuilder; +import org.springframework.batch.item.file.FlatFileItemReader; +import org.springframework.batch.item.file.builder.FlatFileItemReaderBuilder; +import org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.io.ClassPathResource; + +import javax.sql.DataSource; + +/** + * @EnableBatchProcessing 自动注册springbatch的关键组件 + * 比如 JobBuilderFactory、StepBuilderFactory + * + */ +@Configuration +@EnableBatchProcessing +public class BatchConfiguration { + + @Autowired + public JobBuilderFactory jobBuilderFactory; + + @Autowired + public StepBuilderFactory stepBuilderFactory; + + /** + * 输入 + * + * @return + */ + @Bean + public FlatFileItemReader reader() { + return new FlatFileItemReaderBuilder() + .name("personItemReader") + .resource(new ClassPathResource("sample-data.csv")) + .delimited() + .names(new String[]{"firstName", "lastName"}) + .fieldSetMapper(new BeanWrapperFieldSetMapper() {{ + setTargetType(Person.class); + }}) + .build(); + } + + /** + * 处理器 + * + * @return + */ + @Bean + public PersonItemProcessor processor() { + return new PersonItemProcessor(); + } + + /** + * 输出 + * + * @param dataSource + * @return + */ + @Bean + public JdbcBatchItemWriter writer(DataSource dataSource) { + return new JdbcBatchItemWriterBuilder() + .itemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider<>()) + .sql("INSERT INTO people (first_name, last_name) VALUES (:firstName, :lastName)") + .dataSource(dataSource) + .build(); + } + + /** + * 定义作业 + * + * 作业由步骤构建而成,其中每个步骤都可能涉及读取器、处理器和写入器。 + * + * @param listener + * @param step1 + * @return + */ + @Bean + public Job importUserJob(JobCompletionNotificationListener listener, Step step1) { + return jobBuilderFactory.get("importUserJob") + .incrementer(new RunIdIncrementer()) + .listener(listener) + .flow(step1) + .end() + .build(); + } + + @Bean + public Step step1(JdbcBatchItemWriter writer) { + return stepBuilderFactory.get("step1") + . chunk(10) + .reader(reader()) + .processor(processor()) + .writer(writer) + .build(); + } + +} \ No newline at end of file diff --git a/spring-batch/spring-batch/src/main/java/cn/cunchang/batch/listener/JobCompletionNotificationListener.java b/spring-batch/spring-batch/src/main/java/cn/cunchang/batch/listener/JobCompletionNotificationListener.java new file mode 100644 index 00000000..b2877075 --- /dev/null +++ b/spring-batch/spring-batch/src/main/java/cn/cunchang/batch/listener/JobCompletionNotificationListener.java @@ -0,0 +1,45 @@ +package cn.cunchang.batch.listener; + +import cn.cunchang.pojo.Person; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.batch.core.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Component; + +@Component +public class JobCompletionNotificationListener implements JobExecutionListener { + + private static final Logger log = LoggerFactory.getLogger(JobCompletionNotificationListener.class); + + @Autowired + private JdbcTemplate jdbcTemplate; + + @Override + public void beforeJob(JobExecution jobExecution) { + log.info("Job 执行开始. jobName={}, jobId={}, jobExecutionId={}, jobParameters={}", + jobExecution.getJobInstance().getJobName(), jobExecution.getJobId(), jobExecution.getId(), + jobExecution.getJobParameters()); + } + + @Override + public void afterJob(JobExecution jobExecution) { + if (jobExecution.getStatus() == BatchStatus.COMPLETED) { + String jobName = jobExecution.getJobInstance().getJobName(); + Long jobExecutionId = jobExecution.getId(); + BatchStatus batchStatus = jobExecution.getStatus(); + ExitStatus exitStatus = jobExecution.getExitStatus(); + JobParameters jobParameters = jobExecution.getJobParameters(); + log.info("Job 执行结束. jobName={}, jobId={}, jobExecutionId={}, status={}, exitStatus={}, jobParameters={}", + jobName, jobExecution.getJobId(), jobExecutionId, batchStatus, exitStatus, jobParameters); + + jdbcTemplate.query("SELECT first_name, last_name FROM people", + (rs, row) -> new Person( + rs.getString(1), + rs.getString(2)) + ).forEach(person -> log.info("jobName:{},Found <" + person + "> in the database.", jobName)); + } + } + +} \ No newline at end of file diff --git a/spring-batch/spring-batch/src/main/java/cn/cunchang/batch/listener/StepCompletionNotificationListener.java b/spring-batch/spring-batch/src/main/java/cn/cunchang/batch/listener/StepCompletionNotificationListener.java new file mode 100644 index 00000000..3ca81598 --- /dev/null +++ b/spring-batch/spring-batch/src/main/java/cn/cunchang/batch/listener/StepCompletionNotificationListener.java @@ -0,0 +1,41 @@ +package cn.cunchang.batch.listener; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.batch.core.BatchStatus; +import org.springframework.batch.core.ExitStatus; +import org.springframework.batch.core.StepExecution; +import org.springframework.batch.core.StepExecutionListener; +import org.springframework.stereotype.Component; + +/** + * @author cunchang + * @date 2021/9/17 6:54 下午 + */ +@Component +public class StepCompletionNotificationListener implements StepExecutionListener { + + private static final Logger log = LoggerFactory.getLogger(JobCompletionNotificationListener.class); + + @Override + public void beforeStep(StepExecution stepExecution) { + log.info("BEFORE_STEP stepId={}, stepName={}, status={}, exitStatus={}, executionContext={}", + stepExecution.getId(), stepExecution.getStepName(), stepExecution.getStatus(), + stepExecution.getExitStatus(), stepExecution.getExecutionContext()); + } + + @Override + public ExitStatus afterStep(StepExecution stepExecution) { + String jobName = stepExecution.getJobExecution().getJobInstance().getJobName(); + Long jobExecutionId = stepExecution.getJobExecutionId(); + String stepName = stepExecution.getStepName(); + Long stepExecutionId = stepExecution.getId(); + BatchStatus batchStatus = stepExecution.getStatus(); + ExitStatus exitStatus = stepExecution.getExitStatus(); + log.info("AFTER_STEP jobName={}, jobExecutionId={}, stepId={}, stepName={}, status={}, exitStatus={}, executionContext={}", + jobName, jobExecutionId, stepExecutionId, stepName, batchStatus, exitStatus, stepExecution.getExecutionContext()); + + return null; + } + +} diff --git a/spring-batch/spring-batch/src/main/java/cn/cunchang/batch/processor/PersonItemProcessor.java b/spring-batch/spring-batch/src/main/java/cn/cunchang/batch/processor/PersonItemProcessor.java new file mode 100644 index 00000000..540d51ea --- /dev/null +++ b/spring-batch/spring-batch/src/main/java/cn/cunchang/batch/processor/PersonItemProcessor.java @@ -0,0 +1,25 @@ +package cn.cunchang.batch.processor; + +import cn.cunchang.pojo.Person; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.batch.item.ItemProcessor; + +public class PersonItemProcessor implements ItemProcessor { + + private static final Logger log = LoggerFactory.getLogger(PersonItemProcessor.class); + + @Override + public Person process(final Person person) throws Exception { + final String firstName = person.getFirstName().toUpperCase(); + final String lastName = person.getLastName().toUpperCase(); + + final Person transformedPerson = new Person(firstName, lastName); + + log.info("Converting (" + person + ") into (" + transformedPerson + ")"); + + return transformedPerson; + } + +} \ No newline at end of file diff --git a/spring-batch/spring-batch/src/main/java/cn/cunchang/pojo/Person.java b/spring-batch/spring-batch/src/main/java/cn/cunchang/pojo/Person.java new file mode 100644 index 00000000..c7e15245 --- /dev/null +++ b/spring-batch/spring-batch/src/main/java/cn/cunchang/pojo/Person.java @@ -0,0 +1,37 @@ +package cn.cunchang.pojo; + +public class Person { + + private String lastName; + private String firstName; + + public Person() { + } + + public Person(String firstName, String lastName) { + this.firstName = firstName; + this.lastName = lastName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getFirstName() { + return firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + @Override + public String toString() { + return "firstName: " + firstName + ", lastName: " + lastName; + } + +} \ No newline at end of file diff --git a/spring-batch/spring-batch/src/main/java/cn/cunchang/schedule/EntryXxljob.java b/spring-batch/spring-batch/src/main/java/cn/cunchang/schedule/EntryXxljob.java new file mode 100644 index 00000000..6f5067d3 --- /dev/null +++ b/spring-batch/spring-batch/src/main/java/cn/cunchang/schedule/EntryXxljob.java @@ -0,0 +1,21 @@ +package cn.cunchang.schedule; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * 定时任务触发spring batch job + * @author cunchang + * @date 2021/9/16 3:33 下午 + */ +@RestController +public class EntryXxljob { + + @GetMapping("/test") + public String test() { + + + return "success"; + } + +} diff --git a/spring-batch/spring-batch/src/main/resources/application.properties b/spring-batch/spring-batch/src/main/resources/application.properties new file mode 100644 index 00000000..fbcd88e0 --- /dev/null +++ b/spring-batch/spring-batch/src/main/resources/application.properties @@ -0,0 +1 @@ +spring.batch.job.enabled=false diff --git a/spring-batch/spring-batch/src/main/resources/sample-data.csv b/spring-batch/spring-batch/src/main/resources/sample-data.csv new file mode 100644 index 00000000..77a4babe --- /dev/null +++ b/spring-batch/spring-batch/src/main/resources/sample-data.csv @@ -0,0 +1,11 @@ +Jill,Doe +Joe,Doe +Justin,Doe +Jane,Doe +John,Doe +Tom,Doe +Cat,Doe +Zhang,San +Li,Si +Li,Doe +Zhang,Doe \ No newline at end of file diff --git a/spring-batch/spring-batch/src/main/resources/schema-all.sql b/spring-batch/spring-batch/src/main/resources/schema-all.sql new file mode 100644 index 00000000..011297df --- /dev/null +++ b/spring-batch/spring-batch/src/main/resources/schema-all.sql @@ -0,0 +1,8 @@ +DROP TABLE people IF EXISTS; + +CREATE TABLE people +( + person_id BIGINT IDENTITY NOT NULL PRIMARY KEY, + first_name VARCHAR(20), + last_name VARCHAR(20) +); \ No newline at end of file diff --git a/spring-batch/spring-batch/src/test/java/cn/cunchang/SpringBatchApplicationTests.java b/spring-batch/spring-batch/src/test/java/cn/cunchang/SpringBatchApplicationTests.java new file mode 100644 index 00000000..96ac9af5 --- /dev/null +++ b/spring-batch/spring-batch/src/test/java/cn/cunchang/SpringBatchApplicationTests.java @@ -0,0 +1,13 @@ +package cn.cunchang; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class SpringBatchApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/springboot-aop/execution/src/main/java/cn/lastwhisper/config/ArgsAspectConfig.java b/springboot-aop/execution/src/main/java/cn/lastwhisper/config/ArgsAspectConfig.java index f51ed797..40fbc12f 100644 --- a/springboot-aop/execution/src/main/java/cn/lastwhisper/config/ArgsAspectConfig.java +++ b/springboot-aop/execution/src/main/java/cn/lastwhisper/config/ArgsAspectConfig.java @@ -16,7 +16,7 @@ public class ArgsAspectConfig { * 第四节:匹配参数:args() * * // 匹配cn.lastwhisper.service包下任意类,只有一个参数且参数类型为Long的方法 - * @Pointcut("args(Long) && within(cn.lastwhisper.service.*)") + * @Pointcut("args(Long) && within(cn.lastwhisper.service.* )") * // 匹配cn.lastwhisper.service包下任意类,第一个参数类型为Long,其他参数任意或无的方法 * @Pointcut("args(Long,..) && within(cn.lastwhisper.service.*)") * // 匹配cn.lastwhisper.service包下任意类,第一个参数类型为Long,第二个参数类型为String的方法 diff --git a/springboot-aop/principle/README.md b/springboot-aop/principle/README.md new file mode 100644 index 00000000..3c1d7d5f --- /dev/null +++ b/springboot-aop/principle/README.md @@ -0,0 +1,7 @@ +- AOP 底层设计模式 + - 动态代理 + - 责任链 + +动态代理代码,迁移到proxy +责任链代码,迁移到design-pattern + diff --git a/springboot-aop/principle/pom.xml b/springboot-aop/principle/pom.xml deleted file mode 100644 index 87f46a5a..00000000 --- a/springboot-aop/principle/pom.xml +++ /dev/null @@ -1,50 +0,0 @@ - - - 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 2.1.7.RELEASE - - - cn.lastwhisper.springboot - principle - 0.0.1-SNAPSHOT - principle - Spring AOP 底层设计模式 - - - 1.8 - - - - - org.springframework.boot - spring-boot-starter - - - - org.springframework.boot - spring-boot-starter-test - test - - - - cglib - cglib - 3.2.4 - - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - - diff --git a/springboot-aop/principle/src/main/java/cn/lastwhisper/ProxyDemoApplication.java b/springboot-aop/principle/src/main/java/cn/lastwhisper/ProxyDemoApplication.java deleted file mode 100644 index 370447c9..00000000 --- a/springboot-aop/principle/src/main/java/cn/lastwhisper/ProxyDemoApplication.java +++ /dev/null @@ -1,13 +0,0 @@ -package cn.lastwhisper; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class ProxyDemoApplication { - - public static void main(String[] args) { - SpringApplication.run(ProxyDemoApplication.class, args); - } - -} diff --git a/springboot-aop/principle/src/main/java/cn/lastwhisper/chain/v1/Client.java b/springboot-aop/principle/src/main/java/cn/lastwhisper/chain/v1/Client.java deleted file mode 100644 index 7b9b17fc..00000000 --- a/springboot-aop/principle/src/main/java/cn/lastwhisper/chain/v1/Client.java +++ /dev/null @@ -1,39 +0,0 @@ -package cn.lastwhisper.chain.v1; - -/** - * @author lastwhisper - */ -public class Client { - static class HandlerA extends Handler{ - @Override - protected void handleProcess() { - System.out.println("handle by a"); - } - } - - static class HandlerB extends Handler{ - @Override - protected void handleProcess() { - System.out.println("handle by b"); - } - } - - static class HandlerC extends Handler{ - @Override - protected void handleProcess() { - System.out.println("handle by c"); - } - } - - public static void main(String[] args){ - Handler handlerA = new HandlerA(); - Handler handlerB = new HandlerB(); - Handler handlerC = new HandlerC(); - - handlerA.setSucessor(handlerB); - handlerB.setSucessor(handlerC); - - handlerA.execute(); - } - -} diff --git a/springboot-aop/principle/src/main/java/cn/lastwhisper/chain/v2/Chain.java b/springboot-aop/principle/src/main/java/cn/lastwhisper/chain/v2/Chain.java deleted file mode 100644 index 65ec7597..00000000 --- a/springboot-aop/principle/src/main/java/cn/lastwhisper/chain/v2/Chain.java +++ /dev/null @@ -1,24 +0,0 @@ -package cn.lastwhisper.chain.v2; - -import java.util.List; - -/** - * 使用chain进行包装 - * @author lastwhisper - */ -public class Chain { - private List handlers; - private int index = 0; - - public Chain(List handlers) { - this.handlers = handlers; - } - - //将顺序关系封装 - public void proceed() { - if (index >= handlers.size()) { - return; - } - handlers.get(index++).execute(this); - } -} diff --git a/springboot-aop/principle/src/main/java/cn/lastwhisper/chain/v2/ChainClient.java b/springboot-aop/principle/src/main/java/cn/lastwhisper/chain/v2/ChainClient.java deleted file mode 100644 index b7cf9447..00000000 --- a/springboot-aop/principle/src/main/java/cn/lastwhisper/chain/v2/ChainClient.java +++ /dev/null @@ -1,38 +0,0 @@ -package cn.lastwhisper.chain.v2; - -import java.util.Arrays; -import java.util.List; - -/** - * Created by cat on 2017-02-28. - */ -public class ChainClient { - static class ChainHandlerA extends ChainHandler{ - @Override - protected void handleProcess() { - System.out.println("handle by chain a"); - } - } - static class ChainHandlerB extends ChainHandler{ - @Override - protected void handleProcess() { - System.out.println("handle by chain b"); - } - } - static class ChainHandlerC extends ChainHandler{ - @Override - protected void handleProcess() { - System.out.println("handle by chain c"); - } - } - - public static void main(String[] args){ - List handlers = Arrays.asList( - new ChainHandlerA(), - new ChainHandlerB(), - new ChainHandlerC() - ); - Chain chain = new Chain(handlers); - chain.proceed(); - } -} diff --git a/springboot-aop/principle/src/main/java/cn/lastwhisper/chain/v2/ChainHandler.java b/springboot-aop/principle/src/main/java/cn/lastwhisper/chain/v2/ChainHandler.java deleted file mode 100644 index 976ae24b..00000000 --- a/springboot-aop/principle/src/main/java/cn/lastwhisper/chain/v2/ChainHandler.java +++ /dev/null @@ -1,15 +0,0 @@ -package cn.lastwhisper.chain.v2; - -/** - * Created by cat on 2017-02-28. - */ -public abstract class ChainHandler { - - public void execute(Chain chain){ - handleProcess(); - chain.proceed(); - - } - - protected abstract void handleProcess(); -} diff --git a/springboot-aop/principle/src/main/java/cn/lastwhisper/chain/v3/Chain.java b/springboot-aop/principle/src/main/java/cn/lastwhisper/chain/v3/Chain.java deleted file mode 100644 index dea28e06..00000000 --- a/springboot-aop/principle/src/main/java/cn/lastwhisper/chain/v3/Chain.java +++ /dev/null @@ -1,24 +0,0 @@ -package cn.lastwhisper.chain.v3; - -import java.util.List; - -/** - * 使用chain进行包装 - * @author lastwhisper - */ -public class Chain { - private List handlers; - private int index = 0; - - public Chain(List handlers) { - this.handlers = handlers; - } - - //将顺序关系封装 - public void proceed() { - if (index >= handlers.size()) { - return; - } - handlers.get(index++).execute(this); - } -} diff --git a/springboot-aop/principle/src/main/java/cn/lastwhisper/chain/v3/ChainClient.java b/springboot-aop/principle/src/main/java/cn/lastwhisper/chain/v3/ChainClient.java deleted file mode 100644 index 32ec33d3..00000000 --- a/springboot-aop/principle/src/main/java/cn/lastwhisper/chain/v3/ChainClient.java +++ /dev/null @@ -1,57 +0,0 @@ -package cn.lastwhisper.chain.v3; - -import java.util.Arrays; -import java.util.List; - -/** - * Created by cat on 2017-02-28. - */ -public class ChainClient { - static class ChainHandlerA extends ChainHandler { - @Override - protected void handlePreProcess() { - System.out.println("ChainHandlerA handlePreProcess"); - } - - @Override - protected void handlePostProcess() { - System.out.println("ChainHandlerA handlePostProcess"); - } - } - - static class ChainHandlerB extends ChainHandler { - @Override - protected void handlePreProcess() { - System.out.println("ChainHandlerB handlePreProcess"); - } - - @Override - protected void handlePostProcess() { - System.out.println("ChainHandlerB handlePostProcess"); - } - } - - static class ChainHandlerC extends ChainHandler { - @Override - protected void handlePreProcess() { - System.out.println("ChainHandlerC handlePreProcess"); - } - - @Override - protected void handlePostProcess() { - System.out.println("ChainHandlerC handlePostProcess"); - } - } - - public static void main(String[] args) { - List handlers = Arrays.asList( - new ChainHandlerA(), - new ChainHandlerB(), - new ChainHandlerC() - ); - Chain chain = new Chain(handlers); - chain.proceed(); - - - } -} diff --git a/springboot-aop/principle/src/main/java/cn/lastwhisper/chain/v3/ChainHandler.java b/springboot-aop/principle/src/main/java/cn/lastwhisper/chain/v3/ChainHandler.java deleted file mode 100644 index 5d5318a5..00000000 --- a/springboot-aop/principle/src/main/java/cn/lastwhisper/chain/v3/ChainHandler.java +++ /dev/null @@ -1,17 +0,0 @@ -package cn.lastwhisper.chain.v3; - -/** - * Created by cat on 2017-02-28. - */ -public abstract class ChainHandler { - - // 模板方法 - public void execute(Chain chain){ - handlePreProcess(); - chain.proceed(); - handlePostProcess(); - } - - protected abstract void handlePreProcess(); - protected abstract void handlePostProcess(); -} diff --git a/springboot-aop/principle/src/main/java/cn/lastwhisper/proxy/cglibproxy/Client.java b/springboot-aop/principle/src/main/java/cn/lastwhisper/proxy/cglibproxy/Client.java deleted file mode 100644 index 1b34e2ca..00000000 --- a/springboot-aop/principle/src/main/java/cn/lastwhisper/proxy/cglibproxy/Client.java +++ /dev/null @@ -1,18 +0,0 @@ -package cn.lastwhisper.proxy.cglibproxy; - -import cn.lastwhisper.proxy.staticproxy.RealSubject; -import cn.lastwhisper.proxy.staticproxy.Subject; -import net.sf.cglib.proxy.Enhancer; - -/** - * @author lastwhisper - */ -public class Client { - public static void main(String[] args) { - Enhancer enhancer = new Enhancer(); - enhancer.setSuperclass(RealSubject.class); - enhancer.setCallback(new DemoMethodInterceptor()); - Subject subject = (Subject) enhancer.create(); - subject.request(); - } -} diff --git a/springboot-aop/principle/src/main/java/cn/lastwhisper/proxy/cglibproxy/DemoMethodInterceptor.java b/springboot-aop/principle/src/main/java/cn/lastwhisper/proxy/cglibproxy/DemoMethodInterceptor.java deleted file mode 100644 index 52370306..00000000 --- a/springboot-aop/principle/src/main/java/cn/lastwhisper/proxy/cglibproxy/DemoMethodInterceptor.java +++ /dev/null @@ -1,28 +0,0 @@ -package cn.lastwhisper.proxy.cglibproxy; - -import net.sf.cglib.proxy.MethodInterceptor; -import net.sf.cglib.proxy.MethodProxy; - -import java.lang.reflect.Method; - -/** - * @author lastwhisper - */ -public class DemoMethodInterceptor implements MethodInterceptor { - - @Override - public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { - System.out.println("before method"); - Object result =null; - try { - result = methodProxy.invokeSuper(o, objects); - }catch (Exception e){ - System.out.println("ex:"+e.getMessage()); - throw e; - }finally { - System.out.println("after method"); - } - return result; - } - -} diff --git a/springboot-aop/principle/src/main/java/cn/lastwhisper/proxy/dynamicproxy/Client.java b/springboot-aop/principle/src/main/java/cn/lastwhisper/proxy/dynamicproxy/Client.java deleted file mode 100644 index cc50278f..00000000 --- a/springboot-aop/principle/src/main/java/cn/lastwhisper/proxy/dynamicproxy/Client.java +++ /dev/null @@ -1,18 +0,0 @@ -package cn.lastwhisper.proxy.dynamicproxy; - -import cn.lastwhisper.proxy.staticproxy.RealSubject; -import cn.lastwhisper.proxy.staticproxy.Subject; - -/** - * Created by cat on 2017-02-27. - */ -public class Client { - - public static void main(String[] args) { - // 查看生成的代理类 - System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true"); - Subject proxy = (Subject) new JdkProxySubject(new RealSubject()).getProxy(); - //proxy.request(); - proxy.response(); - } -} diff --git a/springboot-aop/principle/src/main/java/cn/lastwhisper/proxy/dynamicproxy/JdkProxySubject.java b/springboot-aop/principle/src/main/java/cn/lastwhisper/proxy/dynamicproxy/JdkProxySubject.java deleted file mode 100644 index 86de6a80..00000000 --- a/springboot-aop/principle/src/main/java/cn/lastwhisper/proxy/dynamicproxy/JdkProxySubject.java +++ /dev/null @@ -1,59 +0,0 @@ -package cn.lastwhisper.proxy.dynamicproxy; - -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; - -/** - * aspect - * @author lastwhisper - */ -public class JdkProxySubject implements InvocationHandler { - // 目标类 - private Object target; - - public JdkProxySubject(Object target) { - this.target = target; - } - - /** - * newProxyInstance - * |-- getProxyClass0 - * |--proxyClassCache.get(loader, interfaces); - * |--ProxyClassFactory - * |--apply - * |--代理类的名称 String proxyName = proxyPkg + proxyClassNamePrefix + num; - * |--生成字节码 byte[] proxyClassFile = ProxyGenerator.generateProxyClass( - * proxyName, interfaces, accessFlags);通过类加载器defineClass0加载 - * |--生成符合Java规范的代码 generateProxyClass - * 在动态生成的对象中,使用h.invoke(this, m3, (Object[])null)这种形式执行方法 - * 这个h就是Proxy的InvocationHandler成员变量,而这个成员变量是在 - * Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this)传入this时赋值的 - */ - public Object getProxy() { - Class clazz = target.getClass(); - return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this); - } - - /** - * target:目标类 - * proxy:代理类 - * method:目标方法 - * args:目标方法参数 - */ - @Override - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - System.out.println("before method"); - Object result = null; - try { - result = method.invoke(target, args); - } catch (Exception e) { - System.out.println("ex:" + e.getMessage()); - throw e;//代理类不要生吞异常 - } finally { - System.out.println("after method"); - } - return result; - } - -} diff --git a/springboot-aop/principle/src/main/java/cn/lastwhisper/proxy/staticproxy/Client.java b/springboot-aop/principle/src/main/java/cn/lastwhisper/proxy/staticproxy/Client.java deleted file mode 100644 index 190477e5..00000000 --- a/springboot-aop/principle/src/main/java/cn/lastwhisper/proxy/staticproxy/Client.java +++ /dev/null @@ -1,12 +0,0 @@ -package cn.lastwhisper.proxy.staticproxy; - -/** - * Created by cat on 2017-02-27. - */ -public class Client { - - public static void main(String[] args){ - Proxy subject = new Proxy(new RealSubject()); - subject.request(); - } -} diff --git a/springboot-aop/principle/src/main/java/cn/lastwhisper/proxy/staticproxy/Proxy.java b/springboot-aop/principle/src/main/java/cn/lastwhisper/proxy/staticproxy/Proxy.java deleted file mode 100644 index 17717bb0..00000000 --- a/springboot-aop/principle/src/main/java/cn/lastwhisper/proxy/staticproxy/Proxy.java +++ /dev/null @@ -1,24 +0,0 @@ -package cn.lastwhisper.proxy.staticproxy; - -/** - * @author lastwhisper - */ -public class Proxy { - private Subject target; - - public Proxy(Subject target) { - this.target = target; - } - - public void request() { - System.out.println("before method"); - target.request(); - System.out.println("after method"); - } - - public void response() { - System.out.println("before method"); - target.response(); - System.out.println("after method"); - } -} diff --git a/springboot-aop/principle/src/main/java/cn/lastwhisper/proxy/staticproxy/RealSubject.java b/springboot-aop/principle/src/main/java/cn/lastwhisper/proxy/staticproxy/RealSubject.java deleted file mode 100644 index 0b69fa8d..00000000 --- a/springboot-aop/principle/src/main/java/cn/lastwhisper/proxy/staticproxy/RealSubject.java +++ /dev/null @@ -1,16 +0,0 @@ -package cn.lastwhisper.proxy.staticproxy; - -/** - * @author lastwhisper - */ -public class RealSubject implements Subject { - @Override - public void request() { - System.out.println("RealSubject request to do"); - } - - @Override - public void response() { - System.out.println("RealSubject response to do"); - } -} diff --git a/springboot-aop/principle/src/main/java/cn/lastwhisper/proxy/staticproxy/Subject.java b/springboot-aop/principle/src/main/java/cn/lastwhisper/proxy/staticproxy/Subject.java deleted file mode 100644 index b6a1746e..00000000 --- a/springboot-aop/principle/src/main/java/cn/lastwhisper/proxy/staticproxy/Subject.java +++ /dev/null @@ -1,10 +0,0 @@ -package cn.lastwhisper.proxy.staticproxy; - -/** - * @author lastwhisper - */ -public interface Subject { - public void request(); - // 新增接口,静态代理需要重新编写代理的代码,而动态代理不用 - public void response(); -} diff --git a/springboot-aop/principle/src/test/java/cn/lastwhisper/ProxyDemoApplicationTests.java b/springboot-aop/principle/src/test/java/cn/lastwhisper/ProxyDemoApplicationTests.java deleted file mode 100644 index d7b2c11f..00000000 --- a/springboot-aop/principle/src/test/java/cn/lastwhisper/ProxyDemoApplicationTests.java +++ /dev/null @@ -1,16 +0,0 @@ -package cn.lastwhisper; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit4.SpringRunner; - -@RunWith(SpringRunner.class) -@SpringBootTest -public class ProxyDemoApplicationTests { - - @Test - public void contextLoads() { - } - -} diff --git a/springboot-integration-examples/README.md b/springboot-integration-examples/README.md deleted file mode 100644 index ec56671b..00000000 --- a/springboot-integration-examples/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# springboot-integration-examples - -基于最新的 SpringBoot2.0+ - -## 1.Idea新建一个SpringBoot项目 - - [Idea新建一个SpringBoot项目](https://www.cnblogs.com/gj-blog/p/10803591.html) - -## 2. springboot-oss(SpringBoot整合阿里云OSS文件上传、下载、查看、删除) - - [SpringBoot整合阿里云OSS文件上传、下载、查看、删除](https://www.cnblogs.com/gj-blog/p/10789544.html) - -## 3. springboot-aoplog(SpringBoot整合aop日志管理) - - [SpringBoot整合aop日志管理](https://www.cnblogs.com/gj-blog/p/10803600.html) - -## 4.springboot-wx(SpringBoot整合微信小程序登录) - - [SpringBoot整合微信小程序登录](https://www.cnblogs.com/gj-blog/p/10803607.html) - -## 5.springboot-mybatisplus(SpringBoot整合MybatisPlus) - -[SpringBoot整合MybatisPlus](https://www.cnblogs.com/gj-blog/p/10803593.html) \ No newline at end of file diff --git a/springboot-integration-examples/spring-dubbo/consumer/pom.xml b/springboot-integration-examples/spring-dubbo/consumer/pom.xml deleted file mode 100644 index dd983887..00000000 --- a/springboot-integration-examples/spring-dubbo/consumer/pom.xml +++ /dev/null @@ -1,79 +0,0 @@ - - - - - spring-dubbo - cn.lastwhisper.dubbo - 1.0-SNAPSHOT - - 4.0.0 - - cn.lastwhisper.dubbo - consumer - - consumer - - http://www.example.com - - - UTF-8 - 1.7 - 1.7 - - - - - junit - junit - 4.11 - test - - - - - - - - - maven-clean-plugin - 3.1.0 - - - - maven-resources-plugin - 3.0.2 - - - maven-compiler-plugin - 3.8.0 - - - maven-surefire-plugin - 2.22.1 - - - maven-jar-plugin - 3.0.2 - - - maven-install-plugin - 2.5.2 - - - maven-deploy-plugin - 2.8.2 - - - - maven-site-plugin - 3.7.1 - - - maven-project-info-reports-plugin - 3.0.0 - - - - - diff --git a/springboot-integration-examples/spring-dubbo/consumer/src/main/java/cn/lastwhisper/dubbo/ConsumerClient.java b/springboot-integration-examples/spring-dubbo/consumer/src/main/java/cn/lastwhisper/dubbo/ConsumerClient.java deleted file mode 100644 index 8764ae2b..00000000 --- a/springboot-integration-examples/spring-dubbo/consumer/src/main/java/cn/lastwhisper/dubbo/ConsumerClient.java +++ /dev/null @@ -1,50 +0,0 @@ -package cn.lastwhisper.dubbo; - -import com.alibaba.dubbo.rpc.RpcContext; -import org.springframework.context.support.ClassPathXmlApplicationContext; - -import java.time.Duration; -import java.time.Instant; -import java.util.Scanner; -import java.util.concurrent.Future; - -public class ConsumerClient { - public static void main(String[] args) throws Exception { - ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext-consumer.xml"); - context.start(); - while (true){ - Scanner scanner = new Scanner(System.in); - String message = scanner.next(); - DemoService demoService = (DemoService) context.getBean("consumerService"); // 获取远程服务代理 - // 测试负载均衡 - //for (int i = 0; i < 10; i++) { - // String hello = demoService.sayHello(message+i); // 执行远程方法 - // System.out.println(hello); // 显示调用结果 - //} - - // 测试同步调用 //关闭超时时间 - //Instant start = Instant.now(); - //demoService.sayHello(message);//业务3秒 - //Instant end = Instant.now(); - //demoService.sayHello2(message);//业务4秒 - //Instant end2 = Instant.now(); - ////sayHello执行完成耗时3127 - ////ayHello2执行完成耗时7129 - //System.out.println("sayHello执行完成耗时"+ Duration.between(start,end).toMillis()); - //System.out.println("sayHello2执行完成耗时"+ Duration.between(start,end2).toMillis()); - // 测试异步调用 - Instant start = Instant.now(); - demoService.sayHello(message);//业务3秒 - Future sendFuture = RpcContext.getContext().getFuture(); - Instant end = Instant.now(); - demoService.sayHello2(message);//业务4秒 - Future sendFuture2 = RpcContext.getContext().getFuture(); - Instant end2 = Instant.now(); - //sayHello执行完成耗时37 - //sayHello2执行完成耗时38 - System.out.println(sendFuture.get()+" sayHello执行完成耗时"+ Duration.between(start,end).toMillis()); - System.out.println(sendFuture2.get()+" sayHello2执行完成耗时"+ Duration.between(start,end2).toMillis()); - - } - } -} \ No newline at end of file diff --git a/springboot-integration-examples/spring-dubbo/consumer/src/main/java/cn/lastwhisper/dubbo/DemoService.java b/springboot-integration-examples/spring-dubbo/consumer/src/main/java/cn/lastwhisper/dubbo/DemoService.java deleted file mode 100644 index 6bea534a..00000000 --- a/springboot-integration-examples/spring-dubbo/consumer/src/main/java/cn/lastwhisper/dubbo/DemoService.java +++ /dev/null @@ -1,13 +0,0 @@ -package cn.lastwhisper.dubbo; - -import java.util.List; - -/** - * @author lastwhisper - */ -public interface DemoService { - String sayHello(String name); - String sayHello2(String name); - - List mergerTest(String message); -} diff --git a/springboot-integration-examples/spring-dubbo/consumer/src/main/java/cn/lastwhisper/dubbo/FilterConsumerClient.java b/springboot-integration-examples/spring-dubbo/consumer/src/main/java/cn/lastwhisper/dubbo/FilterConsumerClient.java deleted file mode 100644 index f812e5ee..00000000 --- a/springboot-integration-examples/spring-dubbo/consumer/src/main/java/cn/lastwhisper/dubbo/FilterConsumerClient.java +++ /dev/null @@ -1,18 +0,0 @@ -package cn.lastwhisper.dubbo; - -import org.springframework.context.support.ClassPathXmlApplicationContext; - -import java.util.Scanner; - -public class FilterConsumerClient { - public static void main(String[] args) throws Exception { - ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext-consumer.xml"); - context.start(); - while (true) { - Scanner scanner = new Scanner(System.in); - String message = scanner.next(); - DemoService demoService = (DemoService) context.getBean("consumerService"); // 获取远程服务代理 - System.out.println(demoService.sayHello(message)); - } - } -} \ No newline at end of file diff --git a/springboot-integration-examples/spring-dubbo/consumer/src/main/java/cn/lastwhisper/dubbo/MyMock.java b/springboot-integration-examples/spring-dubbo/consumer/src/main/java/cn/lastwhisper/dubbo/MyMock.java deleted file mode 100644 index 75d50110..00000000 --- a/springboot-integration-examples/spring-dubbo/consumer/src/main/java/cn/lastwhisper/dubbo/MyMock.java +++ /dev/null @@ -1,24 +0,0 @@ -package cn.lastwhisper.dubbo; - -import java.util.List; - -/** - * @author lastwhisper - */ -public class MyMock implements DemoService { - - @Override - public String sayHello(String name) { - return "抱歉,订单人数过多,请稍后重试"; - } - - @Override - public String sayHello2(String name) { - return "抱歉,订单人数过多,请稍后重试"; - } - - @Override - public List mergerTest(String message) { - return null; - } -} diff --git a/springboot-integration-examples/spring-dubbo/consumer/src/main/java/cn/lastwhisper/dubbo/MyStub.java b/springboot-integration-examples/spring-dubbo/consumer/src/main/java/cn/lastwhisper/dubbo/MyStub.java deleted file mode 100644 index f62ef57e..00000000 --- a/springboot-integration-examples/spring-dubbo/consumer/src/main/java/cn/lastwhisper/dubbo/MyStub.java +++ /dev/null @@ -1,41 +0,0 @@ -package cn.lastwhisper.dubbo; - -import java.util.List; - -/** - * @author lastwhisper - */ -public class MyStub implements DemoService { - - // 注入Proxy的构造函数 - private final DemoService demoService; - - public MyStub(DemoService demoService) { - this.demoService = demoService; - } - - @Override - public String sayHello(String name) { - System.out.println("sayHello ");//被调用直接打印 - if ("123".equals(name)) { - return "抱歉该值无法接受";//返回 - } else { - name = "sayHello " + name; - return this.demoService.sayHello(name);//返回 - } - } - - @Override - public String sayHello2(String name) { - System.out.println("sayHello2"); - return this.sayHello2(name); - } - - @Override - public List mergerTest(String message) { - System.out.println("mergerTest"); - return this.mergerTest(message); - } - - -} diff --git a/springboot-integration-examples/spring-dubbo/consumer/src/main/java/cn/lastwhisper/dubbo/ZipkinConsumerClient.java b/springboot-integration-examples/spring-dubbo/consumer/src/main/java/cn/lastwhisper/dubbo/ZipkinConsumerClient.java deleted file mode 100644 index 2a0d0274..00000000 --- a/springboot-integration-examples/spring-dubbo/consumer/src/main/java/cn/lastwhisper/dubbo/ZipkinConsumerClient.java +++ /dev/null @@ -1,18 +0,0 @@ -package cn.lastwhisper.dubbo; - -import org.springframework.context.support.ClassPathXmlApplicationContext; - -import java.util.Scanner; - -public class ZipkinConsumerClient { - public static void main(String[] args) throws Exception { - ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext-consumer.xml"); - context.start(); - while (true) { - Scanner scanner = new Scanner(System.in); - String message = scanner.next(); - DemoService demoService = (DemoService) context.getBean("consumerService"); // 获取远程服务代理 - System.out.println(demoService.sayHello(message)); - } - } -} \ No newline at end of file diff --git a/springboot-integration-examples/spring-dubbo/consumer/src/main/java/cn/lastwhisper/dubbo/controller/ConsumerControllerClient.java b/springboot-integration-examples/spring-dubbo/consumer/src/main/java/cn/lastwhisper/dubbo/controller/ConsumerControllerClient.java deleted file mode 100644 index 268d69e0..00000000 --- a/springboot-integration-examples/spring-dubbo/consumer/src/main/java/cn/lastwhisper/dubbo/controller/ConsumerControllerClient.java +++ /dev/null @@ -1,26 +0,0 @@ -package cn.lastwhisper.dubbo.controller; - -import cn.lastwhisper.dubbo.DemoService; -import com.alibaba.dubbo.rpc.RpcContext; -import org.springframework.context.support.ClassPathXmlApplicationContext; - -import java.time.Duration; -import java.time.Instant; -import java.util.Scanner; -import java.util.concurrent.Future; - -public class ConsumerControllerClient { - public static void main(String[] args) throws Exception { - ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext-consumer.xml"); - context.start(); - while (true){ - Scanner scanner = new Scanner(System.in); - String message = scanner.next(); - DemoService demoService = (DemoService) context.getBean("consumerService"); // 获取远程服务代理 - - for (int i = 0; i < 10; i++) { - demoService.sayHello(message+i); - } - } - } -} \ No newline at end of file diff --git a/springboot-integration-examples/spring-dubbo/consumer/src/main/java/cn/lastwhisper/dubbo/controller/ConsumerControllerClient2.java b/springboot-integration-examples/spring-dubbo/consumer/src/main/java/cn/lastwhisper/dubbo/controller/ConsumerControllerClient2.java deleted file mode 100644 index 6f8376f2..00000000 --- a/springboot-integration-examples/spring-dubbo/consumer/src/main/java/cn/lastwhisper/dubbo/controller/ConsumerControllerClient2.java +++ /dev/null @@ -1,25 +0,0 @@ -package cn.lastwhisper.dubbo.controller; - -import cn.lastwhisper.dubbo.DemoService; -import com.alibaba.dubbo.rpc.RpcContext; -import org.springframework.context.support.ClassPathXmlApplicationContext; - -import java.time.Duration; -import java.time.Instant; -import java.util.Scanner; -import java.util.concurrent.Future; - -public class ConsumerControllerClient2 { - public static void main(String[] args) throws Exception { - ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext-consumer.xml"); - context.start(); - while (true){ - Scanner scanner = new Scanner(System.in); - String message = scanner.next(); - DemoService demoService = (DemoService) context.getBean("consumerService"); // 获取远程服务代理 - for (int i = 0; i < 10; i++) { - demoService.sayHello(message+i); - } - } - } -} \ No newline at end of file diff --git a/springboot-integration-examples/spring-dubbo/consumer/src/main/java/cn/lastwhisper/dubbo/group/GroupConsumerClient.java b/springboot-integration-examples/spring-dubbo/consumer/src/main/java/cn/lastwhisper/dubbo/group/GroupConsumerClient.java deleted file mode 100644 index 06c67fe9..00000000 --- a/springboot-integration-examples/spring-dubbo/consumer/src/main/java/cn/lastwhisper/dubbo/group/GroupConsumerClient.java +++ /dev/null @@ -1,26 +0,0 @@ -package cn.lastwhisper.dubbo.group; - -import cn.lastwhisper.dubbo.DemoService; -import org.springframework.context.support.ClassPathXmlApplicationContext; - -import java.util.List; -import java.util.Scanner; - -public class GroupConsumerClient { - public static void main(String[] args) throws Exception { - ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext-group-consumer.xml"); - context.start(); - while (true) { - Scanner scanner = new Scanner(System.in); - String message = scanner.next(); - DemoService demoService = (DemoService) context.getBean("consumerService"); // 获取远程服务代理 - - String hello = demoService.sayHello(message ); // 执行远程方法 - List strings = demoService.mergerTest(message); - for (String str : strings) { - System.out.println(str); - } - //System.out.println(hello); // 显示调用结果 - } - } -} \ No newline at end of file diff --git a/springboot-integration-examples/spring-dubbo/consumer/src/main/java/cn/lastwhisper/dubbo/stub/StubConsumerClient.java b/springboot-integration-examples/spring-dubbo/consumer/src/main/java/cn/lastwhisper/dubbo/stub/StubConsumerClient.java deleted file mode 100644 index dbcc6619..00000000 --- a/springboot-integration-examples/spring-dubbo/consumer/src/main/java/cn/lastwhisper/dubbo/stub/StubConsumerClient.java +++ /dev/null @@ -1,21 +0,0 @@ -package cn.lastwhisper.dubbo.stub; - -import cn.lastwhisper.dubbo.DemoService; -import org.springframework.context.support.ClassPathXmlApplicationContext; - -import java.util.Scanner; - -public class StubConsumerClient { - public static void main(String[] args) throws Exception { - ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext-stub-consumer.xml"); - context.start(); - while (true) { - Scanner scanner = new Scanner(System.in); - String message = scanner.next(); - DemoService demoService = (DemoService) context.getBean("consumerService"); // 获取远程服务代理 - - String hello = demoService.sayHello(message); // 执行远程方法 - System.out.println(hello); // 显示调用结果 - } - } -} \ No newline at end of file diff --git a/springboot-integration-examples/spring-dubbo/consumer/src/main/java/cn/lastwhisper/dubbo/version/VersionConsumerClient.java b/springboot-integration-examples/spring-dubbo/consumer/src/main/java/cn/lastwhisper/dubbo/version/VersionConsumerClient.java deleted file mode 100644 index ef31de78..00000000 --- a/springboot-integration-examples/spring-dubbo/consumer/src/main/java/cn/lastwhisper/dubbo/version/VersionConsumerClient.java +++ /dev/null @@ -1,22 +0,0 @@ -package cn.lastwhisper.dubbo.version; - -import cn.lastwhisper.dubbo.DemoService; -import org.springframework.context.support.ClassPathXmlApplicationContext; - -import java.util.List; -import java.util.Scanner; - -public class VersionConsumerClient { - public static void main(String[] args) throws Exception { - ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext-version-consumer.xml"); - context.start(); - while (true) { - Scanner scanner = new Scanner(System.in); - String message = scanner.next(); - DemoService demoService = (DemoService) context.getBean("consumerService"); // 获取远程服务代理 - - String hello = demoService.sayHello(message ); // 执行远程方法 - System.out.println(hello); // 显示调用结果 - } - } -} \ No newline at end of file diff --git a/springboot-integration-examples/spring-dubbo/consumer/src/main/resources/applicationContext-consumer.xml b/springboot-integration-examples/spring-dubbo/consumer/src/main/resources/applicationContext-consumer.xml deleted file mode 100644 index 4958732e..00000000 --- a/springboot-integration-examples/spring-dubbo/consumer/src/main/resources/applicationContext-consumer.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - - - - - diff --git a/springboot-integration-examples/spring-dubbo/consumer/src/main/resources/applicationContext-group-consumer.xml b/springboot-integration-examples/spring-dubbo/consumer/src/main/resources/applicationContext-group-consumer.xml deleted file mode 100644 index ea7ad486..00000000 --- a/springboot-integration-examples/spring-dubbo/consumer/src/main/resources/applicationContext-group-consumer.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - - - - - - - - diff --git a/springboot-integration-examples/spring-dubbo/consumer/src/main/resources/applicationContext-stub-consumer.xml b/springboot-integration-examples/spring-dubbo/consumer/src/main/resources/applicationContext-stub-consumer.xml deleted file mode 100644 index 6a21555c..00000000 --- a/springboot-integration-examples/spring-dubbo/consumer/src/main/resources/applicationContext-stub-consumer.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - - - diff --git a/springboot-integration-examples/spring-dubbo/consumer/src/main/resources/applicationContext-version-consumer.xml b/springboot-integration-examples/spring-dubbo/consumer/src/main/resources/applicationContext-version-consumer.xml deleted file mode 100644 index c63d5ec5..00000000 --- a/springboot-integration-examples/spring-dubbo/consumer/src/main/resources/applicationContext-version-consumer.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - - - - - diff --git a/springboot-integration-examples/spring-dubbo/consumer/src/test/java/cn/lastwhisper/dubbo/AppTest.java b/springboot-integration-examples/spring-dubbo/consumer/src/test/java/cn/lastwhisper/dubbo/AppTest.java deleted file mode 100644 index 7fb1dee2..00000000 --- a/springboot-integration-examples/spring-dubbo/consumer/src/test/java/cn/lastwhisper/dubbo/AppTest.java +++ /dev/null @@ -1,20 +0,0 @@ -package cn.lastwhisper.dubbo; - -import static org.junit.Assert.assertTrue; - -import org.junit.Test; - -/** - * Unit test for simple App. - */ -public class AppTest -{ - /** - * Rigorous Test :-) - */ - @Test - public void shouldAnswerWithTrue() - { - assertTrue( true ); - } -} diff --git a/springboot-integration-examples/spring-dubbo/pom.xml b/springboot-integration-examples/spring-dubbo/pom.xml deleted file mode 100644 index eb49d00f..00000000 --- a/springboot-integration-examples/spring-dubbo/pom.xml +++ /dev/null @@ -1,146 +0,0 @@ - - - 4.0.0 - - cn.lastwhisper.dubbo - spring-dubbo - pom - 1.0-SNAPSHOT - - provider - consumer - - - UTF-8 - 1.7 - 1.7 - - - - - - - io.zipkin.brave - brave-bom - 5.5.0 - pom - import - - - - io.zipkin.reporter2 - zipkin-reporter-bom - 2.7.10 - pom - import - - - - - - - - - io.zipkin.brave - brave-instrumentation-dubbo-rpc - - - - io.zipkin.brave - brave-spring-beans - - - - io.zipkin.brave - brave-context-slf4j - - - - io.zipkin.reporter2 - zipkin-sender-okhttp3 - - - - com.101tec - zkclient - 0.9 - - - org.apache.zookeeper - zookeeper - 3.4.7 - pom - - - com.alibaba - dubbo - 2.5.3 - - - io.netty - netty-all - 4.1.25.Final - - - commons-logging - commons-logging - 1.2 - - - org.javassist - javassist - 3.21.0-GA - - - log4j - log4j - 1.2.17 - - - - org.springframework - spring-context - 4.3.18.RELEASE - - - org.springframework - spring-context-support - 4.3.18.RELEASE - - - org.springframework - spring-core - 4.3.18.RELEASE - - - org.springframework - spring-beans - 4.3.18.RELEASE - - - org.springframework - spring-aop - 4.3.18.RELEASE - - - org.springframework - spring-aspects - 4.3.18.RELEASE - - - org.springframework - spring-expression - 4.3.18.RELEASE - - - junit - junit - 4.12 - test - - - - - \ No newline at end of file diff --git a/springboot-integration-examples/spring-dubbo/provider/pom.xml b/springboot-integration-examples/spring-dubbo/provider/pom.xml deleted file mode 100644 index 4562d095..00000000 --- a/springboot-integration-examples/spring-dubbo/provider/pom.xml +++ /dev/null @@ -1,79 +0,0 @@ - - - - - spring-dubbo - cn.lastwhisper.dubbo - 1.0-SNAPSHOT - - 4.0.0 - - cn.lastwhisper.dubbo - provider - - provider - - http://www.example.com - - - UTF-8 - 1.7 - 1.7 - - - - - junit - junit - 4.11 - test - - - - - - - - - maven-clean-plugin - 3.1.0 - - - - maven-resources-plugin - 3.0.2 - - - maven-compiler-plugin - 3.8.0 - - - maven-surefire-plugin - 2.22.1 - - - maven-jar-plugin - 3.0.2 - - - maven-install-plugin - 2.5.2 - - - maven-deploy-plugin - 2.8.2 - - - - maven-site-plugin - 3.7.1 - - - maven-project-info-reports-plugin - 3.0.0 - - - - - diff --git a/springboot-integration-examples/spring-dubbo/provider/src/main/java/cn/lastwhisper/dubbo/DemoService.java b/springboot-integration-examples/spring-dubbo/provider/src/main/java/cn/lastwhisper/dubbo/DemoService.java deleted file mode 100644 index 16db169e..00000000 --- a/springboot-integration-examples/spring-dubbo/provider/src/main/java/cn/lastwhisper/dubbo/DemoService.java +++ /dev/null @@ -1,14 +0,0 @@ -package cn.lastwhisper.dubbo; - -import java.util.List; - -/** - * @author lastwhisper - */ -public interface DemoService { - String sayHello(String name); - - String sayHello2(String name); - - List mergerTest(String message); -} diff --git a/springboot-integration-examples/spring-dubbo/provider/src/main/java/cn/lastwhisper/dubbo/DemoServiceImpl.java b/springboot-integration-examples/spring-dubbo/provider/src/main/java/cn/lastwhisper/dubbo/DemoServiceImpl.java deleted file mode 100644 index 9a331739..00000000 --- a/springboot-integration-examples/spring-dubbo/provider/src/main/java/cn/lastwhisper/dubbo/DemoServiceImpl.java +++ /dev/null @@ -1,30 +0,0 @@ -package cn.lastwhisper.dubbo; - -import java.util.List; - -public class DemoServiceImpl implements DemoService { - public String sayHello(String name) { - System.out.println("Hello " + name); - try { - Thread.sleep(3000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - return "Hello " + name; - } - - @Override - public String sayHello2(String name) { - try { - Thread.sleep(4000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - return null; - } - - @Override - public List mergerTest(String message) { - return null; - } -} \ No newline at end of file diff --git a/springboot-integration-examples/spring-dubbo/provider/src/main/java/cn/lastwhisper/dubbo/MyMock.java b/springboot-integration-examples/spring-dubbo/provider/src/main/java/cn/lastwhisper/dubbo/MyMock.java deleted file mode 100644 index 75d50110..00000000 --- a/springboot-integration-examples/spring-dubbo/provider/src/main/java/cn/lastwhisper/dubbo/MyMock.java +++ /dev/null @@ -1,24 +0,0 @@ -package cn.lastwhisper.dubbo; - -import java.util.List; - -/** - * @author lastwhisper - */ -public class MyMock implements DemoService { - - @Override - public String sayHello(String name) { - return "抱歉,订单人数过多,请稍后重试"; - } - - @Override - public String sayHello2(String name) { - return "抱歉,订单人数过多,请稍后重试"; - } - - @Override - public List mergerTest(String message) { - return null; - } -} diff --git a/springboot-integration-examples/spring-dubbo/provider/src/main/java/cn/lastwhisper/dubbo/MyStub.java b/springboot-integration-examples/spring-dubbo/provider/src/main/java/cn/lastwhisper/dubbo/MyStub.java deleted file mode 100644 index f62ef57e..00000000 --- a/springboot-integration-examples/spring-dubbo/provider/src/main/java/cn/lastwhisper/dubbo/MyStub.java +++ /dev/null @@ -1,41 +0,0 @@ -package cn.lastwhisper.dubbo; - -import java.util.List; - -/** - * @author lastwhisper - */ -public class MyStub implements DemoService { - - // 注入Proxy的构造函数 - private final DemoService demoService; - - public MyStub(DemoService demoService) { - this.demoService = demoService; - } - - @Override - public String sayHello(String name) { - System.out.println("sayHello ");//被调用直接打印 - if ("123".equals(name)) { - return "抱歉该值无法接受";//返回 - } else { - name = "sayHello " + name; - return this.demoService.sayHello(name);//返回 - } - } - - @Override - public String sayHello2(String name) { - System.out.println("sayHello2"); - return this.sayHello2(name); - } - - @Override - public List mergerTest(String message) { - System.out.println("mergerTest"); - return this.mergerTest(message); - } - - -} diff --git a/springboot-integration-examples/spring-dubbo/provider/src/main/java/cn/lastwhisper/dubbo/ProviderClient.java b/springboot-integration-examples/spring-dubbo/provider/src/main/java/cn/lastwhisper/dubbo/ProviderClient.java deleted file mode 100644 index 137eedd6..00000000 --- a/springboot-integration-examples/spring-dubbo/provider/src/main/java/cn/lastwhisper/dubbo/ProviderClient.java +++ /dev/null @@ -1,21 +0,0 @@ -package cn.lastwhisper.dubbo; - -import org.springframework.context.support.ClassPathXmlApplicationContext; - -import java.io.IOException; - -/** - * @author lastwhisper - */ -public class ProviderClient { - public static void main(String[] args) { - ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext-provider.xml"); - context.start(); - - try { - System.in.read(); - } catch (IOException e) { - e.printStackTrace(); - } - } -} diff --git a/springboot-integration-examples/spring-dubbo/provider/src/main/java/cn/lastwhisper/dubbo/controller/ProviderControllerClient.java b/springboot-integration-examples/spring-dubbo/provider/src/main/java/cn/lastwhisper/dubbo/controller/ProviderControllerClient.java deleted file mode 100644 index 9df33d87..00000000 --- a/springboot-integration-examples/spring-dubbo/provider/src/main/java/cn/lastwhisper/dubbo/controller/ProviderControllerClient.java +++ /dev/null @@ -1,22 +0,0 @@ -package cn.lastwhisper.dubbo.controller; - -import org.springframework.context.support.ClassPathXmlApplicationContext; - -import java.io.IOException; - -/** - * 连接控制 - * @author lastwhisper - */ -public class ProviderControllerClient { - public static void main(String[] args) { - ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext-controller-provider.xml"); - context.start(); - - try { - System.in.read(); - } catch (IOException e) { - e.printStackTrace(); - } - } -} diff --git a/springboot-integration-examples/spring-dubbo/provider/src/main/java/cn/lastwhisper/dubbo/filter/MyFilter.java b/springboot-integration-examples/spring-dubbo/provider/src/main/java/cn/lastwhisper/dubbo/filter/MyFilter.java deleted file mode 100644 index 548bac54..00000000 --- a/springboot-integration-examples/spring-dubbo/provider/src/main/java/cn/lastwhisper/dubbo/filter/MyFilter.java +++ /dev/null @@ -1,20 +0,0 @@ -package cn.lastwhisper.dubbo.filter; - -import com.alibaba.dubbo.rpc.*; - -/** - * @author lastwhisper - */ -public class MyFilter implements Filter { - @Override - public Result invoke(Invoker invoker, Invocation invocation) throws RpcException { - - System.out.println("服务调用之前,方法名:" + invocation.getMethodName()); - //调用后续服务 - Result invoke = invoker.invoke(invocation); - - System.out.println("服务调用之后"); - - return invoke; - } -} diff --git a/springboot-integration-examples/spring-dubbo/provider/src/main/java/cn/lastwhisper/dubbo/group/GroupProviderClient.java b/springboot-integration-examples/spring-dubbo/provider/src/main/java/cn/lastwhisper/dubbo/group/GroupProviderClient.java deleted file mode 100644 index 71c95070..00000000 --- a/springboot-integration-examples/spring-dubbo/provider/src/main/java/cn/lastwhisper/dubbo/group/GroupProviderClient.java +++ /dev/null @@ -1,21 +0,0 @@ -package cn.lastwhisper.dubbo.group; - -import org.springframework.context.support.ClassPathXmlApplicationContext; - -import java.io.IOException; - -/** - * @author lastwhisper - */ -public class GroupProviderClient { - public static void main(String[] args) { - ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext-group-provider.xml"); - context.start(); - - try { - System.in.read(); - } catch (IOException e) { - e.printStackTrace(); - } - } -} diff --git a/springboot-integration-examples/spring-dubbo/provider/src/main/java/cn/lastwhisper/dubbo/group/GroupServiceImplA.java b/springboot-integration-examples/spring-dubbo/provider/src/main/java/cn/lastwhisper/dubbo/group/GroupServiceImplA.java deleted file mode 100644 index 6a44ffba..00000000 --- a/springboot-integration-examples/spring-dubbo/provider/src/main/java/cn/lastwhisper/dubbo/group/GroupServiceImplA.java +++ /dev/null @@ -1,34 +0,0 @@ -package cn.lastwhisper.dubbo.group; - -import cn.lastwhisper.dubbo.DemoService; - -import java.util.Arrays; -import java.util.List; - -public class GroupServiceImplA implements DemoService { - public String sayHello(String name) { - System.out.println("Hello group A " + name); - try { - Thread.sleep(3000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - return "Hello group A " + name; - } - - @Override - public String sayHello2(String name) { - try { - Thread.sleep(4000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - return null; - } - - @Override - public List mergerTest(String message) { - String str = "Group A =" + message; - return Arrays.asList(str); - } -} \ No newline at end of file diff --git a/springboot-integration-examples/spring-dubbo/provider/src/main/java/cn/lastwhisper/dubbo/group/GroupServiceImplB.java b/springboot-integration-examples/spring-dubbo/provider/src/main/java/cn/lastwhisper/dubbo/group/GroupServiceImplB.java deleted file mode 100644 index 8986b4be..00000000 --- a/springboot-integration-examples/spring-dubbo/provider/src/main/java/cn/lastwhisper/dubbo/group/GroupServiceImplB.java +++ /dev/null @@ -1,34 +0,0 @@ -package cn.lastwhisper.dubbo.group; - -import cn.lastwhisper.dubbo.DemoService; - -import java.util.Arrays; -import java.util.List; - -public class GroupServiceImplB implements DemoService { - public String sayHello(String name) { - System.out.println("Hello group B " + name); - try { - Thread.sleep(3000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - return "Hello group B " + name; - } - - @Override - public String sayHello2(String name) { - try { - Thread.sleep(4000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - return null; - } - - @Override - public List mergerTest(String message) { - String str = "Group B =" + message; - return Arrays.asList(str); - } -} \ No newline at end of file diff --git a/springboot-integration-examples/spring-dubbo/provider/src/main/java/cn/lastwhisper/dubbo/loadbalance/LoadBalanceProviderClient_1.java b/springboot-integration-examples/spring-dubbo/provider/src/main/java/cn/lastwhisper/dubbo/loadbalance/LoadBalanceProviderClient_1.java deleted file mode 100644 index ac015ffd..00000000 --- a/springboot-integration-examples/spring-dubbo/provider/src/main/java/cn/lastwhisper/dubbo/loadbalance/LoadBalanceProviderClient_1.java +++ /dev/null @@ -1,21 +0,0 @@ -package cn.lastwhisper.dubbo.loadbalance; - -import org.springframework.context.support.ClassPathXmlApplicationContext; - -import java.io.IOException; - -/** - * @author lastwhisper - */ -public class LoadBalanceProviderClient_1 { - public static void main(String[] args) { - ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext-loadbalance-provider-1.xml"); - context.start(); - - try { - System.in.read(); - } catch (IOException e) { - e.printStackTrace(); - } - } -} diff --git a/springboot-integration-examples/spring-dubbo/provider/src/main/java/cn/lastwhisper/dubbo/loadbalance/LoadBalanceProviderClient_2.java b/springboot-integration-examples/spring-dubbo/provider/src/main/java/cn/lastwhisper/dubbo/loadbalance/LoadBalanceProviderClient_2.java deleted file mode 100644 index c31200b5..00000000 --- a/springboot-integration-examples/spring-dubbo/provider/src/main/java/cn/lastwhisper/dubbo/loadbalance/LoadBalanceProviderClient_2.java +++ /dev/null @@ -1,22 +0,0 @@ -package cn.lastwhisper.dubbo.loadbalance; - -import org.springframework.context.support.ClassPathXmlApplicationContext; - -import java.io.IOException; - -/** - * @author lastwhisper - */ -public class LoadBalanceProviderClient_2 { - public static void main(String[] args) { - ClassPathXmlApplicationContext context = - new ClassPathXmlApplicationContext("applicationContext-loadbalance-provider-2.xml"); - context.start(); - - try { - System.in.read(); - } catch (IOException e) { - e.printStackTrace(); - } - } -} diff --git a/springboot-integration-examples/spring-dubbo/provider/src/main/java/cn/lastwhisper/dubbo/loadbalance/LoadBalanceProviderClient_3.java b/springboot-integration-examples/spring-dubbo/provider/src/main/java/cn/lastwhisper/dubbo/loadbalance/LoadBalanceProviderClient_3.java deleted file mode 100644 index aa2bae8e..00000000 --- a/springboot-integration-examples/spring-dubbo/provider/src/main/java/cn/lastwhisper/dubbo/loadbalance/LoadBalanceProviderClient_3.java +++ /dev/null @@ -1,21 +0,0 @@ -package cn.lastwhisper.dubbo.loadbalance; - -import org.springframework.context.support.ClassPathXmlApplicationContext; - -import java.io.IOException; - -/** - * @author lastwhisper - */ -public class LoadBalanceProviderClient_3 { - public static void main(String[] args) { - ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext-loadbalance-provider-3.xml"); - context.start(); - - try { - System.in.read(); - } catch (IOException e) { - e.printStackTrace(); - } - } -} diff --git a/springboot-integration-examples/spring-dubbo/provider/src/main/java/cn/lastwhisper/dubbo/stub/StubProviderClient.java b/springboot-integration-examples/spring-dubbo/provider/src/main/java/cn/lastwhisper/dubbo/stub/StubProviderClient.java deleted file mode 100644 index 5a299979..00000000 --- a/springboot-integration-examples/spring-dubbo/provider/src/main/java/cn/lastwhisper/dubbo/stub/StubProviderClient.java +++ /dev/null @@ -1,22 +0,0 @@ -package cn.lastwhisper.dubbo.stub; - -import org.springframework.context.support.ClassPathXmlApplicationContext; - -import java.io.IOException; - -/** - * @author lastwhisper - */ -public class StubProviderClient { - // 测试本地存根和本地伪装 - public static void main(String[] args) { - ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext-stub-provider.xml"); - context.start(); - - try { - System.in.read(); - } catch (IOException e) { - e.printStackTrace(); - } - } -} diff --git a/springboot-integration-examples/spring-dubbo/provider/src/main/java/cn/lastwhisper/dubbo/stub/StubServiceImpl.java b/springboot-integration-examples/spring-dubbo/provider/src/main/java/cn/lastwhisper/dubbo/stub/StubServiceImpl.java deleted file mode 100644 index 8b00315a..00000000 --- a/springboot-integration-examples/spring-dubbo/provider/src/main/java/cn/lastwhisper/dubbo/stub/StubServiceImpl.java +++ /dev/null @@ -1,34 +0,0 @@ -package cn.lastwhisper.dubbo.stub; - -import cn.lastwhisper.dubbo.DemoService; - -import java.util.Arrays; -import java.util.List; - -public class StubServiceImpl implements DemoService { - public String sayHello(String name) { - System.out.println("Hello stub " + name); - try { - Thread.sleep(4000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - return "Hello-provider-stub " + name; - } - - @Override - public String sayHello2(String name) { - try { - Thread.sleep(4000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - return null; - } - - @Override - public List mergerTest(String message) { - String str = "Group A =" + message; - return Arrays.asList(str); - } -} \ No newline at end of file diff --git a/springboot-integration-examples/spring-dubbo/provider/src/main/java/cn/lastwhisper/dubbo/version/VersionProviderClient.java b/springboot-integration-examples/spring-dubbo/provider/src/main/java/cn/lastwhisper/dubbo/version/VersionProviderClient.java deleted file mode 100644 index b3583c6b..00000000 --- a/springboot-integration-examples/spring-dubbo/provider/src/main/java/cn/lastwhisper/dubbo/version/VersionProviderClient.java +++ /dev/null @@ -1,21 +0,0 @@ -package cn.lastwhisper.dubbo.version; - -import org.springframework.context.support.ClassPathXmlApplicationContext; - -import java.io.IOException; - -/** - * @author lastwhisper - */ -public class VersionProviderClient { - public static void main(String[] args) { - ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext-Version-provider.xml"); - context.start(); - - try { - System.in.read(); - } catch (IOException e) { - e.printStackTrace(); - } - } -} diff --git a/springboot-integration-examples/spring-dubbo/provider/src/main/java/cn/lastwhisper/dubbo/version/VersionServiceImplA.java b/springboot-integration-examples/spring-dubbo/provider/src/main/java/cn/lastwhisper/dubbo/version/VersionServiceImplA.java deleted file mode 100644 index bb567384..00000000 --- a/springboot-integration-examples/spring-dubbo/provider/src/main/java/cn/lastwhisper/dubbo/version/VersionServiceImplA.java +++ /dev/null @@ -1,34 +0,0 @@ -package cn.lastwhisper.dubbo.version; - -import cn.lastwhisper.dubbo.DemoService; - -import java.util.Arrays; -import java.util.List; - -public class VersionServiceImplA implements DemoService { - public String sayHello(String name) { - System.out.println("Hello group A version 1.0.0 " + name); - try { - Thread.sleep(3000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - return "Hello group A version 1.0.0" + name; - } - - @Override - public String sayHello2(String name) { - try { - Thread.sleep(4000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - return null; - } - - @Override - public List mergerTest(String message) { - String str = "Group A =" + message; - return Arrays.asList(str); - } -} \ No newline at end of file diff --git a/springboot-integration-examples/spring-dubbo/provider/src/main/java/cn/lastwhisper/dubbo/version/VersionServiceImplB.java b/springboot-integration-examples/spring-dubbo/provider/src/main/java/cn/lastwhisper/dubbo/version/VersionServiceImplB.java deleted file mode 100644 index e49a321b..00000000 --- a/springboot-integration-examples/spring-dubbo/provider/src/main/java/cn/lastwhisper/dubbo/version/VersionServiceImplB.java +++ /dev/null @@ -1,34 +0,0 @@ -package cn.lastwhisper.dubbo.version; - -import cn.lastwhisper.dubbo.DemoService; - -import java.util.Arrays; -import java.util.List; - -public class VersionServiceImplB implements DemoService { - public String sayHello(String name) { - System.out.println("Hello group A version 2.0.0 " + name); - try { - Thread.sleep(3000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - return "Hello group A version 2.0.0" + name; - } - - @Override - public String sayHello2(String name) { - try { - Thread.sleep(4000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - return null; - } - - @Override - public List mergerTest(String message) { - String str = "Group B =" + message; - return Arrays.asList(str); - } -} \ No newline at end of file diff --git a/springboot-integration-examples/spring-dubbo/provider/src/main/java/cn/lastwhisper/dubbo/zipkin/ZipkinProviderClient.java b/springboot-integration-examples/spring-dubbo/provider/src/main/java/cn/lastwhisper/dubbo/zipkin/ZipkinProviderClient.java deleted file mode 100644 index a2353d43..00000000 --- a/springboot-integration-examples/spring-dubbo/provider/src/main/java/cn/lastwhisper/dubbo/zipkin/ZipkinProviderClient.java +++ /dev/null @@ -1,21 +0,0 @@ -package cn.lastwhisper.dubbo.zipkin; - -import org.springframework.context.support.ClassPathXmlApplicationContext; - -import java.io.IOException; - -/** - * @author lastwhisper - */ -public class ZipkinProviderClient { - public static void main(String[] args) { - ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext-zipkin-provider.xml"); - context.start(); - - try { - System.in.read(); - } catch (IOException e) { - e.printStackTrace(); - } - } -} diff --git a/springboot-integration-examples/spring-dubbo/provider/src/main/resources/META-INF/dubbo/com.alibaba.dubbo.rpc.Filter b/springboot-integration-examples/spring-dubbo/provider/src/main/resources/META-INF/dubbo/com.alibaba.dubbo.rpc.Filter deleted file mode 100644 index 05b928bf..00000000 --- a/springboot-integration-examples/spring-dubbo/provider/src/main/resources/META-INF/dubbo/com.alibaba.dubbo.rpc.Filter +++ /dev/null @@ -1 +0,0 @@ -MyFilterExt=cn.lastwhisper.dubbo.filter.MyFilter \ No newline at end of file diff --git a/springboot-integration-examples/spring-dubbo/provider/src/main/resources/applicationContext-Version-provider.xml b/springboot-integration-examples/spring-dubbo/provider/src/main/resources/applicationContext-Version-provider.xml deleted file mode 100644 index 4ccc5016..00000000 --- a/springboot-integration-examples/spring-dubbo/provider/src/main/resources/applicationContext-Version-provider.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/springboot-integration-examples/spring-dubbo/provider/src/main/resources/applicationContext-controller-provider.xml b/springboot-integration-examples/spring-dubbo/provider/src/main/resources/applicationContext-controller-provider.xml deleted file mode 100644 index 495033d6..00000000 --- a/springboot-integration-examples/spring-dubbo/provider/src/main/resources/applicationContext-controller-provider.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/springboot-integration-examples/spring-dubbo/provider/src/main/resources/applicationContext-group-provider.xml b/springboot-integration-examples/spring-dubbo/provider/src/main/resources/applicationContext-group-provider.xml deleted file mode 100644 index c1f65b8c..00000000 --- a/springboot-integration-examples/spring-dubbo/provider/src/main/resources/applicationContext-group-provider.xml +++ /dev/null @@ -1,45 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - diff --git a/springboot-integration-examples/spring-dubbo/provider/src/main/resources/applicationContext-loadbalance-provider-1.xml b/springboot-integration-examples/spring-dubbo/provider/src/main/resources/applicationContext-loadbalance-provider-1.xml deleted file mode 100644 index a907aa8e..00000000 --- a/springboot-integration-examples/spring-dubbo/provider/src/main/resources/applicationContext-loadbalance-provider-1.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/springboot-integration-examples/spring-dubbo/provider/src/main/resources/applicationContext-loadbalance-provider-2.xml b/springboot-integration-examples/spring-dubbo/provider/src/main/resources/applicationContext-loadbalance-provider-2.xml deleted file mode 100644 index c4f922de..00000000 --- a/springboot-integration-examples/spring-dubbo/provider/src/main/resources/applicationContext-loadbalance-provider-2.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/springboot-integration-examples/spring-dubbo/provider/src/main/resources/applicationContext-loadbalance-provider-3.xml b/springboot-integration-examples/spring-dubbo/provider/src/main/resources/applicationContext-loadbalance-provider-3.xml deleted file mode 100644 index ec6dce9f..00000000 --- a/springboot-integration-examples/spring-dubbo/provider/src/main/resources/applicationContext-loadbalance-provider-3.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/springboot-integration-examples/spring-dubbo/provider/src/main/resources/applicationContext-provider.xml b/springboot-integration-examples/spring-dubbo/provider/src/main/resources/applicationContext-provider.xml deleted file mode 100644 index 268b912d..00000000 --- a/springboot-integration-examples/spring-dubbo/provider/src/main/resources/applicationContext-provider.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/springboot-integration-examples/spring-dubbo/provider/src/main/resources/applicationContext-stub-provider.xml b/springboot-integration-examples/spring-dubbo/provider/src/main/resources/applicationContext-stub-provider.xml deleted file mode 100644 index 8c1c30fd..00000000 --- a/springboot-integration-examples/spring-dubbo/provider/src/main/resources/applicationContext-stub-provider.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/springboot-integration-examples/spring-dubbo/provider/src/main/resources/applicationContext-zipkin-provider.xml b/springboot-integration-examples/spring-dubbo/provider/src/main/resources/applicationContext-zipkin-provider.xml deleted file mode 100644 index 893c22b6..00000000 --- a/springboot-integration-examples/spring-dubbo/provider/src/main/resources/applicationContext-zipkin-provider.xml +++ /dev/null @@ -1,59 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/springboot-integration-examples/spring-dubbo/provider/src/test/java/cn/lastwhisper/dubbo/AppTest.java b/springboot-integration-examples/spring-dubbo/provider/src/test/java/cn/lastwhisper/dubbo/AppTest.java deleted file mode 100644 index 7fb1dee2..00000000 --- a/springboot-integration-examples/spring-dubbo/provider/src/test/java/cn/lastwhisper/dubbo/AppTest.java +++ /dev/null @@ -1,20 +0,0 @@ -package cn.lastwhisper.dubbo; - -import static org.junit.Assert.assertTrue; - -import org.junit.Test; - -/** - * Unit test for simple App. - */ -public class AppTest -{ - /** - * Rigorous Test :-) - */ - @Test - public void shouldAnswerWithTrue() - { - assertTrue( true ); - } -} diff --git a/springboot-integration-examples/spring-springsecurity/pom.xml b/springboot-integration-examples/spring-springsecurity/pom.xml deleted file mode 100644 index 17cdc158..00000000 --- a/springboot-integration-examples/spring-springsecurity/pom.xml +++ /dev/null @@ -1,60 +0,0 @@ - - - 4.0.0 - - cn.lastwhisper - springsecurity - 1.0-SNAPSHOT - war - - - UTF-8 - 5.0.5.RELEASE - - - - - org.springframework.security - spring-security-web - ${spring.version} - - - org.springframework.security - spring-security-config - ${spring.version} - - - - - junit - junit - 4.11 - test - - - - - javax.servlet - servlet-api - 2.5 - provided - - - - - - org.apache.tomcat.maven - tomcat7-maven-plugin - 2.2 - - - 8080 - - / - - - - - \ No newline at end of file diff --git a/springboot-integration-examples/spring-springsecurity/src/main/java/cn/lastwhisper/springsecurity/UserDetailsServiceImpl.java b/springboot-integration-examples/spring-springsecurity/src/main/java/cn/lastwhisper/springsecurity/UserDetailsServiceImpl.java deleted file mode 100644 index 36a9725a..00000000 --- a/springboot-integration-examples/spring-springsecurity/src/main/java/cn/lastwhisper/springsecurity/UserDetailsServiceImpl.java +++ /dev/null @@ -1,24 +0,0 @@ -package cn.lastwhisper.springsecurity; - -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.authority.SimpleGrantedAuthority; -import org.springframework.security.core.userdetails.User; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.core.userdetails.UserDetailsService; -import org.springframework.security.core.userdetails.UsernameNotFoundException; - -import java.util.ArrayList; -import java.util.List; - -public class UserDetailsServiceImpl implements UserDetailsService { - @Override - public UserDetails loadUserByUsername(String s) throws - UsernameNotFoundException { - System.out.println("经过UserDetailsServiceImpl"); - //构建角色集合,项目中此处应该是根据用户名查询用户的角色列表 - List grantedAuthors = new ArrayList<>(); - grantedAuthors.add(new SimpleGrantedAuthority("ROLE_ADMIN")); - return new User(s, "$2a$10$61ogZY7EXsMDWeVGQpDq3OBF1.phaUu7.xrwLyWFTOu8woE08zMIW", - grantedAuthors); - } -} \ No newline at end of file diff --git a/springboot-integration-examples/spring-springsecurity/src/main/resources/spring-security.xml b/springboot-integration-examples/spring-springsecurity/src/main/resources/spring-security.xml deleted file mode 100644 index 5a33719e..00000000 --- a/springboot-integration-examples/spring-springsecurity/src/main/resources/spring-security.xml +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/springboot-integration-examples/spring-springsecurity/src/main/webapp/WEB-INF/web.xml b/springboot-integration-examples/spring-springsecurity/src/main/webapp/WEB-INF/web.xml deleted file mode 100644 index 4fb5a663..00000000 --- a/springboot-integration-examples/spring-springsecurity/src/main/webapp/WEB-INF/web.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - contextConfigLocation - classpath:spring-security.xml - - - - org.springframework.web.context.ContextLoaderListener - - - - springSecurityFilterChain - org.springframework.web.filter.DelegatingFilterProxy - - - springSecurityFilterChain - /* - - \ No newline at end of file diff --git a/springboot-integration-examples/spring-springsecurity/src/main/webapp/index.html b/springboot-integration-examples/spring-springsecurity/src/main/webapp/index.html deleted file mode 100644 index d69fee62..00000000 --- a/springboot-integration-examples/spring-springsecurity/src/main/webapp/index.html +++ /dev/null @@ -1,10 +0,0 @@ - - - - - index - - - spring security - - \ No newline at end of file diff --git a/springboot-integration-examples/spring-springsecurity/src/main/webapp/login.html b/springboot-integration-examples/spring-springsecurity/src/main/webapp/login.html deleted file mode 100644 index 77e90039..00000000 --- a/springboot-integration-examples/spring-springsecurity/src/main/webapp/login.html +++ /dev/null @@ -1,22 +0,0 @@ - - - - - login - - -

- - - - - - - - - -
username
password
- -
- - \ No newline at end of file diff --git a/springboot-integration-examples/spring-springsecurity/src/main/webapp/login_error.html b/springboot-integration-examples/spring-springsecurity/src/main/webapp/login_error.html deleted file mode 100644 index 0273fd14..00000000 --- a/springboot-integration-examples/spring-springsecurity/src/main/webapp/login_error.html +++ /dev/null @@ -1,10 +0,0 @@ - - - - - login error - - -username or password error! - - \ No newline at end of file diff --git a/springboot-integration-examples/spring-springsecurity/src/test/java/cn/lastwhisper/bcrypt/BcryptTest.java b/springboot-integration-examples/spring-springsecurity/src/test/java/cn/lastwhisper/bcrypt/BcryptTest.java deleted file mode 100644 index 80f3f3eb..00000000 --- a/springboot-integration-examples/spring-springsecurity/src/test/java/cn/lastwhisper/bcrypt/BcryptTest.java +++ /dev/null @@ -1,24 +0,0 @@ -package cn.lastwhisper.bcrypt; - -import org.junit.Assert; -import org.junit.Test; -import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; - - -/** - * - * @author lastwhisper - * @date 2019/11/19 - */ -public class BcryptTest { - - @Test - public void test(){ - // Create an encoder with strength 16 - BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(); - String result = encoder.encode("123456"); - System.out.println(result); - Assert.assertTrue(encoder.matches("123456", result)); - } - -} diff --git a/springboot-integration-examples/spring-thymeleaf/pom.xml b/springboot-integration-examples/spring-thymeleaf/pom.xml deleted file mode 100644 index de1ffde7..00000000 --- a/springboot-integration-examples/spring-thymeleaf/pom.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - 4.0.0 - - cn.lastwhisper - spring-thymeleaf - 1.0-SNAPSHOT - - - - org.thymeleaf - thymeleaf - 3.0.11.RELEASE - - - \ No newline at end of file diff --git a/springboot-integration-examples/spring-thymeleaf/src/main/java/cn/lastwhisper/thymeleaf/Test.java b/springboot-integration-examples/spring-thymeleaf/src/main/java/cn/lastwhisper/thymeleaf/Test.java deleted file mode 100644 index 7065a5b5..00000000 --- a/springboot-integration-examples/spring-thymeleaf/src/main/java/cn/lastwhisper/thymeleaf/Test.java +++ /dev/null @@ -1,47 +0,0 @@ -package cn.lastwhisper.thymeleaf; - -import org.thymeleaf.TemplateEngine; -import org.thymeleaf.context.Context; -import org.thymeleaf.templatemode.TemplateMode; -import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver; - -import java.io.File; -import java.io.PrintWriter; -import java.util.HashMap; -import java.util.Map; - -/** - * - * @author lastwhisper - * @date 2019/11/19 - */ -public class Test { - public static void main(String[] args) { - // 1.上下文 - Context context = new Context(); - //创建数据模型 - Map dataModel = new HashMap(1); - dataModel.put("name", "青橙电商系统"); - context.setVariables(dataModel); - // 2.准备文件 - File dest = new File("d:/test_out.html"); - // 3.生成页面 - try { - PrintWriter writer = new PrintWriter(dest, "UTF-8"); - //模板解析器 - ClassLoaderTemplateResolver resolver = new ClassLoaderTemplateResolver(); - //模板模型 - resolver.setTemplateMode(TemplateMode.HTML); - //后缀 - resolver.setSuffix(".html"); - //创建模板引擎 - TemplateEngine engine = new TemplateEngine(); - //设置模板解析器 - engine.setTemplateResolver(resolver); - //执行模板引擎 - engine.process("test", context, writer); - } catch (Exception e) { - e.printStackTrace(); - } - } -} diff --git a/springboot-integration-examples/spring-thymeleaf/src/main/resources/test.html b/springboot-integration-examples/spring-thymeleaf/src/main/resources/test.html deleted file mode 100644 index d919f7bf..00000000 --- a/springboot-integration-examples/spring-thymeleaf/src/main/resources/test.html +++ /dev/null @@ -1,10 +0,0 @@ - - - - - thymeleaf入门demo - - - - - \ No newline at end of file diff --git a/springboot-integration-examples/spring-validated/.mvn/wrapper/MavenWrapperDownloader.java b/springboot-integration-examples/spring-validated/.mvn/wrapper/MavenWrapperDownloader.java deleted file mode 100644 index 7f91a56e..00000000 --- a/springboot-integration-examples/spring-validated/.mvn/wrapper/MavenWrapperDownloader.java +++ /dev/null @@ -1,114 +0,0 @@ -/* -Licensed to the Apache Software Foundation (ASF) under one -or more contributor license agreements. See the NOTICE file -distributed with this work for additional information -regarding copyright ownership. The ASF licenses this file -to you under the Apache License, Version 2.0 (the -"License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, -software distributed under the License is distributed on an -"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -KIND, either express or implied. See the License for the -specific language governing permissions and limitations -under the License. -*/ - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.net.URL; -import java.nio.channels.Channels; -import java.nio.channels.ReadableByteChannel; -import java.util.Properties; - -public class MavenWrapperDownloader { - - /** - * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. - */ - private static final String DEFAULT_DOWNLOAD_URL = - "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"; - - /** - * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to - * use instead of the default one. - */ - private static final String MAVEN_WRAPPER_PROPERTIES_PATH = - ".mvn/wrapper/maven-wrapper.properties"; - - /** - * Path where the maven-wrapper.jar will be saved to. - */ - private static final String MAVEN_WRAPPER_JAR_PATH = - ".mvn/wrapper/maven-wrapper.jar"; - - /** - * Name of the property which should be used to override the default download url for the wrapper. - */ - private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; - - public static void main(String args[]) { - System.out.println("- Downloader started"); - File baseDirectory = new File(args[0]); - System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); - - // If the maven-wrapper.properties exists, read it and check if it contains a custom - // wrapperUrl parameter. - File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); - String url = DEFAULT_DOWNLOAD_URL; - if (mavenWrapperPropertyFile.exists()) { - FileInputStream mavenWrapperPropertyFileInputStream = null; - try { - mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); - Properties mavenWrapperProperties = new Properties(); - mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); - url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); - } catch (IOException e) { - System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); - } finally { - try { - if (mavenWrapperPropertyFileInputStream != null) { - mavenWrapperPropertyFileInputStream.close(); - } - } catch (IOException e) { - // Ignore ... - } - } - } - System.out.println("- Downloading from: : " + url); - - File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); - if (!outputFile.getParentFile().exists()) { - if (!outputFile.getParentFile().mkdirs()) { - System.out.println( - "- ERROR creating output direcrory '" + outputFile.getParentFile().getAbsolutePath() + "'"); - } - } - System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); - try { - downloadFileFromURL(url, outputFile); - System.out.println("Done"); - System.exit(0); - } catch (Throwable e) { - System.out.println("- Error downloading"); - e.printStackTrace(); - System.exit(1); - } - } - - private static void downloadFileFromURL(String urlString, File destination) throws Exception { - URL website = new URL(urlString); - ReadableByteChannel rbc; - rbc = Channels.newChannel(website.openStream()); - FileOutputStream fos = new FileOutputStream(destination); - fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); - fos.close(); - rbc.close(); - } - -} diff --git a/springboot-integration-examples/spring-validated/.mvn/wrapper/maven-wrapper.jar b/springboot-integration-examples/spring-validated/.mvn/wrapper/maven-wrapper.jar deleted file mode 100644 index 01e67997..00000000 Binary files a/springboot-integration-examples/spring-validated/.mvn/wrapper/maven-wrapper.jar and /dev/null differ diff --git a/springboot-integration-examples/spring-validated/.mvn/wrapper/maven-wrapper.properties b/springboot-integration-examples/spring-validated/.mvn/wrapper/maven-wrapper.properties deleted file mode 100644 index cd0d451c..00000000 --- a/springboot-integration-examples/spring-validated/.mvn/wrapper/maven-wrapper.properties +++ /dev/null @@ -1 +0,0 @@ -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip diff --git a/springboot-integration-examples/spring-validated/pom.xml b/springboot-integration-examples/spring-validated/pom.xml deleted file mode 100644 index ce112841..00000000 --- a/springboot-integration-examples/spring-validated/pom.xml +++ /dev/null @@ -1,72 +0,0 @@ - - - 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 2.2.0.RELEASE - - - cn.lastwhisper - spring-validated - 0.0.1-SNAPSHOT - spring-validated - 验证注解Spring @Validated学习 - - - 1.8 - - - - - org.springframework.boot - spring-boot-starter - - - - org.springframework.boot - spring-boot-starter-test - test - - - org.junit.vintage - junit-vintage-engine - - - - - org.springframework.boot - spring-boot-starter-web - - - org.hibernate - hibernate-validator - 6.0.17.Final - - - com.fasterxml.jackson.core - jackson-databind - - - org.projectlombok - lombok - 1.18.10 - - - junit - junit - test - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - - diff --git a/springboot-integration-examples/spring-validated/src/main/java/cn/lastwhisper/springvalidated/SpringValidatedApplication.java b/springboot-integration-examples/spring-validated/src/main/java/cn/lastwhisper/springvalidated/SpringValidatedApplication.java deleted file mode 100644 index 0971622d..00000000 --- a/springboot-integration-examples/spring-validated/src/main/java/cn/lastwhisper/springvalidated/SpringValidatedApplication.java +++ /dev/null @@ -1,14 +0,0 @@ -package cn.lastwhisper.springvalidated; - -import lombok.extern.slf4j.Slf4j; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class SpringValidatedApplication { - - public static void main(String[] args) { - SpringApplication.run(SpringValidatedApplication.class, args); - } - -} diff --git a/springboot-integration-examples/spring-validated/src/main/java/cn/lastwhisper/springvalidated/bean/Foo.java b/springboot-integration-examples/spring-validated/src/main/java/cn/lastwhisper/springvalidated/bean/Foo.java deleted file mode 100644 index 6830b9b5..00000000 --- a/springboot-integration-examples/spring-validated/src/main/java/cn/lastwhisper/springvalidated/bean/Foo.java +++ /dev/null @@ -1,35 +0,0 @@ -package cn.lastwhisper.springvalidated.bean; - -import lombok.Data; -import lombok.Getter; -import lombok.Setter; - -import javax.validation.constraints.Email; -import javax.validation.constraints.Min; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.Pattern; - -@Getter -@Setter -public class Foo { - @NotBlank - private String name; - - //@Min(value = 18) - @Min(value = 18,groups = {Adult.class}) - private Integer age; - - public interface Adult{} - - public interface Minor{} - - @Pattern(regexp = "^1(3|4|5|7|8)\\d{9}$",message = "手机号码格式错误") - @NotBlank(message = "手机号码不能为空") - private String phone; - - @Email(message = "邮箱格式错误") - private String email; - - //... getter setter - -} \ No newline at end of file diff --git a/springboot-integration-examples/spring-validated/src/main/java/cn/lastwhisper/springvalidated/controller/FooController.java b/springboot-integration-examples/spring-validated/src/main/java/cn/lastwhisper/springvalidated/controller/FooController.java deleted file mode 100644 index 1ec865db..00000000 --- a/springboot-integration-examples/spring-validated/src/main/java/cn/lastwhisper/springvalidated/controller/FooController.java +++ /dev/null @@ -1,46 +0,0 @@ -package cn.lastwhisper.springvalidated.controller; - -import cn.lastwhisper.springvalidated.bean.Foo; -import org.springframework.stereotype.Controller; -import org.springframework.validation.BindingResult; -import org.springframework.validation.FieldError; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.RequestMapping; - -@Controller -public class FooController { - - @RequestMapping("/foo") - public String foo(@Validated Foo foo, BindingResult bindingResult) { - if (bindingResult.hasErrors()) { - for (FieldError fieldError : bindingResult.getFieldErrors()) { - //... - } - return "fail"; - } - return "success"; - } - - @RequestMapping("/drink") - public String drink(@Validated({Foo.Adult.class}) Foo foo, BindingResult bindingResult) { - if (bindingResult.hasErrors()) { - for (FieldError fieldError : bindingResult.getFieldErrors()) { - // fieldError - } - return "fail"; - } - return "success"; - } - - @RequestMapping("/live") - public String live(@Validated Foo foo, BindingResult bindingResult) { - if(bindingResult.hasErrors()){ - for (FieldError fieldError : bindingResult.getFieldErrors()) { - //... - } - return "fail"; - } - return "success"; - } - -} \ No newline at end of file diff --git a/springboot-integration-examples/spring-validated/src/test/java/cn/lastwhisper/springvalidated/TestSpringBean.java b/springboot-integration-examples/spring-validated/src/test/java/cn/lastwhisper/springvalidated/TestSpringBean.java deleted file mode 100644 index ca97f1bc..00000000 --- a/springboot-integration-examples/spring-validated/src/test/java/cn/lastwhisper/springvalidated/TestSpringBean.java +++ /dev/null @@ -1,15 +0,0 @@ -package cn.lastwhisper.springvalidated; - -import org.junit.jupiter.api.Test; -import org.junit.runner.RunWith; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit4.SpringRunner; - -@RunWith(SpringRunner.class) -@SpringBootTest -public class TestSpringBean { - - @Test - public void test1() { - } -} \ No newline at end of file diff --git a/springboot-integration-examples/spring-validated/target/classes/cn/lastwhisper/springvalidated/SpringValidatedApplication.class b/springboot-integration-examples/spring-validated/target/classes/cn/lastwhisper/springvalidated/SpringValidatedApplication.class deleted file mode 100644 index 8e88dc48..00000000 Binary files a/springboot-integration-examples/spring-validated/target/classes/cn/lastwhisper/springvalidated/SpringValidatedApplication.class and /dev/null differ diff --git a/springboot-integration-examples/spring-validated/target/classes/cn/lastwhisper/springvalidated/bean/Foo$Adult.class b/springboot-integration-examples/spring-validated/target/classes/cn/lastwhisper/springvalidated/bean/Foo$Adult.class deleted file mode 100644 index 95d760cb..00000000 Binary files a/springboot-integration-examples/spring-validated/target/classes/cn/lastwhisper/springvalidated/bean/Foo$Adult.class and /dev/null differ diff --git a/springboot-integration-examples/spring-validated/target/classes/cn/lastwhisper/springvalidated/bean/Foo$Minor.class b/springboot-integration-examples/spring-validated/target/classes/cn/lastwhisper/springvalidated/bean/Foo$Minor.class deleted file mode 100644 index 7ccc8235..00000000 Binary files a/springboot-integration-examples/spring-validated/target/classes/cn/lastwhisper/springvalidated/bean/Foo$Minor.class and /dev/null differ diff --git a/springboot-integration-examples/spring-validated/target/classes/cn/lastwhisper/springvalidated/bean/Foo.class b/springboot-integration-examples/spring-validated/target/classes/cn/lastwhisper/springvalidated/bean/Foo.class deleted file mode 100644 index f7cbb3a5..00000000 Binary files a/springboot-integration-examples/spring-validated/target/classes/cn/lastwhisper/springvalidated/bean/Foo.class and /dev/null differ diff --git a/springboot-integration-examples/spring-validated/target/classes/cn/lastwhisper/springvalidated/controller/FooController.class b/springboot-integration-examples/spring-validated/target/classes/cn/lastwhisper/springvalidated/controller/FooController.class deleted file mode 100644 index 260446dc..00000000 Binary files a/springboot-integration-examples/spring-validated/target/classes/cn/lastwhisper/springvalidated/controller/FooController.class and /dev/null differ diff --git a/springboot-integration-examples/spring-validated/target/test-classes/cn/lastwhisper/springvalidated/TestSpringBean.class b/springboot-integration-examples/spring-validated/target/test-classes/cn/lastwhisper/springvalidated/TestSpringBean.class deleted file mode 100644 index 37fab933..00000000 Binary files a/springboot-integration-examples/spring-validated/target/test-classes/cn/lastwhisper/springvalidated/TestSpringBean.class and /dev/null differ diff --git "a/springboot-integration-examples/spring-validated/\345\217\202\350\200\203" "b/springboot-integration-examples/spring-validated/\345\217\202\350\200\203" deleted file mode 100644 index b848b3f2..00000000 --- "a/springboot-integration-examples/spring-validated/\345\217\202\350\200\203" +++ /dev/null @@ -1 +0,0 @@ -https://www.cnkirito.moe/spring-validation/ \ No newline at end of file diff --git a/springboot-integration-examples/springboot-aoplog/.gitignore b/springboot-integration-examples/springboot-aoplog/.gitignore deleted file mode 100644 index 153c9335..00000000 --- a/springboot-integration-examples/springboot-aoplog/.gitignore +++ /dev/null @@ -1,29 +0,0 @@ -HELP.md -/target/ -!.mvn/wrapper/maven-wrapper.jar - -### STS ### -.apt_generated -.classpath -.factorypath -.project -.settings -.springBeans -.sts4-cache - -### IntelliJ IDEA ### -.idea -*.iws -*.iml -*.ipr - -### NetBeans ### -/nbproject/private/ -/nbbuild/ -/dist/ -/nbdist/ -/.nb-gradle/ -/build/ - -### VS Code ### -.vscode/ diff --git a/springboot-integration-examples/springboot-aoplog/.mvn/wrapper/MavenWrapperDownloader.java b/springboot-integration-examples/springboot-aoplog/.mvn/wrapper/MavenWrapperDownloader.java deleted file mode 100644 index 7f91a56e..00000000 --- a/springboot-integration-examples/springboot-aoplog/.mvn/wrapper/MavenWrapperDownloader.java +++ /dev/null @@ -1,114 +0,0 @@ -/* -Licensed to the Apache Software Foundation (ASF) under one -or more contributor license agreements. See the NOTICE file -distributed with this work for additional information -regarding copyright ownership. The ASF licenses this file -to you under the Apache License, Version 2.0 (the -"License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, -software distributed under the License is distributed on an -"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -KIND, either express or implied. See the License for the -specific language governing permissions and limitations -under the License. -*/ - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.net.URL; -import java.nio.channels.Channels; -import java.nio.channels.ReadableByteChannel; -import java.util.Properties; - -public class MavenWrapperDownloader { - - /** - * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. - */ - private static final String DEFAULT_DOWNLOAD_URL = - "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"; - - /** - * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to - * use instead of the default one. - */ - private static final String MAVEN_WRAPPER_PROPERTIES_PATH = - ".mvn/wrapper/maven-wrapper.properties"; - - /** - * Path where the maven-wrapper.jar will be saved to. - */ - private static final String MAVEN_WRAPPER_JAR_PATH = - ".mvn/wrapper/maven-wrapper.jar"; - - /** - * Name of the property which should be used to override the default download url for the wrapper. - */ - private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; - - public static void main(String args[]) { - System.out.println("- Downloader started"); - File baseDirectory = new File(args[0]); - System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); - - // If the maven-wrapper.properties exists, read it and check if it contains a custom - // wrapperUrl parameter. - File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); - String url = DEFAULT_DOWNLOAD_URL; - if (mavenWrapperPropertyFile.exists()) { - FileInputStream mavenWrapperPropertyFileInputStream = null; - try { - mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); - Properties mavenWrapperProperties = new Properties(); - mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); - url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); - } catch (IOException e) { - System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); - } finally { - try { - if (mavenWrapperPropertyFileInputStream != null) { - mavenWrapperPropertyFileInputStream.close(); - } - } catch (IOException e) { - // Ignore ... - } - } - } - System.out.println("- Downloading from: : " + url); - - File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); - if (!outputFile.getParentFile().exists()) { - if (!outputFile.getParentFile().mkdirs()) { - System.out.println( - "- ERROR creating output direcrory '" + outputFile.getParentFile().getAbsolutePath() + "'"); - } - } - System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); - try { - downloadFileFromURL(url, outputFile); - System.out.println("Done"); - System.exit(0); - } catch (Throwable e) { - System.out.println("- Error downloading"); - e.printStackTrace(); - System.exit(1); - } - } - - private static void downloadFileFromURL(String urlString, File destination) throws Exception { - URL website = new URL(urlString); - ReadableByteChannel rbc; - rbc = Channels.newChannel(website.openStream()); - FileOutputStream fos = new FileOutputStream(destination); - fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); - fos.close(); - rbc.close(); - } - -} diff --git a/springboot-integration-examples/springboot-aoplog/.mvn/wrapper/maven-wrapper.jar b/springboot-integration-examples/springboot-aoplog/.mvn/wrapper/maven-wrapper.jar deleted file mode 100644 index 01e67997..00000000 Binary files a/springboot-integration-examples/springboot-aoplog/.mvn/wrapper/maven-wrapper.jar and /dev/null differ diff --git a/springboot-integration-examples/springboot-aoplog/.mvn/wrapper/maven-wrapper.properties b/springboot-integration-examples/springboot-aoplog/.mvn/wrapper/maven-wrapper.properties deleted file mode 100644 index cd0d451c..00000000 --- a/springboot-integration-examples/springboot-aoplog/.mvn/wrapper/maven-wrapper.properties +++ /dev/null @@ -1 +0,0 @@ -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip diff --git a/springboot-integration-examples/springboot-aoplog/mvnw b/springboot-integration-examples/springboot-aoplog/mvnw deleted file mode 100644 index 8b9da3b8..00000000 --- a/springboot-integration-examples/springboot-aoplog/mvnw +++ /dev/null @@ -1,286 +0,0 @@ -#!/bin/sh -# ---------------------------------------------------------------------------- -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# ---------------------------------------------------------------------------- - -# ---------------------------------------------------------------------------- -# Maven2 Start Up Batch script -# -# Required ENV vars: -# ------------------ -# JAVA_HOME - location of a JDK home dir -# -# Optional ENV vars -# ----------------- -# M2_HOME - location of maven2's installed home dir -# MAVEN_OPTS - parameters passed to the Java VM when running Maven -# e.g. to debug Maven itself, use -# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -# MAVEN_SKIP_RC - flag to disable loading of mavenrc files -# ---------------------------------------------------------------------------- - -if [ -z "$MAVEN_SKIP_RC" ] ; then - - if [ -f /etc/mavenrc ] ; then - . /etc/mavenrc - fi - - if [ -f "$HOME/.mavenrc" ] ; then - . "$HOME/.mavenrc" - fi - -fi - -# OS specific support. $var _must_ be set to either true or false. -cygwin=false; -darwin=false; -mingw=false -case "`uname`" in - CYGWIN*) cygwin=true ;; - MINGW*) mingw=true;; - Darwin*) darwin=true - # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home - # See https://developer.apple.com/library/mac/qa/qa1170/_index.html - if [ -z "$JAVA_HOME" ]; then - if [ -x "/usr/libexec/java_home" ]; then - export JAVA_HOME="`/usr/libexec/java_home`" - else - export JAVA_HOME="/Library/Java/Home" - fi - fi - ;; -esac - -if [ -z "$JAVA_HOME" ] ; then - if [ -r /etc/gentoo-release ] ; then - JAVA_HOME=`java-config --jre-home` - fi -fi - -if [ -z "$M2_HOME" ] ; then - ## resolve links - $0 may be a link to maven's home - PRG="$0" - - # need this for relative symlinks - while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG="`dirname "$PRG"`/$link" - fi - done - - saveddir=`pwd` - - M2_HOME=`dirname "$PRG"`/.. - - # make it fully qualified - M2_HOME=`cd "$M2_HOME" && pwd` - - cd "$saveddir" - # echo Using m2 at $M2_HOME -fi - -# For Cygwin, ensure paths are in UNIX format before anything is touched -if $cygwin ; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --unix "$M2_HOME"` - [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --unix "$JAVA_HOME"` - [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --unix "$CLASSPATH"` -fi - -# For Mingw, ensure paths are in UNIX format before anything is touched -if $mingw ; then - [ -n "$M2_HOME" ] && - M2_HOME="`(cd "$M2_HOME"; pwd)`" - [ -n "$JAVA_HOME" ] && - JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" - # TODO classpath? -fi - -if [ -z "$JAVA_HOME" ]; then - javaExecutable="`which javac`" - if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then - # readlink(1) is not available as standard on Solaris 10. - readLink=`which readlink` - if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then - if $darwin ; then - javaHome="`dirname \"$javaExecutable\"`" - javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" - else - javaExecutable="`readlink -f \"$javaExecutable\"`" - fi - javaHome="`dirname \"$javaExecutable\"`" - javaHome=`expr "$javaHome" : '\(.*\)/bin'` - JAVA_HOME="$javaHome" - export JAVA_HOME - fi - fi -fi - -if [ -z "$JAVACMD" ] ; then - if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - else - JAVACMD="`which java`" - fi -fi - -if [ ! -x "$JAVACMD" ] ; then - echo "Error: JAVA_HOME is not defined correctly." >&2 - echo " We cannot execute $JAVACMD" >&2 - exit 1 -fi - -if [ -z "$JAVA_HOME" ] ; then - echo "Warning: JAVA_HOME environment variable is not set." -fi - -CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher - -# traverses directory structure from process work directory to filesystem root -# first directory with .mvn subdirectory is considered project base directory -find_maven_basedir() { - - if [ -z "$1" ] - then - echo "Path not specified to find_maven_basedir" - return 1 - fi - - basedir="$1" - wdir="$1" - while [ "$wdir" != '/' ] ; do - if [ -d "$wdir"/.mvn ] ; then - basedir=$wdir - break - fi - # workaround for JBEAP-8937 (on Solaris 10/Sparc) - if [ -d "${wdir}" ]; then - wdir=`cd "$wdir/.."; pwd` - fi - # end of workaround - done - echo "${basedir}" -} - -# concatenates all lines of a file -concat_lines() { - if [ -f "$1" ]; then - echo "$(tr -s '\n' ' ' < "$1")" - fi -} - -BASE_DIR=`find_maven_basedir "$(pwd)"` -if [ -z "$BASE_DIR" ]; then - exit 1; -fi - -########################################################################################## -# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -# This allows using the maven wrapper in projects that prohibit checking in binary data. -########################################################################################## -if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found .mvn/wrapper/maven-wrapper.jar" - fi -else - if [ "$MVNW_VERBOSE" = true ]; then - echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." - fi - jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar" - while IFS="=" read key value; do - case "$key" in (wrapperUrl) jarUrl="$value"; break ;; - esac - done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" - if [ "$MVNW_VERBOSE" = true ]; then - echo "Downloading from: $jarUrl" - fi - wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" - - if command -v wget > /dev/null; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found wget ... using wget" - fi - wget "$jarUrl" -O "$wrapperJarPath" - elif command -v curl > /dev/null; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found curl ... using curl" - fi - curl -o "$wrapperJarPath" "$jarUrl" - else - if [ "$MVNW_VERBOSE" = true ]; then - echo "Falling back to using Java to download" - fi - javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" - if [ -e "$javaClass" ]; then - if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then - if [ "$MVNW_VERBOSE" = true ]; then - echo " - Compiling MavenWrapperDownloader.java ..." - fi - # Compiling the Java class - ("$JAVA_HOME/bin/javac" "$javaClass") - fi - if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then - # Running the downloader - if [ "$MVNW_VERBOSE" = true ]; then - echo " - Running MavenWrapperDownloader.java ..." - fi - ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") - fi - fi - fi -fi -########################################################################################## -# End of extension -########################################################################################## - -export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} -if [ "$MVNW_VERBOSE" = true ]; then - echo $MAVEN_PROJECTBASEDIR -fi -MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" - -# For Cygwin, switch paths to Windows format before running java -if $cygwin; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --path --windows "$M2_HOME"` - [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` - [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --windows "$CLASSPATH"` - [ -n "$MAVEN_PROJECTBASEDIR" ] && - MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` -fi - -WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -exec "$JAVACMD" \ - $MAVEN_OPTS \ - -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ - "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ - ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/springboot-integration-examples/springboot-aoplog/mvnw.cmd b/springboot-integration-examples/springboot-aoplog/mvnw.cmd deleted file mode 100644 index fef5a8f7..00000000 --- a/springboot-integration-examples/springboot-aoplog/mvnw.cmd +++ /dev/null @@ -1,161 +0,0 @@ -@REM ---------------------------------------------------------------------------- -@REM Licensed to the Apache Software Foundation (ASF) under one -@REM or more contributor license agreements. See the NOTICE file -@REM distributed with this work for additional information -@REM regarding copyright ownership. The ASF licenses this file -@REM to you under the Apache License, Version 2.0 (the -@REM "License"); you may not use this file except in compliance -@REM with the License. You may obtain a copy of the License at -@REM -@REM https://www.apache.org/licenses/LICENSE-2.0 -@REM -@REM Unless required by applicable law or agreed to in writing, -@REM software distributed under the License is distributed on an -@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -@REM KIND, either express or implied. See the License for the -@REM specific language governing permissions and limitations -@REM under the License. -@REM ---------------------------------------------------------------------------- - -@REM ---------------------------------------------------------------------------- -@REM Maven2 Start Up Batch script -@REM -@REM Required ENV vars: -@REM JAVA_HOME - location of a JDK home dir -@REM -@REM Optional ENV vars -@REM M2_HOME - location of maven2's installed home dir -@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands -@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending -@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven -@REM e.g. to debug Maven itself, use -@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files -@REM ---------------------------------------------------------------------------- - -@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' -@echo off -@REM set title of command window -title %0 -@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' -@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% - -@REM set %HOME% to equivalent of $HOME -if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") - -@REM Execute a user defined script before this one -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre -@REM check for pre script, once with legacy .bat ending and once with .cmd ending -if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" -if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" -:skipRcPre - -@setlocal - -set ERROR_CODE=0 - -@REM To isolate internal variables from possible post scripts, we use another setlocal -@setlocal - -@REM ==== START VALIDATION ==== -if not "%JAVA_HOME%" == "" goto OkJHome - -echo. -echo Error: JAVA_HOME not found in your environment. >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -:OkJHome -if exist "%JAVA_HOME%\bin\java.exe" goto init - -echo. -echo Error: JAVA_HOME is set to an invalid directory. >&2 -echo JAVA_HOME = "%JAVA_HOME%" >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -@REM ==== END VALIDATION ==== - -:init - -@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". -@REM Fallback to current working directory if not found. - -set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% -IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir - -set EXEC_DIR=%CD% -set WDIR=%EXEC_DIR% -:findBaseDir -IF EXIST "%WDIR%"\.mvn goto baseDirFound -cd .. -IF "%WDIR%"=="%CD%" goto baseDirNotFound -set WDIR=%CD% -goto findBaseDir - -:baseDirFound -set MAVEN_PROJECTBASEDIR=%WDIR% -cd "%EXEC_DIR%" -goto endDetectBaseDir - -:baseDirNotFound -set MAVEN_PROJECTBASEDIR=%EXEC_DIR% -cd "%EXEC_DIR%" - -:endDetectBaseDir - -IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig - -@setlocal EnableExtensions EnableDelayedExpansion -for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a -@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% - -:endReadAdditionalConfig - -SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" -set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" -set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar" -FOR /F "tokens=1,2 delims==" %%A IN (%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties) DO ( - IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B -) - -@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -@REM This allows using the maven wrapper in projects that prohibit checking in binary data. -if exist %WRAPPER_JAR% ( - echo Found %WRAPPER_JAR% -) else ( - echo Couldn't find %WRAPPER_JAR%, downloading it ... - echo Downloading from: %DOWNLOAD_URL% - powershell -Command "(New-Object Net.WebClient).DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')" - echo Finished downloading %WRAPPER_JAR% -) -@REM End of extension - -%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* -if ERRORLEVEL 1 goto error -goto end - -:error -set ERROR_CODE=1 - -:end -@endlocal & set ERROR_CODE=%ERROR_CODE% - -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost -@REM check for post script, once with legacy .bat ending and once with .cmd ending -if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" -if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" -:skipRcPost - -@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' -if "%MAVEN_BATCH_PAUSE%" == "on" pause - -if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% - -exit /B %ERROR_CODE% diff --git a/springboot-integration-examples/springboot-aoplog/pom.xml b/springboot-integration-examples/springboot-aoplog/pom.xml deleted file mode 100644 index 93280e54..00000000 --- a/springboot-integration-examples/springboot-aoplog/pom.xml +++ /dev/null @@ -1,68 +0,0 @@ - - - 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 2.1.4.RELEASE - - - cn.lastwhisper - springbootaop - 0.0.1-SNAPSHOT - springbootaop - Demo project for Spring Boot - - - 1.8 - - - - - org.springframework.boot - spring-boot-starter-web - - - - org.springframework.boot - spring-boot-starter-test - test - - - - - org.springframework.boot - spring-boot-starter-aop - - - - - org.projectlombok - lombok - true - - - - com.baomidou - mybatis-plus-boot-starter - 3.1.1 - - - - mysql - mysql-connector-java - 5.1.47 - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - - diff --git a/springboot-integration-examples/springboot-aoplog/sql/log.sql b/springboot-integration-examples/springboot-aoplog/sql/log.sql deleted file mode 100644 index b989fe0b..00000000 --- a/springboot-integration-examples/springboot-aoplog/sql/log.sql +++ /dev/null @@ -1,39 +0,0 @@ -/* - Navicat Premium Data Transfer - - Source Server : 本地数据库-mysql5.7 - Source Server Type : MySQL - Source Server Version : 50724 - Source Host : localhost:3306 - Source Schema : wxlogin - - Target Server Type : MySQL - Target Server Version : 50724 - File Encoding : 65001 - - Date: 02/05/2019 17:15:00 -*/ - -SET NAMES utf8mb4; -SET FOREIGN_KEY_CHECKS = 0; - --- ---------------------------- --- Table structure for log --- ---------------------------- -DROP TABLE IF EXISTS `log`; -CREATE TABLE `log` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `operateor` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, - `operateType` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, - `operateDate` datetime(0) NULL DEFAULT NULL, - `operateResult` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, - `ip` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, - PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 13 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; - --- ---------------------------- --- Records of log --- ---------------------------- -INSERT INTO `log` VALUES (12, 'lastwhisper', '添加用户', '2019-05-02 16:16:24', '正常', '0:0:0:0:0:0:0:1'); - -SET FOREIGN_KEY_CHECKS = 1; diff --git a/springboot-integration-examples/springboot-aoplog/src/main/java/cn/lastwhisper/springbootaop/SpringbootaopApplication.java b/springboot-integration-examples/springboot-aoplog/src/main/java/cn/lastwhisper/springbootaop/SpringbootaopApplication.java deleted file mode 100644 index d6ff0531..00000000 --- a/springboot-integration-examples/springboot-aoplog/src/main/java/cn/lastwhisper/springbootaop/SpringbootaopApplication.java +++ /dev/null @@ -1,15 +0,0 @@ -package cn.lastwhisper.springbootaop; - -import org.mybatis.spring.annotation.MapperScan; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@MapperScan("cn.lastwhisper.springbootaop.mapper") //设置mapper接口的扫描包 -@SpringBootApplication -public class SpringbootaopApplication { - - public static void main(String[] args) { - SpringApplication.run(SpringbootaopApplication.class, args); - } - -} diff --git a/springboot-integration-examples/springboot-aoplog/src/main/java/cn/lastwhisper/springbootaop/controller/UserController.java b/springboot-integration-examples/springboot-aoplog/src/main/java/cn/lastwhisper/springbootaop/controller/UserController.java deleted file mode 100644 index 9c19699a..00000000 --- a/springboot-integration-examples/springboot-aoplog/src/main/java/cn/lastwhisper/springbootaop/controller/UserController.java +++ /dev/null @@ -1,25 +0,0 @@ -package cn.lastwhisper.springbootaop.controller; - -import cn.lastwhisper.springbootaop.core.annotation.LogAnno; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -/** - * @author lastwhisper - * @desc - * @email gaojun56@163.com - */ -@RestController -public class UserController { - /** - * @desc 这里为了方便直接在controller上进行aop日志记录,也可以放在service上。 - * @author lastwhisper - * @Param - * @return - */ - @LogAnno(operateType = "添加用户") - @RequestMapping(value = "/user/add") - public void add() { - System.out.println("向数据库中添加用户!!"); - } -} diff --git a/springboot-integration-examples/springboot-aoplog/src/main/java/cn/lastwhisper/springbootaop/core/annotation/LogAnno.java b/springboot-integration-examples/springboot-aoplog/src/main/java/cn/lastwhisper/springbootaop/core/annotation/LogAnno.java deleted file mode 100644 index 9a8bd546..00000000 --- a/springboot-integration-examples/springboot-aoplog/src/main/java/cn/lastwhisper/springbootaop/core/annotation/LogAnno.java +++ /dev/null @@ -1,19 +0,0 @@ -package cn.lastwhisper.springbootaop.core.annotation; - -import org.springframework.core.annotation.Order; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * 日志注解 - * - * @author lastwhisper - */ -@Target(ElementType.METHOD) // 方法注解 -@Retention(RetentionPolicy.RUNTIME) // 运行时可见 -public @interface LogAnno { - String operateType();// 记录日志的操作类型 -} \ No newline at end of file diff --git a/springboot-integration-examples/springboot-aoplog/src/main/java/cn/lastwhisper/springbootaop/core/aop/LogAopAspect.java b/springboot-integration-examples/springboot-aoplog/src/main/java/cn/lastwhisper/springbootaop/core/aop/LogAopAspect.java deleted file mode 100644 index 485596b3..00000000 --- a/springboot-integration-examples/springboot-aoplog/src/main/java/cn/lastwhisper/springbootaop/core/aop/LogAopAspect.java +++ /dev/null @@ -1,77 +0,0 @@ -package cn.lastwhisper.springbootaop.core.aop; - -import java.lang.reflect.Method; -import java.sql.SQLException; -import java.util.Date; - -import cn.lastwhisper.springbootaop.core.annotation.LogAnno; -import cn.lastwhisper.springbootaop.core.common.HttpContextUtil; -import cn.lastwhisper.springbootaop.mapper.LogMapper; -import cn.lastwhisper.springbootaop.pojo.Log; -import org.aspectj.lang.ProceedingJoinPoint; -import org.aspectj.lang.annotation.Around; -import org.aspectj.lang.annotation.Aspect; -import org.aspectj.lang.reflect.MethodSignature; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.core.annotation.Order; -import org.springframework.stereotype.Component; - -/** - * AOP实现日志 - * - * @author 最后的轻语_dd43 - * - */ -@Order(3) -@Component -@Aspect -public class LogAopAspect { - // 日志mapper,这里省事少写了service - @Autowired - private LogMapper logMapper; - - /** - * 环绕通知记录日志通过注解匹配到需要增加日志功能的方法 - * - * @param pjp - * @return - * @throws Throwable - */ - @Around("@annotation(cn.lastwhisper.springbootaop.core.annotation.LogAnno)") - public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable { - // 1.方法执行前的处理,相当于前置通知 - // 获取方法签名 - MethodSignature methodSignature = (MethodSignature) pjp.getSignature(); - // 获取方法 - Method method = methodSignature.getMethod(); - // 获取方法上面的注解 - LogAnno logAnno = method.getAnnotation(LogAnno.class); - // 获取操作描述的属性值 - String operateType = logAnno.operateType(); - // 创建一个日志对象(准备记录日志) - Log log = new Log(); - log.setOperatetype(operateType);// 操作说明 - - // 设置操作人,从session中获取,这里简化了一下,写死了。 - log.setOperateor("lastwhisper"); - String ip = HttpContextUtil.getIpAddress(); - log.setIp(ip); - Object result = null; - try { - // 让代理方法执行 - result = pjp.proceed(); - // 2.相当于后置通知(方法成功执行之后走这里) - log.setOperateresult("正常");// 设置操作结果 - } catch (SQLException e) { - // 3.相当于异常通知部分 - log.setOperateresult("失败");// 设置操作结果 - } finally { - // 4.相当于最终通知 - log.setOperatedate(new Date());// 设置操作日期 - logMapper.insert(log);// 添加日志记录 - } - return result; - } - - -} \ No newline at end of file diff --git a/springboot-integration-examples/springboot-aoplog/src/main/java/cn/lastwhisper/springbootaop/core/common/HttpContextUtil.java b/springboot-integration-examples/springboot-aoplog/src/main/java/cn/lastwhisper/springbootaop/core/common/HttpContextUtil.java deleted file mode 100644 index febc9587..00000000 --- a/springboot-integration-examples/springboot-aoplog/src/main/java/cn/lastwhisper/springbootaop/core/common/HttpContextUtil.java +++ /dev/null @@ -1,46 +0,0 @@ -package cn.lastwhisper.springbootaop.core.common; - -import org.springframework.web.context.request.RequestContextHolder; -import org.springframework.web.context.request.ServletRequestAttributes; - -import javax.servlet.http.HttpServletRequest; - -/** - * @desc - * - * @author lastwhisper - * @email gaojun56@163.com - */ -public class HttpContextUtil { - public static HttpServletRequest getRequest() { - return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()) - .getRequest(); - } - - /** - * 获取IP地址的方法 - * - * @param request 传一个request对象下来 - * @return - */ - public static String getIpAddress() { - HttpServletRequest request = getRequest(); - String ip = request.getHeader("x-forwarded-for"); - if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { - ip = request.getHeader("Proxy-Client-IP"); - } - if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { - ip = request.getHeader("WL-Proxy-Client-IP"); - } - if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { - ip = request.getHeader("HTTP_CLIENT_IP"); - } - if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { - ip = request.getHeader("HTTP_X_FORWARDED_FOR"); - } - if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { - ip = request.getRemoteAddr(); - } - return ip; - } -} diff --git a/springboot-integration-examples/springboot-aoplog/src/main/java/cn/lastwhisper/springbootaop/mapper/LogMapper.java b/springboot-integration-examples/springboot-aoplog/src/main/java/cn/lastwhisper/springbootaop/mapper/LogMapper.java deleted file mode 100644 index a285391d..00000000 --- a/springboot-integration-examples/springboot-aoplog/src/main/java/cn/lastwhisper/springbootaop/mapper/LogMapper.java +++ /dev/null @@ -1,13 +0,0 @@ -package cn.lastwhisper.springbootaop.mapper; - -import cn.lastwhisper.springbootaop.pojo.Log; -import com.baomidou.mybatisplus.core.mapper.BaseMapper; - -/** - * @desc - * - * @author lastwhisper - * @email gaojun56@163.com - */ -public interface LogMapper extends BaseMapper { -} diff --git a/springboot-integration-examples/springboot-aoplog/src/main/java/cn/lastwhisper/springbootaop/pojo/Log.java b/springboot-integration-examples/springboot-aoplog/src/main/java/cn/lastwhisper/springbootaop/pojo/Log.java deleted file mode 100644 index 767ee659..00000000 --- a/springboot-integration-examples/springboot-aoplog/src/main/java/cn/lastwhisper/springbootaop/pojo/Log.java +++ /dev/null @@ -1,33 +0,0 @@ -package cn.lastwhisper.springbootaop.pojo; - -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableField; -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; -import lombok.Data; -import org.springframework.format.annotation.DateTimeFormat; - -import java.util.Date; - -@Data -@TableName("log") -public class Log { - @TableId(value = "id", type = IdType.AUTO) - private Integer id; - - @TableField("operateor") - private String operateor; - - @TableField("operateType") - private String operatetype; - - @TableField("operateDate") - @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") - private Date operatedate; - - @TableField("operatereSult") - private String operateresult; - - @TableField("ip") - private String ip; -} \ No newline at end of file diff --git a/springboot-integration-examples/springboot-aoplog/src/main/resources/application.properties b/springboot-integration-examples/springboot-aoplog/src/main/resources/application.properties deleted file mode 100644 index d3b981dd..00000000 --- a/springboot-integration-examples/springboot-aoplog/src/main/resources/application.properties +++ /dev/null @@ -1,5 +0,0 @@ -spring.application.name = lastwhisper-aoplog -spring.datasource.driver-class-name=com.mysql.jdbc.Driver -spring.datasource.url=jdbc:mysql://127.0.0.1:3306/wxlogin?useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true&useSSL=false -spring.datasource.username=root -spring.datasource.password=root diff --git a/springboot-integration-examples/springboot-aoplog/src/test/java/cn/lastwhisper/springbootaop/SpringbootaopApplicationTests.java b/springboot-integration-examples/springboot-aoplog/src/test/java/cn/lastwhisper/springbootaop/SpringbootaopApplicationTests.java deleted file mode 100644 index 7347dbc2..00000000 --- a/springboot-integration-examples/springboot-aoplog/src/test/java/cn/lastwhisper/springbootaop/SpringbootaopApplicationTests.java +++ /dev/null @@ -1,16 +0,0 @@ -package cn.lastwhisper.springbootaop; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit4.SpringRunner; - -@RunWith(SpringRunner.class) -@SpringBootTest -public class SpringbootaopApplicationTests { - - @Test - public void contextLoads() { - } - -} diff --git a/springboot-integration-examples/springboot-dubbo-tcc-instance/dubbo-api/pom.xml b/springboot-integration-examples/springboot-dubbo-tcc-instance/dubbo-api/pom.xml deleted file mode 100644 index c5acbd23..00000000 --- a/springboot-integration-examples/springboot-dubbo-tcc-instance/dubbo-api/pom.xml +++ /dev/null @@ -1,84 +0,0 @@ - - - - - springboot-dubbo-tcc - cn.lastwhisper.springboot - 0.0.1-SNAPSHOT - - 4.0.0 - - cn.lastwhisper.springboot - dubbo-api - - dubbo-api - - http://www.example.com - - - UTF-8 - 1.7 - 1.7 - - - - - junit - junit - 4.11 - test - - - org.mengyun - tcc-transaction-api - 1.2.4.23 - - - - - - - - - maven-clean-plugin - 3.1.0 - - - - maven-resources-plugin - 3.0.2 - - - maven-compiler-plugin - 3.8.0 - - - maven-surefire-plugin - 2.22.1 - - - maven-jar-plugin - 3.0.2 - - - maven-install-plugin - 2.5.2 - - - maven-deploy-plugin - 2.8.2 - - - - maven-site-plugin - 3.7.1 - - - maven-project-info-reports-plugin - 3.0.0 - - - - - diff --git a/springboot-integration-examples/springboot-dubbo-tcc-instance/dubbo-api/src/main/java/cn/lastwhisper/springboot/ServiceAPI.java b/springboot-integration-examples/springboot-dubbo-tcc-instance/dubbo-api/src/main/java/cn/lastwhisper/springboot/ServiceAPI.java deleted file mode 100644 index d0d3e02a..00000000 --- a/springboot-integration-examples/springboot-dubbo-tcc-instance/dubbo-api/src/main/java/cn/lastwhisper/springboot/ServiceAPI.java +++ /dev/null @@ -1,27 +0,0 @@ -package cn.lastwhisper.springboot; - - -import org.mengyun.tcctransaction.api.Compensable; - -public interface ServiceAPI { - @Compensable - String sendMessage(String message); - - /* - * 传入购票数量、传入购票座位,影厅编号 - * - */ - - //判断座位是否存在,模拟一个事务 - @Compensable - boolean isTrueSeats(String seats); - - //判断座位是否售出,模拟一个事务 - @Compensable - boolean isNotSold(String seats); - - //保存订单,模拟一个事务 - @Compensable - String saveOrder(String field, String seats, String seatsNum); - -} diff --git a/springboot-integration-examples/springboot-dubbo-tcc-instance/dubbo-api/src/test/java/cn/lastwhisper/springboot/AppTest.java b/springboot-integration-examples/springboot-dubbo-tcc-instance/dubbo-api/src/test/java/cn/lastwhisper/springboot/AppTest.java deleted file mode 100644 index ecb89484..00000000 --- a/springboot-integration-examples/springboot-dubbo-tcc-instance/dubbo-api/src/test/java/cn/lastwhisper/springboot/AppTest.java +++ /dev/null @@ -1,20 +0,0 @@ -package cn.lastwhisper.springboot; - -import static org.junit.Assert.assertTrue; - -import org.junit.Test; - -/** - * Unit test for simple App. - */ -public class AppTest -{ - /** - * Rigorous Test :-) - */ - @Test - public void shouldAnswerWithTrue() - { - assertTrue( true ); - } -} diff --git a/springboot-integration-examples/springboot-dubbo-tcc-instance/dubbo-consumer/pom.xml b/springboot-integration-examples/springboot-dubbo-tcc-instance/dubbo-consumer/pom.xml deleted file mode 100644 index 521b26c0..00000000 --- a/springboot-integration-examples/springboot-dubbo-tcc-instance/dubbo-consumer/pom.xml +++ /dev/null @@ -1,136 +0,0 @@ - - - 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 2.1.7.RELEASE - - - cn.lastwhisper.springboot - dubbo-consumer - 0.0.1-SNAPSHOT - dubbo-consumer - 服务消费者 - - - 1.8 - - - - - org.springframework.boot - spring-boot-starter - - - - org.springframework.boot - spring-boot-starter - - - com.alibaba.spring.boot - dubbo-spring-boot-starter - 2.0.0 - - - org.springframework.boot - spring-boot-starter-test - test - - - com.101tec - zkclient - 0.10 - - - org.mengyun - tcc-transaction-dubbo - 1.2.4.23 - - - org.mengyun - tcc-transaction-spring - 1.2.4.23 - - - org.mengyun - tcc-transaction-core - 1.2.4.23 - - - org.mengyun - tcc-transaction-api - 1.2.4.23 - - - com.alibaba - druid - 1.1.12 - - - mysql - mysql-connector-java - 5.1.10 - - - org.springframework.boot - spring-boot-starter-aop - - - org.quartz-scheduler - quartz - 2.2.1 - - - slf4j-api - org.slf4j - - - - - org.springframework - spring-context-support - - - org.springframework.boot - spring-boot-starter-jdbc - - - com.google.guava - guava - 23.0 - - - com.esotericsoftware - kryo-shaded - 4.0.2 - - - org.apache.commons - commons-lang3 - 3.8.1 - - - com.alibaba - fastjson - 1.2.51 - - - cn.lastwhisper.springboot - dubbo-api - 0.0.1-SNAPSHOT - compile - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - - diff --git a/springboot-integration-examples/springboot-dubbo-tcc-instance/dubbo-consumer/src/main/java/cn/lastwhisper/springboot/dubbo/consumer/ConsumerApplication.java b/springboot-integration-examples/springboot-dubbo-tcc-instance/dubbo-consumer/src/main/java/cn/lastwhisper/springboot/dubbo/consumer/ConsumerApplication.java deleted file mode 100644 index 29ec1d64..00000000 --- a/springboot-integration-examples/springboot-dubbo-tcc-instance/dubbo-consumer/src/main/java/cn/lastwhisper/springboot/dubbo/consumer/ConsumerApplication.java +++ /dev/null @@ -1,25 +0,0 @@ -package cn.lastwhisper.springboot.dubbo.consumer; - -import cn.lastwhisper.springboot.dubbo.consumer.transaction.TransactionConsumer; -import com.alibaba.dubbo.spring.boot.annotation.EnableDubboConfiguration; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.context.ConfigurableApplicationContext; - -@SpringBootApplication -@EnableDubboConfiguration -public class ConsumerApplication { - - public static void main(String[] args) { - ConfigurableApplicationContext context = SpringApplication.run(ConsumerApplication.class, args); - //QuickstartConsumer quickstartConsumer = (QuickstartConsumer) context.getBean("quickstartConsumer"); - //quickstartConsumer.sendMessage("你好"); - - TransactionConsumer consumer = (TransactionConsumer) context.getBean("transactionConsumer"); - // 1,2,3 isTrueSeats报错 - // 4,5 - consumer.sendMessage("4,5"); - - } - -} diff --git a/springboot-integration-examples/springboot-dubbo-tcc-instance/dubbo-consumer/src/main/java/cn/lastwhisper/springboot/dubbo/consumer/config/TCCConfig.java b/springboot-integration-examples/springboot-dubbo-tcc-instance/dubbo-consumer/src/main/java/cn/lastwhisper/springboot/dubbo/consumer/config/TCCConfig.java deleted file mode 100644 index f3de5b89..00000000 --- a/springboot-integration-examples/springboot-dubbo-tcc-instance/dubbo-consumer/src/main/java/cn/lastwhisper/springboot/dubbo/consumer/config/TCCConfig.java +++ /dev/null @@ -1,12 +0,0 @@ -package cn.lastwhisper.springboot.dubbo.consumer.config; - -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.ImportResource; - -/** - * @author lastwhisper - */ -@Configuration -@ImportResource(locations = {"classpath:tcc-transaction.xml","classpath:tcc-transaction-dubbo.xml"}) -public class TCCConfig { -} diff --git a/springboot-integration-examples/springboot-dubbo-tcc-instance/dubbo-consumer/src/main/java/cn/lastwhisper/springboot/dubbo/consumer/quickstart/QuickstartConsumer.java b/springboot-integration-examples/springboot-dubbo-tcc-instance/dubbo-consumer/src/main/java/cn/lastwhisper/springboot/dubbo/consumer/quickstart/QuickstartConsumer.java deleted file mode 100644 index 05c24052..00000000 --- a/springboot-integration-examples/springboot-dubbo-tcc-instance/dubbo-consumer/src/main/java/cn/lastwhisper/springboot/dubbo/consumer/quickstart/QuickstartConsumer.java +++ /dev/null @@ -1,19 +0,0 @@ -package cn.lastwhisper.springboot.dubbo.consumer.quickstart; - -import cn.lastwhisper.springboot.ServiceAPI; -import com.alibaba.dubbo.config.annotation.Reference; -import org.springframework.stereotype.Component; - -/** - * @author lastwhisper - */ -//@Component -public class QuickstartConsumer { - //@Reference(url ="dubbo://localhost:20880") - //@Reference(interfaceClass = ServiceAPI.class) - ServiceAPI serviceAPI; - - public void sendMessage(String message) { - System.out.println(serviceAPI.sendMessage(message)); - } -} diff --git a/springboot-integration-examples/springboot-dubbo-tcc-instance/dubbo-consumer/src/main/java/cn/lastwhisper/springboot/dubbo/consumer/transaction/TransactionConsumer.java b/springboot-integration-examples/springboot-dubbo-tcc-instance/dubbo-consumer/src/main/java/cn/lastwhisper/springboot/dubbo/consumer/transaction/TransactionConsumer.java deleted file mode 100644 index 1dada24b..00000000 --- a/springboot-integration-examples/springboot-dubbo-tcc-instance/dubbo-consumer/src/main/java/cn/lastwhisper/springboot/dubbo/consumer/transaction/TransactionConsumer.java +++ /dev/null @@ -1,39 +0,0 @@ -package cn.lastwhisper.springboot.dubbo.consumer.transaction; - -import cn.lastwhisper.springboot.ServiceAPI; -import com.alibaba.dubbo.config.annotation.Reference; -import org.mengyun.tcctransaction.api.Compensable; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -/** - * @author lastwhisper - */ -@Component("transactionConsumer") -public class TransactionConsumer { - //@Reference(interfaceClass = ServiceAPI.class) - @Autowired - ServiceAPI serviceAPI; - - // 主事务 - @Compensable(confirmMethod = "confirmSendMessage", cancelMethod = "cancelSendMessage", asyncConfirm = true) - public void sendMessage(String message) { - //System.out.println("this is consumer sendMessage="+message); - //System.out.println(serviceAPI.sendMessage(message)); - - // 业务 - serviceAPI.saveOrder("001", message, "5"); - - serviceAPI.isTrueSeats(message); - serviceAPI.isNotSold(message); - - } - - public void confirmSendMessage(String message) { - System.out.println("this is consumer confirmSendMessage=" + message); - } - - public void cancelSendMessage(String message) { - System.out.println("this is consumer cancelSendMessage=" + message); - } -} diff --git a/springboot-integration-examples/springboot-dubbo-tcc-instance/dubbo-consumer/src/main/resources/application.properties b/springboot-integration-examples/springboot-dubbo-tcc-instance/dubbo-consumer/src/main/resources/application.properties deleted file mode 100644 index 6f0465df..00000000 --- a/springboot-integration-examples/springboot-dubbo-tcc-instance/dubbo-consumer/src/main/resources/application.properties +++ /dev/null @@ -1,2 +0,0 @@ -spring.application.name=dubbo-spring-boot-starter -spring.dubbo.registry=zookeeper://localhost:2181 \ No newline at end of file diff --git a/springboot-integration-examples/springboot-dubbo-tcc-instance/dubbo-consumer/src/main/resources/tcc-transaction-dubbo.xml b/springboot-integration-examples/springboot-dubbo-tcc-instance/dubbo-consumer/src/main/resources/tcc-transaction-dubbo.xml deleted file mode 100644 index 53d009a0..00000000 --- a/springboot-integration-examples/springboot-dubbo-tcc-instance/dubbo-consumer/src/main/resources/tcc-transaction-dubbo.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/springboot-integration-examples/springboot-dubbo-tcc-instance/dubbo-consumer/src/main/resources/tcc-transaction.xml b/springboot-integration-examples/springboot-dubbo-tcc-instance/dubbo-consumer/src/main/resources/tcc-transaction.xml deleted file mode 100644 index bccba078..00000000 --- a/springboot-integration-examples/springboot-dubbo-tcc-instance/dubbo-consumer/src/main/resources/tcc-transaction.xml +++ /dev/null @@ -1,75 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - com.alibaba.dubbo.remoting.TimeoutException - - - - - \ No newline at end of file diff --git a/springboot-integration-examples/springboot-dubbo-tcc-instance/dubbo-consumer/src/test/java/cn/lastwhisper/springboot/dubboconsumer/DubboConsumerApplicationTests.java b/springboot-integration-examples/springboot-dubbo-tcc-instance/dubbo-consumer/src/test/java/cn/lastwhisper/springboot/dubboconsumer/DubboConsumerApplicationTests.java deleted file mode 100644 index 82925eb9..00000000 --- a/springboot-integration-examples/springboot-dubbo-tcc-instance/dubbo-consumer/src/test/java/cn/lastwhisper/springboot/dubboconsumer/DubboConsumerApplicationTests.java +++ /dev/null @@ -1,16 +0,0 @@ -package cn.lastwhisper.springboot.dubboconsumer; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit4.SpringRunner; - -@RunWith(SpringRunner.class) -@SpringBootTest -public class DubboConsumerApplicationTests { - - @Test - public void contextLoads() { - } - -} diff --git a/springboot-integration-examples/springboot-dubbo-tcc-instance/dubbo-provider/pom.xml b/springboot-integration-examples/springboot-dubbo-tcc-instance/dubbo-provider/pom.xml deleted file mode 100644 index a9b90230..00000000 --- a/springboot-integration-examples/springboot-dubbo-tcc-instance/dubbo-provider/pom.xml +++ /dev/null @@ -1,131 +0,0 @@ - - - 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 2.1.7.RELEASE - - - cn.lastwhisper.springboot - dubbo-provider - 0.0.1-SNAPSHOT - dubbo-provider - Demo project for Spring Boot - - - 1.8 - - - - - org.springframework.boot - spring-boot-starter - - - com.alibaba.spring.boot - dubbo-spring-boot-starter - 2.0.0 - - - org.springframework.boot - spring-boot-starter-test - test - - - com.101tec - zkclient - 0.10 - - - org.mengyun - tcc-transaction-dubbo - 1.2.4.23 - - - org.mengyun - tcc-transaction-spring - 1.2.4.23 - - - org.mengyun - tcc-transaction-core - 1.2.4.23 - - - org.mengyun - tcc-transaction-api - 1.2.4.23 - - - com.alibaba - druid - 1.1.12 - - - mysql - mysql-connector-java - 5.1.10 - - - org.springframework.boot - spring-boot-starter-aop - - - org.quartz-scheduler - quartz - 2.2.1 - - - slf4j-api - org.slf4j - - - - - org.springframework - spring-context-support - - - org.springframework.boot - spring-boot-starter-jdbc - - - com.google.guava - guava - 23.0 - - - com.esotericsoftware - kryo-shaded - 4.0.2 - - - org.apache.commons - commons-lang3 - 3.8.1 - - - com.alibaba - fastjson - 1.2.51 - - - cn.lastwhisper.springboot - dubbo-api - 0.0.1-SNAPSHOT - compile - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - - diff --git a/springboot-integration-examples/springboot-dubbo-tcc-instance/dubbo-provider/src/main/java/cn/lastwhisper/springboot/dubbo/provider/ProviderApplication.java b/springboot-integration-examples/springboot-dubbo-tcc-instance/dubbo-provider/src/main/java/cn/lastwhisper/springboot/dubbo/provider/ProviderApplication.java deleted file mode 100644 index 2d9530d2..00000000 --- a/springboot-integration-examples/springboot-dubbo-tcc-instance/dubbo-provider/src/main/java/cn/lastwhisper/springboot/dubbo/provider/ProviderApplication.java +++ /dev/null @@ -1,17 +0,0 @@ -package cn.lastwhisper.springboot.dubbo.provider; - -import com.alibaba.dubbo.spring.boot.annotation.EnableDubboConfiguration; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -@EnableDubboConfiguration -public class ProviderApplication { - - public static void main(String[] args) { - SpringApplication.run(ProviderApplication.class, args); - - - } - -} diff --git a/springboot-integration-examples/springboot-dubbo-tcc-instance/dubbo-provider/src/main/java/cn/lastwhisper/springboot/dubbo/provider/config/TCCConfig.java b/springboot-integration-examples/springboot-dubbo-tcc-instance/dubbo-provider/src/main/java/cn/lastwhisper/springboot/dubbo/provider/config/TCCConfig.java deleted file mode 100644 index f6cc6a63..00000000 --- a/springboot-integration-examples/springboot-dubbo-tcc-instance/dubbo-provider/src/main/java/cn/lastwhisper/springboot/dubbo/provider/config/TCCConfig.java +++ /dev/null @@ -1,12 +0,0 @@ -package cn.lastwhisper.springboot.dubbo.provider.config; - -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.ImportResource; - -/** - * @author lastwhisper - */ -@Configuration -@ImportResource(locations = {"classpath:tcc-transaction.xml","classpath:tcc-transaction-dubbo.xml"}) -public class TCCConfig { -} diff --git a/springboot-integration-examples/springboot-dubbo-tcc-instance/dubbo-provider/src/main/java/cn/lastwhisper/springboot/dubbo/provider/quickstart/QuickstartServiceImpl.java b/springboot-integration-examples/springboot-dubbo-tcc-instance/dubbo-provider/src/main/java/cn/lastwhisper/springboot/dubbo/provider/quickstart/QuickstartServiceImpl.java deleted file mode 100644 index a0f50fe3..00000000 --- a/springboot-integration-examples/springboot-dubbo-tcc-instance/dubbo-provider/src/main/java/cn/lastwhisper/springboot/dubbo/provider/quickstart/QuickstartServiceImpl.java +++ /dev/null @@ -1,33 +0,0 @@ -package cn.lastwhisper.springboot.dubbo.provider.quickstart; - -import cn.lastwhisper.springboot.ServiceAPI; -import com.alibaba.dubbo.config.annotation.Service; -import org.springframework.stereotype.Component; - -/** - * @author lastwhisper - */ -//@Component -//@Service(interfaceClass = ServiceAPI.class) -public class QuickstartServiceImpl implements ServiceAPI { - - @Override - public String sendMessage(String message) { - return "quickstart-provider-message=" + message; - } - - @Override - public boolean isTrueSeats(String seats) { - return false; - } - - @Override - public boolean isNotSold(String seats) { - return false; - } - - @Override - public String saveOrder(String field, String seats, String seatsNum) { - return null; - } -} diff --git a/springboot-integration-examples/springboot-dubbo-tcc-instance/dubbo-provider/src/main/java/cn/lastwhisper/springboot/dubbo/provider/transaction/TransactionService.java b/springboot-integration-examples/springboot-dubbo-tcc-instance/dubbo-provider/src/main/java/cn/lastwhisper/springboot/dubbo/provider/transaction/TransactionService.java deleted file mode 100644 index 4f8b5c8e..00000000 --- a/springboot-integration-examples/springboot-dubbo-tcc-instance/dubbo-provider/src/main/java/cn/lastwhisper/springboot/dubbo/provider/transaction/TransactionService.java +++ /dev/null @@ -1,96 +0,0 @@ -package cn.lastwhisper.springboot.dubbo.provider.transaction; - -import cn.lastwhisper.springboot.ServiceAPI; -import com.alibaba.dubbo.config.annotation.Service; -import org.mengyun.tcctransaction.api.Compensable; -import org.mengyun.tcctransaction.dubbo.context.DubboTransactionContextEditor; -import org.springframework.stereotype.Component; - -/** - * @author lastwhisper - */ -@Component -@Service(interfaceClass = ServiceAPI.class) -public class TransactionService implements ServiceAPI { - - @Compensable(confirmMethod = "confirmSendMessage", cancelMethod = "cancelSendMessage", transactionContextEditor = DubboTransactionContextEditor.class) - @Override - public String sendMessage(String message) { - System.out.println("this is provider sendMessage=" + message); - if ("123".equals(message)) { - throw new NullPointerException(); - } - return "tcc-provider-message=" + message; - } - - @Override - @Compensable(confirmMethod = "confirmIsTrueSeats", cancelMethod = "cancelIsTrueSeats", transactionContextEditor = DubboTransactionContextEditor.class) - public boolean isTrueSeats(String seats) { - // 假设1,2,3座位不存在 - if ("1,2,3".equals(seats)) { - throw new IllegalArgumentException(); - } else { - return true; - } - } - - - @Override - @Compensable(confirmMethod = "confirmIsNotSold", cancelMethod = "cancelIsNotSold", transactionContextEditor = DubboTransactionContextEditor.class) - public boolean isNotSold(String seats) { - // 假设4,5已经售出 - if ("4,5".equals(seats)) { - throw new IllegalArgumentException(); - } else { - return true; - } - } - - // 幂等性 - @Override - @Compensable(confirmMethod = "confirmSaveOrder", cancelMethod = "cancelSaveOrder", transactionContextEditor = DubboTransactionContextEditor.class) - public String saveOrder(String field, String seats, String seatsNum) { - System.out.println("创建一个待支付状态的订单"); - return ""; - } - - - public String confirmSaveOrder(String field, String seats, String seatsNum) { - System.out.println("将订单修改为支付中"); - return ""; - } - public String cancelSaveOrder(String field, String seats, String seatsNum) { - System.out.println("将订单修改为已关闭"); - return ""; - } - - public boolean confirmIsNotSold(String seats) { - System.out.println("this is confirmIsNotSold"); - return true; - } - - public boolean cancelIsNotSold(String seats) { - System.out.println("this is cancelIsNotSold"); - return true; - } - - public boolean confirmIsTrueSeats(String seats) { - System.out.println("this is confirmIsTrueSeats"); - return true; - } - - public boolean cancelIsTrueSeats(String seats) { - System.out.println("this is cancelIsTrueSeats"); - return true; - } - - public String confirmSendMessage(String message) { - System.out.println("this is provider confirmSendMessage=" + message); - return "tcc-provider-message=" + message; - } - - public String cancelSendMessage(String message) { - System.out.println("this is provider cancelSendMessage=" + message); - return "tcc-provider-message=" + message; - } -} diff --git a/springboot-integration-examples/springboot-dubbo-tcc-instance/dubbo-provider/src/main/resources/application.properties b/springboot-integration-examples/springboot-dubbo-tcc-instance/dubbo-provider/src/main/resources/application.properties deleted file mode 100644 index 0d2d5ac4..00000000 --- a/springboot-integration-examples/springboot-dubbo-tcc-instance/dubbo-provider/src/main/resources/application.properties +++ /dev/null @@ -1,3 +0,0 @@ -spring.application.name=dubbo-spring-boot-starter -spring.dubbo.server=true -spring.dubbo.registry=zookeeper://localhost:2181 \ No newline at end of file diff --git a/springboot-integration-examples/springboot-dubbo-tcc-instance/dubbo-provider/src/main/resources/tcc-transaction-dubbo.xml b/springboot-integration-examples/springboot-dubbo-tcc-instance/dubbo-provider/src/main/resources/tcc-transaction-dubbo.xml deleted file mode 100644 index 6fd7c1f3..00000000 --- a/springboot-integration-examples/springboot-dubbo-tcc-instance/dubbo-provider/src/main/resources/tcc-transaction-dubbo.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - \ No newline at end of file diff --git a/springboot-integration-examples/springboot-dubbo-tcc-instance/dubbo-provider/src/main/resources/tcc-transaction.xml b/springboot-integration-examples/springboot-dubbo-tcc-instance/dubbo-provider/src/main/resources/tcc-transaction.xml deleted file mode 100644 index c3ed94ec..00000000 --- a/springboot-integration-examples/springboot-dubbo-tcc-instance/dubbo-provider/src/main/resources/tcc-transaction.xml +++ /dev/null @@ -1,75 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - com.alibaba.dubbo.remoting.TimeoutException - - - - - \ No newline at end of file diff --git a/springboot-integration-examples/springboot-dubbo-tcc-instance/dubbo-provider/src/test/java/cn/lastwhisper/springboot/dubboprovider/DubboProviderApplicationTests.java b/springboot-integration-examples/springboot-dubbo-tcc-instance/dubbo-provider/src/test/java/cn/lastwhisper/springboot/dubboprovider/DubboProviderApplicationTests.java deleted file mode 100644 index 2cd9a38d..00000000 --- a/springboot-integration-examples/springboot-dubbo-tcc-instance/dubbo-provider/src/test/java/cn/lastwhisper/springboot/dubboprovider/DubboProviderApplicationTests.java +++ /dev/null @@ -1,16 +0,0 @@ -package cn.lastwhisper.springboot.dubboprovider; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit4.SpringRunner; - -@RunWith(SpringRunner.class) -@SpringBootTest -public class DubboProviderApplicationTests { - - @Test - public void contextLoads() { - } - -} diff --git a/springboot-integration-examples/springboot-dubbo-tcc-instance/pom.xml b/springboot-integration-examples/springboot-dubbo-tcc-instance/pom.xml deleted file mode 100644 index 4d2a0da5..00000000 --- a/springboot-integration-examples/springboot-dubbo-tcc-instance/pom.xml +++ /dev/null @@ -1,47 +0,0 @@ - - - 4.0.0 - pom - - dubbo-api - - - org.springframework.boot - spring-boot-starter-parent - 2.1.7.RELEASE - - - cn.lastwhisper.springboot - springboot-dubbo-tcc - 0.0.1-SNAPSHOT - springboot-dubbo-tcc - Demo project for Spring Boot - - - 1.8 - - - - - org.springframework.boot - spring-boot-starter - - - - org.springframework.boot - spring-boot-starter-test - test - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - - diff --git a/springboot-integration-examples/springboot-dubbo-tcc-instance/src/main/java/cn/lastwhisper/springboot/springbootdubbotcc/SpringbootDubboTccApplication.java b/springboot-integration-examples/springboot-dubbo-tcc-instance/src/main/java/cn/lastwhisper/springboot/springbootdubbotcc/SpringbootDubboTccApplication.java deleted file mode 100644 index 4929e634..00000000 --- a/springboot-integration-examples/springboot-dubbo-tcc-instance/src/main/java/cn/lastwhisper/springboot/springbootdubbotcc/SpringbootDubboTccApplication.java +++ /dev/null @@ -1,13 +0,0 @@ -package cn.lastwhisper.springboot.springbootdubbotcc; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class SpringbootDubboTccApplication { - - public static void main(String[] args) { - SpringApplication.run(SpringbootDubboTccApplication.class, args); - } - -} diff --git a/springboot-integration-examples/springboot-dubbo-tcc-instance/src/test/java/cn/lastwhisper/springboot/springbootdubbotcc/SpringbootDubboTccApplicationTests.java b/springboot-integration-examples/springboot-dubbo-tcc-instance/src/test/java/cn/lastwhisper/springboot/springbootdubbotcc/SpringbootDubboTccApplicationTests.java deleted file mode 100644 index 7911d933..00000000 --- a/springboot-integration-examples/springboot-dubbo-tcc-instance/src/test/java/cn/lastwhisper/springboot/springbootdubbotcc/SpringbootDubboTccApplicationTests.java +++ /dev/null @@ -1,16 +0,0 @@ -package cn.lastwhisper.springboot.springbootdubbotcc; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit4.SpringRunner; - -@RunWith(SpringRunner.class) -@SpringBootTest -public class SpringbootDubboTccApplicationTests { - - @Test - public void contextLoads() { - } - -} diff --git a/springboot-integration-examples/springboot-dubbo-tcc-rt/dubbo-api/pom.xml b/springboot-integration-examples/springboot-dubbo-tcc-rt/dubbo-api/pom.xml deleted file mode 100644 index c5acbd23..00000000 --- a/springboot-integration-examples/springboot-dubbo-tcc-rt/dubbo-api/pom.xml +++ /dev/null @@ -1,84 +0,0 @@ - - - - - springboot-dubbo-tcc - cn.lastwhisper.springboot - 0.0.1-SNAPSHOT - - 4.0.0 - - cn.lastwhisper.springboot - dubbo-api - - dubbo-api - - http://www.example.com - - - UTF-8 - 1.7 - 1.7 - - - - - junit - junit - 4.11 - test - - - org.mengyun - tcc-transaction-api - 1.2.4.23 - - - - - - - - - maven-clean-plugin - 3.1.0 - - - - maven-resources-plugin - 3.0.2 - - - maven-compiler-plugin - 3.8.0 - - - maven-surefire-plugin - 2.22.1 - - - maven-jar-plugin - 3.0.2 - - - maven-install-plugin - 2.5.2 - - - maven-deploy-plugin - 2.8.2 - - - - maven-site-plugin - 3.7.1 - - - maven-project-info-reports-plugin - 3.0.0 - - - - - diff --git a/springboot-integration-examples/springboot-dubbo-tcc-rt/dubbo-api/src/main/java/cn/lastwhisper/springboot/ServiceAPI.java b/springboot-integration-examples/springboot-dubbo-tcc-rt/dubbo-api/src/main/java/cn/lastwhisper/springboot/ServiceAPI.java deleted file mode 100644 index 7a1985db..00000000 --- a/springboot-integration-examples/springboot-dubbo-tcc-rt/dubbo-api/src/main/java/cn/lastwhisper/springboot/ServiceAPI.java +++ /dev/null @@ -1,9 +0,0 @@ -package cn.lastwhisper.springboot; - - -import org.mengyun.tcctransaction.api.Compensable; - -public interface ServiceAPI { - @Compensable - String sendMessage(String message); -} diff --git a/springboot-integration-examples/springboot-dubbo-tcc-rt/dubbo-api/src/test/java/cn/lastwhisper/springboot/AppTest.java b/springboot-integration-examples/springboot-dubbo-tcc-rt/dubbo-api/src/test/java/cn/lastwhisper/springboot/AppTest.java deleted file mode 100644 index ecb89484..00000000 --- a/springboot-integration-examples/springboot-dubbo-tcc-rt/dubbo-api/src/test/java/cn/lastwhisper/springboot/AppTest.java +++ /dev/null @@ -1,20 +0,0 @@ -package cn.lastwhisper.springboot; - -import static org.junit.Assert.assertTrue; - -import org.junit.Test; - -/** - * Unit test for simple App. - */ -public class AppTest -{ - /** - * Rigorous Test :-) - */ - @Test - public void shouldAnswerWithTrue() - { - assertTrue( true ); - } -} diff --git a/springboot-integration-examples/springboot-dubbo-tcc-rt/dubbo-consumer/pom.xml b/springboot-integration-examples/springboot-dubbo-tcc-rt/dubbo-consumer/pom.xml deleted file mode 100644 index 521b26c0..00000000 --- a/springboot-integration-examples/springboot-dubbo-tcc-rt/dubbo-consumer/pom.xml +++ /dev/null @@ -1,136 +0,0 @@ - - - 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 2.1.7.RELEASE - - - cn.lastwhisper.springboot - dubbo-consumer - 0.0.1-SNAPSHOT - dubbo-consumer - 服务消费者 - - - 1.8 - - - - - org.springframework.boot - spring-boot-starter - - - - org.springframework.boot - spring-boot-starter - - - com.alibaba.spring.boot - dubbo-spring-boot-starter - 2.0.0 - - - org.springframework.boot - spring-boot-starter-test - test - - - com.101tec - zkclient - 0.10 - - - org.mengyun - tcc-transaction-dubbo - 1.2.4.23 - - - org.mengyun - tcc-transaction-spring - 1.2.4.23 - - - org.mengyun - tcc-transaction-core - 1.2.4.23 - - - org.mengyun - tcc-transaction-api - 1.2.4.23 - - - com.alibaba - druid - 1.1.12 - - - mysql - mysql-connector-java - 5.1.10 - - - org.springframework.boot - spring-boot-starter-aop - - - org.quartz-scheduler - quartz - 2.2.1 - - - slf4j-api - org.slf4j - - - - - org.springframework - spring-context-support - - - org.springframework.boot - spring-boot-starter-jdbc - - - com.google.guava - guava - 23.0 - - - com.esotericsoftware - kryo-shaded - 4.0.2 - - - org.apache.commons - commons-lang3 - 3.8.1 - - - com.alibaba - fastjson - 1.2.51 - - - cn.lastwhisper.springboot - dubbo-api - 0.0.1-SNAPSHOT - compile - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - - diff --git a/springboot-integration-examples/springboot-dubbo-tcc-rt/dubbo-consumer/src/main/java/cn/lastwhisper/springboot/dubbo/consumer/ConsumerApplication.java b/springboot-integration-examples/springboot-dubbo-tcc-rt/dubbo-consumer/src/main/java/cn/lastwhisper/springboot/dubbo/consumer/ConsumerApplication.java deleted file mode 100644 index 9b2bc169..00000000 --- a/springboot-integration-examples/springboot-dubbo-tcc-rt/dubbo-consumer/src/main/java/cn/lastwhisper/springboot/dubbo/consumer/ConsumerApplication.java +++ /dev/null @@ -1,22 +0,0 @@ -package cn.lastwhisper.springboot.dubbo.consumer; - -import cn.lastwhisper.springboot.dubbo.consumer.transaction.TransactionConsumer; -import com.alibaba.dubbo.spring.boot.annotation.EnableDubboConfiguration; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.context.ConfigurableApplicationContext; - -@SpringBootApplication -@EnableDubboConfiguration -public class ConsumerApplication { - - public static void main(String[] args) { - ConfigurableApplicationContext context = SpringApplication.run(ConsumerApplication.class, args); - //QuickstartConsumer quickstartConsumer = (QuickstartConsumer) context.getBean("quickstartConsumer"); - //quickstartConsumer.sendMessage("你好"); - - TransactionConsumer consumer = (TransactionConsumer) context.getBean("transactionConsumer"); - consumer.sendMessage("123"); - } - -} diff --git a/springboot-integration-examples/springboot-dubbo-tcc-rt/dubbo-consumer/src/main/java/cn/lastwhisper/springboot/dubbo/consumer/config/TCCConfig.java b/springboot-integration-examples/springboot-dubbo-tcc-rt/dubbo-consumer/src/main/java/cn/lastwhisper/springboot/dubbo/consumer/config/TCCConfig.java deleted file mode 100644 index f3de5b89..00000000 --- a/springboot-integration-examples/springboot-dubbo-tcc-rt/dubbo-consumer/src/main/java/cn/lastwhisper/springboot/dubbo/consumer/config/TCCConfig.java +++ /dev/null @@ -1,12 +0,0 @@ -package cn.lastwhisper.springboot.dubbo.consumer.config; - -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.ImportResource; - -/** - * @author lastwhisper - */ -@Configuration -@ImportResource(locations = {"classpath:tcc-transaction.xml","classpath:tcc-transaction-dubbo.xml"}) -public class TCCConfig { -} diff --git a/springboot-integration-examples/springboot-dubbo-tcc-rt/dubbo-consumer/src/main/java/cn/lastwhisper/springboot/dubbo/consumer/quickstart/QuickstartConsumer.java b/springboot-integration-examples/springboot-dubbo-tcc-rt/dubbo-consumer/src/main/java/cn/lastwhisper/springboot/dubbo/consumer/quickstart/QuickstartConsumer.java deleted file mode 100644 index 05c24052..00000000 --- a/springboot-integration-examples/springboot-dubbo-tcc-rt/dubbo-consumer/src/main/java/cn/lastwhisper/springboot/dubbo/consumer/quickstart/QuickstartConsumer.java +++ /dev/null @@ -1,19 +0,0 @@ -package cn.lastwhisper.springboot.dubbo.consumer.quickstart; - -import cn.lastwhisper.springboot.ServiceAPI; -import com.alibaba.dubbo.config.annotation.Reference; -import org.springframework.stereotype.Component; - -/** - * @author lastwhisper - */ -//@Component -public class QuickstartConsumer { - //@Reference(url ="dubbo://localhost:20880") - //@Reference(interfaceClass = ServiceAPI.class) - ServiceAPI serviceAPI; - - public void sendMessage(String message) { - System.out.println(serviceAPI.sendMessage(message)); - } -} diff --git a/springboot-integration-examples/springboot-dubbo-tcc-rt/dubbo-consumer/src/main/java/cn/lastwhisper/springboot/dubbo/consumer/transaction/TransactionConsumer.java b/springboot-integration-examples/springboot-dubbo-tcc-rt/dubbo-consumer/src/main/java/cn/lastwhisper/springboot/dubbo/consumer/transaction/TransactionConsumer.java deleted file mode 100644 index 646c687c..00000000 --- a/springboot-integration-examples/springboot-dubbo-tcc-rt/dubbo-consumer/src/main/java/cn/lastwhisper/springboot/dubbo/consumer/transaction/TransactionConsumer.java +++ /dev/null @@ -1,29 +0,0 @@ -package cn.lastwhisper.springboot.dubbo.consumer.transaction; - -import cn.lastwhisper.springboot.ServiceAPI; -import com.alibaba.dubbo.config.annotation.Reference; -import org.mengyun.tcctransaction.api.Compensable; -import org.springframework.stereotype.Component; - -/** - * @author lastwhisper - */ -@Component("transactionConsumer") -public class TransactionConsumer { - @Reference(interfaceClass = ServiceAPI.class) - ServiceAPI serviceAPI; - - @Compensable(confirmMethod = "confirmSendMessage", cancelMethod = "cancelSendMessage", asyncConfirm = true) - public void sendMessage(String message) { - System.out.println("this is consumer sendMessage="+message); - System.out.println(serviceAPI.sendMessage(message)); - } - - public void confirmSendMessage(String message) { - System.out.println("this is consumer confirmSendMessage="+message); - } - - public void cancelSendMessage(String message) { - System.out.println("this is consumer cancelSendMessage="+message); - } -} diff --git a/springboot-integration-examples/springboot-dubbo-tcc-rt/dubbo-consumer/src/main/resources/application.properties b/springboot-integration-examples/springboot-dubbo-tcc-rt/dubbo-consumer/src/main/resources/application.properties deleted file mode 100644 index 6f0465df..00000000 --- a/springboot-integration-examples/springboot-dubbo-tcc-rt/dubbo-consumer/src/main/resources/application.properties +++ /dev/null @@ -1,2 +0,0 @@ -spring.application.name=dubbo-spring-boot-starter -spring.dubbo.registry=zookeeper://localhost:2181 \ No newline at end of file diff --git a/springboot-integration-examples/springboot-dubbo-tcc-rt/dubbo-consumer/src/main/resources/tcc-transaction-dubbo.xml b/springboot-integration-examples/springboot-dubbo-tcc-rt/dubbo-consumer/src/main/resources/tcc-transaction-dubbo.xml deleted file mode 100644 index 7bcd668b..00000000 --- a/springboot-integration-examples/springboot-dubbo-tcc-rt/dubbo-consumer/src/main/resources/tcc-transaction-dubbo.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/springboot-integration-examples/springboot-dubbo-tcc-rt/dubbo-consumer/src/main/resources/tcc-transaction.xml b/springboot-integration-examples/springboot-dubbo-tcc-rt/dubbo-consumer/src/main/resources/tcc-transaction.xml deleted file mode 100644 index bccba078..00000000 --- a/springboot-integration-examples/springboot-dubbo-tcc-rt/dubbo-consumer/src/main/resources/tcc-transaction.xml +++ /dev/null @@ -1,75 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - com.alibaba.dubbo.remoting.TimeoutException - - - - - \ No newline at end of file diff --git a/springboot-integration-examples/springboot-dubbo-tcc-rt/dubbo-consumer/src/test/java/cn/lastwhisper/springboot/dubboconsumer/DubboConsumerApplicationTests.java b/springboot-integration-examples/springboot-dubbo-tcc-rt/dubbo-consumer/src/test/java/cn/lastwhisper/springboot/dubboconsumer/DubboConsumerApplicationTests.java deleted file mode 100644 index 82925eb9..00000000 --- a/springboot-integration-examples/springboot-dubbo-tcc-rt/dubbo-consumer/src/test/java/cn/lastwhisper/springboot/dubboconsumer/DubboConsumerApplicationTests.java +++ /dev/null @@ -1,16 +0,0 @@ -package cn.lastwhisper.springboot.dubboconsumer; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit4.SpringRunner; - -@RunWith(SpringRunner.class) -@SpringBootTest -public class DubboConsumerApplicationTests { - - @Test - public void contextLoads() { - } - -} diff --git a/springboot-integration-examples/springboot-dubbo-tcc-rt/dubbo-provider/pom.xml b/springboot-integration-examples/springboot-dubbo-tcc-rt/dubbo-provider/pom.xml deleted file mode 100644 index a9b90230..00000000 --- a/springboot-integration-examples/springboot-dubbo-tcc-rt/dubbo-provider/pom.xml +++ /dev/null @@ -1,131 +0,0 @@ - - - 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 2.1.7.RELEASE - - - cn.lastwhisper.springboot - dubbo-provider - 0.0.1-SNAPSHOT - dubbo-provider - Demo project for Spring Boot - - - 1.8 - - - - - org.springframework.boot - spring-boot-starter - - - com.alibaba.spring.boot - dubbo-spring-boot-starter - 2.0.0 - - - org.springframework.boot - spring-boot-starter-test - test - - - com.101tec - zkclient - 0.10 - - - org.mengyun - tcc-transaction-dubbo - 1.2.4.23 - - - org.mengyun - tcc-transaction-spring - 1.2.4.23 - - - org.mengyun - tcc-transaction-core - 1.2.4.23 - - - org.mengyun - tcc-transaction-api - 1.2.4.23 - - - com.alibaba - druid - 1.1.12 - - - mysql - mysql-connector-java - 5.1.10 - - - org.springframework.boot - spring-boot-starter-aop - - - org.quartz-scheduler - quartz - 2.2.1 - - - slf4j-api - org.slf4j - - - - - org.springframework - spring-context-support - - - org.springframework.boot - spring-boot-starter-jdbc - - - com.google.guava - guava - 23.0 - - - com.esotericsoftware - kryo-shaded - 4.0.2 - - - org.apache.commons - commons-lang3 - 3.8.1 - - - com.alibaba - fastjson - 1.2.51 - - - cn.lastwhisper.springboot - dubbo-api - 0.0.1-SNAPSHOT - compile - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - - diff --git a/springboot-integration-examples/springboot-dubbo-tcc-rt/dubbo-provider/src/main/java/cn/lastwhisper/springboot/dubbo/provider/ProviderApplication.java b/springboot-integration-examples/springboot-dubbo-tcc-rt/dubbo-provider/src/main/java/cn/lastwhisper/springboot/dubbo/provider/ProviderApplication.java deleted file mode 100644 index 2d9530d2..00000000 --- a/springboot-integration-examples/springboot-dubbo-tcc-rt/dubbo-provider/src/main/java/cn/lastwhisper/springboot/dubbo/provider/ProviderApplication.java +++ /dev/null @@ -1,17 +0,0 @@ -package cn.lastwhisper.springboot.dubbo.provider; - -import com.alibaba.dubbo.spring.boot.annotation.EnableDubboConfiguration; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -@EnableDubboConfiguration -public class ProviderApplication { - - public static void main(String[] args) { - SpringApplication.run(ProviderApplication.class, args); - - - } - -} diff --git a/springboot-integration-examples/springboot-dubbo-tcc-rt/dubbo-provider/src/main/java/cn/lastwhisper/springboot/dubbo/provider/config/TCCConfig.java b/springboot-integration-examples/springboot-dubbo-tcc-rt/dubbo-provider/src/main/java/cn/lastwhisper/springboot/dubbo/provider/config/TCCConfig.java deleted file mode 100644 index f6cc6a63..00000000 --- a/springboot-integration-examples/springboot-dubbo-tcc-rt/dubbo-provider/src/main/java/cn/lastwhisper/springboot/dubbo/provider/config/TCCConfig.java +++ /dev/null @@ -1,12 +0,0 @@ -package cn.lastwhisper.springboot.dubbo.provider.config; - -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.ImportResource; - -/** - * @author lastwhisper - */ -@Configuration -@ImportResource(locations = {"classpath:tcc-transaction.xml","classpath:tcc-transaction-dubbo.xml"}) -public class TCCConfig { -} diff --git a/springboot-integration-examples/springboot-dubbo-tcc-rt/dubbo-provider/src/main/java/cn/lastwhisper/springboot/dubbo/provider/quickstart/QuickstartServiceImpl.java b/springboot-integration-examples/springboot-dubbo-tcc-rt/dubbo-provider/src/main/java/cn/lastwhisper/springboot/dubbo/provider/quickstart/QuickstartServiceImpl.java deleted file mode 100644 index d823e0f9..00000000 --- a/springboot-integration-examples/springboot-dubbo-tcc-rt/dubbo-provider/src/main/java/cn/lastwhisper/springboot/dubbo/provider/quickstart/QuickstartServiceImpl.java +++ /dev/null @@ -1,18 +0,0 @@ -package cn.lastwhisper.springboot.dubbo.provider.quickstart; - -import cn.lastwhisper.springboot.ServiceAPI; -import com.alibaba.dubbo.config.annotation.Service; -import org.springframework.stereotype.Component; - -/** - * @author lastwhisper - */ -//@Component -//@Service(interfaceClass = ServiceAPI.class) -public class QuickstartServiceImpl implements ServiceAPI { - - @Override - public String sendMessage(String message) { - return "quickstart-provider-message=" + message; - } -} diff --git a/springboot-integration-examples/springboot-dubbo-tcc-rt/dubbo-provider/src/main/java/cn/lastwhisper/springboot/dubbo/provider/transaction/TransactionService.java b/springboot-integration-examples/springboot-dubbo-tcc-rt/dubbo-provider/src/main/java/cn/lastwhisper/springboot/dubbo/provider/transaction/TransactionService.java deleted file mode 100644 index 4562e128..00000000 --- a/springboot-integration-examples/springboot-dubbo-tcc-rt/dubbo-provider/src/main/java/cn/lastwhisper/springboot/dubbo/provider/transaction/TransactionService.java +++ /dev/null @@ -1,35 +0,0 @@ -package cn.lastwhisper.springboot.dubbo.provider.transaction; - -import cn.lastwhisper.springboot.ServiceAPI; -import com.alibaba.dubbo.config.annotation.Service; -import org.mengyun.tcctransaction.api.Compensable; -import org.mengyun.tcctransaction.dubbo.context.DubboTransactionContextEditor; -import org.springframework.stereotype.Component; - -/** - * @author lastwhisper - */ -@Component -@Service(interfaceClass = ServiceAPI.class) -public class TransactionService implements ServiceAPI { - - @Compensable(confirmMethod = "confirmSendMessage", cancelMethod = "cancelSendMessage", transactionContextEditor = DubboTransactionContextEditor.class) - @Override - public String sendMessage(String message) { - System.out.println("this is provider sendMessage=" + message); - if ("123".equals(message)) { - throw new NullPointerException(); - } - return "tcc-provider-message=" + message; - } - - public String confirmSendMessage(String message) { - System.out.println("this is provider confirmSendMessage=" + message); - return "tcc-provider-message=" + message; - } - - public String cancelSendMessage(String message) { - System.out.println("this is provider cancelSendMessage=" + message); - return "tcc-provider-message=" + message; - } -} diff --git a/springboot-integration-examples/springboot-dubbo-tcc-rt/dubbo-provider/src/main/resources/application.properties b/springboot-integration-examples/springboot-dubbo-tcc-rt/dubbo-provider/src/main/resources/application.properties deleted file mode 100644 index 0d2d5ac4..00000000 --- a/springboot-integration-examples/springboot-dubbo-tcc-rt/dubbo-provider/src/main/resources/application.properties +++ /dev/null @@ -1,3 +0,0 @@ -spring.application.name=dubbo-spring-boot-starter -spring.dubbo.server=true -spring.dubbo.registry=zookeeper://localhost:2181 \ No newline at end of file diff --git a/springboot-integration-examples/springboot-dubbo-tcc-rt/dubbo-provider/src/main/resources/tcc-transaction-dubbo.xml b/springboot-integration-examples/springboot-dubbo-tcc-rt/dubbo-provider/src/main/resources/tcc-transaction-dubbo.xml deleted file mode 100644 index 6fd7c1f3..00000000 --- a/springboot-integration-examples/springboot-dubbo-tcc-rt/dubbo-provider/src/main/resources/tcc-transaction-dubbo.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - \ No newline at end of file diff --git a/springboot-integration-examples/springboot-dubbo-tcc-rt/dubbo-provider/src/main/resources/tcc-transaction.xml b/springboot-integration-examples/springboot-dubbo-tcc-rt/dubbo-provider/src/main/resources/tcc-transaction.xml deleted file mode 100644 index c3ed94ec..00000000 --- a/springboot-integration-examples/springboot-dubbo-tcc-rt/dubbo-provider/src/main/resources/tcc-transaction.xml +++ /dev/null @@ -1,75 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - com.alibaba.dubbo.remoting.TimeoutException - - - - - \ No newline at end of file diff --git a/springboot-integration-examples/springboot-dubbo-tcc-rt/dubbo-provider/src/test/java/cn/lastwhisper/springboot/dubboprovider/DubboProviderApplicationTests.java b/springboot-integration-examples/springboot-dubbo-tcc-rt/dubbo-provider/src/test/java/cn/lastwhisper/springboot/dubboprovider/DubboProviderApplicationTests.java deleted file mode 100644 index 2cd9a38d..00000000 --- a/springboot-integration-examples/springboot-dubbo-tcc-rt/dubbo-provider/src/test/java/cn/lastwhisper/springboot/dubboprovider/DubboProviderApplicationTests.java +++ /dev/null @@ -1,16 +0,0 @@ -package cn.lastwhisper.springboot.dubboprovider; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit4.SpringRunner; - -@RunWith(SpringRunner.class) -@SpringBootTest -public class DubboProviderApplicationTests { - - @Test - public void contextLoads() { - } - -} diff --git a/springboot-integration-examples/springboot-dubbo-tcc-rt/pom.xml b/springboot-integration-examples/springboot-dubbo-tcc-rt/pom.xml deleted file mode 100644 index 4d2a0da5..00000000 --- a/springboot-integration-examples/springboot-dubbo-tcc-rt/pom.xml +++ /dev/null @@ -1,47 +0,0 @@ - - - 4.0.0 - pom - - dubbo-api - - - org.springframework.boot - spring-boot-starter-parent - 2.1.7.RELEASE - - - cn.lastwhisper.springboot - springboot-dubbo-tcc - 0.0.1-SNAPSHOT - springboot-dubbo-tcc - Demo project for Spring Boot - - - 1.8 - - - - - org.springframework.boot - spring-boot-starter - - - - org.springframework.boot - spring-boot-starter-test - test - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - - diff --git a/springboot-integration-examples/springboot-duboo-filter/dubbo-api/pom.xml b/springboot-integration-examples/springboot-duboo-filter/dubbo-api/pom.xml deleted file mode 100644 index 911d7ddf..00000000 --- a/springboot-integration-examples/springboot-duboo-filter/dubbo-api/pom.xml +++ /dev/null @@ -1,79 +0,0 @@ - - - - - springboot-duboo - cn.lastwhisper.springboot.dubbo - 0.0.1-SNAPSHOT - - 4.0.0 - - cn.lastwhisper.springboot.dubbo - dubbo-api - - dubbo-api - - http://www.example.com - - - UTF-8 - 1.7 - 1.7 - - - - - junit - junit - 4.11 - test - - - - - - - - - maven-clean-plugin - 3.1.0 - - - - maven-resources-plugin - 3.0.2 - - - maven-compiler-plugin - 3.8.0 - - - maven-surefire-plugin - 2.22.1 - - - maven-jar-plugin - 3.0.2 - - - maven-install-plugin - 2.5.2 - - - maven-deploy-plugin - 2.8.2 - - - - maven-site-plugin - 3.7.1 - - - maven-project-info-reports-plugin - 3.0.0 - - - - - diff --git a/springboot-integration-examples/springboot-duboo-filter/dubbo-api/src/main/java/cn/lastwhisper/springboot/dubbo/ServiceAPI.java b/springboot-integration-examples/springboot-duboo-filter/dubbo-api/src/main/java/cn/lastwhisper/springboot/dubbo/ServiceAPI.java deleted file mode 100644 index 8231e710..00000000 --- a/springboot-integration-examples/springboot-duboo-filter/dubbo-api/src/main/java/cn/lastwhisper/springboot/dubbo/ServiceAPI.java +++ /dev/null @@ -1,5 +0,0 @@ -package cn.lastwhisper.springboot.dubbo; - -public interface ServiceAPI { - String sendMessage(String message); -} diff --git a/springboot-integration-examples/springboot-duboo-filter/dubbo-api/src/test/java/cn/lastwhisper/springboot/dubbo/AppTest.java b/springboot-integration-examples/springboot-duboo-filter/dubbo-api/src/test/java/cn/lastwhisper/springboot/dubbo/AppTest.java deleted file mode 100644 index 6aaab91b..00000000 --- a/springboot-integration-examples/springboot-duboo-filter/dubbo-api/src/test/java/cn/lastwhisper/springboot/dubbo/AppTest.java +++ /dev/null @@ -1,20 +0,0 @@ -package cn.lastwhisper.springboot.dubbo; - -import static org.junit.Assert.assertTrue; - -import org.junit.Test; - -/** - * Unit test for simple App. - */ -public class AppTest -{ - /** - * Rigorous Test :-) - */ - @Test - public void shouldAnswerWithTrue() - { - assertTrue( true ); - } -} diff --git a/springboot-integration-examples/springboot-duboo-filter/dubbo-consumer/pom.xml b/springboot-integration-examples/springboot-duboo-filter/dubbo-consumer/pom.xml deleted file mode 100644 index d75196cc..00000000 --- a/springboot-integration-examples/springboot-duboo-filter/dubbo-consumer/pom.xml +++ /dev/null @@ -1,61 +0,0 @@ - - - 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 2.1.7.RELEASE - - - cn.lastwhisper.springboot.dubbo - dubbo-consumer - 0.0.1-SNAPSHOT - dubbo-consumer - Demo project for Spring Boot - - - 1.8 - - - - - org.springframework.boot - spring-boot-starter - - - - org.springframework.boot - spring-boot-starter-test - test - - - com.alibaba.spring.boot - dubbo-spring-boot-starter - 2.0.0 - - - - cn.lastwhisper.springboot.dubbo - dubbo-api - 0.0.1-SNAPSHOT - - - - com.101tec - zkclient - 0.10 - - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - - diff --git a/springboot-integration-examples/springboot-duboo-filter/dubbo-consumer/src/main/java/cn/lastwhisper/springboot/dubbo/consumer/ConsumerApplication.java b/springboot-integration-examples/springboot-duboo-filter/dubbo-consumer/src/main/java/cn/lastwhisper/springboot/dubbo/consumer/ConsumerApplication.java deleted file mode 100644 index 3ad18963..00000000 --- a/springboot-integration-examples/springboot-duboo-filter/dubbo-consumer/src/main/java/cn/lastwhisper/springboot/dubbo/consumer/ConsumerApplication.java +++ /dev/null @@ -1,21 +0,0 @@ -package cn.lastwhisper.springboot.dubbo.consumer; - -import cn.lastwhisper.springboot.dubbo.consumer.quickstart.QuickstartConsumer; -import com.alibaba.dubbo.spring.boot.annotation.EnableDubboConfiguration; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.context.ConfigurableApplicationContext; - -@SpringBootApplication -@EnableDubboConfiguration -public class ConsumerApplication { - - public static void main(String[] args) { - ConfigurableApplicationContext context = SpringApplication.run(ConsumerApplication.class, args); - QuickstartConsumer quickstartConsumer = (QuickstartConsumer) context.getBean("quickstartConsumer"); - - quickstartConsumer.sendMessage("你好"); - - } - -} diff --git a/springboot-integration-examples/springboot-duboo-filter/dubbo-consumer/src/main/java/cn/lastwhisper/springboot/dubbo/consumer/quickstart/QuickstartConsumer.java b/springboot-integration-examples/springboot-duboo-filter/dubbo-consumer/src/main/java/cn/lastwhisper/springboot/dubbo/consumer/quickstart/QuickstartConsumer.java deleted file mode 100644 index cb6e6110..00000000 --- a/springboot-integration-examples/springboot-duboo-filter/dubbo-consumer/src/main/java/cn/lastwhisper/springboot/dubbo/consumer/quickstart/QuickstartConsumer.java +++ /dev/null @@ -1,19 +0,0 @@ -package cn.lastwhisper.springboot.dubbo.consumer.quickstart; - -import cn.lastwhisper.springboot.dubbo.ServiceAPI; -import com.alibaba.dubbo.config.annotation.Reference; -import org.springframework.stereotype.Component; - -/** - * @author lastwhisper - */ -@Component -public class QuickstartConsumer { - //@Reference(url ="dubbo://localhost:20880") - @Reference(interfaceClass = ServiceAPI.class) - ServiceAPI serviceAPI; - - public void sendMessage(String message) { - System.out.println(serviceAPI.sendMessage(message)); - } -} diff --git a/springboot-integration-examples/springboot-duboo-filter/dubbo-consumer/src/main/resources/application.properties b/springboot-integration-examples/springboot-duboo-filter/dubbo-consumer/src/main/resources/application.properties deleted file mode 100644 index 6f0465df..00000000 --- a/springboot-integration-examples/springboot-duboo-filter/dubbo-consumer/src/main/resources/application.properties +++ /dev/null @@ -1,2 +0,0 @@ -spring.application.name=dubbo-spring-boot-starter -spring.dubbo.registry=zookeeper://localhost:2181 \ No newline at end of file diff --git a/springboot-integration-examples/springboot-duboo-filter/dubbo-consumer/src/test/java/cn/lastwhisper/springboot/dubbo/consumer/ConsumerApplicationTests.java b/springboot-integration-examples/springboot-duboo-filter/dubbo-consumer/src/test/java/cn/lastwhisper/springboot/dubbo/consumer/ConsumerApplicationTests.java deleted file mode 100644 index 7c1d8b40..00000000 --- a/springboot-integration-examples/springboot-duboo-filter/dubbo-consumer/src/test/java/cn/lastwhisper/springboot/dubbo/consumer/ConsumerApplicationTests.java +++ /dev/null @@ -1,16 +0,0 @@ -package cn.lastwhisper.springboot.dubbo.consumer; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit4.SpringRunner; - -@RunWith(SpringRunner.class) -@SpringBootTest -public class ConsumerApplicationTests { - - @Test - public void contextLoads() { - } - -} diff --git a/springboot-integration-examples/springboot-duboo-filter/dubbo-provider/pom.xml b/springboot-integration-examples/springboot-duboo-filter/dubbo-provider/pom.xml deleted file mode 100644 index 40ded237..00000000 --- a/springboot-integration-examples/springboot-duboo-filter/dubbo-provider/pom.xml +++ /dev/null @@ -1,60 +0,0 @@ - - - 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 2.1.7.RELEASE - - - cn.lastwhisper.springboot.dubbo - dubbo-provider - 0.0.1-SNAPSHOT - dubbo-provider - Demo project for Spring Boot - - - 1.8 - - - - - org.springframework.boot - spring-boot-starter - - - - org.springframework.boot - spring-boot-starter-test - test - - - com.alibaba.spring.boot - dubbo-spring-boot-starter - 2.0.0 - - - - cn.lastwhisper.springboot.dubbo - dubbo-api - 0.0.1-SNAPSHOT - - - - com.101tec - zkclient - 0.10 - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - - diff --git a/springboot-integration-examples/springboot-duboo-filter/dubbo-provider/src/main/java/cn/lastwhisper/springboot/dubbo/provider/ProviderApplication.java b/springboot-integration-examples/springboot-duboo-filter/dubbo-provider/src/main/java/cn/lastwhisper/springboot/dubbo/provider/ProviderApplication.java deleted file mode 100644 index 2d9530d2..00000000 --- a/springboot-integration-examples/springboot-duboo-filter/dubbo-provider/src/main/java/cn/lastwhisper/springboot/dubbo/provider/ProviderApplication.java +++ /dev/null @@ -1,17 +0,0 @@ -package cn.lastwhisper.springboot.dubbo.provider; - -import com.alibaba.dubbo.spring.boot.annotation.EnableDubboConfiguration; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -@EnableDubboConfiguration -public class ProviderApplication { - - public static void main(String[] args) { - SpringApplication.run(ProviderApplication.class, args); - - - } - -} diff --git a/springboot-integration-examples/springboot-duboo-filter/dubbo-provider/src/main/java/cn/lastwhisper/springboot/dubbo/provider/filter/MyFilter.java b/springboot-integration-examples/springboot-duboo-filter/dubbo-provider/src/main/java/cn/lastwhisper/springboot/dubbo/provider/filter/MyFilter.java deleted file mode 100644 index 48c03acc..00000000 --- a/springboot-integration-examples/springboot-duboo-filter/dubbo-provider/src/main/java/cn/lastwhisper/springboot/dubbo/provider/filter/MyFilter.java +++ /dev/null @@ -1,17 +0,0 @@ -package cn.lastwhisper.springboot.dubbo.provider.filter; - -import com.alibaba.dubbo.rpc.*; - -/** - * @author lastwhisper - */ -public class MyFilter implements Filter { - @Override - public Result invoke(Invoker invoker, Invocation invocation) throws RpcException { - System.out.println("服务调用之前"); - Result invoke = invoker.invoke(invocation); - System.out.println("服务调用之后"); - return invoke; - - } -} diff --git a/springboot-integration-examples/springboot-duboo-filter/dubbo-provider/src/main/java/cn/lastwhisper/springboot/dubbo/provider/quickstart/QuickstartServiceImpl.java b/springboot-integration-examples/springboot-duboo-filter/dubbo-provider/src/main/java/cn/lastwhisper/springboot/dubbo/provider/quickstart/QuickstartServiceImpl.java deleted file mode 100644 index 26729bce..00000000 --- a/springboot-integration-examples/springboot-duboo-filter/dubbo-provider/src/main/java/cn/lastwhisper/springboot/dubbo/provider/quickstart/QuickstartServiceImpl.java +++ /dev/null @@ -1,18 +0,0 @@ -package cn.lastwhisper.springboot.dubbo.provider.quickstart; - -import cn.lastwhisper.springboot.dubbo.ServiceAPI; -import com.alibaba.dubbo.config.annotation.Service; -import org.springframework.stereotype.Component; - -/** - * @author lastwhisper - */ -@Component -@Service(interfaceClass = ServiceAPI.class) -public class QuickstartServiceImpl implements ServiceAPI { - - @Override - public String sendMessage(String message) { - return "quickstart-provider-message=" + message; - } -} diff --git a/springboot-integration-examples/springboot-duboo-filter/dubbo-provider/src/main/resources/META-INF/dubbo/com.alibaba.dubbo.rpc.Filter b/springboot-integration-examples/springboot-duboo-filter/dubbo-provider/src/main/resources/META-INF/dubbo/com.alibaba.dubbo.rpc.Filter deleted file mode 100644 index e195640e..00000000 --- a/springboot-integration-examples/springboot-duboo-filter/dubbo-provider/src/main/resources/META-INF/dubbo/com.alibaba.dubbo.rpc.Filter +++ /dev/null @@ -1 +0,0 @@ -MyFilterExt=cn.lastwhisper.springboot.dubbo.provider.filter.MyFilter \ No newline at end of file diff --git a/springboot-integration-examples/springboot-duboo-filter/dubbo-provider/src/main/resources/application.properties b/springboot-integration-examples/springboot-duboo-filter/dubbo-provider/src/main/resources/application.properties deleted file mode 100644 index 919697c2..00000000 --- a/springboot-integration-examples/springboot-duboo-filter/dubbo-provider/src/main/resources/application.properties +++ /dev/null @@ -1,4 +0,0 @@ -spring.application.name=dubbo-spring-boot-starter -spring.dubbo.server=true -spring.dubbo.registry=zookeeper://localhost:2181 -spring.dubbo.provider.filter=MyFilterExt \ No newline at end of file diff --git a/springboot-integration-examples/springboot-duboo-filter/dubbo-provider/src/test/java/cn/lastwhisper/springboot/dubbo/provider/ProviderApplicationTests.java b/springboot-integration-examples/springboot-duboo-filter/dubbo-provider/src/test/java/cn/lastwhisper/springboot/dubbo/provider/ProviderApplicationTests.java deleted file mode 100644 index 2ceac86a..00000000 --- a/springboot-integration-examples/springboot-duboo-filter/dubbo-provider/src/test/java/cn/lastwhisper/springboot/dubbo/provider/ProviderApplicationTests.java +++ /dev/null @@ -1,16 +0,0 @@ -package cn.lastwhisper.springboot.dubbo.provider; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit4.SpringRunner; - -@RunWith(SpringRunner.class) -@SpringBootTest -public class ProviderApplicationTests { - - @Test - public void contextLoads() { - } - -} diff --git a/springboot-integration-examples/springboot-duboo-filter/pom.xml b/springboot-integration-examples/springboot-duboo-filter/pom.xml deleted file mode 100644 index 6de1e68c..00000000 --- a/springboot-integration-examples/springboot-duboo-filter/pom.xml +++ /dev/null @@ -1,47 +0,0 @@ - - - 4.0.0 - pom - - dubbo-api - - - org.springframework.boot - spring-boot-starter-parent - 2.1.7.RELEASE - - - cn.lastwhisper.springboot.dubbo - springboot-duboo - 0.0.1-SNAPSHOT - springboot-duboo - Demo project for Spring Boot - - - 1.8 - - - - - org.springframework.boot - spring-boot-starter - - - - org.springframework.boot - spring-boot-starter-test - test - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - - diff --git a/springboot-integration-examples/springboot-duboo-filter/src/main/java/cn/lastwhisper/springboot/dubbo/springbootduboo/SpringbootDubooApplication.java b/springboot-integration-examples/springboot-duboo-filter/src/main/java/cn/lastwhisper/springboot/dubbo/springbootduboo/SpringbootDubooApplication.java deleted file mode 100644 index 02963579..00000000 --- a/springboot-integration-examples/springboot-duboo-filter/src/main/java/cn/lastwhisper/springboot/dubbo/springbootduboo/SpringbootDubooApplication.java +++ /dev/null @@ -1,13 +0,0 @@ -package cn.lastwhisper.springboot.dubbo.springbootduboo; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class SpringbootDubooApplication { - - public static void main(String[] args) { - SpringApplication.run(SpringbootDubooApplication.class, args); - } - -} diff --git a/springboot-integration-examples/springboot-duboo-filter/src/test/java/cn/lastwhisper/springboot/dubbo/springbootduboo/SpringbootDubooApplicationTests.java b/springboot-integration-examples/springboot-duboo-filter/src/test/java/cn/lastwhisper/springboot/dubbo/springbootduboo/SpringbootDubooApplicationTests.java deleted file mode 100644 index 213364d4..00000000 --- a/springboot-integration-examples/springboot-duboo-filter/src/test/java/cn/lastwhisper/springboot/dubbo/springbootduboo/SpringbootDubooApplicationTests.java +++ /dev/null @@ -1,16 +0,0 @@ -package cn.lastwhisper.springboot.dubbo.springbootduboo; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit4.SpringRunner; - -@RunWith(SpringRunner.class) -@SpringBootTest -public class SpringbootDubooApplicationTests { - - @Test - public void contextLoads() { - } - -} diff --git a/springboot-integration-examples/springboot-duboo/.gitignore b/springboot-integration-examples/springboot-duboo/.gitignore deleted file mode 100644 index a2a3040a..00000000 --- a/springboot-integration-examples/springboot-duboo/.gitignore +++ /dev/null @@ -1,31 +0,0 @@ -HELP.md -target/ -!.mvn/wrapper/maven-wrapper.jar -!**/src/main/** -!**/src/test/** - -### STS ### -.apt_generated -.classpath -.factorypath -.project -.settings -.springBeans -.sts4-cache - -### IntelliJ IDEA ### -.idea -*.iws -*.iml -*.ipr - -### NetBeans ### -/nbproject/private/ -/nbbuild/ -/dist/ -/nbdist/ -/.nb-gradle/ -build/ - -### VS Code ### -.vscode/ diff --git a/springboot-integration-examples/springboot-duboo/.mvn/wrapper/MavenWrapperDownloader.java b/springboot-integration-examples/springboot-duboo/.mvn/wrapper/MavenWrapperDownloader.java deleted file mode 100644 index 7f91a56e..00000000 --- a/springboot-integration-examples/springboot-duboo/.mvn/wrapper/MavenWrapperDownloader.java +++ /dev/null @@ -1,114 +0,0 @@ -/* -Licensed to the Apache Software Foundation (ASF) under one -or more contributor license agreements. See the NOTICE file -distributed with this work for additional information -regarding copyright ownership. The ASF licenses this file -to you under the Apache License, Version 2.0 (the -"License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, -software distributed under the License is distributed on an -"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -KIND, either express or implied. See the License for the -specific language governing permissions and limitations -under the License. -*/ - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.net.URL; -import java.nio.channels.Channels; -import java.nio.channels.ReadableByteChannel; -import java.util.Properties; - -public class MavenWrapperDownloader { - - /** - * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. - */ - private static final String DEFAULT_DOWNLOAD_URL = - "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"; - - /** - * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to - * use instead of the default one. - */ - private static final String MAVEN_WRAPPER_PROPERTIES_PATH = - ".mvn/wrapper/maven-wrapper.properties"; - - /** - * Path where the maven-wrapper.jar will be saved to. - */ - private static final String MAVEN_WRAPPER_JAR_PATH = - ".mvn/wrapper/maven-wrapper.jar"; - - /** - * Name of the property which should be used to override the default download url for the wrapper. - */ - private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; - - public static void main(String args[]) { - System.out.println("- Downloader started"); - File baseDirectory = new File(args[0]); - System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); - - // If the maven-wrapper.properties exists, read it and check if it contains a custom - // wrapperUrl parameter. - File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); - String url = DEFAULT_DOWNLOAD_URL; - if (mavenWrapperPropertyFile.exists()) { - FileInputStream mavenWrapperPropertyFileInputStream = null; - try { - mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); - Properties mavenWrapperProperties = new Properties(); - mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); - url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); - } catch (IOException e) { - System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); - } finally { - try { - if (mavenWrapperPropertyFileInputStream != null) { - mavenWrapperPropertyFileInputStream.close(); - } - } catch (IOException e) { - // Ignore ... - } - } - } - System.out.println("- Downloading from: : " + url); - - File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); - if (!outputFile.getParentFile().exists()) { - if (!outputFile.getParentFile().mkdirs()) { - System.out.println( - "- ERROR creating output direcrory '" + outputFile.getParentFile().getAbsolutePath() + "'"); - } - } - System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); - try { - downloadFileFromURL(url, outputFile); - System.out.println("Done"); - System.exit(0); - } catch (Throwable e) { - System.out.println("- Error downloading"); - e.printStackTrace(); - System.exit(1); - } - } - - private static void downloadFileFromURL(String urlString, File destination) throws Exception { - URL website = new URL(urlString); - ReadableByteChannel rbc; - rbc = Channels.newChannel(website.openStream()); - FileOutputStream fos = new FileOutputStream(destination); - fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); - fos.close(); - rbc.close(); - } - -} diff --git a/springboot-integration-examples/springboot-duboo/.mvn/wrapper/maven-wrapper.jar b/springboot-integration-examples/springboot-duboo/.mvn/wrapper/maven-wrapper.jar deleted file mode 100644 index 01e67997..00000000 Binary files a/springboot-integration-examples/springboot-duboo/.mvn/wrapper/maven-wrapper.jar and /dev/null differ diff --git a/springboot-integration-examples/springboot-duboo/.mvn/wrapper/maven-wrapper.properties b/springboot-integration-examples/springboot-duboo/.mvn/wrapper/maven-wrapper.properties deleted file mode 100644 index cd0d451c..00000000 --- a/springboot-integration-examples/springboot-duboo/.mvn/wrapper/maven-wrapper.properties +++ /dev/null @@ -1 +0,0 @@ -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip diff --git a/springboot-integration-examples/springboot-duboo/consumer/.gitignore b/springboot-integration-examples/springboot-duboo/consumer/.gitignore deleted file mode 100644 index a2a3040a..00000000 --- a/springboot-integration-examples/springboot-duboo/consumer/.gitignore +++ /dev/null @@ -1,31 +0,0 @@ -HELP.md -target/ -!.mvn/wrapper/maven-wrapper.jar -!**/src/main/** -!**/src/test/** - -### STS ### -.apt_generated -.classpath -.factorypath -.project -.settings -.springBeans -.sts4-cache - -### IntelliJ IDEA ### -.idea -*.iws -*.iml -*.ipr - -### NetBeans ### -/nbproject/private/ -/nbbuild/ -/dist/ -/nbdist/ -/.nb-gradle/ -build/ - -### VS Code ### -.vscode/ diff --git a/springboot-integration-examples/springboot-duboo/consumer/.mvn/wrapper/MavenWrapperDownloader.java b/springboot-integration-examples/springboot-duboo/consumer/.mvn/wrapper/MavenWrapperDownloader.java deleted file mode 100644 index 7f91a56e..00000000 --- a/springboot-integration-examples/springboot-duboo/consumer/.mvn/wrapper/MavenWrapperDownloader.java +++ /dev/null @@ -1,114 +0,0 @@ -/* -Licensed to the Apache Software Foundation (ASF) under one -or more contributor license agreements. See the NOTICE file -distributed with this work for additional information -regarding copyright ownership. The ASF licenses this file -to you under the Apache License, Version 2.0 (the -"License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, -software distributed under the License is distributed on an -"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -KIND, either express or implied. See the License for the -specific language governing permissions and limitations -under the License. -*/ - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.net.URL; -import java.nio.channels.Channels; -import java.nio.channels.ReadableByteChannel; -import java.util.Properties; - -public class MavenWrapperDownloader { - - /** - * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. - */ - private static final String DEFAULT_DOWNLOAD_URL = - "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"; - - /** - * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to - * use instead of the default one. - */ - private static final String MAVEN_WRAPPER_PROPERTIES_PATH = - ".mvn/wrapper/maven-wrapper.properties"; - - /** - * Path where the maven-wrapper.jar will be saved to. - */ - private static final String MAVEN_WRAPPER_JAR_PATH = - ".mvn/wrapper/maven-wrapper.jar"; - - /** - * Name of the property which should be used to override the default download url for the wrapper. - */ - private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; - - public static void main(String args[]) { - System.out.println("- Downloader started"); - File baseDirectory = new File(args[0]); - System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); - - // If the maven-wrapper.properties exists, read it and check if it contains a custom - // wrapperUrl parameter. - File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); - String url = DEFAULT_DOWNLOAD_URL; - if (mavenWrapperPropertyFile.exists()) { - FileInputStream mavenWrapperPropertyFileInputStream = null; - try { - mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); - Properties mavenWrapperProperties = new Properties(); - mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); - url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); - } catch (IOException e) { - System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); - } finally { - try { - if (mavenWrapperPropertyFileInputStream != null) { - mavenWrapperPropertyFileInputStream.close(); - } - } catch (IOException e) { - // Ignore ... - } - } - } - System.out.println("- Downloading from: : " + url); - - File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); - if (!outputFile.getParentFile().exists()) { - if (!outputFile.getParentFile().mkdirs()) { - System.out.println( - "- ERROR creating output direcrory '" + outputFile.getParentFile().getAbsolutePath() + "'"); - } - } - System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); - try { - downloadFileFromURL(url, outputFile); - System.out.println("Done"); - System.exit(0); - } catch (Throwable e) { - System.out.println("- Error downloading"); - e.printStackTrace(); - System.exit(1); - } - } - - private static void downloadFileFromURL(String urlString, File destination) throws Exception { - URL website = new URL(urlString); - ReadableByteChannel rbc; - rbc = Channels.newChannel(website.openStream()); - FileOutputStream fos = new FileOutputStream(destination); - fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); - fos.close(); - rbc.close(); - } - -} diff --git a/springboot-integration-examples/springboot-duboo/consumer/.mvn/wrapper/maven-wrapper.jar b/springboot-integration-examples/springboot-duboo/consumer/.mvn/wrapper/maven-wrapper.jar deleted file mode 100644 index 01e67997..00000000 Binary files a/springboot-integration-examples/springboot-duboo/consumer/.mvn/wrapper/maven-wrapper.jar and /dev/null differ diff --git a/springboot-integration-examples/springboot-duboo/consumer/.mvn/wrapper/maven-wrapper.properties b/springboot-integration-examples/springboot-duboo/consumer/.mvn/wrapper/maven-wrapper.properties deleted file mode 100644 index cd0d451c..00000000 --- a/springboot-integration-examples/springboot-duboo/consumer/.mvn/wrapper/maven-wrapper.properties +++ /dev/null @@ -1 +0,0 @@ -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip diff --git a/springboot-integration-examples/springboot-duboo/consumer/mvnw b/springboot-integration-examples/springboot-duboo/consumer/mvnw deleted file mode 100644 index 8b9da3b8..00000000 --- a/springboot-integration-examples/springboot-duboo/consumer/mvnw +++ /dev/null @@ -1,286 +0,0 @@ -#!/bin/sh -# ---------------------------------------------------------------------------- -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# ---------------------------------------------------------------------------- - -# ---------------------------------------------------------------------------- -# Maven2 Start Up Batch script -# -# Required ENV vars: -# ------------------ -# JAVA_HOME - location of a JDK home dir -# -# Optional ENV vars -# ----------------- -# M2_HOME - location of maven2's installed home dir -# MAVEN_OPTS - parameters passed to the Java VM when running Maven -# e.g. to debug Maven itself, use -# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -# MAVEN_SKIP_RC - flag to disable loading of mavenrc files -# ---------------------------------------------------------------------------- - -if [ -z "$MAVEN_SKIP_RC" ] ; then - - if [ -f /etc/mavenrc ] ; then - . /etc/mavenrc - fi - - if [ -f "$HOME/.mavenrc" ] ; then - . "$HOME/.mavenrc" - fi - -fi - -# OS specific support. $var _must_ be set to either true or false. -cygwin=false; -darwin=false; -mingw=false -case "`uname`" in - CYGWIN*) cygwin=true ;; - MINGW*) mingw=true;; - Darwin*) darwin=true - # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home - # See https://developer.apple.com/library/mac/qa/qa1170/_index.html - if [ -z "$JAVA_HOME" ]; then - if [ -x "/usr/libexec/java_home" ]; then - export JAVA_HOME="`/usr/libexec/java_home`" - else - export JAVA_HOME="/Library/Java/Home" - fi - fi - ;; -esac - -if [ -z "$JAVA_HOME" ] ; then - if [ -r /etc/gentoo-release ] ; then - JAVA_HOME=`java-config --jre-home` - fi -fi - -if [ -z "$M2_HOME" ] ; then - ## resolve links - $0 may be a link to maven's home - PRG="$0" - - # need this for relative symlinks - while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG="`dirname "$PRG"`/$link" - fi - done - - saveddir=`pwd` - - M2_HOME=`dirname "$PRG"`/.. - - # make it fully qualified - M2_HOME=`cd "$M2_HOME" && pwd` - - cd "$saveddir" - # echo Using m2 at $M2_HOME -fi - -# For Cygwin, ensure paths are in UNIX format before anything is touched -if $cygwin ; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --unix "$M2_HOME"` - [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --unix "$JAVA_HOME"` - [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --unix "$CLASSPATH"` -fi - -# For Mingw, ensure paths are in UNIX format before anything is touched -if $mingw ; then - [ -n "$M2_HOME" ] && - M2_HOME="`(cd "$M2_HOME"; pwd)`" - [ -n "$JAVA_HOME" ] && - JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" - # TODO classpath? -fi - -if [ -z "$JAVA_HOME" ]; then - javaExecutable="`which javac`" - if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then - # readlink(1) is not available as standard on Solaris 10. - readLink=`which readlink` - if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then - if $darwin ; then - javaHome="`dirname \"$javaExecutable\"`" - javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" - else - javaExecutable="`readlink -f \"$javaExecutable\"`" - fi - javaHome="`dirname \"$javaExecutable\"`" - javaHome=`expr "$javaHome" : '\(.*\)/bin'` - JAVA_HOME="$javaHome" - export JAVA_HOME - fi - fi -fi - -if [ -z "$JAVACMD" ] ; then - if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - else - JAVACMD="`which java`" - fi -fi - -if [ ! -x "$JAVACMD" ] ; then - echo "Error: JAVA_HOME is not defined correctly." >&2 - echo " We cannot execute $JAVACMD" >&2 - exit 1 -fi - -if [ -z "$JAVA_HOME" ] ; then - echo "Warning: JAVA_HOME environment variable is not set." -fi - -CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher - -# traverses directory structure from process work directory to filesystem root -# first directory with .mvn subdirectory is considered project base directory -find_maven_basedir() { - - if [ -z "$1" ] - then - echo "Path not specified to find_maven_basedir" - return 1 - fi - - basedir="$1" - wdir="$1" - while [ "$wdir" != '/' ] ; do - if [ -d "$wdir"/.mvn ] ; then - basedir=$wdir - break - fi - # workaround for JBEAP-8937 (on Solaris 10/Sparc) - if [ -d "${wdir}" ]; then - wdir=`cd "$wdir/.."; pwd` - fi - # end of workaround - done - echo "${basedir}" -} - -# concatenates all lines of a file -concat_lines() { - if [ -f "$1" ]; then - echo "$(tr -s '\n' ' ' < "$1")" - fi -} - -BASE_DIR=`find_maven_basedir "$(pwd)"` -if [ -z "$BASE_DIR" ]; then - exit 1; -fi - -########################################################################################## -# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -# This allows using the maven wrapper in projects that prohibit checking in binary data. -########################################################################################## -if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found .mvn/wrapper/maven-wrapper.jar" - fi -else - if [ "$MVNW_VERBOSE" = true ]; then - echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." - fi - jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar" - while IFS="=" read key value; do - case "$key" in (wrapperUrl) jarUrl="$value"; break ;; - esac - done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" - if [ "$MVNW_VERBOSE" = true ]; then - echo "Downloading from: $jarUrl" - fi - wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" - - if command -v wget > /dev/null; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found wget ... using wget" - fi - wget "$jarUrl" -O "$wrapperJarPath" - elif command -v curl > /dev/null; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found curl ... using curl" - fi - curl -o "$wrapperJarPath" "$jarUrl" - else - if [ "$MVNW_VERBOSE" = true ]; then - echo "Falling back to using Java to download" - fi - javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" - if [ -e "$javaClass" ]; then - if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then - if [ "$MVNW_VERBOSE" = true ]; then - echo " - Compiling MavenWrapperDownloader.java ..." - fi - # Compiling the Java class - ("$JAVA_HOME/bin/javac" "$javaClass") - fi - if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then - # Running the downloader - if [ "$MVNW_VERBOSE" = true ]; then - echo " - Running MavenWrapperDownloader.java ..." - fi - ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") - fi - fi - fi -fi -########################################################################################## -# End of extension -########################################################################################## - -export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} -if [ "$MVNW_VERBOSE" = true ]; then - echo $MAVEN_PROJECTBASEDIR -fi -MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" - -# For Cygwin, switch paths to Windows format before running java -if $cygwin; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --path --windows "$M2_HOME"` - [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` - [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --windows "$CLASSPATH"` - [ -n "$MAVEN_PROJECTBASEDIR" ] && - MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` -fi - -WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -exec "$JAVACMD" \ - $MAVEN_OPTS \ - -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ - "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ - ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/springboot-integration-examples/springboot-duboo/consumer/mvnw.cmd b/springboot-integration-examples/springboot-duboo/consumer/mvnw.cmd deleted file mode 100644 index fef5a8f7..00000000 --- a/springboot-integration-examples/springboot-duboo/consumer/mvnw.cmd +++ /dev/null @@ -1,161 +0,0 @@ -@REM ---------------------------------------------------------------------------- -@REM Licensed to the Apache Software Foundation (ASF) under one -@REM or more contributor license agreements. See the NOTICE file -@REM distributed with this work for additional information -@REM regarding copyright ownership. The ASF licenses this file -@REM to you under the Apache License, Version 2.0 (the -@REM "License"); you may not use this file except in compliance -@REM with the License. You may obtain a copy of the License at -@REM -@REM https://www.apache.org/licenses/LICENSE-2.0 -@REM -@REM Unless required by applicable law or agreed to in writing, -@REM software distributed under the License is distributed on an -@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -@REM KIND, either express or implied. See the License for the -@REM specific language governing permissions and limitations -@REM under the License. -@REM ---------------------------------------------------------------------------- - -@REM ---------------------------------------------------------------------------- -@REM Maven2 Start Up Batch script -@REM -@REM Required ENV vars: -@REM JAVA_HOME - location of a JDK home dir -@REM -@REM Optional ENV vars -@REM M2_HOME - location of maven2's installed home dir -@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands -@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending -@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven -@REM e.g. to debug Maven itself, use -@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files -@REM ---------------------------------------------------------------------------- - -@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' -@echo off -@REM set title of command window -title %0 -@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' -@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% - -@REM set %HOME% to equivalent of $HOME -if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") - -@REM Execute a user defined script before this one -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre -@REM check for pre script, once with legacy .bat ending and once with .cmd ending -if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" -if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" -:skipRcPre - -@setlocal - -set ERROR_CODE=0 - -@REM To isolate internal variables from possible post scripts, we use another setlocal -@setlocal - -@REM ==== START VALIDATION ==== -if not "%JAVA_HOME%" == "" goto OkJHome - -echo. -echo Error: JAVA_HOME not found in your environment. >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -:OkJHome -if exist "%JAVA_HOME%\bin\java.exe" goto init - -echo. -echo Error: JAVA_HOME is set to an invalid directory. >&2 -echo JAVA_HOME = "%JAVA_HOME%" >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -@REM ==== END VALIDATION ==== - -:init - -@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". -@REM Fallback to current working directory if not found. - -set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% -IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir - -set EXEC_DIR=%CD% -set WDIR=%EXEC_DIR% -:findBaseDir -IF EXIST "%WDIR%"\.mvn goto baseDirFound -cd .. -IF "%WDIR%"=="%CD%" goto baseDirNotFound -set WDIR=%CD% -goto findBaseDir - -:baseDirFound -set MAVEN_PROJECTBASEDIR=%WDIR% -cd "%EXEC_DIR%" -goto endDetectBaseDir - -:baseDirNotFound -set MAVEN_PROJECTBASEDIR=%EXEC_DIR% -cd "%EXEC_DIR%" - -:endDetectBaseDir - -IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig - -@setlocal EnableExtensions EnableDelayedExpansion -for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a -@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% - -:endReadAdditionalConfig - -SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" -set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" -set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar" -FOR /F "tokens=1,2 delims==" %%A IN (%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties) DO ( - IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B -) - -@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -@REM This allows using the maven wrapper in projects that prohibit checking in binary data. -if exist %WRAPPER_JAR% ( - echo Found %WRAPPER_JAR% -) else ( - echo Couldn't find %WRAPPER_JAR%, downloading it ... - echo Downloading from: %DOWNLOAD_URL% - powershell -Command "(New-Object Net.WebClient).DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')" - echo Finished downloading %WRAPPER_JAR% -) -@REM End of extension - -%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* -if ERRORLEVEL 1 goto error -goto end - -:error -set ERROR_CODE=1 - -:end -@endlocal & set ERROR_CODE=%ERROR_CODE% - -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost -@REM check for post script, once with legacy .bat ending and once with .cmd ending -if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" -if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" -:skipRcPost - -@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' -if "%MAVEN_BATCH_PAUSE%" == "on" pause - -if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% - -exit /B %ERROR_CODE% diff --git a/springboot-integration-examples/springboot-duboo/consumer/pom.xml b/springboot-integration-examples/springboot-duboo/consumer/pom.xml deleted file mode 100644 index a9175cea..00000000 --- a/springboot-integration-examples/springboot-duboo/consumer/pom.xml +++ /dev/null @@ -1,61 +0,0 @@ - - - 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 2.1.7.RELEASE - - - cn.lastwhisper.springboot.dubbo - consumer - 0.0.1-SNAPSHOT - consumer - Demo project for Spring Boot - - - 1.8 - - - - - org.springframework.boot - spring-boot-starter - - - - org.springframework.boot - spring-boot-starter-test - test - - - com.alibaba.spring.boot - dubbo-spring-boot-starter - 2.0.0 - - - - cn.lastwhisper.springboot.dubbo - dubbo-api - 0.0.1-SNAPSHOT - - - - com.101tec - zkclient - 0.10 - - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - - diff --git a/springboot-integration-examples/springboot-duboo/consumer/src/main/java/cn/lastwhisper/springboot/dubbo/consumer/ConsumerApplication.java b/springboot-integration-examples/springboot-duboo/consumer/src/main/java/cn/lastwhisper/springboot/dubbo/consumer/ConsumerApplication.java deleted file mode 100644 index 3ad18963..00000000 --- a/springboot-integration-examples/springboot-duboo/consumer/src/main/java/cn/lastwhisper/springboot/dubbo/consumer/ConsumerApplication.java +++ /dev/null @@ -1,21 +0,0 @@ -package cn.lastwhisper.springboot.dubbo.consumer; - -import cn.lastwhisper.springboot.dubbo.consumer.quickstart.QuickstartConsumer; -import com.alibaba.dubbo.spring.boot.annotation.EnableDubboConfiguration; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.context.ConfigurableApplicationContext; - -@SpringBootApplication -@EnableDubboConfiguration -public class ConsumerApplication { - - public static void main(String[] args) { - ConfigurableApplicationContext context = SpringApplication.run(ConsumerApplication.class, args); - QuickstartConsumer quickstartConsumer = (QuickstartConsumer) context.getBean("quickstartConsumer"); - - quickstartConsumer.sendMessage("你好"); - - } - -} diff --git a/springboot-integration-examples/springboot-duboo/consumer/src/main/java/cn/lastwhisper/springboot/dubbo/consumer/quickstart/QuickstartConsumer.java b/springboot-integration-examples/springboot-duboo/consumer/src/main/java/cn/lastwhisper/springboot/dubbo/consumer/quickstart/QuickstartConsumer.java deleted file mode 100644 index cb6e6110..00000000 --- a/springboot-integration-examples/springboot-duboo/consumer/src/main/java/cn/lastwhisper/springboot/dubbo/consumer/quickstart/QuickstartConsumer.java +++ /dev/null @@ -1,19 +0,0 @@ -package cn.lastwhisper.springboot.dubbo.consumer.quickstart; - -import cn.lastwhisper.springboot.dubbo.ServiceAPI; -import com.alibaba.dubbo.config.annotation.Reference; -import org.springframework.stereotype.Component; - -/** - * @author lastwhisper - */ -@Component -public class QuickstartConsumer { - //@Reference(url ="dubbo://localhost:20880") - @Reference(interfaceClass = ServiceAPI.class) - ServiceAPI serviceAPI; - - public void sendMessage(String message) { - System.out.println(serviceAPI.sendMessage(message)); - } -} diff --git a/springboot-integration-examples/springboot-duboo/consumer/src/main/resources/application.properties b/springboot-integration-examples/springboot-duboo/consumer/src/main/resources/application.properties deleted file mode 100644 index 6f0465df..00000000 --- a/springboot-integration-examples/springboot-duboo/consumer/src/main/resources/application.properties +++ /dev/null @@ -1,2 +0,0 @@ -spring.application.name=dubbo-spring-boot-starter -spring.dubbo.registry=zookeeper://localhost:2181 \ No newline at end of file diff --git a/springboot-integration-examples/springboot-duboo/consumer/src/test/java/cn/lastwhisper/springboot/dubbo/consumer/ConsumerApplicationTests.java b/springboot-integration-examples/springboot-duboo/consumer/src/test/java/cn/lastwhisper/springboot/dubbo/consumer/ConsumerApplicationTests.java deleted file mode 100644 index 7c1d8b40..00000000 --- a/springboot-integration-examples/springboot-duboo/consumer/src/test/java/cn/lastwhisper/springboot/dubbo/consumer/ConsumerApplicationTests.java +++ /dev/null @@ -1,16 +0,0 @@ -package cn.lastwhisper.springboot.dubbo.consumer; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit4.SpringRunner; - -@RunWith(SpringRunner.class) -@SpringBootTest -public class ConsumerApplicationTests { - - @Test - public void contextLoads() { - } - -} diff --git a/springboot-integration-examples/springboot-duboo/dubbo-api/pom.xml b/springboot-integration-examples/springboot-duboo/dubbo-api/pom.xml deleted file mode 100644 index 911d7ddf..00000000 --- a/springboot-integration-examples/springboot-duboo/dubbo-api/pom.xml +++ /dev/null @@ -1,79 +0,0 @@ - - - - - springboot-duboo - cn.lastwhisper.springboot.dubbo - 0.0.1-SNAPSHOT - - 4.0.0 - - cn.lastwhisper.springboot.dubbo - dubbo-api - - dubbo-api - - http://www.example.com - - - UTF-8 - 1.7 - 1.7 - - - - - junit - junit - 4.11 - test - - - - - - - - - maven-clean-plugin - 3.1.0 - - - - maven-resources-plugin - 3.0.2 - - - maven-compiler-plugin - 3.8.0 - - - maven-surefire-plugin - 2.22.1 - - - maven-jar-plugin - 3.0.2 - - - maven-install-plugin - 2.5.2 - - - maven-deploy-plugin - 2.8.2 - - - - maven-site-plugin - 3.7.1 - - - maven-project-info-reports-plugin - 3.0.0 - - - - - diff --git a/springboot-integration-examples/springboot-duboo/dubbo-api/src/main/java/cn/lastwhisper/springboot/dubbo/ServiceAPI.java b/springboot-integration-examples/springboot-duboo/dubbo-api/src/main/java/cn/lastwhisper/springboot/dubbo/ServiceAPI.java deleted file mode 100644 index 8231e710..00000000 --- a/springboot-integration-examples/springboot-duboo/dubbo-api/src/main/java/cn/lastwhisper/springboot/dubbo/ServiceAPI.java +++ /dev/null @@ -1,5 +0,0 @@ -package cn.lastwhisper.springboot.dubbo; - -public interface ServiceAPI { - String sendMessage(String message); -} diff --git a/springboot-integration-examples/springboot-duboo/dubbo-api/src/test/java/cn/lastwhisper/springboot/dubbo/AppTest.java b/springboot-integration-examples/springboot-duboo/dubbo-api/src/test/java/cn/lastwhisper/springboot/dubbo/AppTest.java deleted file mode 100644 index 6aaab91b..00000000 --- a/springboot-integration-examples/springboot-duboo/dubbo-api/src/test/java/cn/lastwhisper/springboot/dubbo/AppTest.java +++ /dev/null @@ -1,20 +0,0 @@ -package cn.lastwhisper.springboot.dubbo; - -import static org.junit.Assert.assertTrue; - -import org.junit.Test; - -/** - * Unit test for simple App. - */ -public class AppTest -{ - /** - * Rigorous Test :-) - */ - @Test - public void shouldAnswerWithTrue() - { - assertTrue( true ); - } -} diff --git a/springboot-integration-examples/springboot-duboo/mvnw b/springboot-integration-examples/springboot-duboo/mvnw deleted file mode 100644 index 8b9da3b8..00000000 --- a/springboot-integration-examples/springboot-duboo/mvnw +++ /dev/null @@ -1,286 +0,0 @@ -#!/bin/sh -# ---------------------------------------------------------------------------- -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# ---------------------------------------------------------------------------- - -# ---------------------------------------------------------------------------- -# Maven2 Start Up Batch script -# -# Required ENV vars: -# ------------------ -# JAVA_HOME - location of a JDK home dir -# -# Optional ENV vars -# ----------------- -# M2_HOME - location of maven2's installed home dir -# MAVEN_OPTS - parameters passed to the Java VM when running Maven -# e.g. to debug Maven itself, use -# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -# MAVEN_SKIP_RC - flag to disable loading of mavenrc files -# ---------------------------------------------------------------------------- - -if [ -z "$MAVEN_SKIP_RC" ] ; then - - if [ -f /etc/mavenrc ] ; then - . /etc/mavenrc - fi - - if [ -f "$HOME/.mavenrc" ] ; then - . "$HOME/.mavenrc" - fi - -fi - -# OS specific support. $var _must_ be set to either true or false. -cygwin=false; -darwin=false; -mingw=false -case "`uname`" in - CYGWIN*) cygwin=true ;; - MINGW*) mingw=true;; - Darwin*) darwin=true - # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home - # See https://developer.apple.com/library/mac/qa/qa1170/_index.html - if [ -z "$JAVA_HOME" ]; then - if [ -x "/usr/libexec/java_home" ]; then - export JAVA_HOME="`/usr/libexec/java_home`" - else - export JAVA_HOME="/Library/Java/Home" - fi - fi - ;; -esac - -if [ -z "$JAVA_HOME" ] ; then - if [ -r /etc/gentoo-release ] ; then - JAVA_HOME=`java-config --jre-home` - fi -fi - -if [ -z "$M2_HOME" ] ; then - ## resolve links - $0 may be a link to maven's home - PRG="$0" - - # need this for relative symlinks - while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG="`dirname "$PRG"`/$link" - fi - done - - saveddir=`pwd` - - M2_HOME=`dirname "$PRG"`/.. - - # make it fully qualified - M2_HOME=`cd "$M2_HOME" && pwd` - - cd "$saveddir" - # echo Using m2 at $M2_HOME -fi - -# For Cygwin, ensure paths are in UNIX format before anything is touched -if $cygwin ; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --unix "$M2_HOME"` - [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --unix "$JAVA_HOME"` - [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --unix "$CLASSPATH"` -fi - -# For Mingw, ensure paths are in UNIX format before anything is touched -if $mingw ; then - [ -n "$M2_HOME" ] && - M2_HOME="`(cd "$M2_HOME"; pwd)`" - [ -n "$JAVA_HOME" ] && - JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" - # TODO classpath? -fi - -if [ -z "$JAVA_HOME" ]; then - javaExecutable="`which javac`" - if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then - # readlink(1) is not available as standard on Solaris 10. - readLink=`which readlink` - if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then - if $darwin ; then - javaHome="`dirname \"$javaExecutable\"`" - javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" - else - javaExecutable="`readlink -f \"$javaExecutable\"`" - fi - javaHome="`dirname \"$javaExecutable\"`" - javaHome=`expr "$javaHome" : '\(.*\)/bin'` - JAVA_HOME="$javaHome" - export JAVA_HOME - fi - fi -fi - -if [ -z "$JAVACMD" ] ; then - if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - else - JAVACMD="`which java`" - fi -fi - -if [ ! -x "$JAVACMD" ] ; then - echo "Error: JAVA_HOME is not defined correctly." >&2 - echo " We cannot execute $JAVACMD" >&2 - exit 1 -fi - -if [ -z "$JAVA_HOME" ] ; then - echo "Warning: JAVA_HOME environment variable is not set." -fi - -CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher - -# traverses directory structure from process work directory to filesystem root -# first directory with .mvn subdirectory is considered project base directory -find_maven_basedir() { - - if [ -z "$1" ] - then - echo "Path not specified to find_maven_basedir" - return 1 - fi - - basedir="$1" - wdir="$1" - while [ "$wdir" != '/' ] ; do - if [ -d "$wdir"/.mvn ] ; then - basedir=$wdir - break - fi - # workaround for JBEAP-8937 (on Solaris 10/Sparc) - if [ -d "${wdir}" ]; then - wdir=`cd "$wdir/.."; pwd` - fi - # end of workaround - done - echo "${basedir}" -} - -# concatenates all lines of a file -concat_lines() { - if [ -f "$1" ]; then - echo "$(tr -s '\n' ' ' < "$1")" - fi -} - -BASE_DIR=`find_maven_basedir "$(pwd)"` -if [ -z "$BASE_DIR" ]; then - exit 1; -fi - -########################################################################################## -# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -# This allows using the maven wrapper in projects that prohibit checking in binary data. -########################################################################################## -if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found .mvn/wrapper/maven-wrapper.jar" - fi -else - if [ "$MVNW_VERBOSE" = true ]; then - echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." - fi - jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar" - while IFS="=" read key value; do - case "$key" in (wrapperUrl) jarUrl="$value"; break ;; - esac - done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" - if [ "$MVNW_VERBOSE" = true ]; then - echo "Downloading from: $jarUrl" - fi - wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" - - if command -v wget > /dev/null; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found wget ... using wget" - fi - wget "$jarUrl" -O "$wrapperJarPath" - elif command -v curl > /dev/null; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found curl ... using curl" - fi - curl -o "$wrapperJarPath" "$jarUrl" - else - if [ "$MVNW_VERBOSE" = true ]; then - echo "Falling back to using Java to download" - fi - javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" - if [ -e "$javaClass" ]; then - if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then - if [ "$MVNW_VERBOSE" = true ]; then - echo " - Compiling MavenWrapperDownloader.java ..." - fi - # Compiling the Java class - ("$JAVA_HOME/bin/javac" "$javaClass") - fi - if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then - # Running the downloader - if [ "$MVNW_VERBOSE" = true ]; then - echo " - Running MavenWrapperDownloader.java ..." - fi - ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") - fi - fi - fi -fi -########################################################################################## -# End of extension -########################################################################################## - -export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} -if [ "$MVNW_VERBOSE" = true ]; then - echo $MAVEN_PROJECTBASEDIR -fi -MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" - -# For Cygwin, switch paths to Windows format before running java -if $cygwin; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --path --windows "$M2_HOME"` - [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` - [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --windows "$CLASSPATH"` - [ -n "$MAVEN_PROJECTBASEDIR" ] && - MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` -fi - -WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -exec "$JAVACMD" \ - $MAVEN_OPTS \ - -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ - "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ - ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/springboot-integration-examples/springboot-duboo/mvnw.cmd b/springboot-integration-examples/springboot-duboo/mvnw.cmd deleted file mode 100644 index fef5a8f7..00000000 --- a/springboot-integration-examples/springboot-duboo/mvnw.cmd +++ /dev/null @@ -1,161 +0,0 @@ -@REM ---------------------------------------------------------------------------- -@REM Licensed to the Apache Software Foundation (ASF) under one -@REM or more contributor license agreements. See the NOTICE file -@REM distributed with this work for additional information -@REM regarding copyright ownership. The ASF licenses this file -@REM to you under the Apache License, Version 2.0 (the -@REM "License"); you may not use this file except in compliance -@REM with the License. You may obtain a copy of the License at -@REM -@REM https://www.apache.org/licenses/LICENSE-2.0 -@REM -@REM Unless required by applicable law or agreed to in writing, -@REM software distributed under the License is distributed on an -@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -@REM KIND, either express or implied. See the License for the -@REM specific language governing permissions and limitations -@REM under the License. -@REM ---------------------------------------------------------------------------- - -@REM ---------------------------------------------------------------------------- -@REM Maven2 Start Up Batch script -@REM -@REM Required ENV vars: -@REM JAVA_HOME - location of a JDK home dir -@REM -@REM Optional ENV vars -@REM M2_HOME - location of maven2's installed home dir -@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands -@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending -@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven -@REM e.g. to debug Maven itself, use -@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files -@REM ---------------------------------------------------------------------------- - -@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' -@echo off -@REM set title of command window -title %0 -@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' -@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% - -@REM set %HOME% to equivalent of $HOME -if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") - -@REM Execute a user defined script before this one -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre -@REM check for pre script, once with legacy .bat ending and once with .cmd ending -if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" -if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" -:skipRcPre - -@setlocal - -set ERROR_CODE=0 - -@REM To isolate internal variables from possible post scripts, we use another setlocal -@setlocal - -@REM ==== START VALIDATION ==== -if not "%JAVA_HOME%" == "" goto OkJHome - -echo. -echo Error: JAVA_HOME not found in your environment. >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -:OkJHome -if exist "%JAVA_HOME%\bin\java.exe" goto init - -echo. -echo Error: JAVA_HOME is set to an invalid directory. >&2 -echo JAVA_HOME = "%JAVA_HOME%" >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -@REM ==== END VALIDATION ==== - -:init - -@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". -@REM Fallback to current working directory if not found. - -set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% -IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir - -set EXEC_DIR=%CD% -set WDIR=%EXEC_DIR% -:findBaseDir -IF EXIST "%WDIR%"\.mvn goto baseDirFound -cd .. -IF "%WDIR%"=="%CD%" goto baseDirNotFound -set WDIR=%CD% -goto findBaseDir - -:baseDirFound -set MAVEN_PROJECTBASEDIR=%WDIR% -cd "%EXEC_DIR%" -goto endDetectBaseDir - -:baseDirNotFound -set MAVEN_PROJECTBASEDIR=%EXEC_DIR% -cd "%EXEC_DIR%" - -:endDetectBaseDir - -IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig - -@setlocal EnableExtensions EnableDelayedExpansion -for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a -@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% - -:endReadAdditionalConfig - -SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" -set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" -set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar" -FOR /F "tokens=1,2 delims==" %%A IN (%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties) DO ( - IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B -) - -@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -@REM This allows using the maven wrapper in projects that prohibit checking in binary data. -if exist %WRAPPER_JAR% ( - echo Found %WRAPPER_JAR% -) else ( - echo Couldn't find %WRAPPER_JAR%, downloading it ... - echo Downloading from: %DOWNLOAD_URL% - powershell -Command "(New-Object Net.WebClient).DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')" - echo Finished downloading %WRAPPER_JAR% -) -@REM End of extension - -%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* -if ERRORLEVEL 1 goto error -goto end - -:error -set ERROR_CODE=1 - -:end -@endlocal & set ERROR_CODE=%ERROR_CODE% - -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost -@REM check for post script, once with legacy .bat ending and once with .cmd ending -if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" -if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" -:skipRcPost - -@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' -if "%MAVEN_BATCH_PAUSE%" == "on" pause - -if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% - -exit /B %ERROR_CODE% diff --git a/springboot-integration-examples/springboot-duboo/pom.xml b/springboot-integration-examples/springboot-duboo/pom.xml deleted file mode 100644 index 6de1e68c..00000000 --- a/springboot-integration-examples/springboot-duboo/pom.xml +++ /dev/null @@ -1,47 +0,0 @@ - - - 4.0.0 - pom - - dubbo-api - - - org.springframework.boot - spring-boot-starter-parent - 2.1.7.RELEASE - - - cn.lastwhisper.springboot.dubbo - springboot-duboo - 0.0.1-SNAPSHOT - springboot-duboo - Demo project for Spring Boot - - - 1.8 - - - - - org.springframework.boot - spring-boot-starter - - - - org.springframework.boot - spring-boot-starter-test - test - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - - diff --git a/springboot-integration-examples/springboot-duboo/provider/.gitignore b/springboot-integration-examples/springboot-duboo/provider/.gitignore deleted file mode 100644 index a2a3040a..00000000 --- a/springboot-integration-examples/springboot-duboo/provider/.gitignore +++ /dev/null @@ -1,31 +0,0 @@ -HELP.md -target/ -!.mvn/wrapper/maven-wrapper.jar -!**/src/main/** -!**/src/test/** - -### STS ### -.apt_generated -.classpath -.factorypath -.project -.settings -.springBeans -.sts4-cache - -### IntelliJ IDEA ### -.idea -*.iws -*.iml -*.ipr - -### NetBeans ### -/nbproject/private/ -/nbbuild/ -/dist/ -/nbdist/ -/.nb-gradle/ -build/ - -### VS Code ### -.vscode/ diff --git a/springboot-integration-examples/springboot-duboo/provider/.mvn/wrapper/MavenWrapperDownloader.java b/springboot-integration-examples/springboot-duboo/provider/.mvn/wrapper/MavenWrapperDownloader.java deleted file mode 100644 index 7f91a56e..00000000 --- a/springboot-integration-examples/springboot-duboo/provider/.mvn/wrapper/MavenWrapperDownloader.java +++ /dev/null @@ -1,114 +0,0 @@ -/* -Licensed to the Apache Software Foundation (ASF) under one -or more contributor license agreements. See the NOTICE file -distributed with this work for additional information -regarding copyright ownership. The ASF licenses this file -to you under the Apache License, Version 2.0 (the -"License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, -software distributed under the License is distributed on an -"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -KIND, either express or implied. See the License for the -specific language governing permissions and limitations -under the License. -*/ - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.net.URL; -import java.nio.channels.Channels; -import java.nio.channels.ReadableByteChannel; -import java.util.Properties; - -public class MavenWrapperDownloader { - - /** - * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. - */ - private static final String DEFAULT_DOWNLOAD_URL = - "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"; - - /** - * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to - * use instead of the default one. - */ - private static final String MAVEN_WRAPPER_PROPERTIES_PATH = - ".mvn/wrapper/maven-wrapper.properties"; - - /** - * Path where the maven-wrapper.jar will be saved to. - */ - private static final String MAVEN_WRAPPER_JAR_PATH = - ".mvn/wrapper/maven-wrapper.jar"; - - /** - * Name of the property which should be used to override the default download url for the wrapper. - */ - private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; - - public static void main(String args[]) { - System.out.println("- Downloader started"); - File baseDirectory = new File(args[0]); - System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); - - // If the maven-wrapper.properties exists, read it and check if it contains a custom - // wrapperUrl parameter. - File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); - String url = DEFAULT_DOWNLOAD_URL; - if (mavenWrapperPropertyFile.exists()) { - FileInputStream mavenWrapperPropertyFileInputStream = null; - try { - mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); - Properties mavenWrapperProperties = new Properties(); - mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); - url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); - } catch (IOException e) { - System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); - } finally { - try { - if (mavenWrapperPropertyFileInputStream != null) { - mavenWrapperPropertyFileInputStream.close(); - } - } catch (IOException e) { - // Ignore ... - } - } - } - System.out.println("- Downloading from: : " + url); - - File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); - if (!outputFile.getParentFile().exists()) { - if (!outputFile.getParentFile().mkdirs()) { - System.out.println( - "- ERROR creating output direcrory '" + outputFile.getParentFile().getAbsolutePath() + "'"); - } - } - System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); - try { - downloadFileFromURL(url, outputFile); - System.out.println("Done"); - System.exit(0); - } catch (Throwable e) { - System.out.println("- Error downloading"); - e.printStackTrace(); - System.exit(1); - } - } - - private static void downloadFileFromURL(String urlString, File destination) throws Exception { - URL website = new URL(urlString); - ReadableByteChannel rbc; - rbc = Channels.newChannel(website.openStream()); - FileOutputStream fos = new FileOutputStream(destination); - fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); - fos.close(); - rbc.close(); - } - -} diff --git a/springboot-integration-examples/springboot-duboo/provider/.mvn/wrapper/maven-wrapper.jar b/springboot-integration-examples/springboot-duboo/provider/.mvn/wrapper/maven-wrapper.jar deleted file mode 100644 index 01e67997..00000000 Binary files a/springboot-integration-examples/springboot-duboo/provider/.mvn/wrapper/maven-wrapper.jar and /dev/null differ diff --git a/springboot-integration-examples/springboot-duboo/provider/.mvn/wrapper/maven-wrapper.properties b/springboot-integration-examples/springboot-duboo/provider/.mvn/wrapper/maven-wrapper.properties deleted file mode 100644 index cd0d451c..00000000 --- a/springboot-integration-examples/springboot-duboo/provider/.mvn/wrapper/maven-wrapper.properties +++ /dev/null @@ -1 +0,0 @@ -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip diff --git a/springboot-integration-examples/springboot-duboo/provider/mvnw b/springboot-integration-examples/springboot-duboo/provider/mvnw deleted file mode 100644 index 8b9da3b8..00000000 --- a/springboot-integration-examples/springboot-duboo/provider/mvnw +++ /dev/null @@ -1,286 +0,0 @@ -#!/bin/sh -# ---------------------------------------------------------------------------- -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# ---------------------------------------------------------------------------- - -# ---------------------------------------------------------------------------- -# Maven2 Start Up Batch script -# -# Required ENV vars: -# ------------------ -# JAVA_HOME - location of a JDK home dir -# -# Optional ENV vars -# ----------------- -# M2_HOME - location of maven2's installed home dir -# MAVEN_OPTS - parameters passed to the Java VM when running Maven -# e.g. to debug Maven itself, use -# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -# MAVEN_SKIP_RC - flag to disable loading of mavenrc files -# ---------------------------------------------------------------------------- - -if [ -z "$MAVEN_SKIP_RC" ] ; then - - if [ -f /etc/mavenrc ] ; then - . /etc/mavenrc - fi - - if [ -f "$HOME/.mavenrc" ] ; then - . "$HOME/.mavenrc" - fi - -fi - -# OS specific support. $var _must_ be set to either true or false. -cygwin=false; -darwin=false; -mingw=false -case "`uname`" in - CYGWIN*) cygwin=true ;; - MINGW*) mingw=true;; - Darwin*) darwin=true - # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home - # See https://developer.apple.com/library/mac/qa/qa1170/_index.html - if [ -z "$JAVA_HOME" ]; then - if [ -x "/usr/libexec/java_home" ]; then - export JAVA_HOME="`/usr/libexec/java_home`" - else - export JAVA_HOME="/Library/Java/Home" - fi - fi - ;; -esac - -if [ -z "$JAVA_HOME" ] ; then - if [ -r /etc/gentoo-release ] ; then - JAVA_HOME=`java-config --jre-home` - fi -fi - -if [ -z "$M2_HOME" ] ; then - ## resolve links - $0 may be a link to maven's home - PRG="$0" - - # need this for relative symlinks - while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG="`dirname "$PRG"`/$link" - fi - done - - saveddir=`pwd` - - M2_HOME=`dirname "$PRG"`/.. - - # make it fully qualified - M2_HOME=`cd "$M2_HOME" && pwd` - - cd "$saveddir" - # echo Using m2 at $M2_HOME -fi - -# For Cygwin, ensure paths are in UNIX format before anything is touched -if $cygwin ; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --unix "$M2_HOME"` - [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --unix "$JAVA_HOME"` - [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --unix "$CLASSPATH"` -fi - -# For Mingw, ensure paths are in UNIX format before anything is touched -if $mingw ; then - [ -n "$M2_HOME" ] && - M2_HOME="`(cd "$M2_HOME"; pwd)`" - [ -n "$JAVA_HOME" ] && - JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" - # TODO classpath? -fi - -if [ -z "$JAVA_HOME" ]; then - javaExecutable="`which javac`" - if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then - # readlink(1) is not available as standard on Solaris 10. - readLink=`which readlink` - if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then - if $darwin ; then - javaHome="`dirname \"$javaExecutable\"`" - javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" - else - javaExecutable="`readlink -f \"$javaExecutable\"`" - fi - javaHome="`dirname \"$javaExecutable\"`" - javaHome=`expr "$javaHome" : '\(.*\)/bin'` - JAVA_HOME="$javaHome" - export JAVA_HOME - fi - fi -fi - -if [ -z "$JAVACMD" ] ; then - if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - else - JAVACMD="`which java`" - fi -fi - -if [ ! -x "$JAVACMD" ] ; then - echo "Error: JAVA_HOME is not defined correctly." >&2 - echo " We cannot execute $JAVACMD" >&2 - exit 1 -fi - -if [ -z "$JAVA_HOME" ] ; then - echo "Warning: JAVA_HOME environment variable is not set." -fi - -CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher - -# traverses directory structure from process work directory to filesystem root -# first directory with .mvn subdirectory is considered project base directory -find_maven_basedir() { - - if [ -z "$1" ] - then - echo "Path not specified to find_maven_basedir" - return 1 - fi - - basedir="$1" - wdir="$1" - while [ "$wdir" != '/' ] ; do - if [ -d "$wdir"/.mvn ] ; then - basedir=$wdir - break - fi - # workaround for JBEAP-8937 (on Solaris 10/Sparc) - if [ -d "${wdir}" ]; then - wdir=`cd "$wdir/.."; pwd` - fi - # end of workaround - done - echo "${basedir}" -} - -# concatenates all lines of a file -concat_lines() { - if [ -f "$1" ]; then - echo "$(tr -s '\n' ' ' < "$1")" - fi -} - -BASE_DIR=`find_maven_basedir "$(pwd)"` -if [ -z "$BASE_DIR" ]; then - exit 1; -fi - -########################################################################################## -# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -# This allows using the maven wrapper in projects that prohibit checking in binary data. -########################################################################################## -if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found .mvn/wrapper/maven-wrapper.jar" - fi -else - if [ "$MVNW_VERBOSE" = true ]; then - echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." - fi - jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar" - while IFS="=" read key value; do - case "$key" in (wrapperUrl) jarUrl="$value"; break ;; - esac - done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" - if [ "$MVNW_VERBOSE" = true ]; then - echo "Downloading from: $jarUrl" - fi - wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" - - if command -v wget > /dev/null; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found wget ... using wget" - fi - wget "$jarUrl" -O "$wrapperJarPath" - elif command -v curl > /dev/null; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found curl ... using curl" - fi - curl -o "$wrapperJarPath" "$jarUrl" - else - if [ "$MVNW_VERBOSE" = true ]; then - echo "Falling back to using Java to download" - fi - javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" - if [ -e "$javaClass" ]; then - if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then - if [ "$MVNW_VERBOSE" = true ]; then - echo " - Compiling MavenWrapperDownloader.java ..." - fi - # Compiling the Java class - ("$JAVA_HOME/bin/javac" "$javaClass") - fi - if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then - # Running the downloader - if [ "$MVNW_VERBOSE" = true ]; then - echo " - Running MavenWrapperDownloader.java ..." - fi - ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") - fi - fi - fi -fi -########################################################################################## -# End of extension -########################################################################################## - -export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} -if [ "$MVNW_VERBOSE" = true ]; then - echo $MAVEN_PROJECTBASEDIR -fi -MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" - -# For Cygwin, switch paths to Windows format before running java -if $cygwin; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --path --windows "$M2_HOME"` - [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` - [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --windows "$CLASSPATH"` - [ -n "$MAVEN_PROJECTBASEDIR" ] && - MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` -fi - -WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -exec "$JAVACMD" \ - $MAVEN_OPTS \ - -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ - "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ - ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/springboot-integration-examples/springboot-duboo/provider/mvnw.cmd b/springboot-integration-examples/springboot-duboo/provider/mvnw.cmd deleted file mode 100644 index fef5a8f7..00000000 --- a/springboot-integration-examples/springboot-duboo/provider/mvnw.cmd +++ /dev/null @@ -1,161 +0,0 @@ -@REM ---------------------------------------------------------------------------- -@REM Licensed to the Apache Software Foundation (ASF) under one -@REM or more contributor license agreements. See the NOTICE file -@REM distributed with this work for additional information -@REM regarding copyright ownership. The ASF licenses this file -@REM to you under the Apache License, Version 2.0 (the -@REM "License"); you may not use this file except in compliance -@REM with the License. You may obtain a copy of the License at -@REM -@REM https://www.apache.org/licenses/LICENSE-2.0 -@REM -@REM Unless required by applicable law or agreed to in writing, -@REM software distributed under the License is distributed on an -@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -@REM KIND, either express or implied. See the License for the -@REM specific language governing permissions and limitations -@REM under the License. -@REM ---------------------------------------------------------------------------- - -@REM ---------------------------------------------------------------------------- -@REM Maven2 Start Up Batch script -@REM -@REM Required ENV vars: -@REM JAVA_HOME - location of a JDK home dir -@REM -@REM Optional ENV vars -@REM M2_HOME - location of maven2's installed home dir -@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands -@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending -@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven -@REM e.g. to debug Maven itself, use -@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files -@REM ---------------------------------------------------------------------------- - -@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' -@echo off -@REM set title of command window -title %0 -@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' -@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% - -@REM set %HOME% to equivalent of $HOME -if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") - -@REM Execute a user defined script before this one -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre -@REM check for pre script, once with legacy .bat ending and once with .cmd ending -if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" -if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" -:skipRcPre - -@setlocal - -set ERROR_CODE=0 - -@REM To isolate internal variables from possible post scripts, we use another setlocal -@setlocal - -@REM ==== START VALIDATION ==== -if not "%JAVA_HOME%" == "" goto OkJHome - -echo. -echo Error: JAVA_HOME not found in your environment. >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -:OkJHome -if exist "%JAVA_HOME%\bin\java.exe" goto init - -echo. -echo Error: JAVA_HOME is set to an invalid directory. >&2 -echo JAVA_HOME = "%JAVA_HOME%" >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -@REM ==== END VALIDATION ==== - -:init - -@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". -@REM Fallback to current working directory if not found. - -set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% -IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir - -set EXEC_DIR=%CD% -set WDIR=%EXEC_DIR% -:findBaseDir -IF EXIST "%WDIR%"\.mvn goto baseDirFound -cd .. -IF "%WDIR%"=="%CD%" goto baseDirNotFound -set WDIR=%CD% -goto findBaseDir - -:baseDirFound -set MAVEN_PROJECTBASEDIR=%WDIR% -cd "%EXEC_DIR%" -goto endDetectBaseDir - -:baseDirNotFound -set MAVEN_PROJECTBASEDIR=%EXEC_DIR% -cd "%EXEC_DIR%" - -:endDetectBaseDir - -IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig - -@setlocal EnableExtensions EnableDelayedExpansion -for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a -@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% - -:endReadAdditionalConfig - -SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" -set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" -set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar" -FOR /F "tokens=1,2 delims==" %%A IN (%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties) DO ( - IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B -) - -@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -@REM This allows using the maven wrapper in projects that prohibit checking in binary data. -if exist %WRAPPER_JAR% ( - echo Found %WRAPPER_JAR% -) else ( - echo Couldn't find %WRAPPER_JAR%, downloading it ... - echo Downloading from: %DOWNLOAD_URL% - powershell -Command "(New-Object Net.WebClient).DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')" - echo Finished downloading %WRAPPER_JAR% -) -@REM End of extension - -%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* -if ERRORLEVEL 1 goto error -goto end - -:error -set ERROR_CODE=1 - -:end -@endlocal & set ERROR_CODE=%ERROR_CODE% - -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost -@REM check for post script, once with legacy .bat ending and once with .cmd ending -if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" -if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" -:skipRcPost - -@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' -if "%MAVEN_BATCH_PAUSE%" == "on" pause - -if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% - -exit /B %ERROR_CODE% diff --git a/springboot-integration-examples/springboot-duboo/provider/pom.xml b/springboot-integration-examples/springboot-duboo/provider/pom.xml deleted file mode 100644 index 8f919c2a..00000000 --- a/springboot-integration-examples/springboot-duboo/provider/pom.xml +++ /dev/null @@ -1,60 +0,0 @@ - - - 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 2.1.7.RELEASE - - - cn.lastwhisper.springboot.dubbo - provider - 0.0.1-SNAPSHOT - provider - Demo project for Spring Boot - - - 1.8 - - - - - org.springframework.boot - spring-boot-starter - - - - org.springframework.boot - spring-boot-starter-test - test - - - com.alibaba.spring.boot - dubbo-spring-boot-starter - 2.0.0 - - - - cn.lastwhisper.springboot.dubbo - dubbo-api - 0.0.1-SNAPSHOT - - - - com.101tec - zkclient - 0.10 - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - - diff --git a/springboot-integration-examples/springboot-duboo/provider/src/main/java/cn/lastwhisper/springboot/dubbo/provider/ProviderApplication.java b/springboot-integration-examples/springboot-duboo/provider/src/main/java/cn/lastwhisper/springboot/dubbo/provider/ProviderApplication.java deleted file mode 100644 index 2d9530d2..00000000 --- a/springboot-integration-examples/springboot-duboo/provider/src/main/java/cn/lastwhisper/springboot/dubbo/provider/ProviderApplication.java +++ /dev/null @@ -1,17 +0,0 @@ -package cn.lastwhisper.springboot.dubbo.provider; - -import com.alibaba.dubbo.spring.boot.annotation.EnableDubboConfiguration; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -@EnableDubboConfiguration -public class ProviderApplication { - - public static void main(String[] args) { - SpringApplication.run(ProviderApplication.class, args); - - - } - -} diff --git a/springboot-integration-examples/springboot-duboo/provider/src/main/java/cn/lastwhisper/springboot/dubbo/provider/quickstart/QuickstartServiceImpl.java b/springboot-integration-examples/springboot-duboo/provider/src/main/java/cn/lastwhisper/springboot/dubbo/provider/quickstart/QuickstartServiceImpl.java deleted file mode 100644 index 26729bce..00000000 --- a/springboot-integration-examples/springboot-duboo/provider/src/main/java/cn/lastwhisper/springboot/dubbo/provider/quickstart/QuickstartServiceImpl.java +++ /dev/null @@ -1,18 +0,0 @@ -package cn.lastwhisper.springboot.dubbo.provider.quickstart; - -import cn.lastwhisper.springboot.dubbo.ServiceAPI; -import com.alibaba.dubbo.config.annotation.Service; -import org.springframework.stereotype.Component; - -/** - * @author lastwhisper - */ -@Component -@Service(interfaceClass = ServiceAPI.class) -public class QuickstartServiceImpl implements ServiceAPI { - - @Override - public String sendMessage(String message) { - return "quickstart-provider-message=" + message; - } -} diff --git a/springboot-integration-examples/springboot-duboo/provider/src/main/resources/application.properties b/springboot-integration-examples/springboot-duboo/provider/src/main/resources/application.properties deleted file mode 100644 index 0d2d5ac4..00000000 --- a/springboot-integration-examples/springboot-duboo/provider/src/main/resources/application.properties +++ /dev/null @@ -1,3 +0,0 @@ -spring.application.name=dubbo-spring-boot-starter -spring.dubbo.server=true -spring.dubbo.registry=zookeeper://localhost:2181 \ No newline at end of file diff --git a/springboot-integration-examples/springboot-duboo/provider/src/test/java/cn/lastwhisper/springboot/dubbo/provider/ProviderApplicationTests.java b/springboot-integration-examples/springboot-duboo/provider/src/test/java/cn/lastwhisper/springboot/dubbo/provider/ProviderApplicationTests.java deleted file mode 100644 index 2ceac86a..00000000 --- a/springboot-integration-examples/springboot-duboo/provider/src/test/java/cn/lastwhisper/springboot/dubbo/provider/ProviderApplicationTests.java +++ /dev/null @@ -1,16 +0,0 @@ -package cn.lastwhisper.springboot.dubbo.provider; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit4.SpringRunner; - -@RunWith(SpringRunner.class) -@SpringBootTest -public class ProviderApplicationTests { - - @Test - public void contextLoads() { - } - -} diff --git a/springboot-integration-examples/springboot-duboo/src/main/java/cn/lastwhisper/springboot/dubbo/springbootduboo/SpringbootDubooApplication.java b/springboot-integration-examples/springboot-duboo/src/main/java/cn/lastwhisper/springboot/dubbo/springbootduboo/SpringbootDubooApplication.java deleted file mode 100644 index 02963579..00000000 --- a/springboot-integration-examples/springboot-duboo/src/main/java/cn/lastwhisper/springboot/dubbo/springbootduboo/SpringbootDubooApplication.java +++ /dev/null @@ -1,13 +0,0 @@ -package cn.lastwhisper.springboot.dubbo.springbootduboo; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class SpringbootDubooApplication { - - public static void main(String[] args) { - SpringApplication.run(SpringbootDubooApplication.class, args); - } - -} diff --git a/springboot-integration-examples/springboot-duboo/src/main/resources/application.properties b/springboot-integration-examples/springboot-duboo/src/main/resources/application.properties deleted file mode 100644 index 8b137891..00000000 --- a/springboot-integration-examples/springboot-duboo/src/main/resources/application.properties +++ /dev/null @@ -1 +0,0 @@ - diff --git a/springboot-integration-examples/springboot-duboo/src/test/java/cn/lastwhisper/springboot/dubbo/springbootduboo/SpringbootDubooApplicationTests.java b/springboot-integration-examples/springboot-duboo/src/test/java/cn/lastwhisper/springboot/dubbo/springbootduboo/SpringbootDubooApplicationTests.java deleted file mode 100644 index 213364d4..00000000 --- a/springboot-integration-examples/springboot-duboo/src/test/java/cn/lastwhisper/springboot/dubbo/springbootduboo/SpringbootDubooApplicationTests.java +++ /dev/null @@ -1,16 +0,0 @@ -package cn.lastwhisper.springboot.dubbo.springbootduboo; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit4.SpringRunner; - -@RunWith(SpringRunner.class) -@SpringBootTest -public class SpringbootDubooApplicationTests { - - @Test - public void contextLoads() { - } - -} diff --git a/springboot-integration-examples/springboot-flyway-old/pom.xml b/springboot-integration-examples/springboot-flyway-old/pom.xml deleted file mode 100644 index 73052707..00000000 --- a/springboot-integration-examples/springboot-flyway-old/pom.xml +++ /dev/null @@ -1,60 +0,0 @@ - - - 4.0.0 - - com.didispace - Chapter3-2-9 - 1.0.0 - jar - - Chapter3-2-9 - Spring Boot with JDBCTemplate - - - org.springframework.boot - spring-boot-starter-parent - 1.5.9.RELEASE - - - - - UTF-8 - 1.8 - - - - - org.springframework.boot - spring-boot-starter-test - test - - - - mysql - mysql-connector-java - 5.1.21 - - - - org.springframework.boot - spring-boot-starter-jdbc - - - - org.flywaydb - flyway-core - 5.0.3 - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - - \ No newline at end of file diff --git a/springboot-integration-examples/springboot-flyway-old/src/main/java/com/didispace/Application.java b/springboot-integration-examples/springboot-flyway-old/src/main/java/com/didispace/Application.java deleted file mode 100644 index 2a14b751..00000000 --- a/springboot-integration-examples/springboot-flyway-old/src/main/java/com/didispace/Application.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.didispace; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class Application { - - public static void main(String[] args) { - SpringApplication.run(Application.class, args); - } - -} diff --git a/springboot-integration-examples/springboot-flyway-old/src/main/java/com/didispace/service/UserService.java b/springboot-integration-examples/springboot-flyway-old/src/main/java/com/didispace/service/UserService.java deleted file mode 100644 index 620a443f..00000000 --- a/springboot-integration-examples/springboot-flyway-old/src/main/java/com/didispace/service/UserService.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.didispace.service; - -/** - * @author 程序猿DD - * @version 1.0.0 - * @date 16/3/17 下午7:04. - * @blog http://blog.didispace.com - */ -public interface UserService { - - /** - * 新增一个用户 - * @param name - * @param age - */ - void create(String name, Integer age); - - /** - * 根据name删除一个用户高 - * @param name - */ - void deleteByName(String name); - - /** - * 获取用户总量 - */ - Integer getAllUsers(); - - /** - * 删除所有用户 - */ - void deleteAllUsers(); - - -} diff --git a/springboot-integration-examples/springboot-flyway-old/src/main/java/com/didispace/service/UserServiceImpl.java b/springboot-integration-examples/springboot-flyway-old/src/main/java/com/didispace/service/UserServiceImpl.java deleted file mode 100644 index 05c04f09..00000000 --- a/springboot-integration-examples/springboot-flyway-old/src/main/java/com/didispace/service/UserServiceImpl.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.didispace.service; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.stereotype.Service; - -/** - * @author 程序猿DD - * @version 1.0.0 - * @date 16/3/17 下午6:44. - * @blog http://blog.didispace.com - */ -@Service -public class UserServiceImpl implements UserService { - - @Autowired - private JdbcTemplate jdbcTemplate; - - @Override - public void create(String name, Integer age) { - jdbcTemplate.update("insert into user(NAME, AGE) values(?, ?)", name, age); - } - - @Override - public void deleteByName(String name) { - jdbcTemplate.update("delete from user where NAME = ?", name); - } - - @Override - public Integer getAllUsers() { - return jdbcTemplate.queryForObject("select count(1) from user", Integer.class); - } - - @Override - public void deleteAllUsers() { - jdbcTemplate.update("delete from user"); - } -} diff --git a/springboot-integration-examples/springboot-flyway-old/src/main/resources/application.properties b/springboot-integration-examples/springboot-flyway-old/src/main/resources/application.properties deleted file mode 100644 index 5a82ecff..00000000 --- a/springboot-integration-examples/springboot-flyway-old/src/main/resources/application.properties +++ /dev/null @@ -1,6 +0,0 @@ -spring.datasource.url=jdbc:mysql://localhost:3306/test -spring.datasource.username=root -spring.datasource.password=root -spring.datasource.driver-class-name=com.mysql.jdbc.Driver - -flyway.locations=classpath:/db \ No newline at end of file diff --git a/springboot-integration-examples/springboot-flyway-old/src/main/resources/db/V1__Base_version.sql b/springboot-integration-examples/springboot-flyway-old/src/main/resources/db/V1__Base_version.sql deleted file mode 100644 index ff8bce17..00000000 --- a/springboot-integration-examples/springboot-flyway-old/src/main/resources/db/V1__Base_version.sql +++ /dev/null @@ -1,9 +0,0 @@ -DROP TABLE IF EXISTS `user` ; - - -CREATE TABLE `user` ( - `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键', - `name` varchar(30) NOT NULL COMMENT '姓名', - `age` int(5) DEFAULT NULL COMMENT '年龄', - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; diff --git a/springboot-integration-examples/springboot-flyway-old/src/test/java/com/didispace/ApplicationTests.java b/springboot-integration-examples/springboot-flyway-old/src/test/java/com/didispace/ApplicationTests.java deleted file mode 100644 index ec6f8985..00000000 --- a/springboot-integration-examples/springboot-flyway-old/src/test/java/com/didispace/ApplicationTests.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.didispace; - -import com.didispace.service.UserService; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; - - -@RunWith(SpringJUnit4ClassRunner.class) -@SpringBootTest -public class ApplicationTests { - - @Autowired - private UserService userSerivce; - - @Before - public void setUp() { - // 准备,清空user表 - userSerivce.deleteAllUsers(); - } - - @Test - public void test() throws Exception { - // 插入5个用户 - userSerivce.create("a", 1); - userSerivce.create("b", 2); - userSerivce.create("c", 3); - userSerivce.create("d", 4); - userSerivce.create("e", 5); - - // 查数据库,应该有5个用户 - Assert.assertEquals(5, userSerivce.getAllUsers().intValue()); - - // 删除两个用户 - userSerivce.deleteByName("a"); - userSerivce.deleteByName("e"); - - // 查数据库,应该有5个用户 - Assert.assertEquals(3, userSerivce.getAllUsers().intValue()); - - } - - -} diff --git a/springboot-integration-examples/springboot-flyway/.gitignore b/springboot-integration-examples/springboot-flyway/.gitignore deleted file mode 100644 index a2a3040a..00000000 --- a/springboot-integration-examples/springboot-flyway/.gitignore +++ /dev/null @@ -1,31 +0,0 @@ -HELP.md -target/ -!.mvn/wrapper/maven-wrapper.jar -!**/src/main/** -!**/src/test/** - -### STS ### -.apt_generated -.classpath -.factorypath -.project -.settings -.springBeans -.sts4-cache - -### IntelliJ IDEA ### -.idea -*.iws -*.iml -*.ipr - -### NetBeans ### -/nbproject/private/ -/nbbuild/ -/dist/ -/nbdist/ -/.nb-gradle/ -build/ - -### VS Code ### -.vscode/ diff --git a/springboot-integration-examples/springboot-flyway/.mvn/wrapper/MavenWrapperDownloader.java b/springboot-integration-examples/springboot-flyway/.mvn/wrapper/MavenWrapperDownloader.java deleted file mode 100644 index 7f91a56e..00000000 --- a/springboot-integration-examples/springboot-flyway/.mvn/wrapper/MavenWrapperDownloader.java +++ /dev/null @@ -1,114 +0,0 @@ -/* -Licensed to the Apache Software Foundation (ASF) under one -or more contributor license agreements. See the NOTICE file -distributed with this work for additional information -regarding copyright ownership. The ASF licenses this file -to you under the Apache License, Version 2.0 (the -"License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, -software distributed under the License is distributed on an -"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -KIND, either express or implied. See the License for the -specific language governing permissions and limitations -under the License. -*/ - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.net.URL; -import java.nio.channels.Channels; -import java.nio.channels.ReadableByteChannel; -import java.util.Properties; - -public class MavenWrapperDownloader { - - /** - * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. - */ - private static final String DEFAULT_DOWNLOAD_URL = - "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"; - - /** - * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to - * use instead of the default one. - */ - private static final String MAVEN_WRAPPER_PROPERTIES_PATH = - ".mvn/wrapper/maven-wrapper.properties"; - - /** - * Path where the maven-wrapper.jar will be saved to. - */ - private static final String MAVEN_WRAPPER_JAR_PATH = - ".mvn/wrapper/maven-wrapper.jar"; - - /** - * Name of the property which should be used to override the default download url for the wrapper. - */ - private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; - - public static void main(String args[]) { - System.out.println("- Downloader started"); - File baseDirectory = new File(args[0]); - System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); - - // If the maven-wrapper.properties exists, read it and check if it contains a custom - // wrapperUrl parameter. - File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); - String url = DEFAULT_DOWNLOAD_URL; - if (mavenWrapperPropertyFile.exists()) { - FileInputStream mavenWrapperPropertyFileInputStream = null; - try { - mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); - Properties mavenWrapperProperties = new Properties(); - mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); - url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); - } catch (IOException e) { - System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); - } finally { - try { - if (mavenWrapperPropertyFileInputStream != null) { - mavenWrapperPropertyFileInputStream.close(); - } - } catch (IOException e) { - // Ignore ... - } - } - } - System.out.println("- Downloading from: : " + url); - - File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); - if (!outputFile.getParentFile().exists()) { - if (!outputFile.getParentFile().mkdirs()) { - System.out.println( - "- ERROR creating output direcrory '" + outputFile.getParentFile().getAbsolutePath() + "'"); - } - } - System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); - try { - downloadFileFromURL(url, outputFile); - System.out.println("Done"); - System.exit(0); - } catch (Throwable e) { - System.out.println("- Error downloading"); - e.printStackTrace(); - System.exit(1); - } - } - - private static void downloadFileFromURL(String urlString, File destination) throws Exception { - URL website = new URL(urlString); - ReadableByteChannel rbc; - rbc = Channels.newChannel(website.openStream()); - FileOutputStream fos = new FileOutputStream(destination); - fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); - fos.close(); - rbc.close(); - } - -} diff --git a/springboot-integration-examples/springboot-flyway/.mvn/wrapper/maven-wrapper.jar b/springboot-integration-examples/springboot-flyway/.mvn/wrapper/maven-wrapper.jar deleted file mode 100644 index 01e67997..00000000 Binary files a/springboot-integration-examples/springboot-flyway/.mvn/wrapper/maven-wrapper.jar and /dev/null differ diff --git a/springboot-integration-examples/springboot-flyway/.mvn/wrapper/maven-wrapper.properties b/springboot-integration-examples/springboot-flyway/.mvn/wrapper/maven-wrapper.properties deleted file mode 100644 index cd0d451c..00000000 --- a/springboot-integration-examples/springboot-flyway/.mvn/wrapper/maven-wrapper.properties +++ /dev/null @@ -1 +0,0 @@ -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip diff --git a/springboot-integration-examples/springboot-flyway/mvnw b/springboot-integration-examples/springboot-flyway/mvnw deleted file mode 100644 index 8b9da3b8..00000000 --- a/springboot-integration-examples/springboot-flyway/mvnw +++ /dev/null @@ -1,286 +0,0 @@ -#!/bin/sh -# ---------------------------------------------------------------------------- -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# ---------------------------------------------------------------------------- - -# ---------------------------------------------------------------------------- -# Maven2 Start Up Batch script -# -# Required ENV vars: -# ------------------ -# JAVA_HOME - location of a JDK home dir -# -# Optional ENV vars -# ----------------- -# M2_HOME - location of maven2's installed home dir -# MAVEN_OPTS - parameters passed to the Java VM when running Maven -# e.g. to debug Maven itself, use -# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -# MAVEN_SKIP_RC - flag to disable loading of mavenrc files -# ---------------------------------------------------------------------------- - -if [ -z "$MAVEN_SKIP_RC" ] ; then - - if [ -f /etc/mavenrc ] ; then - . /etc/mavenrc - fi - - if [ -f "$HOME/.mavenrc" ] ; then - . "$HOME/.mavenrc" - fi - -fi - -# OS specific support. $var _must_ be set to either true or false. -cygwin=false; -darwin=false; -mingw=false -case "`uname`" in - CYGWIN*) cygwin=true ;; - MINGW*) mingw=true;; - Darwin*) darwin=true - # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home - # See https://developer.apple.com/library/mac/qa/qa1170/_index.html - if [ -z "$JAVA_HOME" ]; then - if [ -x "/usr/libexec/java_home" ]; then - export JAVA_HOME="`/usr/libexec/java_home`" - else - export JAVA_HOME="/Library/Java/Home" - fi - fi - ;; -esac - -if [ -z "$JAVA_HOME" ] ; then - if [ -r /etc/gentoo-release ] ; then - JAVA_HOME=`java-config --jre-home` - fi -fi - -if [ -z "$M2_HOME" ] ; then - ## resolve links - $0 may be a link to maven's home - PRG="$0" - - # need this for relative symlinks - while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG="`dirname "$PRG"`/$link" - fi - done - - saveddir=`pwd` - - M2_HOME=`dirname "$PRG"`/.. - - # make it fully qualified - M2_HOME=`cd "$M2_HOME" && pwd` - - cd "$saveddir" - # echo Using m2 at $M2_HOME -fi - -# For Cygwin, ensure paths are in UNIX format before anything is touched -if $cygwin ; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --unix "$M2_HOME"` - [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --unix "$JAVA_HOME"` - [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --unix "$CLASSPATH"` -fi - -# For Mingw, ensure paths are in UNIX format before anything is touched -if $mingw ; then - [ -n "$M2_HOME" ] && - M2_HOME="`(cd "$M2_HOME"; pwd)`" - [ -n "$JAVA_HOME" ] && - JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" - # TODO classpath? -fi - -if [ -z "$JAVA_HOME" ]; then - javaExecutable="`which javac`" - if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then - # readlink(1) is not available as standard on Solaris 10. - readLink=`which readlink` - if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then - if $darwin ; then - javaHome="`dirname \"$javaExecutable\"`" - javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" - else - javaExecutable="`readlink -f \"$javaExecutable\"`" - fi - javaHome="`dirname \"$javaExecutable\"`" - javaHome=`expr "$javaHome" : '\(.*\)/bin'` - JAVA_HOME="$javaHome" - export JAVA_HOME - fi - fi -fi - -if [ -z "$JAVACMD" ] ; then - if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - else - JAVACMD="`which java`" - fi -fi - -if [ ! -x "$JAVACMD" ] ; then - echo "Error: JAVA_HOME is not defined correctly." >&2 - echo " We cannot execute $JAVACMD" >&2 - exit 1 -fi - -if [ -z "$JAVA_HOME" ] ; then - echo "Warning: JAVA_HOME environment variable is not set." -fi - -CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher - -# traverses directory structure from process work directory to filesystem root -# first directory with .mvn subdirectory is considered project base directory -find_maven_basedir() { - - if [ -z "$1" ] - then - echo "Path not specified to find_maven_basedir" - return 1 - fi - - basedir="$1" - wdir="$1" - while [ "$wdir" != '/' ] ; do - if [ -d "$wdir"/.mvn ] ; then - basedir=$wdir - break - fi - # workaround for JBEAP-8937 (on Solaris 10/Sparc) - if [ -d "${wdir}" ]; then - wdir=`cd "$wdir/.."; pwd` - fi - # end of workaround - done - echo "${basedir}" -} - -# concatenates all lines of a file -concat_lines() { - if [ -f "$1" ]; then - echo "$(tr -s '\n' ' ' < "$1")" - fi -} - -BASE_DIR=`find_maven_basedir "$(pwd)"` -if [ -z "$BASE_DIR" ]; then - exit 1; -fi - -########################################################################################## -# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -# This allows using the maven wrapper in projects that prohibit checking in binary data. -########################################################################################## -if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found .mvn/wrapper/maven-wrapper.jar" - fi -else - if [ "$MVNW_VERBOSE" = true ]; then - echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." - fi - jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar" - while IFS="=" read key value; do - case "$key" in (wrapperUrl) jarUrl="$value"; break ;; - esac - done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" - if [ "$MVNW_VERBOSE" = true ]; then - echo "Downloading from: $jarUrl" - fi - wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" - - if command -v wget > /dev/null; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found wget ... using wget" - fi - wget "$jarUrl" -O "$wrapperJarPath" - elif command -v curl > /dev/null; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found curl ... using curl" - fi - curl -o "$wrapperJarPath" "$jarUrl" - else - if [ "$MVNW_VERBOSE" = true ]; then - echo "Falling back to using Java to download" - fi - javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" - if [ -e "$javaClass" ]; then - if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then - if [ "$MVNW_VERBOSE" = true ]; then - echo " - Compiling MavenWrapperDownloader.java ..." - fi - # Compiling the Java class - ("$JAVA_HOME/bin/javac" "$javaClass") - fi - if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then - # Running the downloader - if [ "$MVNW_VERBOSE" = true ]; then - echo " - Running MavenWrapperDownloader.java ..." - fi - ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") - fi - fi - fi -fi -########################################################################################## -# End of extension -########################################################################################## - -export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} -if [ "$MVNW_VERBOSE" = true ]; then - echo $MAVEN_PROJECTBASEDIR -fi -MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" - -# For Cygwin, switch paths to Windows format before running java -if $cygwin; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --path --windows "$M2_HOME"` - [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` - [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --windows "$CLASSPATH"` - [ -n "$MAVEN_PROJECTBASEDIR" ] && - MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` -fi - -WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -exec "$JAVACMD" \ - $MAVEN_OPTS \ - -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ - "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ - ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/springboot-integration-examples/springboot-flyway/mvnw.cmd b/springboot-integration-examples/springboot-flyway/mvnw.cmd deleted file mode 100644 index fef5a8f7..00000000 --- a/springboot-integration-examples/springboot-flyway/mvnw.cmd +++ /dev/null @@ -1,161 +0,0 @@ -@REM ---------------------------------------------------------------------------- -@REM Licensed to the Apache Software Foundation (ASF) under one -@REM or more contributor license agreements. See the NOTICE file -@REM distributed with this work for additional information -@REM regarding copyright ownership. The ASF licenses this file -@REM to you under the Apache License, Version 2.0 (the -@REM "License"); you may not use this file except in compliance -@REM with the License. You may obtain a copy of the License at -@REM -@REM https://www.apache.org/licenses/LICENSE-2.0 -@REM -@REM Unless required by applicable law or agreed to in writing, -@REM software distributed under the License is distributed on an -@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -@REM KIND, either express or implied. See the License for the -@REM specific language governing permissions and limitations -@REM under the License. -@REM ---------------------------------------------------------------------------- - -@REM ---------------------------------------------------------------------------- -@REM Maven2 Start Up Batch script -@REM -@REM Required ENV vars: -@REM JAVA_HOME - location of a JDK home dir -@REM -@REM Optional ENV vars -@REM M2_HOME - location of maven2's installed home dir -@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands -@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending -@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven -@REM e.g. to debug Maven itself, use -@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files -@REM ---------------------------------------------------------------------------- - -@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' -@echo off -@REM set title of command window -title %0 -@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' -@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% - -@REM set %HOME% to equivalent of $HOME -if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") - -@REM Execute a user defined script before this one -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre -@REM check for pre script, once with legacy .bat ending and once with .cmd ending -if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" -if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" -:skipRcPre - -@setlocal - -set ERROR_CODE=0 - -@REM To isolate internal variables from possible post scripts, we use another setlocal -@setlocal - -@REM ==== START VALIDATION ==== -if not "%JAVA_HOME%" == "" goto OkJHome - -echo. -echo Error: JAVA_HOME not found in your environment. >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -:OkJHome -if exist "%JAVA_HOME%\bin\java.exe" goto init - -echo. -echo Error: JAVA_HOME is set to an invalid directory. >&2 -echo JAVA_HOME = "%JAVA_HOME%" >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -@REM ==== END VALIDATION ==== - -:init - -@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". -@REM Fallback to current working directory if not found. - -set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% -IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir - -set EXEC_DIR=%CD% -set WDIR=%EXEC_DIR% -:findBaseDir -IF EXIST "%WDIR%"\.mvn goto baseDirFound -cd .. -IF "%WDIR%"=="%CD%" goto baseDirNotFound -set WDIR=%CD% -goto findBaseDir - -:baseDirFound -set MAVEN_PROJECTBASEDIR=%WDIR% -cd "%EXEC_DIR%" -goto endDetectBaseDir - -:baseDirNotFound -set MAVEN_PROJECTBASEDIR=%EXEC_DIR% -cd "%EXEC_DIR%" - -:endDetectBaseDir - -IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig - -@setlocal EnableExtensions EnableDelayedExpansion -for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a -@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% - -:endReadAdditionalConfig - -SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" -set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" -set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar" -FOR /F "tokens=1,2 delims==" %%A IN (%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties) DO ( - IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B -) - -@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -@REM This allows using the maven wrapper in projects that prohibit checking in binary data. -if exist %WRAPPER_JAR% ( - echo Found %WRAPPER_JAR% -) else ( - echo Couldn't find %WRAPPER_JAR%, downloading it ... - echo Downloading from: %DOWNLOAD_URL% - powershell -Command "(New-Object Net.WebClient).DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')" - echo Finished downloading %WRAPPER_JAR% -) -@REM End of extension - -%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* -if ERRORLEVEL 1 goto error -goto end - -:error -set ERROR_CODE=1 - -:end -@endlocal & set ERROR_CODE=%ERROR_CODE% - -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost -@REM check for post script, once with legacy .bat ending and once with .cmd ending -if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" -if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" -:skipRcPost - -@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' -if "%MAVEN_BATCH_PAUSE%" == "on" pause - -if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% - -exit /B %ERROR_CODE% diff --git a/springboot-integration-examples/springboot-flyway/pom.xml b/springboot-integration-examples/springboot-flyway/pom.xml deleted file mode 100644 index 0f6397cb..00000000 --- a/springboot-integration-examples/springboot-flyway/pom.xml +++ /dev/null @@ -1,57 +0,0 @@ - - - 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 2.1.9.RELEASE - - - cn.lastwhisper.springboot - flyway - 0.0.1-SNAPSHOT - flyway - Demo project for Spring Boot - - - 1.8 - - - - - org.springframework.boot - spring-boot-starter - - - - org.springframework.boot - spring-boot-starter-test - test - - - - org.flywaydb - flyway-core - 6.0.6 - - - - - mysql - mysql-connector-java - 8.0.17 - - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - - diff --git a/springboot-integration-examples/springboot-flyway/src/main/java/cn/lastwhisper/springboot/flyway/App.java b/springboot-integration-examples/springboot-flyway/src/main/java/cn/lastwhisper/springboot/flyway/App.java deleted file mode 100644 index f79de26b..00000000 --- a/springboot-integration-examples/springboot-flyway/src/main/java/cn/lastwhisper/springboot/flyway/App.java +++ /dev/null @@ -1,13 +0,0 @@ -package cn.lastwhisper.springboot.flyway; - -import org.flywaydb.core.Flyway; - -public class App { - public static void main(String[] args) { - // Create the Flyway instance and point it to the database - Flyway flyway = Flyway.configure().dataSource("jdbc:mysql://localhost:3306/flyway", "root", "root").load(); - - // Start the migration - flyway.migrate(); - } -} \ No newline at end of file diff --git a/springboot-integration-examples/springboot-flyway/src/main/java/cn/lastwhisper/springboot/flyway/FlywayApplication.java b/springboot-integration-examples/springboot-flyway/src/main/java/cn/lastwhisper/springboot/flyway/FlywayApplication.java deleted file mode 100644 index 97a323cb..00000000 --- a/springboot-integration-examples/springboot-flyway/src/main/java/cn/lastwhisper/springboot/flyway/FlywayApplication.java +++ /dev/null @@ -1,13 +0,0 @@ -package cn.lastwhisper.springboot.flyway; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class FlywayApplication { - - public static void main(String[] args) { - SpringApplication.run(FlywayApplication.class, args); - } - -} diff --git a/springboot-integration-examples/springboot-flyway/src/main/resources/application.properties b/springboot-integration-examples/springboot-flyway/src/main/resources/application.properties deleted file mode 100644 index 8b137891..00000000 --- a/springboot-integration-examples/springboot-flyway/src/main/resources/application.properties +++ /dev/null @@ -1 +0,0 @@ - diff --git a/springboot-integration-examples/springboot-flyway/src/test/java/cn/lastwhisper/springboot/flyway/FlywayApplicationTests.java b/springboot-integration-examples/springboot-flyway/src/test/java/cn/lastwhisper/springboot/flyway/FlywayApplicationTests.java deleted file mode 100644 index 9dfed952..00000000 --- a/springboot-integration-examples/springboot-flyway/src/test/java/cn/lastwhisper/springboot/flyway/FlywayApplicationTests.java +++ /dev/null @@ -1,16 +0,0 @@ -package cn.lastwhisper.springboot.flyway; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit4.SpringRunner; - -@RunWith(SpringRunner.class) -@SpringBootTest -public class FlywayApplicationTests { - - @Test - public void contextLoads() { - } - -} diff --git a/springboot-integration-examples/springboot-mybatisplus/.gitignore b/springboot-integration-examples/springboot-mybatisplus/.gitignore deleted file mode 100644 index 153c9335..00000000 --- a/springboot-integration-examples/springboot-mybatisplus/.gitignore +++ /dev/null @@ -1,29 +0,0 @@ -HELP.md -/target/ -!.mvn/wrapper/maven-wrapper.jar - -### STS ### -.apt_generated -.classpath -.factorypath -.project -.settings -.springBeans -.sts4-cache - -### IntelliJ IDEA ### -.idea -*.iws -*.iml -*.ipr - -### NetBeans ### -/nbproject/private/ -/nbbuild/ -/dist/ -/nbdist/ -/.nb-gradle/ -/build/ - -### VS Code ### -.vscode/ diff --git a/springboot-integration-examples/springboot-mybatisplus/.mvn/wrapper/MavenWrapperDownloader.java b/springboot-integration-examples/springboot-mybatisplus/.mvn/wrapper/MavenWrapperDownloader.java deleted file mode 100644 index 7f91a56e..00000000 --- a/springboot-integration-examples/springboot-mybatisplus/.mvn/wrapper/MavenWrapperDownloader.java +++ /dev/null @@ -1,114 +0,0 @@ -/* -Licensed to the Apache Software Foundation (ASF) under one -or more contributor license agreements. See the NOTICE file -distributed with this work for additional information -regarding copyright ownership. The ASF licenses this file -to you under the Apache License, Version 2.0 (the -"License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, -software distributed under the License is distributed on an -"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -KIND, either express or implied. See the License for the -specific language governing permissions and limitations -under the License. -*/ - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.net.URL; -import java.nio.channels.Channels; -import java.nio.channels.ReadableByteChannel; -import java.util.Properties; - -public class MavenWrapperDownloader { - - /** - * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. - */ - private static final String DEFAULT_DOWNLOAD_URL = - "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"; - - /** - * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to - * use instead of the default one. - */ - private static final String MAVEN_WRAPPER_PROPERTIES_PATH = - ".mvn/wrapper/maven-wrapper.properties"; - - /** - * Path where the maven-wrapper.jar will be saved to. - */ - private static final String MAVEN_WRAPPER_JAR_PATH = - ".mvn/wrapper/maven-wrapper.jar"; - - /** - * Name of the property which should be used to override the default download url for the wrapper. - */ - private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; - - public static void main(String args[]) { - System.out.println("- Downloader started"); - File baseDirectory = new File(args[0]); - System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); - - // If the maven-wrapper.properties exists, read it and check if it contains a custom - // wrapperUrl parameter. - File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); - String url = DEFAULT_DOWNLOAD_URL; - if (mavenWrapperPropertyFile.exists()) { - FileInputStream mavenWrapperPropertyFileInputStream = null; - try { - mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); - Properties mavenWrapperProperties = new Properties(); - mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); - url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); - } catch (IOException e) { - System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); - } finally { - try { - if (mavenWrapperPropertyFileInputStream != null) { - mavenWrapperPropertyFileInputStream.close(); - } - } catch (IOException e) { - // Ignore ... - } - } - } - System.out.println("- Downloading from: : " + url); - - File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); - if (!outputFile.getParentFile().exists()) { - if (!outputFile.getParentFile().mkdirs()) { - System.out.println( - "- ERROR creating output direcrory '" + outputFile.getParentFile().getAbsolutePath() + "'"); - } - } - System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); - try { - downloadFileFromURL(url, outputFile); - System.out.println("Done"); - System.exit(0); - } catch (Throwable e) { - System.out.println("- Error downloading"); - e.printStackTrace(); - System.exit(1); - } - } - - private static void downloadFileFromURL(String urlString, File destination) throws Exception { - URL website = new URL(urlString); - ReadableByteChannel rbc; - rbc = Channels.newChannel(website.openStream()); - FileOutputStream fos = new FileOutputStream(destination); - fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); - fos.close(); - rbc.close(); - } - -} diff --git a/springboot-integration-examples/springboot-mybatisplus/.mvn/wrapper/maven-wrapper.jar b/springboot-integration-examples/springboot-mybatisplus/.mvn/wrapper/maven-wrapper.jar deleted file mode 100644 index 01e67997..00000000 Binary files a/springboot-integration-examples/springboot-mybatisplus/.mvn/wrapper/maven-wrapper.jar and /dev/null differ diff --git a/springboot-integration-examples/springboot-mybatisplus/.mvn/wrapper/maven-wrapper.properties b/springboot-integration-examples/springboot-mybatisplus/.mvn/wrapper/maven-wrapper.properties deleted file mode 100644 index cd0d451c..00000000 --- a/springboot-integration-examples/springboot-mybatisplus/.mvn/wrapper/maven-wrapper.properties +++ /dev/null @@ -1 +0,0 @@ -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip diff --git a/springboot-integration-examples/springboot-mybatisplus/mvnw b/springboot-integration-examples/springboot-mybatisplus/mvnw deleted file mode 100644 index 8b9da3b8..00000000 --- a/springboot-integration-examples/springboot-mybatisplus/mvnw +++ /dev/null @@ -1,286 +0,0 @@ -#!/bin/sh -# ---------------------------------------------------------------------------- -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# ---------------------------------------------------------------------------- - -# ---------------------------------------------------------------------------- -# Maven2 Start Up Batch script -# -# Required ENV vars: -# ------------------ -# JAVA_HOME - location of a JDK home dir -# -# Optional ENV vars -# ----------------- -# M2_HOME - location of maven2's installed home dir -# MAVEN_OPTS - parameters passed to the Java VM when running Maven -# e.g. to debug Maven itself, use -# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -# MAVEN_SKIP_RC - flag to disable loading of mavenrc files -# ---------------------------------------------------------------------------- - -if [ -z "$MAVEN_SKIP_RC" ] ; then - - if [ -f /etc/mavenrc ] ; then - . /etc/mavenrc - fi - - if [ -f "$HOME/.mavenrc" ] ; then - . "$HOME/.mavenrc" - fi - -fi - -# OS specific support. $var _must_ be set to either true or false. -cygwin=false; -darwin=false; -mingw=false -case "`uname`" in - CYGWIN*) cygwin=true ;; - MINGW*) mingw=true;; - Darwin*) darwin=true - # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home - # See https://developer.apple.com/library/mac/qa/qa1170/_index.html - if [ -z "$JAVA_HOME" ]; then - if [ -x "/usr/libexec/java_home" ]; then - export JAVA_HOME="`/usr/libexec/java_home`" - else - export JAVA_HOME="/Library/Java/Home" - fi - fi - ;; -esac - -if [ -z "$JAVA_HOME" ] ; then - if [ -r /etc/gentoo-release ] ; then - JAVA_HOME=`java-config --jre-home` - fi -fi - -if [ -z "$M2_HOME" ] ; then - ## resolve links - $0 may be a link to maven's home - PRG="$0" - - # need this for relative symlinks - while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG="`dirname "$PRG"`/$link" - fi - done - - saveddir=`pwd` - - M2_HOME=`dirname "$PRG"`/.. - - # make it fully qualified - M2_HOME=`cd "$M2_HOME" && pwd` - - cd "$saveddir" - # echo Using m2 at $M2_HOME -fi - -# For Cygwin, ensure paths are in UNIX format before anything is touched -if $cygwin ; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --unix "$M2_HOME"` - [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --unix "$JAVA_HOME"` - [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --unix "$CLASSPATH"` -fi - -# For Mingw, ensure paths are in UNIX format before anything is touched -if $mingw ; then - [ -n "$M2_HOME" ] && - M2_HOME="`(cd "$M2_HOME"; pwd)`" - [ -n "$JAVA_HOME" ] && - JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" - # TODO classpath? -fi - -if [ -z "$JAVA_HOME" ]; then - javaExecutable="`which javac`" - if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then - # readlink(1) is not available as standard on Solaris 10. - readLink=`which readlink` - if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then - if $darwin ; then - javaHome="`dirname \"$javaExecutable\"`" - javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" - else - javaExecutable="`readlink -f \"$javaExecutable\"`" - fi - javaHome="`dirname \"$javaExecutable\"`" - javaHome=`expr "$javaHome" : '\(.*\)/bin'` - JAVA_HOME="$javaHome" - export JAVA_HOME - fi - fi -fi - -if [ -z "$JAVACMD" ] ; then - if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - else - JAVACMD="`which java`" - fi -fi - -if [ ! -x "$JAVACMD" ] ; then - echo "Error: JAVA_HOME is not defined correctly." >&2 - echo " We cannot execute $JAVACMD" >&2 - exit 1 -fi - -if [ -z "$JAVA_HOME" ] ; then - echo "Warning: JAVA_HOME environment variable is not set." -fi - -CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher - -# traverses directory structure from process work directory to filesystem root -# first directory with .mvn subdirectory is considered project base directory -find_maven_basedir() { - - if [ -z "$1" ] - then - echo "Path not specified to find_maven_basedir" - return 1 - fi - - basedir="$1" - wdir="$1" - while [ "$wdir" != '/' ] ; do - if [ -d "$wdir"/.mvn ] ; then - basedir=$wdir - break - fi - # workaround for JBEAP-8937 (on Solaris 10/Sparc) - if [ -d "${wdir}" ]; then - wdir=`cd "$wdir/.."; pwd` - fi - # end of workaround - done - echo "${basedir}" -} - -# concatenates all lines of a file -concat_lines() { - if [ -f "$1" ]; then - echo "$(tr -s '\n' ' ' < "$1")" - fi -} - -BASE_DIR=`find_maven_basedir "$(pwd)"` -if [ -z "$BASE_DIR" ]; then - exit 1; -fi - -########################################################################################## -# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -# This allows using the maven wrapper in projects that prohibit checking in binary data. -########################################################################################## -if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found .mvn/wrapper/maven-wrapper.jar" - fi -else - if [ "$MVNW_VERBOSE" = true ]; then - echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." - fi - jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar" - while IFS="=" read key value; do - case "$key" in (wrapperUrl) jarUrl="$value"; break ;; - esac - done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" - if [ "$MVNW_VERBOSE" = true ]; then - echo "Downloading from: $jarUrl" - fi - wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" - - if command -v wget > /dev/null; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found wget ... using wget" - fi - wget "$jarUrl" -O "$wrapperJarPath" - elif command -v curl > /dev/null; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found curl ... using curl" - fi - curl -o "$wrapperJarPath" "$jarUrl" - else - if [ "$MVNW_VERBOSE" = true ]; then - echo "Falling back to using Java to download" - fi - javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" - if [ -e "$javaClass" ]; then - if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then - if [ "$MVNW_VERBOSE" = true ]; then - echo " - Compiling MavenWrapperDownloader.java ..." - fi - # Compiling the Java class - ("$JAVA_HOME/bin/javac" "$javaClass") - fi - if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then - # Running the downloader - if [ "$MVNW_VERBOSE" = true ]; then - echo " - Running MavenWrapperDownloader.java ..." - fi - ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") - fi - fi - fi -fi -########################################################################################## -# End of extension -########################################################################################## - -export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} -if [ "$MVNW_VERBOSE" = true ]; then - echo $MAVEN_PROJECTBASEDIR -fi -MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" - -# For Cygwin, switch paths to Windows format before running java -if $cygwin; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --path --windows "$M2_HOME"` - [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` - [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --windows "$CLASSPATH"` - [ -n "$MAVEN_PROJECTBASEDIR" ] && - MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` -fi - -WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -exec "$JAVACMD" \ - $MAVEN_OPTS \ - -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ - "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ - ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/springboot-integration-examples/springboot-mybatisplus/mvnw.cmd b/springboot-integration-examples/springboot-mybatisplus/mvnw.cmd deleted file mode 100644 index fef5a8f7..00000000 --- a/springboot-integration-examples/springboot-mybatisplus/mvnw.cmd +++ /dev/null @@ -1,161 +0,0 @@ -@REM ---------------------------------------------------------------------------- -@REM Licensed to the Apache Software Foundation (ASF) under one -@REM or more contributor license agreements. See the NOTICE file -@REM distributed with this work for additional information -@REM regarding copyright ownership. The ASF licenses this file -@REM to you under the Apache License, Version 2.0 (the -@REM "License"); you may not use this file except in compliance -@REM with the License. You may obtain a copy of the License at -@REM -@REM https://www.apache.org/licenses/LICENSE-2.0 -@REM -@REM Unless required by applicable law or agreed to in writing, -@REM software distributed under the License is distributed on an -@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -@REM KIND, either express or implied. See the License for the -@REM specific language governing permissions and limitations -@REM under the License. -@REM ---------------------------------------------------------------------------- - -@REM ---------------------------------------------------------------------------- -@REM Maven2 Start Up Batch script -@REM -@REM Required ENV vars: -@REM JAVA_HOME - location of a JDK home dir -@REM -@REM Optional ENV vars -@REM M2_HOME - location of maven2's installed home dir -@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands -@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending -@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven -@REM e.g. to debug Maven itself, use -@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files -@REM ---------------------------------------------------------------------------- - -@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' -@echo off -@REM set title of command window -title %0 -@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' -@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% - -@REM set %HOME% to equivalent of $HOME -if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") - -@REM Execute a user defined script before this one -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre -@REM check for pre script, once with legacy .bat ending and once with .cmd ending -if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" -if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" -:skipRcPre - -@setlocal - -set ERROR_CODE=0 - -@REM To isolate internal variables from possible post scripts, we use another setlocal -@setlocal - -@REM ==== START VALIDATION ==== -if not "%JAVA_HOME%" == "" goto OkJHome - -echo. -echo Error: JAVA_HOME not found in your environment. >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -:OkJHome -if exist "%JAVA_HOME%\bin\java.exe" goto init - -echo. -echo Error: JAVA_HOME is set to an invalid directory. >&2 -echo JAVA_HOME = "%JAVA_HOME%" >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -@REM ==== END VALIDATION ==== - -:init - -@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". -@REM Fallback to current working directory if not found. - -set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% -IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir - -set EXEC_DIR=%CD% -set WDIR=%EXEC_DIR% -:findBaseDir -IF EXIST "%WDIR%"\.mvn goto baseDirFound -cd .. -IF "%WDIR%"=="%CD%" goto baseDirNotFound -set WDIR=%CD% -goto findBaseDir - -:baseDirFound -set MAVEN_PROJECTBASEDIR=%WDIR% -cd "%EXEC_DIR%" -goto endDetectBaseDir - -:baseDirNotFound -set MAVEN_PROJECTBASEDIR=%EXEC_DIR% -cd "%EXEC_DIR%" - -:endDetectBaseDir - -IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig - -@setlocal EnableExtensions EnableDelayedExpansion -for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a -@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% - -:endReadAdditionalConfig - -SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" -set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" -set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar" -FOR /F "tokens=1,2 delims==" %%A IN (%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties) DO ( - IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B -) - -@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -@REM This allows using the maven wrapper in projects that prohibit checking in binary data. -if exist %WRAPPER_JAR% ( - echo Found %WRAPPER_JAR% -) else ( - echo Couldn't find %WRAPPER_JAR%, downloading it ... - echo Downloading from: %DOWNLOAD_URL% - powershell -Command "(New-Object Net.WebClient).DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')" - echo Finished downloading %WRAPPER_JAR% -) -@REM End of extension - -%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* -if ERRORLEVEL 1 goto error -goto end - -:error -set ERROR_CODE=1 - -:end -@endlocal & set ERROR_CODE=%ERROR_CODE% - -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost -@REM check for post script, once with legacy .bat ending and once with .cmd ending -if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" -if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" -:skipRcPost - -@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' -if "%MAVEN_BATCH_PAUSE%" == "on" pause - -if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% - -exit /B %ERROR_CODE% diff --git a/springboot-integration-examples/springboot-mybatisplus/pom.xml b/springboot-integration-examples/springboot-mybatisplus/pom.xml deleted file mode 100644 index 0d5b47bd..00000000 --- a/springboot-integration-examples/springboot-mybatisplus/pom.xml +++ /dev/null @@ -1,62 +0,0 @@ - - - 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 2.1.4.RELEASE - - - cn.lastwhisper - springbootmybatisplus - 0.0.1-SNAPSHOT - springbootmybatisplus - Demo project for Spring Boot - - - 1.8 - - - - - org.springframework.boot - spring-boot-starter-web - - - - org.springframework.boot - spring-boot-starter-test - test - - - - - org.projectlombok - lombok - true - - - - com.baomidou - mybatis-plus-boot-starter - 3.1.1 - - - - mysql - mysql-connector-java - 5.1.47 - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - - diff --git a/springboot-integration-examples/springboot-mybatisplus/sql/mybatisplus.sql b/springboot-integration-examples/springboot-mybatisplus/sql/mybatisplus.sql deleted file mode 100644 index e2864c3f..00000000 --- a/springboot-integration-examples/springboot-mybatisplus/sql/mybatisplus.sql +++ /dev/null @@ -1,41 +0,0 @@ -/* - Navicat Premium Data Transfer - - Source Server : 本地数据库-mysql5.7 - Source Server Type : MySQL - Source Server Version : 50724 - Source Host : localhost:3306 - Source Schema : mybatisplus - - Target Server Type : MySQL - Target Server Version : 50724 - File Encoding : 65001 - - Date: 02/05/2019 11:00:02 -*/ - -SET NAMES utf8mb4; -SET FOREIGN_KEY_CHECKS = 0; - --- ---------------------------- --- Table structure for user --- ---------------------------- -DROP TABLE IF EXISTS `user`; -CREATE TABLE `user` ( - `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID', - `name` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '姓名', - `age` int(11) NULL DEFAULT NULL COMMENT '年龄', - `email` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '邮箱', - PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; - --- ---------------------------- --- Records of user --- ---------------------------- -INSERT INTO `user` VALUES (1, 'Jone', 18, 'test1@baomidou.com'); -INSERT INTO `user` VALUES (2, 'Jack', 20, 'test2@baomidou.com'); -INSERT INTO `user` VALUES (3, 'Tom', 28, 'test3@baomidou.com'); -INSERT INTO `user` VALUES (4, 'Sandy', 21, 'test4@baomidou.com'); -INSERT INTO `user` VALUES (5, 'gaojun', 24, 'gaojun56@163.com'); - -SET FOREIGN_KEY_CHECKS = 1; diff --git a/springboot-integration-examples/springboot-mybatisplus/src/main/java/cn/lastwhisper/springbootmybatisplus/SpringbootmybatisplusApplication.java b/springboot-integration-examples/springboot-mybatisplus/src/main/java/cn/lastwhisper/springbootmybatisplus/SpringbootmybatisplusApplication.java deleted file mode 100644 index 7a345070..00000000 --- a/springboot-integration-examples/springboot-mybatisplus/src/main/java/cn/lastwhisper/springbootmybatisplus/SpringbootmybatisplusApplication.java +++ /dev/null @@ -1,25 +0,0 @@ -package cn.lastwhisper.springbootmybatisplus; - -import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor; -import org.mybatis.spring.annotation.MapperScan; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.context.annotation.Bean; - -@MapperScan("cn.lastwhisper.springbootmybatisplus.mapper") //设置mapper接口的扫描包 -@SpringBootApplication -public class SpringbootmybatisplusApplication { - - /** - * 分页插件 - */ - @Bean - public PaginationInterceptor paginationInterceptor() { - return new PaginationInterceptor(); - } - - public static void main(String[] args) { - SpringApplication.run(SpringbootmybatisplusApplication.class, args); - } - -} diff --git a/springboot-integration-examples/springboot-mybatisplus/src/main/java/cn/lastwhisper/springbootmybatisplus/mapper/UserMapper.java b/springboot-integration-examples/springboot-mybatisplus/src/main/java/cn/lastwhisper/springbootmybatisplus/mapper/UserMapper.java deleted file mode 100644 index f8a29919..00000000 --- a/springboot-integration-examples/springboot-mybatisplus/src/main/java/cn/lastwhisper/springbootmybatisplus/mapper/UserMapper.java +++ /dev/null @@ -1,12 +0,0 @@ -package cn.lastwhisper.springbootmybatisplus.mapper; - -import cn.lastwhisper.springbootmybatisplus.pojo.User; -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -/** - * @desc - * - * @author lastwhisper - * @email gaojun56@163.com - */ -public interface UserMapper extends BaseMapper { -} \ No newline at end of file diff --git a/springboot-integration-examples/springboot-mybatisplus/src/main/java/cn/lastwhisper/springbootmybatisplus/pojo/User.java b/springboot-integration-examples/springboot-mybatisplus/src/main/java/cn/lastwhisper/springbootmybatisplus/pojo/User.java deleted file mode 100644 index 264c3c01..00000000 --- a/springboot-integration-examples/springboot-mybatisplus/src/main/java/cn/lastwhisper/springbootmybatisplus/pojo/User.java +++ /dev/null @@ -1,22 +0,0 @@ -package cn.lastwhisper.springbootmybatisplus.pojo; - -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableId; -import lombok.Data; -import lombok.ToString; - -/** - * @desc - * - * @author lastwhisper - * @email gaojun56@163.com - */ -@Data -@ToString -public class User { - @TableId(value = "ID", type = IdType.AUTO) - private Long id; - private String name; - private Integer age; - private String email; -} diff --git a/springboot-integration-examples/springboot-mybatisplus/src/main/resources/application.properties b/springboot-integration-examples/springboot-mybatisplus/src/main/resources/application.properties deleted file mode 100644 index c243caf8..00000000 --- a/springboot-integration-examples/springboot-mybatisplus/src/main/resources/application.properties +++ /dev/null @@ -1,5 +0,0 @@ -spring.application.name = lastwhisper-mybatis-plus -spring.datasource.driver-class-name=com.mysql.jdbc.Driver -spring.datasource.url=jdbc:mysql://127.0.0.1:3306/mybatisplus?useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true&useSSL=false -spring.datasource.username=root -spring.datasource.password=root \ No newline at end of file diff --git a/springboot-integration-examples/springboot-mybatisplus/src/test/java/cn/lastwhisper/springbootmybatisplus/SpringbootmybatisplusApplicationTests.java b/springboot-integration-examples/springboot-mybatisplus/src/test/java/cn/lastwhisper/springbootmybatisplus/SpringbootmybatisplusApplicationTests.java deleted file mode 100644 index 6b6198e5..00000000 --- a/springboot-integration-examples/springboot-mybatisplus/src/test/java/cn/lastwhisper/springbootmybatisplus/SpringbootmybatisplusApplicationTests.java +++ /dev/null @@ -1,104 +0,0 @@ -package cn.lastwhisper.springbootmybatisplus; - -import cn.lastwhisper.springbootmybatisplus.mapper.UserMapper; -import cn.lastwhisper.springbootmybatisplus.pojo.User; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit4.SpringRunner; - -import java.util.List; - -import static org.assertj.core.api.Assertions.assertThat; - -@RunWith(SpringRunner.class) -@SpringBootTest -public class SpringbootmybatisplusApplicationTests { - - - @Autowired - private UserMapper userMapper; - - @Test - public void testSelect() { - System.out.println(("----- selectAll method test ------")); - List userList = userMapper.selectList(null); - for (User user : userList) { - System.out.println(user); - } - } - - // like查询 - @Test - public void testselectByLike() { - QueryWrapper queryWrapper = new QueryWrapper<>(new User()); - // 查询名字中包含"o"的用户 - queryWrapper.like("name", "o"); - - List users = this.userMapper.selectList(queryWrapper); - for (User user : users) { - System.out.println(user); - } - } - - // 条件查询 - @Test - public void testselectByLe() { - QueryWrapper queryWrapper = new QueryWrapper<>(new User()); - //查询年龄小于等于20的用户 - queryWrapper.le("age", 20); - - List users = this.userMapper.selectList(queryWrapper); - for (User user : users) { - System.out.println(user); - } - } - - //插入数据 - @Test - public void testSave() { - User user = new User(); - user.setAge(21); - user.setEmail("gaojun56@163.com"); - user.setName("gaojun"); - int count = this.userMapper.insert(user); - System.out.println("新增数据成功! count => " + count); - } - - //删除数据 - @Test - public void testDelete() { - this.userMapper.deleteById(6L); - System.out.println("删除成功!"); - } - - //修改数据 - @Test - public void testUpdate() { - User user = new User(); - user.setId(5L); - user.setName("gaojun"); - user.setEmail("gaojun56@163.com"); - this.userMapper.updateById(user); - System.out.println("修改成功!"); - } - - //分页查询 - @Test - public void testselectPage() { - Page page = new Page<>(1, 2); - IPage userIPage = this.userMapper.selectPage(page, null); - System.out.println("总条数 ------> " + userIPage.getTotal()); - System.out.println("当前页数 ------> " + userIPage.getCurrent()); - System.out.println("当前每页显示数 ------> " + userIPage.getSize()); - List records = userIPage.getRecords(); - for (User user : records) { - System.out.println(user); - } - } - -} diff --git a/springboot-integration-examples/springboot-oss/.gitignore b/springboot-integration-examples/springboot-oss/.gitignore deleted file mode 100644 index 153c9335..00000000 --- a/springboot-integration-examples/springboot-oss/.gitignore +++ /dev/null @@ -1,29 +0,0 @@ -HELP.md -/target/ -!.mvn/wrapper/maven-wrapper.jar - -### STS ### -.apt_generated -.classpath -.factorypath -.project -.settings -.springBeans -.sts4-cache - -### IntelliJ IDEA ### -.idea -*.iws -*.iml -*.ipr - -### NetBeans ### -/nbproject/private/ -/nbbuild/ -/dist/ -/nbdist/ -/.nb-gradle/ -/build/ - -### VS Code ### -.vscode/ diff --git a/springboot-integration-examples/springboot-oss/.mvn/wrapper/MavenWrapperDownloader.java b/springboot-integration-examples/springboot-oss/.mvn/wrapper/MavenWrapperDownloader.java deleted file mode 100644 index 7f91a56e..00000000 --- a/springboot-integration-examples/springboot-oss/.mvn/wrapper/MavenWrapperDownloader.java +++ /dev/null @@ -1,114 +0,0 @@ -/* -Licensed to the Apache Software Foundation (ASF) under one -or more contributor license agreements. See the NOTICE file -distributed with this work for additional information -regarding copyright ownership. The ASF licenses this file -to you under the Apache License, Version 2.0 (the -"License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, -software distributed under the License is distributed on an -"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -KIND, either express or implied. See the License for the -specific language governing permissions and limitations -under the License. -*/ - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.net.URL; -import java.nio.channels.Channels; -import java.nio.channels.ReadableByteChannel; -import java.util.Properties; - -public class MavenWrapperDownloader { - - /** - * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. - */ - private static final String DEFAULT_DOWNLOAD_URL = - "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"; - - /** - * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to - * use instead of the default one. - */ - private static final String MAVEN_WRAPPER_PROPERTIES_PATH = - ".mvn/wrapper/maven-wrapper.properties"; - - /** - * Path where the maven-wrapper.jar will be saved to. - */ - private static final String MAVEN_WRAPPER_JAR_PATH = - ".mvn/wrapper/maven-wrapper.jar"; - - /** - * Name of the property which should be used to override the default download url for the wrapper. - */ - private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; - - public static void main(String args[]) { - System.out.println("- Downloader started"); - File baseDirectory = new File(args[0]); - System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); - - // If the maven-wrapper.properties exists, read it and check if it contains a custom - // wrapperUrl parameter. - File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); - String url = DEFAULT_DOWNLOAD_URL; - if (mavenWrapperPropertyFile.exists()) { - FileInputStream mavenWrapperPropertyFileInputStream = null; - try { - mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); - Properties mavenWrapperProperties = new Properties(); - mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); - url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); - } catch (IOException e) { - System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); - } finally { - try { - if (mavenWrapperPropertyFileInputStream != null) { - mavenWrapperPropertyFileInputStream.close(); - } - } catch (IOException e) { - // Ignore ... - } - } - } - System.out.println("- Downloading from: : " + url); - - File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); - if (!outputFile.getParentFile().exists()) { - if (!outputFile.getParentFile().mkdirs()) { - System.out.println( - "- ERROR creating output direcrory '" + outputFile.getParentFile().getAbsolutePath() + "'"); - } - } - System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); - try { - downloadFileFromURL(url, outputFile); - System.out.println("Done"); - System.exit(0); - } catch (Throwable e) { - System.out.println("- Error downloading"); - e.printStackTrace(); - System.exit(1); - } - } - - private static void downloadFileFromURL(String urlString, File destination) throws Exception { - URL website = new URL(urlString); - ReadableByteChannel rbc; - rbc = Channels.newChannel(website.openStream()); - FileOutputStream fos = new FileOutputStream(destination); - fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); - fos.close(); - rbc.close(); - } - -} diff --git a/springboot-integration-examples/springboot-oss/.mvn/wrapper/maven-wrapper.jar b/springboot-integration-examples/springboot-oss/.mvn/wrapper/maven-wrapper.jar deleted file mode 100644 index 01e67997..00000000 Binary files a/springboot-integration-examples/springboot-oss/.mvn/wrapper/maven-wrapper.jar and /dev/null differ diff --git a/springboot-integration-examples/springboot-oss/.mvn/wrapper/maven-wrapper.properties b/springboot-integration-examples/springboot-oss/.mvn/wrapper/maven-wrapper.properties deleted file mode 100644 index cd0d451c..00000000 --- a/springboot-integration-examples/springboot-oss/.mvn/wrapper/maven-wrapper.properties +++ /dev/null @@ -1 +0,0 @@ -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip diff --git a/springboot-integration-examples/springboot-oss/mvnw b/springboot-integration-examples/springboot-oss/mvnw deleted file mode 100644 index 8b9da3b8..00000000 --- a/springboot-integration-examples/springboot-oss/mvnw +++ /dev/null @@ -1,286 +0,0 @@ -#!/bin/sh -# ---------------------------------------------------------------------------- -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# ---------------------------------------------------------------------------- - -# ---------------------------------------------------------------------------- -# Maven2 Start Up Batch script -# -# Required ENV vars: -# ------------------ -# JAVA_HOME - location of a JDK home dir -# -# Optional ENV vars -# ----------------- -# M2_HOME - location of maven2's installed home dir -# MAVEN_OPTS - parameters passed to the Java VM when running Maven -# e.g. to debug Maven itself, use -# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -# MAVEN_SKIP_RC - flag to disable loading of mavenrc files -# ---------------------------------------------------------------------------- - -if [ -z "$MAVEN_SKIP_RC" ] ; then - - if [ -f /etc/mavenrc ] ; then - . /etc/mavenrc - fi - - if [ -f "$HOME/.mavenrc" ] ; then - . "$HOME/.mavenrc" - fi - -fi - -# OS specific support. $var _must_ be set to either true or false. -cygwin=false; -darwin=false; -mingw=false -case "`uname`" in - CYGWIN*) cygwin=true ;; - MINGW*) mingw=true;; - Darwin*) darwin=true - # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home - # See https://developer.apple.com/library/mac/qa/qa1170/_index.html - if [ -z "$JAVA_HOME" ]; then - if [ -x "/usr/libexec/java_home" ]; then - export JAVA_HOME="`/usr/libexec/java_home`" - else - export JAVA_HOME="/Library/Java/Home" - fi - fi - ;; -esac - -if [ -z "$JAVA_HOME" ] ; then - if [ -r /etc/gentoo-release ] ; then - JAVA_HOME=`java-config --jre-home` - fi -fi - -if [ -z "$M2_HOME" ] ; then - ## resolve links - $0 may be a link to maven's home - PRG="$0" - - # need this for relative symlinks - while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG="`dirname "$PRG"`/$link" - fi - done - - saveddir=`pwd` - - M2_HOME=`dirname "$PRG"`/.. - - # make it fully qualified - M2_HOME=`cd "$M2_HOME" && pwd` - - cd "$saveddir" - # echo Using m2 at $M2_HOME -fi - -# For Cygwin, ensure paths are in UNIX format before anything is touched -if $cygwin ; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --unix "$M2_HOME"` - [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --unix "$JAVA_HOME"` - [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --unix "$CLASSPATH"` -fi - -# For Mingw, ensure paths are in UNIX format before anything is touched -if $mingw ; then - [ -n "$M2_HOME" ] && - M2_HOME="`(cd "$M2_HOME"; pwd)`" - [ -n "$JAVA_HOME" ] && - JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" - # TODO classpath? -fi - -if [ -z "$JAVA_HOME" ]; then - javaExecutable="`which javac`" - if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then - # readlink(1) is not available as standard on Solaris 10. - readLink=`which readlink` - if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then - if $darwin ; then - javaHome="`dirname \"$javaExecutable\"`" - javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" - else - javaExecutable="`readlink -f \"$javaExecutable\"`" - fi - javaHome="`dirname \"$javaExecutable\"`" - javaHome=`expr "$javaHome" : '\(.*\)/bin'` - JAVA_HOME="$javaHome" - export JAVA_HOME - fi - fi -fi - -if [ -z "$JAVACMD" ] ; then - if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - else - JAVACMD="`which java`" - fi -fi - -if [ ! -x "$JAVACMD" ] ; then - echo "Error: JAVA_HOME is not defined correctly." >&2 - echo " We cannot execute $JAVACMD" >&2 - exit 1 -fi - -if [ -z "$JAVA_HOME" ] ; then - echo "Warning: JAVA_HOME environment variable is not set." -fi - -CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher - -# traverses directory structure from process work directory to filesystem root -# first directory with .mvn subdirectory is considered project base directory -find_maven_basedir() { - - if [ -z "$1" ] - then - echo "Path not specified to find_maven_basedir" - return 1 - fi - - basedir="$1" - wdir="$1" - while [ "$wdir" != '/' ] ; do - if [ -d "$wdir"/.mvn ] ; then - basedir=$wdir - break - fi - # workaround for JBEAP-8937 (on Solaris 10/Sparc) - if [ -d "${wdir}" ]; then - wdir=`cd "$wdir/.."; pwd` - fi - # end of workaround - done - echo "${basedir}" -} - -# concatenates all lines of a file -concat_lines() { - if [ -f "$1" ]; then - echo "$(tr -s '\n' ' ' < "$1")" - fi -} - -BASE_DIR=`find_maven_basedir "$(pwd)"` -if [ -z "$BASE_DIR" ]; then - exit 1; -fi - -########################################################################################## -# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -# This allows using the maven wrapper in projects that prohibit checking in binary data. -########################################################################################## -if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found .mvn/wrapper/maven-wrapper.jar" - fi -else - if [ "$MVNW_VERBOSE" = true ]; then - echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." - fi - jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar" - while IFS="=" read key value; do - case "$key" in (wrapperUrl) jarUrl="$value"; break ;; - esac - done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" - if [ "$MVNW_VERBOSE" = true ]; then - echo "Downloading from: $jarUrl" - fi - wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" - - if command -v wget > /dev/null; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found wget ... using wget" - fi - wget "$jarUrl" -O "$wrapperJarPath" - elif command -v curl > /dev/null; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found curl ... using curl" - fi - curl -o "$wrapperJarPath" "$jarUrl" - else - if [ "$MVNW_VERBOSE" = true ]; then - echo "Falling back to using Java to download" - fi - javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" - if [ -e "$javaClass" ]; then - if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then - if [ "$MVNW_VERBOSE" = true ]; then - echo " - Compiling MavenWrapperDownloader.java ..." - fi - # Compiling the Java class - ("$JAVA_HOME/bin/javac" "$javaClass") - fi - if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then - # Running the downloader - if [ "$MVNW_VERBOSE" = true ]; then - echo " - Running MavenWrapperDownloader.java ..." - fi - ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") - fi - fi - fi -fi -########################################################################################## -# End of extension -########################################################################################## - -export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} -if [ "$MVNW_VERBOSE" = true ]; then - echo $MAVEN_PROJECTBASEDIR -fi -MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" - -# For Cygwin, switch paths to Windows format before running java -if $cygwin; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --path --windows "$M2_HOME"` - [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` - [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --windows "$CLASSPATH"` - [ -n "$MAVEN_PROJECTBASEDIR" ] && - MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` -fi - -WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -exec "$JAVACMD" \ - $MAVEN_OPTS \ - -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ - "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ - ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/springboot-integration-examples/springboot-oss/mvnw.cmd b/springboot-integration-examples/springboot-oss/mvnw.cmd deleted file mode 100644 index fef5a8f7..00000000 --- a/springboot-integration-examples/springboot-oss/mvnw.cmd +++ /dev/null @@ -1,161 +0,0 @@ -@REM ---------------------------------------------------------------------------- -@REM Licensed to the Apache Software Foundation (ASF) under one -@REM or more contributor license agreements. See the NOTICE file -@REM distributed with this work for additional information -@REM regarding copyright ownership. The ASF licenses this file -@REM to you under the Apache License, Version 2.0 (the -@REM "License"); you may not use this file except in compliance -@REM with the License. You may obtain a copy of the License at -@REM -@REM https://www.apache.org/licenses/LICENSE-2.0 -@REM -@REM Unless required by applicable law or agreed to in writing, -@REM software distributed under the License is distributed on an -@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -@REM KIND, either express or implied. See the License for the -@REM specific language governing permissions and limitations -@REM under the License. -@REM ---------------------------------------------------------------------------- - -@REM ---------------------------------------------------------------------------- -@REM Maven2 Start Up Batch script -@REM -@REM Required ENV vars: -@REM JAVA_HOME - location of a JDK home dir -@REM -@REM Optional ENV vars -@REM M2_HOME - location of maven2's installed home dir -@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands -@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending -@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven -@REM e.g. to debug Maven itself, use -@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files -@REM ---------------------------------------------------------------------------- - -@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' -@echo off -@REM set title of command window -title %0 -@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' -@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% - -@REM set %HOME% to equivalent of $HOME -if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") - -@REM Execute a user defined script before this one -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre -@REM check for pre script, once with legacy .bat ending and once with .cmd ending -if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" -if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" -:skipRcPre - -@setlocal - -set ERROR_CODE=0 - -@REM To isolate internal variables from possible post scripts, we use another setlocal -@setlocal - -@REM ==== START VALIDATION ==== -if not "%JAVA_HOME%" == "" goto OkJHome - -echo. -echo Error: JAVA_HOME not found in your environment. >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -:OkJHome -if exist "%JAVA_HOME%\bin\java.exe" goto init - -echo. -echo Error: JAVA_HOME is set to an invalid directory. >&2 -echo JAVA_HOME = "%JAVA_HOME%" >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -@REM ==== END VALIDATION ==== - -:init - -@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". -@REM Fallback to current working directory if not found. - -set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% -IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir - -set EXEC_DIR=%CD% -set WDIR=%EXEC_DIR% -:findBaseDir -IF EXIST "%WDIR%"\.mvn goto baseDirFound -cd .. -IF "%WDIR%"=="%CD%" goto baseDirNotFound -set WDIR=%CD% -goto findBaseDir - -:baseDirFound -set MAVEN_PROJECTBASEDIR=%WDIR% -cd "%EXEC_DIR%" -goto endDetectBaseDir - -:baseDirNotFound -set MAVEN_PROJECTBASEDIR=%EXEC_DIR% -cd "%EXEC_DIR%" - -:endDetectBaseDir - -IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig - -@setlocal EnableExtensions EnableDelayedExpansion -for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a -@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% - -:endReadAdditionalConfig - -SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" -set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" -set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar" -FOR /F "tokens=1,2 delims==" %%A IN (%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties) DO ( - IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B -) - -@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -@REM This allows using the maven wrapper in projects that prohibit checking in binary data. -if exist %WRAPPER_JAR% ( - echo Found %WRAPPER_JAR% -) else ( - echo Couldn't find %WRAPPER_JAR%, downloading it ... - echo Downloading from: %DOWNLOAD_URL% - powershell -Command "(New-Object Net.WebClient).DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')" - echo Finished downloading %WRAPPER_JAR% -) -@REM End of extension - -%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* -if ERRORLEVEL 1 goto error -goto end - -:error -set ERROR_CODE=1 - -:end -@endlocal & set ERROR_CODE=%ERROR_CODE% - -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost -@REM check for post script, once with legacy .bat ending and once with .cmd ending -if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" -if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" -:skipRcPost - -@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' -if "%MAVEN_BATCH_PAUSE%" == "on" pause - -if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% - -exit /B %ERROR_CODE% diff --git a/springboot-integration-examples/springboot-oss/pom.xml b/springboot-integration-examples/springboot-oss/pom.xml deleted file mode 100644 index c34123bb..00000000 --- a/springboot-integration-examples/springboot-oss/pom.xml +++ /dev/null @@ -1,75 +0,0 @@ - - - 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 2.1.4.RELEASE - - - cn.lastwhisper - springbootoss - 0.0.1-SNAPSHOT - springbootoss - Demo project for Spring Boot - - - 1.8 - - - - - org.springframework.boot - spring-boot-starter-web - - - - org.springframework.boot - spring-boot-starter-test - test - - - - org.springframework.boot - spring-boot-devtools - true - - - - com.aliyun.oss - aliyun-sdk-oss - 2.8.3 - - - org.projectlombok - lombok - 1.18.4 - provided - - - joda-time - joda-time - 2.9.9 - - - - org.apache.commons - commons-lang3 - 3.8.1 - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - true - - - - - - diff --git a/springboot-integration-examples/springboot-oss/src/main/java/cn/lastwhisper/springbootoss/OssdemoApplication.java b/springboot-integration-examples/springboot-oss/src/main/java/cn/lastwhisper/springbootoss/OssdemoApplication.java deleted file mode 100644 index fb771ba2..00000000 --- a/springboot-integration-examples/springboot-oss/src/main/java/cn/lastwhisper/springbootoss/OssdemoApplication.java +++ /dev/null @@ -1,13 +0,0 @@ -package cn.lastwhisper.springbootoss; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class OssdemoApplication { - - public static void main(String[] args) { - SpringApplication.run(OssdemoApplication.class, args); - } - -} diff --git a/springboot-integration-examples/springboot-oss/src/main/java/cn/lastwhisper/springbootoss/config/AliyunConfig.java b/springboot-integration-examples/springboot-oss/src/main/java/cn/lastwhisper/springbootoss/config/AliyunConfig.java deleted file mode 100644 index 8e266c5e..00000000 --- a/springboot-integration-examples/springboot-oss/src/main/java/cn/lastwhisper/springbootoss/config/AliyunConfig.java +++ /dev/null @@ -1,31 +0,0 @@ -package cn.lastwhisper.springbootoss.config; - -import com.aliyun.oss.OSS; -import com.aliyun.oss.OSSClient; -import lombok.Data; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.PropertySource; -/** - * @desc - * - * @author lastwhisper - * @email gaojun56@163.com - */ -@Configuration -@PropertySource(value = {"classpath:application-oss.properties"}) -@ConfigurationProperties(prefix = "aliyun") -@Data -public class AliyunConfig { - private String endpoint; - private String accessKeyId; - private String accessKeySecret; - private String bucketName; - private String urlPrefix; - - @Bean - public OSS oSSClient() { - return new OSSClient(endpoint, accessKeyId, accessKeySecret); - } -} \ No newline at end of file diff --git a/springboot-integration-examples/springboot-oss/src/main/java/cn/lastwhisper/springbootoss/controller/FileUploadController.java b/springboot-integration-examples/springboot-oss/src/main/java/cn/lastwhisper/springbootoss/controller/FileUploadController.java deleted file mode 100644 index b8c2d821..00000000 --- a/springboot-integration-examples/springboot-oss/src/main/java/cn/lastwhisper/springbootoss/controller/FileUploadController.java +++ /dev/null @@ -1,82 +0,0 @@ -package cn.lastwhisper.springbootoss.controller; - -import cn.lastwhisper.springbootoss.service.FileUploadService; -import cn.lastwhisper.springbootoss.vo.FileUploadResult; -import com.aliyun.oss.model.OSSObjectSummary; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.multipart.MultipartFile; - -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.util.List; - -/** - * @author lastwhisper - * @desc - * @email gaojun56@163.com - */ -@Controller -public class FileUploadController { - @Autowired - private FileUploadService fileUploadService; - - /** - * @author lastwhisper - * @desc 文件上传到oss - * @return FileUploadResult - * @Param uploadFile - */ - @RequestMapping("file/upload") - @ResponseBody - public FileUploadResult upload(@RequestParam("file") MultipartFile uploadFile) - throws Exception { - return this.fileUploadService.upload(uploadFile); - } - - /** - * @return FileUploadResult - * @desc 根据文件名删除oss上的文件 - * http://localhost:8080/file/delete?fileName=images/2019/04/28/1556429167175766.jpg - * @author lastwhisper - * @Param objectName - */ - @RequestMapping("file/delete") - @ResponseBody - public FileUploadResult delete(@RequestParam("fileName") String objectName) - throws Exception { - return this.fileUploadService.delete(objectName); - } - - /** - * @author lastwhisper - * @desc 查询oss上的所有文件 - * http://localhost:8080/file/list - * @return List - * @Param - */ - @RequestMapping("file/list") - @ResponseBody - public List list() - throws Exception { - return this.fileUploadService.list(); - } - - /** - * @author lastwhisper - * @desc 根据文件名下载oss上的文件 - * @return - * @Param objectName - */ - @RequestMapping("file/download") - @ResponseBody - public void download(@RequestParam("fileName") String objectName, HttpServletResponse response) throws IOException { - //通知浏览器以附件形式下载 - response.setHeader("Content-Disposition", - "attachment;filename=" + new String(objectName.getBytes(), "ISO-8859-1")); - this.fileUploadService.exportOssFile(response.getOutputStream(),objectName); - } -} \ No newline at end of file diff --git a/springboot-integration-examples/springboot-oss/src/main/java/cn/lastwhisper/springbootoss/service/FileUploadService.java b/springboot-integration-examples/springboot-oss/src/main/java/cn/lastwhisper/springbootoss/service/FileUploadService.java deleted file mode 100644 index 245138a6..00000000 --- a/springboot-integration-examples/springboot-oss/src/main/java/cn/lastwhisper/springbootoss/service/FileUploadService.java +++ /dev/null @@ -1,145 +0,0 @@ -package cn.lastwhisper.springbootoss.service; - -import cn.lastwhisper.springbootoss.config.AliyunConfig; -import cn.lastwhisper.springbootoss.vo.FileUploadResult; -import com.aliyun.oss.OSS; -import com.aliyun.oss.model.*; -import org.apache.commons.lang3.RandomUtils; -import org.apache.commons.lang3.StringUtils; -import org.joda.time.DateTime; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.web.multipart.MultipartFile; - -import java.io.*; -import java.util.List; - -/** - * @author lastwhisper - * @desc - * @email gaojun56@163.com - */ -@Service -public class FileUploadService { - // 允许上传的格式 - private static final String[] IMAGE_TYPE = new String[]{".bmp", ".jpg", - ".jpeg", ".gif", ".png"}; - @Autowired - private OSS ossClient; - @Autowired - private AliyunConfig aliyunConfig; - - /** - * @author lastwhisper - * @desc 文件上传 - * 文档链接 https://help.aliyun.com/document_detail/84781.html?spm=a2c4g.11186623.6.749.11987a7dRYVSzn - * @email gaojun56@163.com - */ - public FileUploadResult upload(MultipartFile uploadFile) { - // 校验图片格式 - boolean isLegal = false; - for (String type : IMAGE_TYPE) { - if (StringUtils.endsWithIgnoreCase(uploadFile.getOriginalFilename(), - type)) { - isLegal = true; - break; - } - } - //封装Result对象,并且将文件的byte数组放置到result对象中 - FileUploadResult fileUploadResult = new FileUploadResult(); - if (!isLegal) { - fileUploadResult.setStatus("error"); - return fileUploadResult; - } - //文件新路径 - String fileName = uploadFile.getOriginalFilename(); - String filePath = getFilePath(fileName); - // 上传到阿里云 - try { - ossClient.putObject(aliyunConfig.getBucketName(), filePath, new - ByteArrayInputStream(uploadFile.getBytes())); - } catch (Exception e) { - e.printStackTrace(); - //上传失败 - fileUploadResult.setStatus("error"); - return fileUploadResult; - } - fileUploadResult.setStatus("done"); - fileUploadResult.setResponse("success"); - //this.aliyunConfig.getUrlPrefix() + filePath 文件路径需要保存到数据库 - fileUploadResult.setName(this.aliyunConfig.getUrlPrefix() + filePath); - fileUploadResult.setUid(String.valueOf(System.currentTimeMillis())); - return fileUploadResult; - } - - /** - * @author lastwhisper - * @desc 生成路径以及文件名 例如://images/2019/04/28/15564277465972939.jpg - * @email gaojun56@163.com - */ - private String getFilePath(String sourceFileName) { - DateTime dateTime = new DateTime(); - return "images/" + dateTime.toString("yyyy") - + "/" + dateTime.toString("MM") + "/" - + dateTime.toString("dd") + "/" + System.currentTimeMillis() + - RandomUtils.nextInt(100, 9999) + "." + - StringUtils.substringAfterLast(sourceFileName, "."); - } - - /** - * @author lastwhisper - * @desc 查看文件列表 - * 文档链接 https://help.aliyun.com/document_detail/84841.html?spm=a2c4g.11186623.2.13.3ad5b5ddqxWWRu#concept-84841-zh - * @email gaojun56@163.com - */ - public List list() { - // 设置最大个数。 - final int maxKeys = 200; - // 列举文件。 - ObjectListing objectListing = ossClient.listObjects(new ListObjectsRequest(aliyunConfig.getBucketName()).withMaxKeys(maxKeys)); - List sums = objectListing.getObjectSummaries(); - return sums; - } - - /** - * @author lastwhisper - * @desc 删除文件 - * 文档链接 https://help.aliyun.com/document_detail/84842.html?spm=a2c4g.11186623.6.770.4f9474b4UYlCtr - * @email gaojun56@163.com - */ - public FileUploadResult delete(String objectName) { - // 根据BucketName,objectName删除文件 - ossClient.deleteObject(aliyunConfig.getBucketName(), objectName); - FileUploadResult fileUploadResult = new FileUploadResult(); - fileUploadResult.setName(objectName); - fileUploadResult.setStatus("removed"); - fileUploadResult.setResponse("success"); - return fileUploadResult; - } - - /** - * @author lastwhisper - * @desc 下载文件 - * 文档链接 https://help.aliyun.com/document_detail/84823.html?spm=a2c4g.11186623.2.7.37836e84ZIuZaC#concept-84823-zh - * @email gaojun56@163.com - */ - public void exportOssFile(OutputStream os, String objectName) throws IOException { - // ossObject包含文件所在的存储空间名称、文件名称、文件元信息以及一个输入流。 - OSSObject ossObject = ossClient.getObject(aliyunConfig.getBucketName(), objectName); - // 读取文件内容。 - BufferedInputStream in = new BufferedInputStream(ossObject.getObjectContent()); - BufferedOutputStream out = new BufferedOutputStream(os); - byte[] buffer = new byte[1024]; - int lenght = 0; - while ((lenght = in.read(buffer)) != -1) { - out.write(buffer, 0, lenght); - } - if (out != null) { - out.flush(); - out.close(); - } - if (in != null) { - in.close(); - } - } -} diff --git a/springboot-integration-examples/springboot-oss/src/main/java/cn/lastwhisper/springbootoss/vo/FileUploadResult.java b/springboot-integration-examples/springboot-oss/src/main/java/cn/lastwhisper/springbootoss/vo/FileUploadResult.java deleted file mode 100644 index f45e5a87..00000000 --- a/springboot-integration-examples/springboot-oss/src/main/java/cn/lastwhisper/springbootoss/vo/FileUploadResult.java +++ /dev/null @@ -1,20 +0,0 @@ -package cn.lastwhisper.springbootoss.vo; - -import lombok.Data; - -/** - * @author lastwhisper - * @desc 用于前后端交互的返回值 - * @email gaojun56@163.com - */ -@Data -public class FileUploadResult { - // 文件唯一标识 - private String uid; - // 文件名 - private String name; - // 状态有:uploading done error removed - private String status; - // 服务端响应内容,如:'{"status": "success"}' - private String response; -} diff --git a/springboot-integration-examples/springboot-oss/src/main/resources/application-oss.properties b/springboot-integration-examples/springboot-oss/src/main/resources/application-oss.properties deleted file mode 100644 index 0a361027..00000000 --- a/springboot-integration-examples/springboot-oss/src/main/resources/application-oss.properties +++ /dev/null @@ -1,5 +0,0 @@ -aliyun.endpoint=oss-cn-shanghai.aliyuncs.com -aliyun.accessKeyId=LTAIHaqMtRfQjaUl -aliyun.accessKeySecret=xz3UyFUTHyqnBK9ZxGstQ6hMwrLclw -aliyun.bucketName=gaojun-testbucket -aliyun.urlPrefix=http://gaojun-testbucket.oss-cn-shanghai.aliyuncs.com/ diff --git a/springboot-integration-examples/springboot-oss/src/main/resources/application.properties b/springboot-integration-examples/springboot-oss/src/main/resources/application.properties deleted file mode 100644 index b10d3b5d..00000000 --- a/springboot-integration-examples/springboot-oss/src/main/resources/application.properties +++ /dev/null @@ -1,2 +0,0 @@ -spring.servlet.multipart.max-file-size=100MB -spring.servlet.multipart.max-request-size=1000MB \ No newline at end of file diff --git a/springboot-integration-examples/springboot-oss/src/main/resources/static/manager.html b/springboot-integration-examples/springboot-oss/src/main/resources/static/manager.html deleted file mode 100644 index d5c6d9f9..00000000 --- a/springboot-integration-examples/springboot-oss/src/main/resources/static/manager.html +++ /dev/null @@ -1,56 +0,0 @@ - - - - - oss文件管理 - - - - -单击下载oss上的图片、双击删除oss上的图片
-
- -
- - \ No newline at end of file diff --git a/springboot-integration-examples/springboot-oss/src/main/resources/static/upload.html b/springboot-integration-examples/springboot-oss/src/main/resources/static/upload.html deleted file mode 100644 index a858aa49..00000000 --- a/springboot-integration-examples/springboot-oss/src/main/resources/static/upload.html +++ /dev/null @@ -1,45 +0,0 @@ - - - - - - oss文件上传 - - - - -
   -    -
     -
-
-
- - \ No newline at end of file diff --git a/springboot-integration-examples/springboot-oss/src/test/java/cn/lastwhisper/springbootoss/OssdemoApplicationTests.java b/springboot-integration-examples/springboot-oss/src/test/java/cn/lastwhisper/springbootoss/OssdemoApplicationTests.java deleted file mode 100644 index 79ec8346..00000000 --- a/springboot-integration-examples/springboot-oss/src/test/java/cn/lastwhisper/springbootoss/OssdemoApplicationTests.java +++ /dev/null @@ -1,16 +0,0 @@ -package cn.lastwhisper.springbootoss; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit4.SpringRunner; - -@RunWith(SpringRunner.class) -@SpringBootTest -public class OssdemoApplicationTests { - - @Test - public void contextLoads() { - } - -} diff --git a/springboot-integration-examples/springboot-websocket/.gitignore b/springboot-integration-examples/springboot-websocket/.gitignore deleted file mode 100644 index 153c9335..00000000 --- a/springboot-integration-examples/springboot-websocket/.gitignore +++ /dev/null @@ -1,29 +0,0 @@ -HELP.md -/target/ -!.mvn/wrapper/maven-wrapper.jar - -### STS ### -.apt_generated -.classpath -.factorypath -.project -.settings -.springBeans -.sts4-cache - -### IntelliJ IDEA ### -.idea -*.iws -*.iml -*.ipr - -### NetBeans ### -/nbproject/private/ -/nbbuild/ -/dist/ -/nbdist/ -/.nb-gradle/ -/build/ - -### VS Code ### -.vscode/ diff --git a/springboot-integration-examples/springboot-websocket/.mvn/wrapper/MavenWrapperDownloader.java b/springboot-integration-examples/springboot-websocket/.mvn/wrapper/MavenWrapperDownloader.java deleted file mode 100644 index 7f91a56e..00000000 --- a/springboot-integration-examples/springboot-websocket/.mvn/wrapper/MavenWrapperDownloader.java +++ /dev/null @@ -1,114 +0,0 @@ -/* -Licensed to the Apache Software Foundation (ASF) under one -or more contributor license agreements. See the NOTICE file -distributed with this work for additional information -regarding copyright ownership. The ASF licenses this file -to you under the Apache License, Version 2.0 (the -"License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, -software distributed under the License is distributed on an -"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -KIND, either express or implied. See the License for the -specific language governing permissions and limitations -under the License. -*/ - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.net.URL; -import java.nio.channels.Channels; -import java.nio.channels.ReadableByteChannel; -import java.util.Properties; - -public class MavenWrapperDownloader { - - /** - * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. - */ - private static final String DEFAULT_DOWNLOAD_URL = - "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"; - - /** - * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to - * use instead of the default one. - */ - private static final String MAVEN_WRAPPER_PROPERTIES_PATH = - ".mvn/wrapper/maven-wrapper.properties"; - - /** - * Path where the maven-wrapper.jar will be saved to. - */ - private static final String MAVEN_WRAPPER_JAR_PATH = - ".mvn/wrapper/maven-wrapper.jar"; - - /** - * Name of the property which should be used to override the default download url for the wrapper. - */ - private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; - - public static void main(String args[]) { - System.out.println("- Downloader started"); - File baseDirectory = new File(args[0]); - System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); - - // If the maven-wrapper.properties exists, read it and check if it contains a custom - // wrapperUrl parameter. - File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); - String url = DEFAULT_DOWNLOAD_URL; - if (mavenWrapperPropertyFile.exists()) { - FileInputStream mavenWrapperPropertyFileInputStream = null; - try { - mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); - Properties mavenWrapperProperties = new Properties(); - mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); - url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); - } catch (IOException e) { - System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); - } finally { - try { - if (mavenWrapperPropertyFileInputStream != null) { - mavenWrapperPropertyFileInputStream.close(); - } - } catch (IOException e) { - // Ignore ... - } - } - } - System.out.println("- Downloading from: : " + url); - - File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); - if (!outputFile.getParentFile().exists()) { - if (!outputFile.getParentFile().mkdirs()) { - System.out.println( - "- ERROR creating output direcrory '" + outputFile.getParentFile().getAbsolutePath() + "'"); - } - } - System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); - try { - downloadFileFromURL(url, outputFile); - System.out.println("Done"); - System.exit(0); - } catch (Throwable e) { - System.out.println("- Error downloading"); - e.printStackTrace(); - System.exit(1); - } - } - - private static void downloadFileFromURL(String urlString, File destination) throws Exception { - URL website = new URL(urlString); - ReadableByteChannel rbc; - rbc = Channels.newChannel(website.openStream()); - FileOutputStream fos = new FileOutputStream(destination); - fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); - fos.close(); - rbc.close(); - } - -} diff --git a/springboot-integration-examples/springboot-websocket/.mvn/wrapper/maven-wrapper.jar b/springboot-integration-examples/springboot-websocket/.mvn/wrapper/maven-wrapper.jar deleted file mode 100644 index 01e67997..00000000 Binary files a/springboot-integration-examples/springboot-websocket/.mvn/wrapper/maven-wrapper.jar and /dev/null differ diff --git a/springboot-integration-examples/springboot-websocket/.mvn/wrapper/maven-wrapper.properties b/springboot-integration-examples/springboot-websocket/.mvn/wrapper/maven-wrapper.properties deleted file mode 100644 index cd0d451c..00000000 --- a/springboot-integration-examples/springboot-websocket/.mvn/wrapper/maven-wrapper.properties +++ /dev/null @@ -1 +0,0 @@ -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip diff --git a/springboot-integration-examples/springboot-websocket/mvnw b/springboot-integration-examples/springboot-websocket/mvnw deleted file mode 100644 index 8b9da3b8..00000000 --- a/springboot-integration-examples/springboot-websocket/mvnw +++ /dev/null @@ -1,286 +0,0 @@ -#!/bin/sh -# ---------------------------------------------------------------------------- -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# ---------------------------------------------------------------------------- - -# ---------------------------------------------------------------------------- -# Maven2 Start Up Batch script -# -# Required ENV vars: -# ------------------ -# JAVA_HOME - location of a JDK home dir -# -# Optional ENV vars -# ----------------- -# M2_HOME - location of maven2's installed home dir -# MAVEN_OPTS - parameters passed to the Java VM when running Maven -# e.g. to debug Maven itself, use -# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -# MAVEN_SKIP_RC - flag to disable loading of mavenrc files -# ---------------------------------------------------------------------------- - -if [ -z "$MAVEN_SKIP_RC" ] ; then - - if [ -f /etc/mavenrc ] ; then - . /etc/mavenrc - fi - - if [ -f "$HOME/.mavenrc" ] ; then - . "$HOME/.mavenrc" - fi - -fi - -# OS specific support. $var _must_ be set to either true or false. -cygwin=false; -darwin=false; -mingw=false -case "`uname`" in - CYGWIN*) cygwin=true ;; - MINGW*) mingw=true;; - Darwin*) darwin=true - # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home - # See https://developer.apple.com/library/mac/qa/qa1170/_index.html - if [ -z "$JAVA_HOME" ]; then - if [ -x "/usr/libexec/java_home" ]; then - export JAVA_HOME="`/usr/libexec/java_home`" - else - export JAVA_HOME="/Library/Java/Home" - fi - fi - ;; -esac - -if [ -z "$JAVA_HOME" ] ; then - if [ -r /etc/gentoo-release ] ; then - JAVA_HOME=`java-config --jre-home` - fi -fi - -if [ -z "$M2_HOME" ] ; then - ## resolve links - $0 may be a link to maven's home - PRG="$0" - - # need this for relative symlinks - while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG="`dirname "$PRG"`/$link" - fi - done - - saveddir=`pwd` - - M2_HOME=`dirname "$PRG"`/.. - - # make it fully qualified - M2_HOME=`cd "$M2_HOME" && pwd` - - cd "$saveddir" - # echo Using m2 at $M2_HOME -fi - -# For Cygwin, ensure paths are in UNIX format before anything is touched -if $cygwin ; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --unix "$M2_HOME"` - [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --unix "$JAVA_HOME"` - [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --unix "$CLASSPATH"` -fi - -# For Mingw, ensure paths are in UNIX format before anything is touched -if $mingw ; then - [ -n "$M2_HOME" ] && - M2_HOME="`(cd "$M2_HOME"; pwd)`" - [ -n "$JAVA_HOME" ] && - JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" - # TODO classpath? -fi - -if [ -z "$JAVA_HOME" ]; then - javaExecutable="`which javac`" - if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then - # readlink(1) is not available as standard on Solaris 10. - readLink=`which readlink` - if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then - if $darwin ; then - javaHome="`dirname \"$javaExecutable\"`" - javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" - else - javaExecutable="`readlink -f \"$javaExecutable\"`" - fi - javaHome="`dirname \"$javaExecutable\"`" - javaHome=`expr "$javaHome" : '\(.*\)/bin'` - JAVA_HOME="$javaHome" - export JAVA_HOME - fi - fi -fi - -if [ -z "$JAVACMD" ] ; then - if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - else - JAVACMD="`which java`" - fi -fi - -if [ ! -x "$JAVACMD" ] ; then - echo "Error: JAVA_HOME is not defined correctly." >&2 - echo " We cannot execute $JAVACMD" >&2 - exit 1 -fi - -if [ -z "$JAVA_HOME" ] ; then - echo "Warning: JAVA_HOME environment variable is not set." -fi - -CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher - -# traverses directory structure from process work directory to filesystem root -# first directory with .mvn subdirectory is considered project base directory -find_maven_basedir() { - - if [ -z "$1" ] - then - echo "Path not specified to find_maven_basedir" - return 1 - fi - - basedir="$1" - wdir="$1" - while [ "$wdir" != '/' ] ; do - if [ -d "$wdir"/.mvn ] ; then - basedir=$wdir - break - fi - # workaround for JBEAP-8937 (on Solaris 10/Sparc) - if [ -d "${wdir}" ]; then - wdir=`cd "$wdir/.."; pwd` - fi - # end of workaround - done - echo "${basedir}" -} - -# concatenates all lines of a file -concat_lines() { - if [ -f "$1" ]; then - echo "$(tr -s '\n' ' ' < "$1")" - fi -} - -BASE_DIR=`find_maven_basedir "$(pwd)"` -if [ -z "$BASE_DIR" ]; then - exit 1; -fi - -########################################################################################## -# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -# This allows using the maven wrapper in projects that prohibit checking in binary data. -########################################################################################## -if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found .mvn/wrapper/maven-wrapper.jar" - fi -else - if [ "$MVNW_VERBOSE" = true ]; then - echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." - fi - jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar" - while IFS="=" read key value; do - case "$key" in (wrapperUrl) jarUrl="$value"; break ;; - esac - done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" - if [ "$MVNW_VERBOSE" = true ]; then - echo "Downloading from: $jarUrl" - fi - wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" - - if command -v wget > /dev/null; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found wget ... using wget" - fi - wget "$jarUrl" -O "$wrapperJarPath" - elif command -v curl > /dev/null; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found curl ... using curl" - fi - curl -o "$wrapperJarPath" "$jarUrl" - else - if [ "$MVNW_VERBOSE" = true ]; then - echo "Falling back to using Java to download" - fi - javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" - if [ -e "$javaClass" ]; then - if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then - if [ "$MVNW_VERBOSE" = true ]; then - echo " - Compiling MavenWrapperDownloader.java ..." - fi - # Compiling the Java class - ("$JAVA_HOME/bin/javac" "$javaClass") - fi - if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then - # Running the downloader - if [ "$MVNW_VERBOSE" = true ]; then - echo " - Running MavenWrapperDownloader.java ..." - fi - ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") - fi - fi - fi -fi -########################################################################################## -# End of extension -########################################################################################## - -export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} -if [ "$MVNW_VERBOSE" = true ]; then - echo $MAVEN_PROJECTBASEDIR -fi -MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" - -# For Cygwin, switch paths to Windows format before running java -if $cygwin; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --path --windows "$M2_HOME"` - [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` - [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --windows "$CLASSPATH"` - [ -n "$MAVEN_PROJECTBASEDIR" ] && - MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` -fi - -WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -exec "$JAVACMD" \ - $MAVEN_OPTS \ - -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ - "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ - ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/springboot-integration-examples/springboot-websocket/mvnw.cmd b/springboot-integration-examples/springboot-websocket/mvnw.cmd deleted file mode 100644 index fef5a8f7..00000000 --- a/springboot-integration-examples/springboot-websocket/mvnw.cmd +++ /dev/null @@ -1,161 +0,0 @@ -@REM ---------------------------------------------------------------------------- -@REM Licensed to the Apache Software Foundation (ASF) under one -@REM or more contributor license agreements. See the NOTICE file -@REM distributed with this work for additional information -@REM regarding copyright ownership. The ASF licenses this file -@REM to you under the Apache License, Version 2.0 (the -@REM "License"); you may not use this file except in compliance -@REM with the License. You may obtain a copy of the License at -@REM -@REM https://www.apache.org/licenses/LICENSE-2.0 -@REM -@REM Unless required by applicable law or agreed to in writing, -@REM software distributed under the License is distributed on an -@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -@REM KIND, either express or implied. See the License for the -@REM specific language governing permissions and limitations -@REM under the License. -@REM ---------------------------------------------------------------------------- - -@REM ---------------------------------------------------------------------------- -@REM Maven2 Start Up Batch script -@REM -@REM Required ENV vars: -@REM JAVA_HOME - location of a JDK home dir -@REM -@REM Optional ENV vars -@REM M2_HOME - location of maven2's installed home dir -@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands -@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending -@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven -@REM e.g. to debug Maven itself, use -@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files -@REM ---------------------------------------------------------------------------- - -@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' -@echo off -@REM set title of command window -title %0 -@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' -@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% - -@REM set %HOME% to equivalent of $HOME -if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") - -@REM Execute a user defined script before this one -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre -@REM check for pre script, once with legacy .bat ending and once with .cmd ending -if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" -if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" -:skipRcPre - -@setlocal - -set ERROR_CODE=0 - -@REM To isolate internal variables from possible post scripts, we use another setlocal -@setlocal - -@REM ==== START VALIDATION ==== -if not "%JAVA_HOME%" == "" goto OkJHome - -echo. -echo Error: JAVA_HOME not found in your environment. >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -:OkJHome -if exist "%JAVA_HOME%\bin\java.exe" goto init - -echo. -echo Error: JAVA_HOME is set to an invalid directory. >&2 -echo JAVA_HOME = "%JAVA_HOME%" >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -@REM ==== END VALIDATION ==== - -:init - -@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". -@REM Fallback to current working directory if not found. - -set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% -IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir - -set EXEC_DIR=%CD% -set WDIR=%EXEC_DIR% -:findBaseDir -IF EXIST "%WDIR%"\.mvn goto baseDirFound -cd .. -IF "%WDIR%"=="%CD%" goto baseDirNotFound -set WDIR=%CD% -goto findBaseDir - -:baseDirFound -set MAVEN_PROJECTBASEDIR=%WDIR% -cd "%EXEC_DIR%" -goto endDetectBaseDir - -:baseDirNotFound -set MAVEN_PROJECTBASEDIR=%EXEC_DIR% -cd "%EXEC_DIR%" - -:endDetectBaseDir - -IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig - -@setlocal EnableExtensions EnableDelayedExpansion -for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a -@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% - -:endReadAdditionalConfig - -SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" -set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" -set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar" -FOR /F "tokens=1,2 delims==" %%A IN (%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties) DO ( - IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B -) - -@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -@REM This allows using the maven wrapper in projects that prohibit checking in binary data. -if exist %WRAPPER_JAR% ( - echo Found %WRAPPER_JAR% -) else ( - echo Couldn't find %WRAPPER_JAR%, downloading it ... - echo Downloading from: %DOWNLOAD_URL% - powershell -Command "(New-Object Net.WebClient).DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')" - echo Finished downloading %WRAPPER_JAR% -) -@REM End of extension - -%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* -if ERRORLEVEL 1 goto error -goto end - -:error -set ERROR_CODE=1 - -:end -@endlocal & set ERROR_CODE=%ERROR_CODE% - -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost -@REM check for post script, once with legacy .bat ending and once with .cmd ending -if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" -if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" -:skipRcPost - -@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' -if "%MAVEN_BATCH_PAUSE%" == "on" pause - -if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% - -exit /B %ERROR_CODE% diff --git a/springboot-integration-examples/springboot-websocket/pom.xml b/springboot-integration-examples/springboot-websocket/pom.xml deleted file mode 100644 index 44ccb431..00000000 --- a/springboot-integration-examples/springboot-websocket/pom.xml +++ /dev/null @@ -1,55 +0,0 @@ - - - 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 2.1.5.RELEASE - - - cn.lastwhisper - springboot-websocket - 0.0.1-SNAPSHOT - springboot-websocket - Demo project for websocket - - - 1.8 - - - - - org.springframework.boot - spring-boot-starter-websocket - - - - org.springframework.boot - spring-boot-starter-test - test - - - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.2 - - 1.8 - 1.8 - UTF-8 - - - - org.springframework.boot - spring-boot-maven-plugin - - - - - diff --git a/springboot-integration-examples/springboot-websocket/src/main/java/cn/lastwhisper/springbootwebsocket/SpringbootWebsocketApplication.java b/springboot-integration-examples/springboot-websocket/src/main/java/cn/lastwhisper/springbootwebsocket/SpringbootWebsocketApplication.java deleted file mode 100644 index cf2b337f..00000000 --- a/springboot-integration-examples/springboot-websocket/src/main/java/cn/lastwhisper/springbootwebsocket/SpringbootWebsocketApplication.java +++ /dev/null @@ -1,13 +0,0 @@ -package cn.lastwhisper.springbootwebsocket; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class SpringbootWebsocketApplication { - - public static void main(String[] args) { - SpringApplication.run(SpringbootWebsocketApplication.class, args); - } - -} diff --git a/springboot-integration-examples/springboot-websocket/src/main/java/cn/lastwhisper/springbootwebsocket/spring/MyHandler.java b/springboot-integration-examples/springboot-websocket/src/main/java/cn/lastwhisper/springbootwebsocket/spring/MyHandler.java deleted file mode 100644 index e12ba84e..00000000 --- a/springboot-integration-examples/springboot-websocket/src/main/java/cn/lastwhisper/springbootwebsocket/spring/MyHandler.java +++ /dev/null @@ -1,41 +0,0 @@ -package cn.lastwhisper.springbootwebsocket.spring; - -import org.springframework.web.socket.CloseStatus; -import org.springframework.web.socket.TextMessage; -import org.springframework.web.socket.WebSocketSession; -import org.springframework.web.socket.handler.TextWebSocketHandler; - -/** - * @author lastwhisper - * @desc - */ -public class MyHandler extends TextWebSocketHandler { - @Override - protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception { - System.out.println("获取到消息 >> " + message.getPayload()); - - session.sendMessage(new TextMessage("消息已收到")); - if (message.getPayload().equals("10")) { - for (int i = 0; i < 10; i++) { - session.sendMessage(new TextMessage("消息 -> " + i)); - Thread.sleep(100); - } - } - } - /** - * @author lastwhisper - * @desc - * @param session - * @return void - */ - @Override - public void afterConnectionEstablished(WebSocketSession session) throws Exception { - Integer uid = (Integer) session.getAttributes().get("uid"); - session.sendMessage(new TextMessage(uid+", 你好!欢迎连接到ws服务")); - } - - @Override - public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception { - System.out.println("断开连接!"); - } -} diff --git a/springboot-integration-examples/springboot-websocket/src/main/java/cn/lastwhisper/springbootwebsocket/spring/MyHandshakeInterceptor.java b/springboot-integration-examples/springboot-websocket/src/main/java/cn/lastwhisper/springbootwebsocket/spring/MyHandshakeInterceptor.java deleted file mode 100644 index c859997d..00000000 --- a/springboot-integration-examples/springboot-websocket/src/main/java/cn/lastwhisper/springbootwebsocket/spring/MyHandshakeInterceptor.java +++ /dev/null @@ -1,40 +0,0 @@ -package cn.lastwhisper.springbootwebsocket.spring; - -import org.springframework.http.server.ServerHttpRequest; -import org.springframework.http.server.ServerHttpResponse; -import org.springframework.stereotype.Component; -import org.springframework.web.socket.WebSocketHandler; -import org.springframework.web.socket.server.HandshakeInterceptor; - -import java.util.Map; - -/** - * @author lastwhisper - * @desc - */ -@Component -public class MyHandshakeInterceptor implements HandshakeInterceptor { - /** - * @author lastwhisper - * @desc 握手之前,若返回false,则不建立链接 - * @param request - * @param response - * @param wsHandler - * @param attributes - * @return boolean - */ - @Override - public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse - response, WebSocketHandler wsHandler, Map attributes) throws - Exception { - //将用户id放入socket处理器的会话(WebSocketSession)中 - attributes.put("uid", 1001); - System.out.println("开始握手。。。。。。。"); - return true; - } - - @Override - public void afterHandshake(ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse, WebSocketHandler webSocketHandler, Exception e) { - System.out.println("握手成功啦。。。。。。"); - } -} diff --git a/springboot-integration-examples/springboot-websocket/src/main/java/cn/lastwhisper/springbootwebsocket/spring/WebSocketConfig.java b/springboot-integration-examples/springboot-websocket/src/main/java/cn/lastwhisper/springbootwebsocket/spring/WebSocketConfig.java deleted file mode 100644 index 82d7cea0..00000000 --- a/springboot-integration-examples/springboot-websocket/src/main/java/cn/lastwhisper/springbootwebsocket/spring/WebSocketConfig.java +++ /dev/null @@ -1,33 +0,0 @@ -package cn.lastwhisper.springbootwebsocket.spring; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.web.socket.WebSocketHandler; -import org.springframework.web.socket.config.annotation.EnableWebSocket; -import org.springframework.web.socket.config.annotation.WebSocketConfigurer; -import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry; - -/** - * @author lastwhisper - * @desc - */ -@Configuration -@EnableWebSocket -public class WebSocketConfig implements WebSocketConfigurer { - - @Autowired - private MyHandshakeInterceptor myHandshakeInterceptor; - - @Override - public void registerWebSocketHandlers(WebSocketHandlerRegistry webSocketHandlerRegistry) { - webSocketHandlerRegistry.addHandler(myHandler(), "/ws") - .setAllowedOrigins("*") - .addInterceptors(myHandshakeInterceptor); - } - - @Bean - public WebSocketHandler myHandler() { - return new MyHandler(); - } -} diff --git a/springboot-integration-examples/springboot-websocket/src/main/resources/application.properties b/springboot-integration-examples/springboot-websocket/src/main/resources/application.properties deleted file mode 100644 index 712b6c53..00000000 --- a/springboot-integration-examples/springboot-websocket/src/main/resources/application.properties +++ /dev/null @@ -1 +0,0 @@ -server.port=9501 \ No newline at end of file diff --git a/springboot-integration-examples/springboot-websocket/src/test/java/cn/lastwhisper/springbootwebsocket/SpringbootWebsocketApplicationTests.java b/springboot-integration-examples/springboot-websocket/src/test/java/cn/lastwhisper/springbootwebsocket/SpringbootWebsocketApplicationTests.java deleted file mode 100644 index 02613926..00000000 --- a/springboot-integration-examples/springboot-websocket/src/test/java/cn/lastwhisper/springbootwebsocket/SpringbootWebsocketApplicationTests.java +++ /dev/null @@ -1,16 +0,0 @@ -package cn.lastwhisper.springbootwebsocket; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit4.SpringRunner; - -@RunWith(SpringRunner.class) -@SpringBootTest -public class SpringbootWebsocketApplicationTests { - - @Test - public void contextLoads() { - } - -} diff --git a/springboot-integration-examples/springboot-wx/.gitignore b/springboot-integration-examples/springboot-wx/.gitignore deleted file mode 100644 index 153c9335..00000000 --- a/springboot-integration-examples/springboot-wx/.gitignore +++ /dev/null @@ -1,29 +0,0 @@ -HELP.md -/target/ -!.mvn/wrapper/maven-wrapper.jar - -### STS ### -.apt_generated -.classpath -.factorypath -.project -.settings -.springBeans -.sts4-cache - -### IntelliJ IDEA ### -.idea -*.iws -*.iml -*.ipr - -### NetBeans ### -/nbproject/private/ -/nbbuild/ -/dist/ -/nbdist/ -/.nb-gradle/ -/build/ - -### VS Code ### -.vscode/ diff --git a/springboot-integration-examples/springboot-wx/.mvn/wrapper/MavenWrapperDownloader.java b/springboot-integration-examples/springboot-wx/.mvn/wrapper/MavenWrapperDownloader.java deleted file mode 100644 index 7f91a56e..00000000 --- a/springboot-integration-examples/springboot-wx/.mvn/wrapper/MavenWrapperDownloader.java +++ /dev/null @@ -1,114 +0,0 @@ -/* -Licensed to the Apache Software Foundation (ASF) under one -or more contributor license agreements. See the NOTICE file -distributed with this work for additional information -regarding copyright ownership. The ASF licenses this file -to you under the Apache License, Version 2.0 (the -"License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, -software distributed under the License is distributed on an -"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -KIND, either express or implied. See the License for the -specific language governing permissions and limitations -under the License. -*/ - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.net.URL; -import java.nio.channels.Channels; -import java.nio.channels.ReadableByteChannel; -import java.util.Properties; - -public class MavenWrapperDownloader { - - /** - * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. - */ - private static final String DEFAULT_DOWNLOAD_URL = - "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"; - - /** - * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to - * use instead of the default one. - */ - private static final String MAVEN_WRAPPER_PROPERTIES_PATH = - ".mvn/wrapper/maven-wrapper.properties"; - - /** - * Path where the maven-wrapper.jar will be saved to. - */ - private static final String MAVEN_WRAPPER_JAR_PATH = - ".mvn/wrapper/maven-wrapper.jar"; - - /** - * Name of the property which should be used to override the default download url for the wrapper. - */ - private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; - - public static void main(String args[]) { - System.out.println("- Downloader started"); - File baseDirectory = new File(args[0]); - System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); - - // If the maven-wrapper.properties exists, read it and check if it contains a custom - // wrapperUrl parameter. - File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); - String url = DEFAULT_DOWNLOAD_URL; - if (mavenWrapperPropertyFile.exists()) { - FileInputStream mavenWrapperPropertyFileInputStream = null; - try { - mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); - Properties mavenWrapperProperties = new Properties(); - mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); - url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); - } catch (IOException e) { - System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); - } finally { - try { - if (mavenWrapperPropertyFileInputStream != null) { - mavenWrapperPropertyFileInputStream.close(); - } - } catch (IOException e) { - // Ignore ... - } - } - } - System.out.println("- Downloading from: : " + url); - - File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); - if (!outputFile.getParentFile().exists()) { - if (!outputFile.getParentFile().mkdirs()) { - System.out.println( - "- ERROR creating output direcrory '" + outputFile.getParentFile().getAbsolutePath() + "'"); - } - } - System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); - try { - downloadFileFromURL(url, outputFile); - System.out.println("Done"); - System.exit(0); - } catch (Throwable e) { - System.out.println("- Error downloading"); - e.printStackTrace(); - System.exit(1); - } - } - - private static void downloadFileFromURL(String urlString, File destination) throws Exception { - URL website = new URL(urlString); - ReadableByteChannel rbc; - rbc = Channels.newChannel(website.openStream()); - FileOutputStream fos = new FileOutputStream(destination); - fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); - fos.close(); - rbc.close(); - } - -} diff --git a/springboot-integration-examples/springboot-wx/.mvn/wrapper/maven-wrapper.jar b/springboot-integration-examples/springboot-wx/.mvn/wrapper/maven-wrapper.jar deleted file mode 100644 index 01e67997..00000000 Binary files a/springboot-integration-examples/springboot-wx/.mvn/wrapper/maven-wrapper.jar and /dev/null differ diff --git a/springboot-integration-examples/springboot-wx/.mvn/wrapper/maven-wrapper.properties b/springboot-integration-examples/springboot-wx/.mvn/wrapper/maven-wrapper.properties deleted file mode 100644 index cd0d451c..00000000 --- a/springboot-integration-examples/springboot-wx/.mvn/wrapper/maven-wrapper.properties +++ /dev/null @@ -1 +0,0 @@ -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip diff --git a/springboot-integration-examples/springboot-wx/mvnw b/springboot-integration-examples/springboot-wx/mvnw deleted file mode 100644 index 8b9da3b8..00000000 --- a/springboot-integration-examples/springboot-wx/mvnw +++ /dev/null @@ -1,286 +0,0 @@ -#!/bin/sh -# ---------------------------------------------------------------------------- -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# ---------------------------------------------------------------------------- - -# ---------------------------------------------------------------------------- -# Maven2 Start Up Batch script -# -# Required ENV vars: -# ------------------ -# JAVA_HOME - location of a JDK home dir -# -# Optional ENV vars -# ----------------- -# M2_HOME - location of maven2's installed home dir -# MAVEN_OPTS - parameters passed to the Java VM when running Maven -# e.g. to debug Maven itself, use -# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -# MAVEN_SKIP_RC - flag to disable loading of mavenrc files -# ---------------------------------------------------------------------------- - -if [ -z "$MAVEN_SKIP_RC" ] ; then - - if [ -f /etc/mavenrc ] ; then - . /etc/mavenrc - fi - - if [ -f "$HOME/.mavenrc" ] ; then - . "$HOME/.mavenrc" - fi - -fi - -# OS specific support. $var _must_ be set to either true or false. -cygwin=false; -darwin=false; -mingw=false -case "`uname`" in - CYGWIN*) cygwin=true ;; - MINGW*) mingw=true;; - Darwin*) darwin=true - # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home - # See https://developer.apple.com/library/mac/qa/qa1170/_index.html - if [ -z "$JAVA_HOME" ]; then - if [ -x "/usr/libexec/java_home" ]; then - export JAVA_HOME="`/usr/libexec/java_home`" - else - export JAVA_HOME="/Library/Java/Home" - fi - fi - ;; -esac - -if [ -z "$JAVA_HOME" ] ; then - if [ -r /etc/gentoo-release ] ; then - JAVA_HOME=`java-config --jre-home` - fi -fi - -if [ -z "$M2_HOME" ] ; then - ## resolve links - $0 may be a link to maven's home - PRG="$0" - - # need this for relative symlinks - while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG="`dirname "$PRG"`/$link" - fi - done - - saveddir=`pwd` - - M2_HOME=`dirname "$PRG"`/.. - - # make it fully qualified - M2_HOME=`cd "$M2_HOME" && pwd` - - cd "$saveddir" - # echo Using m2 at $M2_HOME -fi - -# For Cygwin, ensure paths are in UNIX format before anything is touched -if $cygwin ; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --unix "$M2_HOME"` - [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --unix "$JAVA_HOME"` - [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --unix "$CLASSPATH"` -fi - -# For Mingw, ensure paths are in UNIX format before anything is touched -if $mingw ; then - [ -n "$M2_HOME" ] && - M2_HOME="`(cd "$M2_HOME"; pwd)`" - [ -n "$JAVA_HOME" ] && - JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" - # TODO classpath? -fi - -if [ -z "$JAVA_HOME" ]; then - javaExecutable="`which javac`" - if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then - # readlink(1) is not available as standard on Solaris 10. - readLink=`which readlink` - if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then - if $darwin ; then - javaHome="`dirname \"$javaExecutable\"`" - javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" - else - javaExecutable="`readlink -f \"$javaExecutable\"`" - fi - javaHome="`dirname \"$javaExecutable\"`" - javaHome=`expr "$javaHome" : '\(.*\)/bin'` - JAVA_HOME="$javaHome" - export JAVA_HOME - fi - fi -fi - -if [ -z "$JAVACMD" ] ; then - if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - else - JAVACMD="`which java`" - fi -fi - -if [ ! -x "$JAVACMD" ] ; then - echo "Error: JAVA_HOME is not defined correctly." >&2 - echo " We cannot execute $JAVACMD" >&2 - exit 1 -fi - -if [ -z "$JAVA_HOME" ] ; then - echo "Warning: JAVA_HOME environment variable is not set." -fi - -CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher - -# traverses directory structure from process work directory to filesystem root -# first directory with .mvn subdirectory is considered project base directory -find_maven_basedir() { - - if [ -z "$1" ] - then - echo "Path not specified to find_maven_basedir" - return 1 - fi - - basedir="$1" - wdir="$1" - while [ "$wdir" != '/' ] ; do - if [ -d "$wdir"/.mvn ] ; then - basedir=$wdir - break - fi - # workaround for JBEAP-8937 (on Solaris 10/Sparc) - if [ -d "${wdir}" ]; then - wdir=`cd "$wdir/.."; pwd` - fi - # end of workaround - done - echo "${basedir}" -} - -# concatenates all lines of a file -concat_lines() { - if [ -f "$1" ]; then - echo "$(tr -s '\n' ' ' < "$1")" - fi -} - -BASE_DIR=`find_maven_basedir "$(pwd)"` -if [ -z "$BASE_DIR" ]; then - exit 1; -fi - -########################################################################################## -# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -# This allows using the maven wrapper in projects that prohibit checking in binary data. -########################################################################################## -if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found .mvn/wrapper/maven-wrapper.jar" - fi -else - if [ "$MVNW_VERBOSE" = true ]; then - echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." - fi - jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar" - while IFS="=" read key value; do - case "$key" in (wrapperUrl) jarUrl="$value"; break ;; - esac - done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" - if [ "$MVNW_VERBOSE" = true ]; then - echo "Downloading from: $jarUrl" - fi - wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" - - if command -v wget > /dev/null; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found wget ... using wget" - fi - wget "$jarUrl" -O "$wrapperJarPath" - elif command -v curl > /dev/null; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found curl ... using curl" - fi - curl -o "$wrapperJarPath" "$jarUrl" - else - if [ "$MVNW_VERBOSE" = true ]; then - echo "Falling back to using Java to download" - fi - javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" - if [ -e "$javaClass" ]; then - if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then - if [ "$MVNW_VERBOSE" = true ]; then - echo " - Compiling MavenWrapperDownloader.java ..." - fi - # Compiling the Java class - ("$JAVA_HOME/bin/javac" "$javaClass") - fi - if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then - # Running the downloader - if [ "$MVNW_VERBOSE" = true ]; then - echo " - Running MavenWrapperDownloader.java ..." - fi - ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") - fi - fi - fi -fi -########################################################################################## -# End of extension -########################################################################################## - -export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} -if [ "$MVNW_VERBOSE" = true ]; then - echo $MAVEN_PROJECTBASEDIR -fi -MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" - -# For Cygwin, switch paths to Windows format before running java -if $cygwin; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --path --windows "$M2_HOME"` - [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` - [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --windows "$CLASSPATH"` - [ -n "$MAVEN_PROJECTBASEDIR" ] && - MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` -fi - -WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -exec "$JAVACMD" \ - $MAVEN_OPTS \ - -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ - "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ - ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/springboot-integration-examples/springboot-wx/mvnw.cmd b/springboot-integration-examples/springboot-wx/mvnw.cmd deleted file mode 100644 index fef5a8f7..00000000 --- a/springboot-integration-examples/springboot-wx/mvnw.cmd +++ /dev/null @@ -1,161 +0,0 @@ -@REM ---------------------------------------------------------------------------- -@REM Licensed to the Apache Software Foundation (ASF) under one -@REM or more contributor license agreements. See the NOTICE file -@REM distributed with this work for additional information -@REM regarding copyright ownership. The ASF licenses this file -@REM to you under the Apache License, Version 2.0 (the -@REM "License"); you may not use this file except in compliance -@REM with the License. You may obtain a copy of the License at -@REM -@REM https://www.apache.org/licenses/LICENSE-2.0 -@REM -@REM Unless required by applicable law or agreed to in writing, -@REM software distributed under the License is distributed on an -@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -@REM KIND, either express or implied. See the License for the -@REM specific language governing permissions and limitations -@REM under the License. -@REM ---------------------------------------------------------------------------- - -@REM ---------------------------------------------------------------------------- -@REM Maven2 Start Up Batch script -@REM -@REM Required ENV vars: -@REM JAVA_HOME - location of a JDK home dir -@REM -@REM Optional ENV vars -@REM M2_HOME - location of maven2's installed home dir -@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands -@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending -@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven -@REM e.g. to debug Maven itself, use -@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files -@REM ---------------------------------------------------------------------------- - -@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' -@echo off -@REM set title of command window -title %0 -@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' -@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% - -@REM set %HOME% to equivalent of $HOME -if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") - -@REM Execute a user defined script before this one -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre -@REM check for pre script, once with legacy .bat ending and once with .cmd ending -if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" -if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" -:skipRcPre - -@setlocal - -set ERROR_CODE=0 - -@REM To isolate internal variables from possible post scripts, we use another setlocal -@setlocal - -@REM ==== START VALIDATION ==== -if not "%JAVA_HOME%" == "" goto OkJHome - -echo. -echo Error: JAVA_HOME not found in your environment. >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -:OkJHome -if exist "%JAVA_HOME%\bin\java.exe" goto init - -echo. -echo Error: JAVA_HOME is set to an invalid directory. >&2 -echo JAVA_HOME = "%JAVA_HOME%" >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -@REM ==== END VALIDATION ==== - -:init - -@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". -@REM Fallback to current working directory if not found. - -set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% -IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir - -set EXEC_DIR=%CD% -set WDIR=%EXEC_DIR% -:findBaseDir -IF EXIST "%WDIR%"\.mvn goto baseDirFound -cd .. -IF "%WDIR%"=="%CD%" goto baseDirNotFound -set WDIR=%CD% -goto findBaseDir - -:baseDirFound -set MAVEN_PROJECTBASEDIR=%WDIR% -cd "%EXEC_DIR%" -goto endDetectBaseDir - -:baseDirNotFound -set MAVEN_PROJECTBASEDIR=%EXEC_DIR% -cd "%EXEC_DIR%" - -:endDetectBaseDir - -IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig - -@setlocal EnableExtensions EnableDelayedExpansion -for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a -@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% - -:endReadAdditionalConfig - -SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" -set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" -set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar" -FOR /F "tokens=1,2 delims==" %%A IN (%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties) DO ( - IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B -) - -@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -@REM This allows using the maven wrapper in projects that prohibit checking in binary data. -if exist %WRAPPER_JAR% ( - echo Found %WRAPPER_JAR% -) else ( - echo Couldn't find %WRAPPER_JAR%, downloading it ... - echo Downloading from: %DOWNLOAD_URL% - powershell -Command "(New-Object Net.WebClient).DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')" - echo Finished downloading %WRAPPER_JAR% -) -@REM End of extension - -%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* -if ERRORLEVEL 1 goto error -goto end - -:error -set ERROR_CODE=1 - -:end -@endlocal & set ERROR_CODE=%ERROR_CODE% - -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost -@REM check for post script, once with legacy .bat ending and once with .cmd ending -if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" -if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" -:skipRcPost - -@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' -if "%MAVEN_BATCH_PAUSE%" == "on" pause - -if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% - -exit /B %ERROR_CODE% diff --git a/springboot-integration-examples/springboot-wx/pom.xml b/springboot-integration-examples/springboot-wx/pom.xml deleted file mode 100644 index 192581f5..00000000 --- a/springboot-integration-examples/springboot-wx/pom.xml +++ /dev/null @@ -1,96 +0,0 @@ - - - 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 2.1.4.RELEASE - - - cn.lastwhisper - springbootwx - 0.0.1-SNAPSHOT - springbootwx - Demo project for Spring Boot - - - 1.8 - - - - - org.springframework.boot - spring-boot-starter-web - - - - org.springframework.boot - spring-boot-starter-test - test - - - - - org.apache.httpcomponents - httpclient - 4.5.2 - - - - org.bouncycastle - bcprov-jdk16 - 1.46 - - - - - - org.apache.shiro - shiro-core - 1.4.0 - - - slf4j-api - org.slf4j - - - - - - - com.alibaba - fastjson - 1.2.47 - - - - - org.projectlombok - lombok - true - - - - com.baomidou - mybatis-plus-boot-starter - 3.1.1 - - - - mysql - mysql-connector-java - 5.1.47 - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - - diff --git a/springboot-integration-examples/springboot-wx/sql/wxlogin.sql b/springboot-integration-examples/springboot-wx/sql/wxlogin.sql deleted file mode 100644 index 92d1e6f6..00000000 --- a/springboot-integration-examples/springboot-wx/sql/wxlogin.sql +++ /dev/null @@ -1,39 +0,0 @@ -/* - Navicat Premium Data Transfer - - Source Server : 本地数据库-mysql5.7 - Source Server Type : MySQL - Source Server Version : 50724 - Source Host : localhost:3306 - Source Schema : wxlogin - - Target Server Type : MySQL - Target Server Version : 50724 - File Encoding : 65001 - - Date: 02/05/2019 11:33:43 -*/ - -SET NAMES utf8mb4; -SET FOREIGN_KEY_CHECKS = 0; - --- ---------------------------- --- Table structure for user --- ---------------------------- -DROP TABLE IF EXISTS `user`; -CREATE TABLE `user` ( - `open_id` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'open_id', - `skey` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'skey', - `create_time` timestamp(0) NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `last_visit_time` timestamp(0) NULL DEFAULT CURRENT_TIMESTAMP COMMENT '最后登录时间', - `session_key` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'session_key', - `city` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '市', - `province` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '省', - `country` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '国', - `avatar_url` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '头像', - `gender` tinyint(11) NULL DEFAULT NULL COMMENT '性别', - `nick_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '网名', - PRIMARY KEY (`open_id`) USING BTREE -) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '微信用户信息' ROW_FORMAT = Dynamic; - -SET FOREIGN_KEY_CHECKS = 1; diff --git a/springboot-integration-examples/springboot-wx/src/main/java/cn/lastwhisper/springbootwx/SpringbootwxApplication.java b/springboot-integration-examples/springboot-wx/src/main/java/cn/lastwhisper/springbootwx/SpringbootwxApplication.java deleted file mode 100644 index 1f3b6a1f..00000000 --- a/springboot-integration-examples/springboot-wx/src/main/java/cn/lastwhisper/springbootwx/SpringbootwxApplication.java +++ /dev/null @@ -1,14 +0,0 @@ -package cn.lastwhisper.springbootwx; - -import org.mybatis.spring.annotation.MapperScan; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -@MapperScan("cn.lastwhisper.springbootwx.mapper") //设置mapper接口的扫描包 -@SpringBootApplication -public class SpringbootwxApplication { - - public static void main(String[] args) { - SpringApplication.run(SpringbootwxApplication.class, args); - } - -} diff --git a/springboot-integration-examples/springboot-wx/src/main/java/cn/lastwhisper/springbootwx/common/GlobalResult.java b/springboot-integration-examples/springboot-wx/src/main/java/cn/lastwhisper/springbootwx/common/GlobalResult.java deleted file mode 100644 index f7d42ab2..00000000 --- a/springboot-integration-examples/springboot-wx/src/main/java/cn/lastwhisper/springbootwx/common/GlobalResult.java +++ /dev/null @@ -1,107 +0,0 @@ -package cn.lastwhisper.springbootwx.common; - -/** - * @Description: 自定义响应数据结构 - * 这个类是提供给门户,ios,安卓,微信商城用的 - * 门户接受此类数据后需要使用本类的方法转换成对于的数据类型格式(类,或者list) - * 其他自行处理 - * 200:表示成功 - * 500:表示错误,错误信息在msg字段中 - * 501:bean验证错误,不管多少个错误都以map形式返回 - * 502:拦截器拦截到用户token出错 - * 555:异常抛出信息 - */ -public class GlobalResult { - - // 响应业务状态 - private Integer status; - - // 响应消息 - private String msg; - - // 响应中的数据 - private Object data; - - private String ok; // 不使用 - - public static GlobalResult build(Integer status, String msg, Object data) { - return new GlobalResult(status, msg, data); - } - - public static GlobalResult ok(Object data) { - return new GlobalResult(data); - } - - public static GlobalResult ok() { - return new GlobalResult(null); - } - - public static GlobalResult errorMsg(String msg) { - return new GlobalResult(500, msg, null); - } - - public static GlobalResult errorMap(Object data) { - return new GlobalResult(501, "error", data); - } - - public static GlobalResult errorTokenMsg(String msg) { - return new GlobalResult(502, msg, null); - } - - public static GlobalResult errorException(String msg) { - return new GlobalResult(555, msg, null); - } - - public GlobalResult() { - - } - - public GlobalResult(Integer status, String msg, Object data) { - this.status = status; - this.msg = msg; - this.data = data; - } - - public GlobalResult(Object data) { - this.status = 200; - this.msg = "OK"; - this.data = data; - } - - public Boolean isOK() { - return this.status == 200; - } - - public Integer getStatus() { - return status; - } - - public void setStatus(Integer status) { - this.status = status; - } - - public String getMsg() { - return msg; - } - - public void setMsg(String msg) { - this.msg = msg; - } - - public Object getData() { - return data; - } - - public void setData(Object data) { - this.data = data; - } - - public String getOk() { - return ok; - } - - public void setOk(String ok) { - this.ok = ok; - } - -} diff --git a/springboot-integration-examples/springboot-wx/src/main/java/cn/lastwhisper/springbootwx/common/HttpClientUtil.java b/springboot-integration-examples/springboot-wx/src/main/java/cn/lastwhisper/springbootwx/common/HttpClientUtil.java deleted file mode 100644 index 15631c49..00000000 --- a/springboot-integration-examples/springboot-wx/src/main/java/cn/lastwhisper/springbootwx/common/HttpClientUtil.java +++ /dev/null @@ -1,133 +0,0 @@ -package cn.lastwhisper.springbootwx.common; - -import org.apache.http.NameValuePair; -import org.apache.http.client.entity.UrlEncodedFormEntity; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.client.utils.URIBuilder; -import org.apache.http.entity.ContentType; -import org.apache.http.entity.StringEntity; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClients; -import org.apache.http.message.BasicNameValuePair; -import org.apache.http.util.EntityUtils; - -import java.io.IOException; -import java.net.URI; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -public class HttpClientUtil { - - public static String doGet(String url, Map param) { - - // 创建Httpclient对象 - CloseableHttpClient httpclient = HttpClients.createDefault(); - - String resultString = ""; - CloseableHttpResponse response = null; - try { - // 创建uri - URIBuilder builder = new URIBuilder(url); - if (param != null) { - for (String key : param.keySet()) { - builder.addParameter(key, param.get(key)); - } - } - URI uri = builder.build(); - - // 创建http GET请求 - HttpGet httpGet = new HttpGet(uri); - - // 执行请求 - response = httpclient.execute(httpGet); - // 判断返回状态是否为200 - if (response.getStatusLine().getStatusCode() == 200) { - resultString = EntityUtils.toString(response.getEntity(), "UTF-8"); - } - } catch (Exception e) { - e.printStackTrace(); - } finally { - try { - if (response != null) { - response.close(); - } - httpclient.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - return resultString; - } - - public static String doGet(String url) { - return doGet(url, null); - } - - public static String doPost(String url, Map param) { - // 创建Httpclient对象 - CloseableHttpClient httpClient = HttpClients.createDefault(); - CloseableHttpResponse response = null; - String resultString = ""; - try { - // 创建Http Post请求 - HttpPost httpPost = new HttpPost(url); - // 创建参数列表 - if (param != null) { - List paramList = new ArrayList<>(); - for (String key : param.keySet()) { - paramList.add(new BasicNameValuePair(key, param.get(key))); - } - // 模拟表单 - UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramList); - httpPost.setEntity(entity); - } - // 执行http请求 - response = httpClient.execute(httpPost); - resultString = EntityUtils.toString(response.getEntity(), "utf-8"); - } catch (Exception e) { - e.printStackTrace(); - } finally { - try { - response.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - - return resultString; - } - - public static String doPost(String url) { - return doPost(url, null); - } - - public static String doPostJson(String url, String json) { - // 创建Httpclient对象 - CloseableHttpClient httpClient = HttpClients.createDefault(); - CloseableHttpResponse response = null; - String resultString = ""; - try { - // 创建Http Post请求 - HttpPost httpPost = new HttpPost(url); - // 创建请求内容 - StringEntity entity = new StringEntity(json, ContentType.APPLICATION_JSON); - httpPost.setEntity(entity); - // 执行http请求 - response = httpClient.execute(httpPost); - resultString = EntityUtils.toString(response.getEntity(), "utf-8"); - } catch (Exception e) { - e.printStackTrace(); - } finally { - try { - response.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - - return resultString; - } -} diff --git a/springboot-integration-examples/springboot-wx/src/main/java/cn/lastwhisper/springbootwx/common/WechatUtil.java b/springboot-integration-examples/springboot-wx/src/main/java/cn/lastwhisper/springbootwx/common/WechatUtil.java deleted file mode 100644 index a28af706..00000000 --- a/springboot-integration-examples/springboot-wx/src/main/java/cn/lastwhisper/springbootwx/common/WechatUtil.java +++ /dev/null @@ -1,77 +0,0 @@ -package cn.lastwhisper.springbootwx.common;/** - * Create by eval on 2019/3/20 - */ - -import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONObject; -import org.apache.shiro.codec.Base64; -import org.bouncycastle.jce.provider.BouncyCastleProvider; - -import javax.crypto.Cipher; -import javax.crypto.spec.IvParameterSpec; -import javax.crypto.spec.SecretKeySpec; -import java.security.AlgorithmParameters; -import java.security.Security; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; - -/** - * @ClassName WechatUtil - * @Description TODO - * @Author eval - * @Date 9:44 2019/3/20 - * @Version 1.0 - */ -public class WechatUtil { - public static JSONObject getSessionKeyOrOpenId(String code) { - String requestUrl = "https://api.weixin.qq.com/sns/jscode2session"; - Map requestUrlParam = new HashMap<>(); - // https://mp.weixin.qq.com/wxopen/devprofile?action=get_profile&token=164113089&lang=zh_CN - //小程序appId - requestUrlParam.put("appid", "wx8405074e879dab6e"); - //小程序secret - requestUrlParam.put("secret", "3d599bbd3395fbb286e2814909cd841e"); - //小程序端返回的code - requestUrlParam.put("js_code", code); - //默认参数 - requestUrlParam.put("grant_type", "authorization_code"); - //发送post请求读取调用微信接口获取openid用户唯一标识 - JSONObject jsonObject = JSON.parseObject(HttpClientUtil.doPost(requestUrl, requestUrlParam)); - return jsonObject; - } - - public static JSONObject getUserInfo(String encryptedData, String sessionKey, String iv) { - // 被加密的数据 - byte[] dataByte = Base64.decode(encryptedData); - // 加密秘钥 - byte[] keyByte = Base64.decode(sessionKey); - // 偏移量 - byte[] ivByte = Base64.decode(iv); - try { - // 如果密钥不足16位,那么就补足. 这个if 中的内容很重要 - int base = 16; - if (keyByte.length % base != 0) { - int groups = keyByte.length / base + (keyByte.length % base != 0 ? 1 : 0); - byte[] temp = new byte[groups * base]; - Arrays.fill(temp, (byte) 0); - System.arraycopy(keyByte, 0, temp, 0, keyByte.length); - keyByte = temp; - } - // 初始化 - Security.addProvider(new BouncyCastleProvider()); - Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding", "BC"); - SecretKeySpec spec = new SecretKeySpec(keyByte, "AES"); - AlgorithmParameters parameters = AlgorithmParameters.getInstance("AES"); - parameters.init(new IvParameterSpec(ivByte)); - cipher.init(Cipher.DECRYPT_MODE, spec, parameters);// 初始化 - byte[] resultByte = cipher.doFinal(dataByte); - if (null != resultByte && resultByte.length > 0) { - String result = new String(resultByte, "UTF-8"); - return JSON.parseObject(result); - } - } catch (Exception e) { - } - return null; - } -} diff --git a/springboot-integration-examples/springboot-wx/src/main/java/cn/lastwhisper/springbootwx/controller/UserController.java b/springboot-integration-examples/springboot-wx/src/main/java/cn/lastwhisper/springbootwx/controller/UserController.java deleted file mode 100644 index 44225184..00000000 --- a/springboot-integration-examples/springboot-wx/src/main/java/cn/lastwhisper/springbootwx/controller/UserController.java +++ /dev/null @@ -1,95 +0,0 @@ -package cn.lastwhisper.springbootwx.controller; - -import cn.lastwhisper.springbootwx.common.GlobalResult; -import cn.lastwhisper.springbootwx.mapper.UserMapper; -import cn.lastwhisper.springbootwx.pojo.User; -import cn.lastwhisper.springbootwx.common.WechatUtil; -import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONObject; -import org.apache.commons.codec.digest.DigestUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseBody; - -import java.util.Date; -import java.util.UUID; - -/** - * @author lastwhisper - * @desc - * @email gaojun56@163.com - */ -@Controller -public class UserController { - - @Autowired - private UserMapper userMapper; - - /** - * 微信用户登录详情 - */ - @PostMapping("wx/login") - @ResponseBody - public GlobalResult user_login(@RequestParam(value = "code", required = false) String code, - @RequestParam(value = "rawData", required = false) String rawData, - @RequestParam(value = "signature", required = false) String signature, - @RequestParam(value = "encrypteData", required = false) String encrypteData, - @RequestParam(value = "iv", required = false) String iv) { - // 用户非敏感信息:rawData - // 签名:signature - JSONObject rawDataJson = JSON.parseObject(rawData); - // 1.接收小程序发送的code - // 2.开发者服务器 登录凭证校验接口 appi + appsecret + code - JSONObject SessionKeyOpenId = WechatUtil.getSessionKeyOrOpenId(code); - // 3.接收微信接口服务 获取返回的参数 - String openid = SessionKeyOpenId.getString("openid"); - String sessionKey = SessionKeyOpenId.getString("session_key"); - - // 4.校验签名 小程序发送的签名signature与服务器端生成的签名signature2 = sha1(rawData + sessionKey) - String signature2 = DigestUtils.sha1Hex(rawData + sessionKey); - if (!signature.equals(signature2)) { - return GlobalResult.build(500, "签名校验失败", null); - } - // 5.根据返回的User实体类,判断用户是否是新用户,是的话,将用户信息存到数据库;不是的话,更新最新登录时间 - User user = this.userMapper.selectById(openid); - // uuid生成唯一key,用于维护微信小程序用户与服务端的会话 - String skey = UUID.randomUUID().toString(); - if (user == null) { - // 用户信息入库 - String nickName = rawDataJson.getString("nickName"); - String avatarUrl = rawDataJson.getString("avatarUrl"); - String gender = rawDataJson.getString("gender"); - String city = rawDataJson.getString("city"); - String country = rawDataJson.getString("country"); - String province = rawDataJson.getString("province"); - - user = new User(); - user.setOpenId(openid); - user.setSkey(skey); - user.setCreateTime(new Date()); - user.setLastVisitTime(new Date()); - user.setSessionKey(sessionKey); - user.setCity(city); - user.setProvince(province); - user.setCountry(country); - user.setAvatarUrl(avatarUrl); - user.setGender(Integer.parseInt(gender)); - user.setNickName(nickName); - - this.userMapper.insert(user); - } else { - // 已存在,更新用户登录时间 - user.setLastVisitTime(new Date()); - // 重新设置会话skey - user.setSkey(skey); - this.userMapper.updateById(user); - } - //encrypteData比rowData多了appid和openid - //JSONObject userInfo = WechatUtil.getUserInfo(encrypteData, sessionKey, iv); - //6. 把新的skey返回给小程序 - GlobalResult result = GlobalResult.build(200, null, skey); - return result; - } -} diff --git a/springboot-integration-examples/springboot-wx/src/main/java/cn/lastwhisper/springbootwx/mapper/UserMapper.java b/springboot-integration-examples/springboot-wx/src/main/java/cn/lastwhisper/springbootwx/mapper/UserMapper.java deleted file mode 100644 index f5c386c2..00000000 --- a/springboot-integration-examples/springboot-wx/src/main/java/cn/lastwhisper/springbootwx/mapper/UserMapper.java +++ /dev/null @@ -1,13 +0,0 @@ -package cn.lastwhisper.springbootwx.mapper; - -import cn.lastwhisper.springbootwx.pojo.User; -import com.baomidou.mybatisplus.core.mapper.BaseMapper; - -/** - * @desc - * - * @author lastwhisper - * @email gaojun56@163.com - */ -public interface UserMapper extends BaseMapper { -} diff --git a/springboot-integration-examples/springboot-wx/src/main/java/cn/lastwhisper/springbootwx/pojo/User.java b/springboot-integration-examples/springboot-wx/src/main/java/cn/lastwhisper/springbootwx/pojo/User.java deleted file mode 100644 index 5c6270b3..00000000 --- a/springboot-integration-examples/springboot-wx/src/main/java/cn/lastwhisper/springbootwx/pojo/User.java +++ /dev/null @@ -1,78 +0,0 @@ -package cn.lastwhisper.springbootwx.pojo; - -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableField; -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; -import lombok.Data; -import org.springframework.format.annotation.DateTimeFormat; - -import java.util.Date; - -/** - * @author lastwhisper - * @desc - * @email gaojun56@163.com - */ -@Data -@TableName("user") -public class User { - private static final long serialVersionUID = 1L; - /** - * open_id - */ - @TableId(value = "open_id",type = IdType.INPUT) - private String openId; - /** - * skey - */ - private String skey; - /** - * 创建时间 - */ - @TableField("create_time") - @DateTimeFormat(pattern = "yyyy-MM-dd") - private Date createTime; - /** - * 最后登录时间 - */ - @TableField("last_visit_time") - @DateTimeFormat(pattern = "yyyy-MM-dd") - private Date lastVisitTime; - /** - * session_key - */ - @TableField("session_key") - private String sessionKey; - /** - * 市 - */ - @TableField("city") - private String city; - /** - * 省 - */ - @TableField("province") - private String province; - /** - * 国 - */ - @TableField("country") - private String country; - /** - * 头像 - */ - @TableField("avatar_url") - private String avatarUrl; - /** - * 性别 - */ - @TableField("gender") - private Integer gender; - /** - * 网名 - */ - @TableField("nick_name") - private String nickName; - -} diff --git a/springboot-integration-examples/springboot-wx/src/main/resources/application.properties b/springboot-integration-examples/springboot-wx/src/main/resources/application.properties deleted file mode 100644 index d232612b..00000000 --- a/springboot-integration-examples/springboot-wx/src/main/resources/application.properties +++ /dev/null @@ -1,5 +0,0 @@ -spring.application.name = lastwhisper-wxlogin -spring.datasource.driver-class-name=com.mysql.jdbc.Driver -spring.datasource.url=jdbc:mysql://127.0.0.1:3306/wxlogin?useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true&useSSL=false -spring.datasource.username=root -spring.datasource.password=root \ No newline at end of file diff --git a/springboot-integration-examples/springboot-wx/src/test/java/cn/lastwhisper/springbootwx/SpringbootwxApplicationTests.java b/springboot-integration-examples/springboot-wx/src/test/java/cn/lastwhisper/springbootwx/SpringbootwxApplicationTests.java deleted file mode 100644 index 84a162f3..00000000 --- a/springboot-integration-examples/springboot-wx/src/test/java/cn/lastwhisper/springbootwx/SpringbootwxApplicationTests.java +++ /dev/null @@ -1,16 +0,0 @@ -package cn.lastwhisper.springbootwx; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit4.SpringRunner; - -@RunWith(SpringRunner.class) -@SpringBootTest -public class SpringbootwxApplicationTests { - - @Test - public void contextLoads() { - } - -} diff --git a/springboot-integration-examples/springcloud-gateway/pom.xml b/springboot-integration-examples/springcloud-gateway/pom.xml deleted file mode 100644 index f4522d2c..00000000 --- a/springboot-integration-examples/springcloud-gateway/pom.xml +++ /dev/null @@ -1,69 +0,0 @@ - - - 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 2.2.1.RELEASE - - - cn.lastwhisper - springcloud-gateway - 0.0.1-SNAPSHOT - springcloud-gateway - SpringCloud Gateway - - - 1.8 - Hoxton.RELEASE - - - - - org.springframework.cloud - spring-cloud-starter-gateway - - - org.springframework.cloud - spring-cloud-starter-netflix-hystrix - - - org.springframework.cloud - spring-cloud-starter-contract-stub-runner - - - spring-boot-starter-web - org.springframework.boot - - - - - org.springframework.boot - spring-boot-starter-test - test - - - - - - - org.springframework.cloud - spring-cloud-dependencies - ${spring-cloud.version} - pom - import - - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - - diff --git a/springboot-integration-examples/springcloud-gateway/src/main/java/cn/lastwhisper/gateway/SpringCloudGatewayApplication.java b/springboot-integration-examples/springcloud-gateway/src/main/java/cn/lastwhisper/gateway/SpringCloudGatewayApplication.java deleted file mode 100644 index 9c1a14ca..00000000 --- a/springboot-integration-examples/springcloud-gateway/src/main/java/cn/lastwhisper/gateway/SpringCloudGatewayApplication.java +++ /dev/null @@ -1,41 +0,0 @@ -package cn.lastwhisper.gateway; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.cloud.gateway.route.RouteLocator; -import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder; -import org.springframework.context.annotation.Bean; -import org.springframework.web.bind.annotation.RequestMapping; -import reactor.core.publisher.Mono; - -/** - * @author lastwhisper - */ -@SpringBootApplication -public class SpringCloudGatewayApplication { - - public static void main(String[] args) { - SpringApplication.run(SpringCloudGatewayApplication.class, args); - } - - @Bean - public RouteLocator myRoutes(RouteLocatorBuilder builder) { - return builder.routes() - .route(p -> p - .path("/get") - .filters(f -> f.addRequestHeader("Hello", "World")) - .uri("http://httpbin.org:80")) - .route(p -> p - .host("*.hystrix.com") - .filters(f -> f.hystrix(config -> config - .setName("mycmd") - .setFallbackUri("forward:/fallback"))) - .uri("http://httpbin.org:80")) - .build(); - } - - @RequestMapping("/fallback") - public Mono fallback() { - return Mono.just("fallback"); - } -} diff --git a/springboot-integration-examples/springcloud-gateway/src/main/resources/application.properties b/springboot-integration-examples/springcloud-gateway/src/main/resources/application.properties deleted file mode 100644 index 8b137891..00000000 --- a/springboot-integration-examples/springcloud-gateway/src/main/resources/application.properties +++ /dev/null @@ -1 +0,0 @@ - diff --git a/springboot-integration-examples/springcloud-gateway/src/test/java/cn/lastwhisper/gateway/SpringcloudGatewayApplicationTests.java b/springboot-integration-examples/springcloud-gateway/src/test/java/cn/lastwhisper/gateway/SpringcloudGatewayApplicationTests.java deleted file mode 100644 index 079bb5b4..00000000 --- a/springboot-integration-examples/springcloud-gateway/src/test/java/cn/lastwhisper/gateway/SpringcloudGatewayApplicationTests.java +++ /dev/null @@ -1,13 +0,0 @@ -package cn.lastwhisper.gateway; - -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.context.SpringBootTest; - -@SpringBootTest -class SpringcloudGatewayApplicationTests { - - @Test - void contextLoads() { - } - -} diff --git a/springboot-integration-examples/springcloud-gateway/target/classes/application.properties b/springboot-integration-examples/springcloud-gateway/target/classes/application.properties deleted file mode 100644 index 8b137891..00000000 --- a/springboot-integration-examples/springcloud-gateway/target/classes/application.properties +++ /dev/null @@ -1 +0,0 @@ - diff --git a/springboot-integration-examples/springcloud-gateway/target/classes/cn/lastwhisper/gateway/SpringCloudGatewayApplication.class b/springboot-integration-examples/springcloud-gateway/target/classes/cn/lastwhisper/gateway/SpringCloudGatewayApplication.class deleted file mode 100644 index cb20226b..00000000 Binary files a/springboot-integration-examples/springcloud-gateway/target/classes/cn/lastwhisper/gateway/SpringCloudGatewayApplication.class and /dev/null differ diff --git a/springboot-integration-examples/springcloud-gateway/target/test-classes/cn/lastwhisper/gateway/SpringcloudGatewayApplicationTests.class b/springboot-integration-examples/springcloud-gateway/target/test-classes/cn/lastwhisper/gateway/SpringcloudGatewayApplicationTests.class deleted file mode 100644 index 66e431ac..00000000 Binary files a/springboot-integration-examples/springcloud-gateway/target/test-classes/cn/lastwhisper/gateway/SpringcloudGatewayApplicationTests.class and /dev/null differ diff --git "a/springboot-integration-examples/\345\257\271\345\272\224\347\254\224\350\256\260/SpringBoot-aoplogmd.md" "b/springboot-integration-examples/\345\257\271\345\272\224\347\254\224\350\256\260/SpringBoot-aoplogmd.md" deleted file mode 100644 index d8ca4ede..00000000 --- "a/springboot-integration-examples/\345\257\271\345\272\224\347\254\224\350\256\260/SpringBoot-aoplogmd.md" +++ /dev/null @@ -1,362 +0,0 @@ -> **该项目源码地址:https://github.com/ggb2312/springboot-integration-examples(其中包含SpringBoot和其他常用技术的整合,配套源码以及笔记。基于最新的 SpringBoot2.1+,欢迎各位 Star)** - -# 1. 开发前准备 - -## 1.1 前置知识 -- java基础自定义注解、反射 -- Spring aop -- SpringBoot简单基础知识即可 - -## 1.2 环境参数 -- 开发工具:IDEA -- 基础环境:Maven+JDK8 -- 所用技术:SpringBoot、lombok、mybatisplus、**Spring aop** -- SpringBoot版本:2.1.4 - -## 1.3 涉及知识点 -- 自定义注解、 反射 -- spring aop 环绕通知 - - - -# 2. aop日志实现 - -AOP(Aspect Oriented Programming)是一个大话题,这里不做介绍,直接使用。 -**实现效果:**用户在浏览器操作web页面,对应的操作会被记录到数据库中。 -**实现思路:**自定义一个注解,将注解加到某个方法上,使用aop环绕通知代理带有注解的方法,在环绕前进行日志准备,执行完方法后进行日志入库。 -**项目结构:** -![项目结构](https://upload-images.jianshu.io/upload_images/5336514-c965fd1d513dedec.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - - - -## 2.1 log表 - -```sql -CREATE TABLE `log` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `operateor` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, - `operateType` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, - `operateDate` datetime(0) NULL DEFAULT NULL, - `operateResult` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, - `ip` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, - PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 13 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; -``` - - - -## 2.2 pojo - -log表对应的实体类,使用了lombok的`@Data`注解,也可以使用get、set代替,使用了mybatisplus,所以配置了@TableName等注解,如果使用mybatis或者其他的orm,可以把注解拿掉。 - -```java -package cn.lastwhisper.springbootaop.pojo; - -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableField; -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; -import lombok.Data; -import org.springframework.format.annotation.DateTimeFormat; - -import java.util.Date; - -@Data -@TableName("log") -public class Log { - @TableId(value = "id", type = IdType.AUTO) - private Integer id; - - @TableField("operateor") - private String operateor; - - @TableField("operateType") - private String operatetype; - - @TableField("operateDate") - @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") - private Date operatedate; - - @TableField("operatereSult") - private String operateresult; - - @TableField("ip") - private String ip; -} -``` - - - -## 2.3 controller - -该Controller用于接收用户的请求,并对用户操作进行记录。 - -```java -package cn.lastwhisper.springbootaop.controller; -import cn.lastwhisper.springbootaop.core.annotation.LogAnno; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -/** - * @author lastwhisper - * @desc - * @email gaojun56@163.com - */ -@RestController -public class UserController { - /** - * @desc 这里为了方便直接在controller上进行aop日志记录,也可以放在service上。 - * @author lastwhisper - * @Param - * @return - */ - @LogAnno(operateType = "添加用户") - @RequestMapping(value = "/user/add") - public void add() { - System.out.println("向数据库中添加用户!!"); - } -} -``` - - - -## 2.4 mapper - -该mapper用于对log表进行操作 - -```java -package cn.lastwhisper.springbootaop.mapper; - -import cn.lastwhisper.springbootaop.pojo.Log; -import com.baomidou.mybatisplus.core.mapper.BaseMapper; - -/** - * @desc - * - * @author lastwhisper - * @email gaojun56@163.com - */ -public interface LogMapper extends BaseMapper { -} - -``` - - - -## 2.5 core - -### 2.5.1 日志注解 - -该注解用于标识需要被环绕通知进行日志操作的方法 - -```java -package cn.lastwhisper.springbootaop.core.annotation; - -import org.springframework.core.annotation.Order; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * 日志注解 - * - * @author lastwhisper - */ -@Order(20) -@Target(ElementType.METHOD) // 方法注解 -@Retention(RetentionPolicy.RUNTIME) // 运行时可见 -public @interface LogAnno { - String operateType();// 记录日志的操作类型 -} -``` - -### 2.5.2 aop环绕通知类 - -对带有LogAnno注解的方法进行环绕通知日志记录。 - -`@Order(3)`注解一定要带上,**标记支持AspectJ的切面排序**。 - -```java -package cn.lastwhisper.springbootaop.core.aop; - -import java.lang.reflect.Method; -import java.sql.SQLException; -import java.util.Date; - -import cn.lastwhisper.springbootaop.core.annotation.LogAnno; -import cn.lastwhisper.springbootaop.core.common.HttpContextUtil; -import cn.lastwhisper.springbootaop.mapper.LogMapper; -import cn.lastwhisper.springbootaop.pojo.Log; -import org.aspectj.lang.ProceedingJoinPoint; -import org.aspectj.lang.annotation.Around; -import org.aspectj.lang.annotation.Aspect; -import org.aspectj.lang.reflect.MethodSignature; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.core.annotation.Order; -import org.springframework.stereotype.Component; - -/** - * AOP实现日志 - * - * @author 最后的轻语_dd43 - * - */ -@Order(3) -@Component -@Aspect -public class LogAopAspect { - // 日志mapper,这里省事少写了service - @Autowired - private LogMapper logMapper; - - /** - * 环绕通知记录日志通过注解匹配到需要增加日志功能的方法 - * - * @param pjp - * @return - * @throws Throwable - */ - @Around("@annotation(cn.lastwhisper.springbootaop.core.annotation.LogAnno)") - public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable { - // 1.方法执行前的处理,相当于前置通知 - // 获取方法签名 - MethodSignature methodSignature = (MethodSignature) pjp.getSignature(); - // 获取方法 - Method method = methodSignature.getMethod(); - // 获取方法上面的注解 - LogAnno logAnno = method.getAnnotation(LogAnno.class); - // 获取操作描述的属性值 - String operateType = logAnno.operateType(); - // 创建一个日志对象(准备记录日志) - Log log = new Log(); - log.setOperatetype(operateType);// 操作说明 - - // 设置操作人,从session中获取,这里简化了一下,写死了。 - log.setOperateor("lastwhisper"); - String ip = HttpContextUtil.getIpAddress(); - log.setIp(ip); - Object result = null; - try { - // 让代理方法执行 - result = pjp.proceed(); - // 2.相当于后置通知(方法成功执行之后走这里) - log.setOperateresult("正常");// 设置操作结果 - } catch (SQLException e) { - // 3.相当于异常通知部分 - log.setOperateresult("失败");// 设置操作结果 - } finally { - // 4.相当于最终通知 - log.setOperatedate(new Date());// 设置操作日期 - logMapper.insert(log);// 添加日志记录 - } - return result; - } - -} -``` - -### 2.5.3 common - -用于获取用户的ip - -```java -package cn.lastwhisper.springbootaop.core.common; - -import org.springframework.web.context.request.RequestContextHolder; -import org.springframework.web.context.request.ServletRequestAttributes; - -import javax.servlet.http.HttpServletRequest; - -/** - * @desc - * - * @author lastwhisper - * @email gaojun56@163.com - */ -public class HttpContextUtil { - public static HttpServletRequest getRequest() { - return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()) - .getRequest(); - } - - /** - * 获取IP地址的方法 - * - * @param request 传一个request对象下来 - * @return - */ - public static String getIpAddress() { - HttpServletRequest request = getRequest(); - String ip = request.getHeader("x-forwarded-for"); - if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { - ip = request.getHeader("Proxy-Client-IP"); - } - if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { - ip = request.getHeader("WL-Proxy-Client-IP"); - } - if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { - ip = request.getHeader("HTTP_CLIENT_IP"); - } - if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { - ip = request.getHeader("HTTP_X_FORWARDED_FOR"); - } - if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { - ip = request.getRemoteAddr(); - } - return ip; - } -} -``` - -## 2.6 最终配置 - -配置application.properties文件 - -```properties -spring.application.name = lastwhisper-aoplog -spring.datasource.driver-class-name=com.mysql.jdbc.Driver -spring.datasource.url=jdbc:mysql://127.0.0.1:3306/wxlogin?useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true&useSSL=false -spring.datasource.username=root -spring.datasource.password=root - -``` - -配置springboot启动类SpringbootaopApplication - -```java -package cn.lastwhisper.springbootaop; - -import org.mybatis.spring.annotation.MapperScan; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@MapperScan("cn.lastwhisper.springbootaop.mapper") //设置mapper接口的扫描包 -@SpringBootApplication -public class SpringbootaopApplication { - - public static void main(String[] args) { - SpringApplication.run(SpringbootaopApplication.class, args); - } - -} - -``` - -至此一个完整的SpringBoot AOP日志系统基本成型。 - -# 3. 测试 - -启动`SpringbootaopApplication`的main方法。访问 http://localhost:8080/user/add - -会在idea的控制台看到 `` - -![console](https://upload-images.jianshu.io/upload_images/5336514-f8f34db34104ff59.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -然后再看一下数据库,保存了日志信息。 -![aop 日志](https://upload-images.jianshu.io/upload_images/5336514-7239a28ae9997af1.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - - - -如果是springmvc项目没有生效,应该是自定义aop与事务aop顺序问题,需要在配置文件中配置`order="200"`。如果配置文件配置order无效,建议不要使用配置文件事务,使用注解事务。 \ No newline at end of file diff --git "a/springboot-integration-examples/\345\257\271\345\272\224\347\254\224\350\256\260/SpringBoot-mybatisplus.md" "b/springboot-integration-examples/\345\257\271\345\272\224\347\254\224\350\256\260/SpringBoot-mybatisplus.md" deleted file mode 100644 index eb282307..00000000 --- "a/springboot-integration-examples/\345\257\271\345\272\224\347\254\224\350\256\260/SpringBoot-mybatisplus.md" +++ /dev/null @@ -1,542 +0,0 @@ -> **该项目源码地址:https://github.com/ggb2312/springboot-integration-examples(其中包含SpringBoot和其他常用技术的整合,配套源码以及笔记。基于最新的 SpringBoot2.1+,欢迎各位 Star)** - -# 1. 开发前准备 - -## 1.1 前置知识 -- java基础 -- SpringBoot简单基础知识 - - -## 1.2 环境参数 -- 开发工具:IDEA -- 基础环境:Maven+JDK8 -- 所用技术:SpringBoot、lombok、MybatisPlus -- SpringBoot版本:2.1.4 - -## 1.3 涉及知识点 -- MybatisPlus简介、特性、架构 -- MybatisPlus快速入门 -- MybatisPlus的基本CRUD -- MybatisPlus的高级查询:like查询、条件查询、分页查询等 - -# 2. MybatisPlus入门 - -## 2.1 简介 - -[MyBatis-Plus](https://github.com/baomidou/mybatis-plus)(简称 MP)是一个 [MyBatis](http://www.mybatis.org/mybatis-3/) 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。 - -## 2.2 特性 - -- **无侵入**:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑 -- **损耗小**:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作 -- **强大的 CRUD 操作**:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求 -- **支持 Lambda 形式调用**:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错 -- **支持多种数据库**:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer2005、SQLServer 等多种数据库 -- **支持主键自动生成**:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题 -- **支持 XML 热加载**:Mapper 对应的 XML 支持热加载,对于简单的 CRUD 操作,甚至可以无 XML 启动 -- **支持 ActiveRecord 模式**:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作 -- **支持自定义全局通用操作**:支持全局通用方法注入( Write once, use anywhere ) -- **支持关键词自动转义**:支持数据库关键词(order、key......)自动转义,还可自定义关键词 -- **内置代码生成器**:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用 -- **内置分页插件**:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询 -- **内置性能分析插件**:可输出 Sql 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询 -- **内置全局拦截插件**:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作 -- **内置 Sql 注入剥离器**:支持 Sql 注入剥离,有效预防 Sql 注入攻击 - -## 2.3 架构 -![MybatisPlus架构](https://upload-images.jianshu.io/upload_images/5336514-de256f59d2e18cf3.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -## 2.4 快速入门 -项目结构: -![项目结构](https://upload-images.jianshu.io/upload_images/5336514-93f1ecb4766522a5.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -### 2.4.1 创建表 - -```sql -DROP TABLE IF EXISTS user; - -CREATE TABLE user -( - id BIGINT(20) NOT NULL COMMENT '主键ID', - name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名', - age INT(11) NULL DEFAULT NULL COMMENT '年龄', - email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱', - PRIMARY KEY (id) -)ENGINE=InnoDB DEFAULT CHARSET=utf8; - -DELETE FROM user; - -INSERT INTO user (id, name, age, email) VALUES -(1, 'Jone', 18, 'test1@baomidou.com'), -(2, 'Jack', 20, 'test2@baomidou.com'), -(3, 'Tom', 28, 'test3@baomidou.com'), -(4, 'Sandy', 21, 'test4@baomidou.com'), -(5, 'Billie', 24, 'test5@baomidou.com'); -``` - -### 2.4.2 创建工程以及导入依赖 - -[SpringBoot项目新建](https://www.jianshu.com/p/c6f4fbd1e492) - -```xml - - - - org.projectlombok - lombok - true - - - - com.baomidou - mybatis-plus-boot-starter - 3.1.1 - - - - mysql - mysql-connector-java - 5.1.47 - - - -``` - -### 2.4.3 编写application.properties文件 - -```properties -spring.application.name = lastwhisper-mybatis-plus -spring.datasource.driver-class-name=com.mysql.jdbc.Driver -spring.datasource.url=jdbc:mysql://127.0.0.1:3306/mybatisplus?useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true&useSSL=false -spring.datasource.username=root -spring.datasource.password=root -``` - -### 2.4.4 创建User对象 - -```java -package cn.lastwhisper.springbootmybatisplus.pojo; - -import lombok.Data; -import lombok.ToString; - -/** - * @desc - * - * @author lastwhisper - * @email gaojun56@163.com - */ -@Data -@ToString -public class User { - private Long id; - private String name; - private Integer age; - private String email; -} - -``` - -### 2.4.5 编写UserMapper - -```java -package cn.lastwhisper.springbootmybatisplus.mapper; - -import cn.lastwhisper.springbootmybatisplus.pojo.User; -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -/** - * @desc - * - * @author lastwhisper - * @email gaojun56@163.com - */ -public interface UserMapper extends BaseMapper { -} -``` - -### 2.4.6 设置Mapper接口的包扫描 - -修改SpringBoot启动类 - -```java -package cn.lastwhisper.springbootmybatisplus; - -import org.mybatis.spring.annotation.MapperScan; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@MapperScan("cn.lastwhisper.springbootmybatisplus.mapper") //设置mapper接口的扫描包 -@SpringBootApplication -public class SpringbootmybatisplusApplication { - - public static void main(String[] args) { - SpringApplication.run(SpringbootmybatisplusApplication.class, args); - } - -} - -``` - -### 2.4.7 编写测试单元 - -```java -package cn.lastwhisper.springbootmybatisplus; - -import cn.lastwhisper.springbootmybatisplus.mapper.UserMapper; -import cn.lastwhisper.springbootmybatisplus.pojo.User; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit4.SpringRunner; - -import java.util.List; - -@RunWith(SpringRunner.class) -@SpringBootTest -public class SpringbootmybatisplusApplicationTests { - - - @Autowired - private UserMapper userMapper; - - @Test - public void testSelect() { - System.out.println(("----- selectAll method test ------")); - List userList = userMapper.selectList(null); - for (User user : userList) { - System.out.println(user); - } - } -} - -``` -![测试结果](https://upload-images.jianshu.io/upload_images/5336514-64faf3f0a913d511.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - - - -## 2.5 BaseMapper - -在MybatisPlus中,BaseMapper中定义了一些常用的CRUD方法,当我们自定义的Mapper接口继承BaseMapper后即可拥有了这些方法。 - -> 需要说明的是:这些方法仅适合单表操作。 - -BaseMapper接口的代码如下 - -```java -/** - * Mapper 继承该接口后,无需编写 mapper.xml 文件,即可获得CRUD功能 - *

这个 Mapper 支持 id 泛型

- * - * @author hubin - * @since 2016-01-23 - */ -public interface BaseMapper extends Mapper { - - /** - * 插入一条记录 - * - * @param entity 实体对象 - */ - int insert(T entity); - - /** - * 根据 ID 删除 - * - * @param id 主键ID - */ - int deleteById(Serializable id); - - /** - * 根据 columnMap 条件,删除记录 - * - * @param columnMap 表字段 map 对象 - */ - int deleteByMap(@Param(Constants.COLUMN_MAP) Map columnMap); - - /** - * 根据 entity 条件,删除记录 - * - * @param wrapper 实体对象封装操作类(可以为 null) - */ - int delete(@Param(Constants.WRAPPER) Wrapper wrapper); - - /** - * 删除(根据ID 批量删除) - * - * @param idList 主键ID列表(不能为 null 以及 empty) - */ - int deleteBatchIds(@Param(Constants.COLLECTION) Collection idList); - - /** - * 根据 ID 修改 - * - * @param entity 实体对象 - */ - int updateById(@Param(Constants.ENTITY) T entity); - - /** - * 根据 whereEntity 条件,更新记录 - * - * @param entity 实体对象 (set 条件值,可以为 null) - * @param updateWrapper 实体对象封装操作类(可以为 null,里面的 entity 用于生成 where 语句) - */ - int update(@Param(Constants.ENTITY) T entity, @Param(Constants.WRAPPER) Wrapper updateWrapper); - - /** - * 根据 ID 查询 - * - * @param id 主键ID - */ - T selectById(Serializable id); - - /** - * 查询(根据ID 批量查询) - * - * @param idList 主键ID列表(不能为 null 以及 empty) - */ - List selectBatchIds(@Param(Constants.COLLECTION) Collection idList); - - /** - * 查询(根据 columnMap 条件) - * - * @param columnMap 表字段 map 对象 - */ - List selectByMap(@Param(Constants.COLUMN_MAP) Map columnMap); - - /** - * 根据 entity 条件,查询一条记录 - * - * @param queryWrapper 实体对象封装操作类(可以为 null) - */ - T selectOne(@Param(Constants.WRAPPER) Wrapper queryWrapper); - - /** - * 根据 Wrapper 条件,查询总记录数 - * - * @param queryWrapper 实体对象封装操作类(可以为 null) - */ - Integer selectCount(@Param(Constants.WRAPPER) Wrapper queryWrapper); - - /** - * 根据 entity 条件,查询全部记录 - * - * @param queryWrapper 实体对象封装操作类(可以为 null) - */ - List selectList(@Param(Constants.WRAPPER) Wrapper queryWrapper); - - /** - * 根据 Wrapper 条件,查询全部记录 - * - * @param queryWrapper 实体对象封装操作类(可以为 null) - */ - List> selectMaps(@Param(Constants.WRAPPER) Wrapper queryWrapper); - - /** - * 根据 Wrapper 条件,查询全部记录 - *

注意: 只返回第一个字段的值

- * - * @param queryWrapper 实体对象封装操作类(可以为 null) - */ - List selectObjs(@Param(Constants.WRAPPER) Wrapper queryWrapper); - - /** - * 根据 entity 条件,查询全部记录(并翻页) - * - * @param page 分页查询条件(可以为 RowBounds.DEFAULT) - * @param queryWrapper 实体对象封装操作类(可以为 null) - */ - IPage selectPage(IPage page, @Param(Constants.WRAPPER) Wrapper queryWrapper); - - /** - * 根据 Wrapper 条件,查询全部记录(并翻页) - * - * @param page 分页查询条件 - * @param queryWrapper 实体对象封装操作类 - */ - IPage> selectMapsPage(IPage page, @Param(Constants.WRAPPER) Wrapper queryWrapper); -} - -``` - - - -### 2.5.1 like查询 - -```java -@Test - public void testselectByLike() { - QueryWrapper queryWrapper = new QueryWrapper<>(new User()); - // 查询名字中包含"o"的用户 - queryWrapper.like("name", "o"); - - List users = this.userMapper.selectList(queryWrapper); - for (User user : users) { - System.out.println(user); - } - } -``` -测试结果: - -![like查询](https://upload-images.jianshu.io/upload_images/5336514-5628a2b4fca702c7.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -### 2.5.2 条件查询 -```java -// 条件查询 - @Test - public void testselectByLe(){ - QueryWrapper queryWrapper = new QueryWrapper<>(new User()); - //查询年龄小于等于20的用户 - queryWrapper.le("age",20); - - List users = this.userMapper.selectList(queryWrapper); - for (User user:users) { - System.out.println(user); - } - } -``` - -测试结果: - -![条件查询](https://upload-images.jianshu.io/upload_images/5336514-cf18cb54eb560256.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -更多查看:http://mp.baomidou.com/guide/wrapper.html#abstractwrapper - -### 2.5.3 插入数据 -数据库主键自增: @TableId(value = "ID", type = IdType.AUTO) -数据库主键自己维护:@TableId(value = "open_id",type = IdType.INPUT) - -设置主键自增长 -```java -@Data -@ToString -public class User { - @TableId(value = "ID", type = IdType.AUTO) - private Long id; - private String name; - private Integer age; - private String email; -} -``` - -设置表主键自增 - -![主键自增](https://upload-images.jianshu.io/upload_images/5336514-9b01af648b413e8f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -测试代码 - -```java -//插入数据 - @Test - public void testSave(){ - User user = new User(); - user.setAge(21); - user.setEmail("gaojun56@163.com"); - user.setName("gaojun"); - int count = this.userMapper.insert(user); - System.out.println("新增数据成功! count => " + count); - } -``` -测试结果: - -![测试结果](https://upload-images.jianshu.io/upload_images/5336514-147f70abd8225e68.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -数据库: - -![测试结果](https://upload-images.jianshu.io/upload_images/5336514-5e1f34cb0f368f80.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -### 2.5.4 删除数据 -```java -//删除数据 - @Test - public void testDelete(){ - this.userMapper.deleteById(6L); - System.out.println("删除成功!"); - } -``` -测试结果: - -![测试结果](https://upload-images.jianshu.io/upload_images/5336514-e1479c0a8b5e7c02.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -### 2.5.5 修改数据 -根据id修改数据,修改不为null的字段 -```java -//修改数据 -@Test - public void testUpdate(){ - User user = new User(); - user.setId(5L); - user.setName("gaojun"); - user.setEmail("gaojun56@163.com"); - this.userMapper.updateById(user); - System.out.println("修改成功!"); - } -``` -测试结果: - -![测试结果](https://upload-images.jianshu.io/upload_images/5336514-c1db5140e574d5f5.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -![测试结果](https://upload-images.jianshu.io/upload_images/5336514-843fd6e20cdedafa.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -### 2.5.6 分页查询 - -首先在SpringBoot启动类中配置分页插件 - -```java -@MapperScan("cn.lastwhisper.springbootmybatisplus.mapper") //设置mapper接口的扫描包 -@SpringBootApplication -public class SpringbootmybatisplusApplication { - - /** - * 分页插件 - */ - @Bean - public PaginationInterceptor paginationInterceptor() { - return new PaginationInterceptor(); - } - - public static void main(String[] args) { - SpringApplication.run(SpringbootmybatisplusApplication.class, args); - } - -} - -``` - -测试类: - -```java -//分页查询 - @Test - public void testselectPage() { - Page page = new Page<>(1, 2); - IPage userIPage = this.userMapper.selectPage(page, null); - System.out.println("总条数 ------> " + userIPage.getTotal()); - System.out.println("当前页数 ------> " + userIPage.getCurrent()); - System.out.println("当前每页显示数 ------> " + userIPage.getSize()); - List records = userIPage.getRecords(); - for (User user : records) { - System.out.println(user); - } - } -``` - -测试结果: -![测试结果](https://upload-images.jianshu.io/upload_images/5336514-2da133a78d36d3a9.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - - - -## 2.6 配置 - -虽然在MybatisPlus中可以实现零配置,但是有些时候需要我们自定义一些配置,就需要使用Mybatis原生的一些配置文件方式了。 - - application.properties: - -```properties -# 指定全局配置文件 -mybatis-plus.config-location = classpath:mybatis-config.xml -# 指定mapper.xml文件 -mybatis-plus.mapper-locations = classpath*:mybatis/*.xml -``` - -更多配置:https://mp.baomidou.com/guide/config.html \ No newline at end of file diff --git "a/springboot-integration-examples/\345\257\271\345\272\224\347\254\224\350\256\260/SpringBoot-oss.md" "b/springboot-integration-examples/\345\257\271\345\272\224\347\254\224\350\256\260/SpringBoot-oss.md" deleted file mode 100644 index 98336d26..00000000 --- "a/springboot-integration-examples/\345\257\271\345\272\224\347\254\224\350\256\260/SpringBoot-oss.md" +++ /dev/null @@ -1,579 +0,0 @@ -> **该项目源码地址:https://github.com/ggb2312/springboot-integration-examples(其中包含SpringBoot和其他常用技术的整合,配套源码以及笔记。基于最新的 SpringBoot2.1+,欢迎各位 Star)** - -# 1. 开发前准备 - -## 1.1 前置知识 -- java基础 -- SpringBoot简单基础知识 - -## 1.2 环境参数 -- 开发工具:IDEA -- 基础环境:Maven+JDK8 -- 所用技术:SpringBoot、lombok、阿里云OSS存储服务 -- SpringBoot版本:2.1.4 - -## 1.3 涉及知识点 -- OSS简介,以及阿里云OSS控制台快速入门使用 -- SpringBoot 整合 阿里云OSS 存储服务,进行文件上传、下载、查看、删除 -- 阿里云OSS文档介绍,以及快速入门使用 -- lombok入门使用以及IDEA lombok插件安装 -- SpringMVC与AJAX前后端分离交互 -- AJAX文件异步上传 - -# 2. 使用阿里云OSS -对象存储OSS的多重冗余架构设计,为数据持久存储提供可靠保障。 -## 2.1 创建Bucket -使用OSS,首先需要创建Bucket,Bucket翻译成中文是水桶的意思,把存储的图片资源看做是水,想要盛水必须得 -有桶。 -进入控制台,https://oss.console.aliyun.com/overview - -![新建Bucket](https://upload-images.jianshu.io/upload_images/5336514-f8c5512fa6084fe5.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -![新建 Bucket](https://upload-images.jianshu.io/upload_images/5336514-e3006193988291c4.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -创建完成后,在左侧可以看到已经创建好的Bucket: - -![Bucket](https://upload-images.jianshu.io/upload_images/5336514-b42a82d12baa340b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -选择Bucket后,即可看到对应的信息,如:url、消耗流量等 - -![Bucket相关信息](https://upload-images.jianshu.io/upload_images/5336514-38cb38befa6aeaf6.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -## 2.2 管理文件 -可以通过在线的方式进行管理文件 - -![管理文件](https://upload-images.jianshu.io/upload_images/5336514-4eea09a699e304ac.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -## 2.3 阿里云OSS文档 - -[阿里云OSS文档](https://help.aliyun.com/product/31815.html?spm=a2c4g.11186623.6.540.517822372ASOvk) - -![阿里云OSS文档](https://upload-images.jianshu.io/upload_images/5336514-4df24be98ecfa55b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -右侧的开发指南说的更加详细 -![开发指南](https://upload-images.jianshu.io/upload_images/5336514-4f709bb5848c7c3f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -阿里云虽然提供了完整的文档,但是做一个完整的前后端交互的文件上传、下载、查看、删除等操作,对于小白来说还是有点难度的,所以我把自己学习OSS的步骤以及代码分享了出来,共有需要的人使用。 - -# 3. 项目初始化 - -## 3.1 创建SpringBoot项目 -在Idea中File——>New——>Project -![创建SpringBoot项目 步骤一](https://upload-images.jianshu.io/upload_images/5336514-0f9a30d8fe087c50.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -![创建SpringBoot项目 步骤二](https://upload-images.jianshu.io/upload_images/5336514-a658fb76a0950b01.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -![创建SpringBoot项目 步骤三](https://upload-images.jianshu.io/upload_images/5336514-6be4593b1c65adec.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -![创建SpringBoot项目 步骤四](https://upload-images.jianshu.io/upload_images/5336514-0ae22056caa7f423.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -## 3.2 Maven依赖 -导入Maven相关依赖 -``` - - com.aliyun.oss - aliyun-sdk-oss - 2.8.3 - - - - org.projectlombok - lombok - 1.18.4 - provided - - - - joda-time - joda-time - 2.9.9 - - - - org.apache.commons - commons-lang3 - 3.8.1 - -``` -## 3.3 安装lombok插件 -因为项目中使用了lombok的`@Data`注解,当然你也可以自己写get、set等方法。 -File——>settings——>Plugins -![安装lombok插件](https://upload-images.jianshu.io/upload_images/5336514-5276d48cc6776ce4.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -![安装lombok插件](https://upload-images.jianshu.io/upload_images/5336514-d5ac2a7871a502f2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -然后restart IDEA即可。 - -# 4. 后端服务编写 -![项目结构](https://upload-images.jianshu.io/upload_images/5336514-aada92c3c74e00d2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -## 4.1 阿里云OSS配置 -在resource下新建一个application-oss.properties -``` -aliyun.endpoint=oss-cn-shanghai.aliyuncs.com -aliyun.accessKeyId=你的accessKeyId -aliyun.accessKeySecret=你的accessKeySecret -aliyun.bucketName=gaojun-testbucket -aliyun.urlPrefix=http://gaojun-testbucket.oss-cn-shanghai.aliyuncs.com/ -spring.servlet.multipart.max-file-size=100MB -spring.servlet.multipart.max-request-size=1000MB -``` - -endpoint、bucketName、urlPrefix在OSS主面板就可以看到 - -![bucketName、endpoint与urlPrefix](https://upload-images.jianshu.io/upload_images/5336514-2818153bf58ebfce.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -accessKeyId、accessKeySecret需要在accesskeys里面查看 - -![accesskeys与accessKeySecret](https://upload-images.jianshu.io/upload_images/5336514-176959cccd4e52de.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -在java的包下新建一个config包,创建一个AliyunConfig.java -```java -package com.example.ossdemo.config; - -import com.aliyun.oss.OSS; -import com.aliyun.oss.OSSClient; -import lombok.Data; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.PropertySource; -/** - * @desc - * - * @author lastwhisper - * @email gaojun56@163.com - */ -@Configuration -@PropertySource(value = {"classpath:application-oss.properties"}) -@ConfigurationProperties(prefix = "aliyun") -@Data -public class AliyunConfig { - private String endpoint; - private String accessKeyId; - private String accessKeySecret; - private String bucketName; - private String urlPrefix; - - @Bean - public OSS oSSClient() { - return new OSSClient(endpoint, accessKeyId, accessKeySecret); - } -} -``` - -## 4.2 后端业务 -### 4.2.1 vo - -该实体类用于后台返回给前台。 - -```java -package com.example.ossdemo.vo; - -import lombok.Data; - -/** - * @author lastwhisper - * @desc 用于前后端交互的返回值 - * @email gaojun56@163.com - */ -@Data -public class FileUploadResult { - // 文件唯一标识 - private String uid; - // 文件名 - private String name; - // 状态有:uploading done error removed - private String status; - // 服务端响应内容,如:'{"status": "success"}' - private String response; -} - -``` -### 4.2.2 service - -在service使用ossClient操作阿里云OSS,进行上传、下载、删除、查看所有文件等操作,同时可以将图片的url进行入库操作。 - -```java -package com.example.ossdemo.service; - -import com.aliyun.oss.OSS; -import com.aliyun.oss.model.*; -import com.example.ossdemo.config.AliyunConfig; -import com.example.ossdemo.vo.FileUploadResult; -import org.apache.commons.lang3.RandomUtils; -import org.apache.commons.lang3.StringUtils; -import org.joda.time.DateTime; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.web.multipart.MultipartFile; - -import java.io.*; -import java.util.List; - -/** - * @author lastwhisper - * @desc - * @email gaojun56@163.com - */ -@Service -public class FileUploadService { - // 允许上传的格式 - private static final String[] IMAGE_TYPE = new String[]{".bmp", ".jpg", - ".jpeg", ".gif", ".png"}; - @Autowired - private OSS ossClient; - @Autowired - private AliyunConfig aliyunConfig; - - /** - * @author lastwhisper - * @desc 文件上传 - * 文档链接 https://help.aliyun.com/document_detail/84781.html?spm=a2c4g.11186623.6.749.11987a7dRYVSzn - * @email gaojun56@163.com - */ - public FileUploadResult upload(MultipartFile uploadFile) { - // 校验图片格式 - boolean isLegal = false; - for (String type : IMAGE_TYPE) { - if (StringUtils.endsWithIgnoreCase(uploadFile.getOriginalFilename(), - type)) { - isLegal = true; - break; - } - } - //封装Result对象,并且将文件的byte数组放置到result对象中 - FileUploadResult fileUploadResult = new FileUploadResult(); - if (!isLegal) { - fileUploadResult.setStatus("error"); - return fileUploadResult; - } - //文件新路径 - String fileName = uploadFile.getOriginalFilename(); - String filePath = getFilePath(fileName); - // 上传到阿里云 - try { - ossClient.putObject(aliyunConfig.getBucketName(), filePath, new - ByteArrayInputStream(uploadFile.getBytes())); - } catch (Exception e) { - e.printStackTrace(); - //上传失败 - fileUploadResult.setStatus("error"); - return fileUploadResult; - } - fileUploadResult.setStatus("done"); - fileUploadResult.setResponse("success"); - //this.aliyunConfig.getUrlPrefix() + filePath 文件路径需要保存到数据库 - fileUploadResult.setName(this.aliyunConfig.getUrlPrefix() + filePath); - fileUploadResult.setUid(String.valueOf(System.currentTimeMillis())); - return fileUploadResult; - } - - /** - * @author lastwhisper - * @desc 生成路径以及文件名 例如://images/2019/04/28/15564277465972939.jpg - * @email gaojun56@163.com - */ - private String getFilePath(String sourceFileName) { - DateTime dateTime = new DateTime(); - return "images/" + dateTime.toString("yyyy") - + "/" + dateTime.toString("MM") + "/" - + dateTime.toString("dd") + "/" + System.currentTimeMillis() + - RandomUtils.nextInt(100, 9999) + "." + - StringUtils.substringAfterLast(sourceFileName, "."); - } - - /** - * @author lastwhisper - * @desc 查看文件列表 - * 文档链接 https://help.aliyun.com/document_detail/84841.html?spm=a2c4g.11186623.2.13.3ad5b5ddqxWWRu#concept-84841-zh - * @email gaojun56@163.com - */ - public List list() { - // 设置最大个数。 - final int maxKeys = 200; - // 列举文件。 - ObjectListing objectListing = ossClient.listObjects(new ListObjectsRequest(aliyunConfig.getBucketName()).withMaxKeys(maxKeys)); - List sums = objectListing.getObjectSummaries(); - return sums; - } - - /** - * @author lastwhisper - * @desc 删除文件 - * 文档链接 https://help.aliyun.com/document_detail/84842.html?spm=a2c4g.11186623.6.770.4f9474b4UYlCtr - * @email gaojun56@163.com - */ - public FileUploadResult delete(String objectName) { - // 根据BucketName,objectName删除文件 - ossClient.deleteObject(aliyunConfig.getBucketName(), objectName); - FileUploadResult fileUploadResult = new FileUploadResult(); - fileUploadResult.setName(objectName); - fileUploadResult.setStatus("removed"); - fileUploadResult.setResponse("success"); - return fileUploadResult; - } - - /** - * @author lastwhisper - * @desc 下载文件 - * 文档链接 https://help.aliyun.com/document_detail/84823.html?spm=a2c4g.11186623.2.7.37836e84ZIuZaC#concept-84823-zh - * @email gaojun56@163.com - */ - public void exportOssFile(OutputStream os, String objectName) throws IOException { - // ossObject包含文件所在的存储空间名称、文件名称、文件元信息以及一个输入流。 - OSSObject ossObject = ossClient.getObject(aliyunConfig.getBucketName(), objectName); - // 读取文件内容。 - BufferedInputStream in = new BufferedInputStream(ossObject.getObjectContent()); - BufferedOutputStream out = new BufferedOutputStream(os); - byte[] buffer = new byte[1024]; - int lenght = 0; - while ((lenght = in.read(buffer)) != -1) { - out.write(buffer, 0, lenght); - } - if (out != null) { - out.flush(); - out.close(); - } - if (in != null) { - in.close(); - } - } -} - -``` -### 4.2.3 controller - -controller进行接收用户请求 - -```java -package com.example.ossdemo.controller; - -import com.aliyun.oss.model.OSSObjectSummary; -import com.example.ossdemo.service.FileUploadService; -import com.example.ossdemo.vo.FileUploadResult; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.multipart.MultipartFile; - -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.io.InputStream; -import java.net.URLEncoder; -import java.util.List; - -/** - * @author lastwhisper - * @desc - * @email gaojun56@163.com - */ -@Controller -public class FileUploadController { - @Autowired - private FileUploadService fileUploadService; - - /** - * @author lastwhisper - * @desc 文件上传到oss - * @return FileUploadResult - * @Param uploadFile - */ - @RequestMapping("file/upload") - @ResponseBody - public FileUploadResult upload(@RequestParam("file") MultipartFile uploadFile) - throws Exception { - return this.fileUploadService.upload(uploadFile); - } - - /** - * @return FileUploadResult - * @desc 根据文件名删除oss上的文件 - * http://localhost:8080/file/delete?fileName=images/2019/04/28/1556429167175766.jpg - * @author lastwhisper - * @Param objectName - */ - @RequestMapping("file/delete") - @ResponseBody - public FileUploadResult delete(@RequestParam("fileName") String objectName) - throws Exception { - return this.fileUploadService.delete(objectName); - } - - /** - * @author lastwhisper - * @desc 查询oss上的所有文件 - * http://localhost:8080/file/list - * @return List - * @Param - */ - @RequestMapping("file/list") - @ResponseBody - public List list() - throws Exception { - return this.fileUploadService.list(); - } - - /** - * @author lastwhisper - * @desc 根据文件名下载oss上的文件 - * @return - * @Param objectName - */ - @RequestMapping("file/download") - @ResponseBody - public void download(@RequestParam("fileName") String objectName, HttpServletResponse response) throws IOException { - //通知浏览器以附件形式下载 - response.setHeader("Content-Disposition", - "attachment;filename=" + new String(objectName.getBytes(), "ISO-8859-1")); - this.fileUploadService.exportOssFile(response.getOutputStream(),objectName); - } -} -``` - - -# 5. 前端页面编写与测试 - -## 5.1 文件上传页面 - -使用ajax异步文件上传到后端对接的OSS上。 - -```html - - - - - - oss文件上传 - - - - -
   -    -
     -
-
-
- - -``` - -**效果展示:** - -![ajax文件上传到OSS](https://upload-images.jianshu.io/upload_images/5336514-9ce7586f3cff4448.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -![ajax文件上传到OSS](https://upload-images.jianshu.io/upload_images/5336514-8979815659db74f7.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -![ajax文件上传到OSS成功](https://upload-images.jianshu.io/upload_images/5336514-74764aaef98c5634.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -## 5.2 文件管理页面 - -```html - - - - - oss文件管理 - - - - -单击下载oss上的图片、双击删除oss上的图片
-
- -
- - -``` - -**效果展示:** - -刚才上传了一张照片,可以立马看到 - -![文件管理](https://upload-images.jianshu.io/upload_images/5336514-62efcdedbb874287.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -单击页面即可下载图片 - -![image.png](https://upload-images.jianshu.io/upload_images/5336514-fa9b54c11e9a7ba4.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -双击即可删除图片: - -![删除图片](https://upload-images.jianshu.io/upload_images/5336514-a69777b462e3b919.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -![删除图片](https://upload-images.jianshu.io/upload_images/5336514-670a3aa6e65cfb9e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) \ No newline at end of file diff --git "a/springboot-integration-examples/\345\257\271\345\272\224\347\254\224\350\256\260/SpringBoot-wx.md" "b/springboot-integration-examples/\345\257\271\345\272\224\347\254\224\350\256\260/SpringBoot-wx.md" deleted file mode 100644 index b129c456..00000000 --- "a/springboot-integration-examples/\345\257\271\345\272\224\347\254\224\350\256\260/SpringBoot-wx.md" +++ /dev/null @@ -1,901 +0,0 @@ -> **该项目源码地址:https://github.com/ggb2312/springboot-integration-examples(其中包含SpringBoot和其他常用技术的整合,配套源码以及笔记。基于最新的 SpringBoot2.1+,欢迎各位 Star)** - -# 1. 开发前准备 - -## 1.1 前置知识 -- java基础 -- SpringBoot简单基础知识 - -## 1.2 环境参数 -- 开发工具:IDEA -- 基础环境:Maven+JDK8 -- 所用技术:SpringBoot、lombok、mybatisplus、微信小程序 -- SpringBoot版本:2.1.4 - -## 1.3 涉及知识点 -- 微信小程序登录流程 - -# 2. 微信小程序登录流程 -微信小程序登录流程涉及到三个角色:**小程序、开发者服务器、微信服务器** - -三者交互步骤如下: - ->第一步:`小程序`通过wx.login()获取code。 ->第二步:`小程序`通过wx.request()发送code到开发者服务器。 ->第三步:`开发者服务器`接收小程序发送的code,并携带appid、appsecret(这两个需要到微信小程序后台查看)、code发送到`微信服务器`。 ->第四步:`微信服务器`接收开发者服务器发送的appid、appsecret、code进行校验。校验通过后向`开发者服务器`发送session_key、openid。 ->第五步:`开发者服务器`自己生成一个skey(自定义登录状态)与openid、session_key进行关联,并存到数据库中(mysql、redis等)。 ->第六步:`开发者服务器`返回生成skey(自定义登录状态)到小程序。 ->第七步:`小程序`存储skey(自定义登录状态)到本地。 ->第八步:`小程序`通过wx.request()发起业务请求到`开发者服务器`,同时携带skey(自定义登录状态)。 ->第九步:`开发者服务器`接收`小程序`发送的skey(自定义登录状态),查询skey在数据库中是否有对应的openid、session_key。 ->第十步:`开发者服务器`返回业务数据到`小程序`。 - - - -登录流程时序如下: - - - -![登录流程时序](https://upload-images.jianshu.io/upload_images/5336514-96d351a21eb8cbad.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - - - -本文实现了前七个步骤,因为微信小程序登录的核心就是前七个步骤。 - - - ->第一步:`小程序`通过wx.login()获取code。 ->第二步:`小程序`通过wx.request()发送code到开发者服务器。 ->第三步:`开发者服务器`接收小程序发送的code,并携带appid、appsecret(这两个需要到微信小程序后台查看)、code发送到`微信服务器。` ->第四步:`微信服务器`接收开发者服务器发送的appid、appsecret、code进行校验。校验通过后向`开发者服务器`发送session_key、openid。 ->第五步:`开发者服务器`自己生成一个skey(自定义登录状态)与openid、session_key进行关联,并存到数据库中(mysql、redis等)。 ->第六步:`开发者服务器`返回生成skey(自定义登录状态)到小程序。 ->第七步:`小程序`存储skey(自定义登录状态)到本地。 - - - -![本文介绍的流程](https://upload-images.jianshu.io/upload_images/5336514-fe6e3cb43c775db0.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - - - -# 3. 开发者服务器 - -项目结构: - -![项目结构](https://upload-images.jianshu.io/upload_images/5336514-e0568415537890ba.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -## 3.1 初始配置 - -(1)pom.xml配置 - -```xml - - - org.apache.httpcomponents - httpclient - 4.5.2 - - - - org.bouncycastle - bcprov-jdk16 - 1.46 - - - - - - org.apache.shiro - shiro-core - 1.4.0 - - - slf4j-api - org.slf4j - - - - - - - com.alibaba - fastjson - 1.2.47 - - - - - org.projectlombok - lombok - true - - - - com.baomidou - mybatis-plus-boot-starter - 3.1.1 - - - - mysql - mysql-connector-java - 5.1.47 - -``` - -(2)application.properties - -```properties -spring.application.name = lastwhisper-wxlogin -spring.datasource.driver-class-name=com.mysql.jdbc.Driver -spring.datasource.url=jdbc:mysql://127.0.0.1:3306/wxlogin?useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true&useSSL=false -spring.datasource.username=root -spring.datasource.password=root -``` - -## 3.2 小程序用户表 - -创建一个用户表存储用户的openid等数据。 - -```sql -CREATE TABLE `user` ( - `open_id` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'open_id', - `skey` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'skey', - `create_time` timestamp(0) NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `last_visit_time` timestamp(0) NULL DEFAULT CURRENT_TIMESTAMP COMMENT '最后登录时间', - `session_key` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'session_key', - `city` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '市', - `province` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '省', - `country` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '国', - `avatar_url` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '头像', - `gender` tinyint(11) NULL DEFAULT NULL COMMENT '性别', - `nick_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '网名', - PRIMARY KEY (`open_id`) USING BTREE -) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '微信用户信息' ROW_FORMAT = Dynamic; - -``` - -## 3.3 pojo - - - -```java -package cn.lastwhisper.springbootwx.pojo; - -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableField; -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; -import lombok.Data; -import org.springframework.format.annotation.DateTimeFormat; - -import java.util.Date; - -/** - * @author lastwhisper - * @desc - * @email gaojun56@163.com - */ -@Data -@TableName("user") -public class User { - private static final long serialVersionUID = 1L; - /** - * open_id - */ - @TableId(value = "open_id",type = IdType.INPUT) - private String openId; - /** - * skey - */ - private String skey; - /** - * 创建时间 - */ - @TableField("create_time") - @DateTimeFormat(pattern = "yyyy-MM-dd") - private Date createTime; - /** - * 最后登录时间 - */ - @TableField("last_visit_time") - @DateTimeFormat(pattern = "yyyy-MM-dd") - private Date lastVisitTime; - /** - * session_key - */ - @TableField("session_key") - private String sessionKey; - /** - * 市 - */ - @TableField("city") - private String city; - /** - * 省 - */ - @TableField("province") - private String province; - /** - * 国 - */ - @TableField("country") - private String country; - /** - * 头像 - */ - @TableField("avatar_url") - private String avatarUrl; - /** - * 性别 - */ - @TableField("gender") - private Integer gender; - /** - * 网名 - */ - @TableField("nick_name") - private String nickName; - -} - -``` - -## 3.4 common - -封装一些工具类 - -(1)GlobalResult - -```java -package cn.lastwhisper.springbootwx.common; - -/** - * @Description: 自定义响应数据结构 - * 这个类是提供给门户,ios,安卓,微信商城用的 - * 门户接受此类数据后需要使用本类的方法转换成对于的数据类型格式(类,或者list) - * 其他自行处理 - * 200:表示成功 - * 500:表示错误,错误信息在msg字段中 - * 501:bean验证错误,不管多少个错误都以map形式返回 - * 502:拦截器拦截到用户token出错 - * 555:异常抛出信息 - */ -public class GlobalResult { - - // 响应业务状态 - private Integer status; - - // 响应消息 - private String msg; - - // 响应中的数据 - private Object data; - - private String ok; // 不使用 - - public static GlobalResult build(Integer status, String msg, Object data) { - return new GlobalResult(status, msg, data); - } - - public static GlobalResult ok(Object data) { - return new GlobalResult(data); - } - - public static GlobalResult ok() { - return new GlobalResult(null); - } - - public static GlobalResult errorMsg(String msg) { - return new GlobalResult(500, msg, null); - } - - public static GlobalResult errorMap(Object data) { - return new GlobalResult(501, "error", data); - } - - public static GlobalResult errorTokenMsg(String msg) { - return new GlobalResult(502, msg, null); - } - - public static GlobalResult errorException(String msg) { - return new GlobalResult(555, msg, null); - } - - public GlobalResult() { - - } - - public GlobalResult(Integer status, String msg, Object data) { - this.status = status; - this.msg = msg; - this.data = data; - } - - public GlobalResult(Object data) { - this.status = 200; - this.msg = "OK"; - this.data = data; - } - - public Boolean isOK() { - return this.status == 200; - } - - public Integer getStatus() { - return status; - } - - public void setStatus(Integer status) { - this.status = status; - } - - public String getMsg() { - return msg; - } - - public void setMsg(String msg) { - this.msg = msg; - } - - public Object getData() { - return data; - } - - public void setData(Object data) { - this.data = data; - } - - public String getOk() { - return ok; - } - - public void setOk(String ok) { - this.ok = ok; - } - -} -``` - -(2)HttpClientUtil - -```java -package cn.lastwhisper.springbootwx.common; - -import org.apache.http.NameValuePair; -import org.apache.http.client.entity.UrlEncodedFormEntity; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.client.utils.URIBuilder; -import org.apache.http.entity.ContentType; -import org.apache.http.entity.StringEntity; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClients; -import org.apache.http.message.BasicNameValuePair; -import org.apache.http.util.EntityUtils; - -import java.io.IOException; -import java.net.URI; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -public class HttpClientUtil { - - public static String doGet(String url, Map param) { - - // 创建Httpclient对象 - CloseableHttpClient httpclient = HttpClients.createDefault(); - - String resultString = ""; - CloseableHttpResponse response = null; - try { - // 创建uri - URIBuilder builder = new URIBuilder(url); - if (param != null) { - for (String key : param.keySet()) { - builder.addParameter(key, param.get(key)); - } - } - URI uri = builder.build(); - - // 创建http GET请求 - HttpGet httpGet = new HttpGet(uri); - - // 执行请求 - response = httpclient.execute(httpGet); - // 判断返回状态是否为200 - if (response.getStatusLine().getStatusCode() == 200) { - resultString = EntityUtils.toString(response.getEntity(), "UTF-8"); - } - } catch (Exception e) { - e.printStackTrace(); - } finally { - try { - if (response != null) { - response.close(); - } - httpclient.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - return resultString; - } - - public static String doGet(String url) { - return doGet(url, null); - } - - public static String doPost(String url, Map param) { - // 创建Httpclient对象 - CloseableHttpClient httpClient = HttpClients.createDefault(); - CloseableHttpResponse response = null; - String resultString = ""; - try { - // 创建Http Post请求 - HttpPost httpPost = new HttpPost(url); - // 创建参数列表 - if (param != null) { - List paramList = new ArrayList<>(); - for (String key : param.keySet()) { - paramList.add(new BasicNameValuePair(key, param.get(key))); - } - // 模拟表单 - UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramList); - httpPost.setEntity(entity); - } - // 执行http请求 - response = httpClient.execute(httpPost); - resultString = EntityUtils.toString(response.getEntity(), "utf-8"); - } catch (Exception e) { - e.printStackTrace(); - } finally { - try { - response.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - - return resultString; - } - - public static String doPost(String url) { - return doPost(url, null); - } - - public static String doPostJson(String url, String json) { - // 创建Httpclient对象 - CloseableHttpClient httpClient = HttpClients.createDefault(); - CloseableHttpResponse response = null; - String resultString = ""; - try { - // 创建Http Post请求 - HttpPost httpPost = new HttpPost(url); - // 创建请求内容 - StringEntity entity = new StringEntity(json, ContentType.APPLICATION_JSON); - httpPost.setEntity(entity); - // 执行http请求 - response = httpClient.execute(httpPost); - resultString = EntityUtils.toString(response.getEntity(), "utf-8"); - } catch (Exception e) { - e.printStackTrace(); - } finally { - try { - response.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - - return resultString; - } -} -``` - -(3)WechatUtil - -```java -package cn.lastwhisper.springbootwx.common;/** - * Create by eval on 2019/3/20 - */ - -import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONObject; -import org.apache.shiro.codec.Base64; -import org.bouncycastle.jce.provider.BouncyCastleProvider; - -import javax.crypto.Cipher; -import javax.crypto.spec.IvParameterSpec; -import javax.crypto.spec.SecretKeySpec; -import java.security.AlgorithmParameters; -import java.security.Security; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; - -/** - * @ClassName WechatUtil - * @Description TODO - * @Author eval - * @Date 9:44 2019/3/20 - * @Version 1.0 - */ -public class WechatUtil { - public static JSONObject getSessionKeyOrOpenId(String code) { - String requestUrl = "https://api.weixin.qq.com/sns/jscode2session"; - Map requestUrlParam = new HashMap<>(); - // https://mp.weixin.qq.com/wxopen/devprofile?action=get_profile&token=164113089&lang=zh_CN - //小程序appId - requestUrlParam.put("appid", "小程序appId"); - //小程序secret - requestUrlParam.put("secret", "小程序secret"); - //小程序端返回的code - requestUrlParam.put("js_code", code); - //默认参数 - requestUrlParam.put("grant_type", "authorization_code"); - //发送post请求读取调用微信接口获取openid用户唯一标识 - JSONObject jsonObject = JSON.parseObject(HttpClientUtil.doPost(requestUrl, requestUrlParam)); - return jsonObject; - } - - public static JSONObject getUserInfo(String encryptedData, String sessionKey, String iv) { - // 被加密的数据 - byte[] dataByte = Base64.decode(encryptedData); - // 加密秘钥 - byte[] keyByte = Base64.decode(sessionKey); - // 偏移量 - byte[] ivByte = Base64.decode(iv); - try { - // 如果密钥不足16位,那么就补足. 这个if 中的内容很重要 - int base = 16; - if (keyByte.length % base != 0) { - int groups = keyByte.length / base + (keyByte.length % base != 0 ? 1 : 0); - byte[] temp = new byte[groups * base]; - Arrays.fill(temp, (byte) 0); - System.arraycopy(keyByte, 0, temp, 0, keyByte.length); - keyByte = temp; - } - // 初始化 - Security.addProvider(new BouncyCastleProvider()); - Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding", "BC"); - SecretKeySpec spec = new SecretKeySpec(keyByte, "AES"); - AlgorithmParameters parameters = AlgorithmParameters.getInstance("AES"); - parameters.init(new IvParameterSpec(ivByte)); - cipher.init(Cipher.DECRYPT_MODE, spec, parameters);// 初始化 - byte[] resultByte = cipher.doFinal(dataByte); - if (null != resultByte && resultByte.length > 0) { - String result = new String(resultByte, "UTF-8"); - return JSON.parseObject(result); - } - } catch (Exception e) { - } - return null; - } -} - -``` - -## 3.5 mapper - - - -```java -package cn.lastwhisper.springbootwx.mapper; - -import cn.lastwhisper.springbootwx.pojo.User; -import com.baomidou.mybatisplus.core.mapper.BaseMapper; - -/** - * @desc - * - * @author lastwhisper - * @email gaojun56@163.com - */ -public interface UserMapper extends BaseMapper { -} - -``` - -配置SpringBoot扫描mapper - -```java -package cn.lastwhisper.springbootwx; - -import org.mybatis.spring.annotation.MapperScan; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -@MapperScan("cn.lastwhisper.springbootwx.mapper") //设置mapper接口的扫描包 -@SpringBootApplication -public class SpringbootwxApplication { - - public static void main(String[] args) { - SpringApplication.run(SpringbootwxApplication.class, args); - } - -} - -``` - -## 3.6 controller - -用于接收用户请求,校验签名,并生成skey,存储skey、openid等数据 - -```java -package cn.lastwhisper.springbootwx.controller; - -import cn.lastwhisper.springbootwx.common.GlobalResult; -import cn.lastwhisper.springbootwx.mapper.UserMapper; -import cn.lastwhisper.springbootwx.pojo.User; -import cn.lastwhisper.springbootwx.common.WechatUtil; -import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONObject; -import org.apache.commons.codec.digest.DigestUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseBody; - -import java.util.Date; -import java.util.UUID; - -/** - * @author lastwhisper - * @desc - * @email gaojun56@163.com - */ -@Controller -public class UserController { - - @Autowired - private UserMapper userMapper; - - /** - * 微信用户登录详情 - */ - @PostMapping("wx/login") - @ResponseBody - public GlobalResult user_login(@RequestParam(value = "code", required = false) String code, - @RequestParam(value = "rawData", required = false) String rawData, - @RequestParam(value = "signature", required = false) String signature, - @RequestParam(value = "encrypteData", required = false) String encrypteData, - @RequestParam(value = "iv", required = false) String iv) { - // 用户非敏感信息:rawData - // 签名:signature - JSONObject rawDataJson = JSON.parseObject(rawData); - // 1.接收小程序发送的code - // 2.开发者服务器 登录凭证校验接口 appi + appsecret + code - JSONObject SessionKeyOpenId = WechatUtil.getSessionKeyOrOpenId(code); - // 3.接收微信接口服务 获取返回的参数 - String openid = SessionKeyOpenId.getString("openid"); - String sessionKey = SessionKeyOpenId.getString("session_key"); - - // 4.校验签名 小程序发送的签名signature与服务器端生成的签名signature2 = sha1(rawData + sessionKey) - String signature2 = DigestUtils.sha1Hex(rawData + sessionKey); - if (!signature.equals(signature2)) { - return GlobalResult.build(500, "签名校验失败", null); - } - // 5.根据返回的User实体类,判断用户是否是新用户,是的话,将用户信息存到数据库;不是的话,更新最新登录时间 - User user = this.userMapper.selectById(openid); - // uuid生成唯一key,用于维护微信小程序用户与服务端的会话 - String skey = UUID.randomUUID().toString(); - if (user == null) { - // 用户信息入库 - String nickName = rawDataJson.getString("nickName"); - String avatarUrl = rawDataJson.getString("avatarUrl"); - String gender = rawDataJson.getString("gender"); - String city = rawDataJson.getString("city"); - String country = rawDataJson.getString("country"); - String province = rawDataJson.getString("province"); - - user = new User(); - user.setOpenId(openid); - user.setSkey(skey); - user.setCreateTime(new Date()); - user.setLastVisitTime(new Date()); - user.setSessionKey(sessionKey); - user.setCity(city); - user.setProvince(province); - user.setCountry(country); - user.setAvatarUrl(avatarUrl); - user.setGender(Integer.parseInt(gender)); - user.setNickName(nickName); - - this.userMapper.insert(user); - } else { - // 已存在,更新用户登录时间 - user.setLastVisitTime(new Date()); - // 重新设置会话skey - user.setSkey(skey); - this.userMapper.updateById(user); - } - //encrypteData比rowData多了appid和openid - //JSONObject userInfo = WechatUtil.getUserInfo(encrypteData, sessionKey, iv); - //6. 把新的skey返回给小程序 - GlobalResult result = GlobalResult.build(200, null, skey); - return result; - } -} - -``` - - -# 4. 微信小程序 - -项目结构: - -![项目结构](https://upload-images.jianshu.io/upload_images/5336514-5d79f5e8685c1451.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -## 4.1 初始配置 - -![初始配置](https://upload-images.jianshu.io/upload_images/5336514-f3c3d1b092e2bc43.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - - - -## 4.2 me.wxml - -```html - - - - - - - - - -``` - -## 4.3 me.wxss - -无 - -## 4.4 me.json - -```javascript -{ - -} -``` - - - -## 4.5 me.js - -```javascript -// pages/me/me.js -Page({ - - /** - * 页面的初始数据 - */ - data: { - hasUserInfo: false, - userInfo: null - }, - - onLoad: function() { - // 页面加载时使用用户授权逻辑,弹出确认的框 - this.userAuthorized() - }, - - userAuthorized() { - wx.getSetting({ - success: data => { - if (data.authSetting['scope.userInfo']) { - wx.getUserInfo({ - success: data => { - this.setData({ - hasUserInfo: true, - userInfo: data.userInfo - }) - } - }) - } else { - this.setData({ - hasUserInfo: false - }) - } - } - }) - }, - - onGetUserInfo(e) { - const userInfo = e.detail.userInfo - if (userInfo) { - // 1. 小程序通过wx.login()获取code - wx.login({ - success: function(login_res) { - //获取用户信息 - wx.getUserInfo({ - success: function(info_res) { - // 2. 小程序通过wx.request()发送code到开发者服务器 - wx.request({ - url: 'http://localhost:8080/wx/login', - method: 'POST', - header: { - 'content-type': 'application/x-www-form-urlencoded' - }, - data: { - code: login_res.code, //临时登录凭证 - rawData: info_res.rawData, //用户非敏感信息 - signature: info_res.signature, //签名 - encrypteData: info_res.encryptedData, //用户敏感信息 - iv: info_res.iv //解密算法的向量 - }, - success: function(res) { - if (res.data.status == 200) { - // 7.小程序存储skey(自定义登录状态)到本地 - wx.setStorageSync('userInfo', userInfo); - wx.setStorageSync('skey', res.data.data); - } else{ - console.log('服务器异常'); - } - }, - fail: function(error) { - //调用服务端登录接口失败 - console.log(error); - } - }) - } - }) - } - }) - this.setData({ - hasUserInfo: true, - userInfo: userInfo - }) - } - } - -}) -``` - -## 4.6 app.json - -设置app.json的pages - -```javascript -{ - "pages":[ - "pages/me/me" - ], - "window":{ - "backgroundTextStyle":"light", - "navigationBarBackgroundColor": "#fff", - "navigationBarTitleText": "WeChat", - "navigationBarTextStyle":"black" - }, - "debug":true -} -``` - - - -# 5. 测试 - -启动开发者服务器,启动SpringBoot的main方法。 - -打开微信小程序开发者工具 - -![清空缓存](https://upload-images.jianshu.io/upload_images/5336514-6390ebbe06fd2966.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -点击授权登录,并允许。 - -![授权登录](https://upload-images.jianshu.io/upload_images/5336514-f91936c2c2506ac1.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -登录成功 - -![登录成功](https://upload-images.jianshu.io/upload_images/5336514-b2cbb72779e75f98.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -查看数据库,openid、skey以及用户信息等存入了数据库。 - -![用户信息入库](https://upload-images.jianshu.io/upload_images/5336514-640be1be797a4121.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -同时微信小程序将skey等存储到本地,每次发起请求时都可以携带上。 - -![skey存储本地](https://upload-images.jianshu.io/upload_images/5336514-c37c3231a752219c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) \ No newline at end of file diff --git a/springcloud/api-gateway/src/main/resources/bootstrap.yml b/springcloud/api-gateway/src/main/resources/bootstrap.yml deleted file mode 100644 index 8beb9a1c..00000000 --- a/springcloud/api-gateway/src/main/resources/bootstrap.yml +++ /dev/null @@ -1,31 +0,0 @@ -spring: - application: - name: api-gateway - cloud: - config: - discovery: - enabled: true - service-id: CONFIG - profile: dev -eureka: - client: - service-url: - defaultZone: http://localhost:8761/eureka/ -server: - port: 8083 -#1.修改路由映射名(有简洁写法) -#2.忽略某些路由 -zuul: - #全部服务忽略敏感头(全部服务都可以传递cookie) - sensitive-headers: - routes: - # /myProduct/product/list -> /product/product/list - aaaaaa: #这个名字随便写 - path: /myProduct/** - serviceId: product - sensitiveHeaders: #敏感头 - #简洁写法 -# product: /myProduct/** - #排除某些路由 - ignored-patterns: - - /**/product/listForOrder \ No newline at end of file diff --git a/springcloud/config/src/main/resources/application.yml b/springcloud/config/src/main/resources/application.yml deleted file mode 100644 index dfc875c2..00000000 --- a/springcloud/config/src/main/resources/application.yml +++ /dev/null @@ -1,22 +0,0 @@ -spring: - application: - name: config - cloud: - config: - server: - git: - uri: https://gitee.com/ggb2312/config-repo - username: gjgb2312@gmail.com - password: 15037584397.gg - basedir: D:\Temp -eureka: - client: - service-url: - defaultZone: http://localhost:8761/eureka/ -server: - port: 8082 -management: - endpoints: - web: - exposure: - include: "*" \ No newline at end of file diff --git a/springcloud/order/order-server/pom.xml b/springcloud/order/order-server/pom.xml deleted file mode 100644 index 8b46ac9c..00000000 --- a/springcloud/order/order-server/pom.xml +++ /dev/null @@ -1,125 +0,0 @@ - - - - order - cn.lastwhisper - 0.0.1-SNAPSHOT - - 4.0.0 - - order-server - - - - org.springframework.boot - spring-boot-starter-data-jpa - - - org.springframework.boot - spring-boot-starter-web - - - - org.springframework.cloud - spring-cloud-starter-netflix-eureka-client - - - - org.springframework.cloud - spring-cloud-starter-openfeign - - - - org.springframework.cloud - spring-cloud-config-client - - - - org.springframework.boot - spring-boot-starter-amqp - - - - org.springframework.cloud - spring-cloud-starter-stream-rabbit - - - - org.springframework.boot - spring-boot-starter-data-redis - - - - org.springframework.cloud - spring-cloud-starter-netflix-hystrix - - - - - org.springframework.cloud - spring-cloud-starter-netflix-hystrix-dashboard - - - - org.springframework.boot - spring-boot-starter-actuator - - - - - - - - - mysql - mysql-connector-java - runtime - - - - org.projectlombok - lombok - true - - - - org.springframework.boot - spring-boot-starter-test - test - - - org.junit.vintage - junit-vintage-engine - - - - - - com.google.code.gson - gson - 2.8.6 - - - - cn.lastwhisper - product-client - - - - cn.lastwhisper - product-common - - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - \ No newline at end of file diff --git a/springcloud/order/order-server/src/main/java/cn/lastwhisper/order/controller/HystrixController.java b/springcloud/order/order-server/src/main/java/cn/lastwhisper/order/controller/HystrixController.java deleted file mode 100644 index 2549df88..00000000 --- a/springcloud/order/order-server/src/main/java/cn/lastwhisper/order/controller/HystrixController.java +++ /dev/null @@ -1,49 +0,0 @@ -package cn.lastwhisper.order.controller; - -import com.netflix.hystrix.contrib.javanica.annotation.DefaultProperties; -import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; -import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.client.RestTemplate; - -import java.util.Collections; - -/** - * Hystrix学习 - * @author lastwhisper - * @date 2019/11/3 - */ -@RestController -@DefaultProperties(defaultFallback = "defaultFallback") -public class HystrixController { - - @GetMapping("/getProductInfoList") - //@HystrixCommand(fallbackMethod = "fallback") - //@HystrixCommand(commandProperties = { - // @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000") - //}) - @HystrixCommand(commandProperties = { - @HystrixProperty(name = "circuitBreaker.enabled", value = "true"), - @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"), - @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "10000"), - @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "60") - }) - //@HystrixCommand - public String getProductInfoList(@RequestParam("number") Integer number) { - if (number % 2 == 0) { - return "success"; - } - RestTemplate restTemplate = new RestTemplate(); - return restTemplate.postForObject("http://localhost:8080/product/listForOrder", Collections.singletonList("157875227953464068"), String.class); - } - - public String fallback() { - return "服务降级方法"; - } - - public String defaultFallback() { - return "默认服务降级方法"; - } -} diff --git a/springcloud/order/order-server/src/main/java/cn/lastwhisper/order/controller/OrderController.java b/springcloud/order/order-server/src/main/java/cn/lastwhisper/order/controller/OrderController.java deleted file mode 100644 index 767bd620..00000000 --- a/springcloud/order/order-server/src/main/java/cn/lastwhisper/order/controller/OrderController.java +++ /dev/null @@ -1,76 +0,0 @@ -package cn.lastwhisper.order.controller; - -import cn.lastwhisper.order.convert.OrderForm2OrderDTOConvert; -import cn.lastwhisper.order.dto.OrderDTO; -import cn.lastwhisper.order.enums.ResultEnum; -import cn.lastwhisper.order.exception.OrderException; -import cn.lastwhisper.order.form.OrderForm; -import cn.lastwhisper.order.service.OrderService; -import cn.lastwhisper.order.utils.ResultVOUtil; -import cn.lastwhisper.order.vo.ResultVO; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.util.CollectionUtils; -import org.springframework.validation.BindingResult; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -import javax.validation.Valid; -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; - -/** - * 订单 - * @author lastwhisper - * @date 2019/10/26 - */ -@RestController -@RequestMapping("/order") -@Slf4j -public class OrderController { - - @Autowired - private OrderService orderService; - - /** - * 保存主订单以及订单详情 - * 1.参数校验() - * 2.查询商品信息(调用商品服务) - * 3.计算总价 - * 4.扣库存(调用商品服务) - * 5.订单入库 - */ - @PostMapping("/create") - public ResultVO> create(@Valid OrderForm orderForm, - BindingResult bindingResult) { - // 1.参数校验 - if (bindingResult.hasErrors()) { - log.error("[创建订单]参数不正确, orderForm={}", orderForm); - throw new OrderException(ResultEnum.PARAM_ERROR.getCode(), - Objects.requireNonNull(bindingResult.getFieldError()).getDefaultMessage()); - } - OrderDTO orderDTO = OrderForm2OrderDTOConvert.convert(orderForm); - if (CollectionUtils.isEmpty(orderDTO.getOrderDetailList())) { - log.error("[创建订单]购物车商品信息为空"); - throw new OrderException(ResultEnum.CART_EMPTY); - } - - // 2.创建订单 - OrderDTO order = orderService.create(orderDTO); - - Map map = new HashMap<>(); - map.put("orderId", order.getOrderId()); - - return ResultVOUtil.success(map); - - } - - @PostMapping("/finish") - public ResultVO finish(@RequestParam("orderId") String orderId) { - return ResultVOUtil.success(orderService.finish(orderId)); - } - -} diff --git a/springcloud/order/order-server/src/main/java/cn/lastwhisper/order/service/impl/OrderServiceImpl.java b/springcloud/order/order-server/src/main/java/cn/lastwhisper/order/service/impl/OrderServiceImpl.java deleted file mode 100644 index 50418462..00000000 --- a/springcloud/order/order-server/src/main/java/cn/lastwhisper/order/service/impl/OrderServiceImpl.java +++ /dev/null @@ -1,119 +0,0 @@ -package cn.lastwhisper.order.service.impl; - -import cn.lastwhisper.order.domain.OrderDetail; -import cn.lastwhisper.order.domain.OrderMaster; -import cn.lastwhisper.order.dto.OrderDTO; -import cn.lastwhisper.order.enums.OrderStatusEnum; -import cn.lastwhisper.order.enums.PayStatusEnum; -import cn.lastwhisper.order.enums.ResultEnum; -import cn.lastwhisper.order.exception.OrderException; -import cn.lastwhisper.order.repository.OrderDetailRepository; -import cn.lastwhisper.order.repository.OrderMasterRepository; -import cn.lastwhisper.order.service.OrderService; -import cn.lastwhisper.order.utils.KeyUtil; -import cn.lastwhisper.product.client.ProductClient; -import cn.lastwhisper.product.common.DecreaseStockInput; -import cn.lastwhisper.product.common.ProductInfoOutput; -import org.springframework.beans.BeanUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.util.CollectionUtils; - -import javax.transaction.Transactional; -import java.math.BigDecimal; -import java.math.BigInteger; -import java.util.List; -import java.util.Optional; -import java.util.stream.Collectors; - -/** - * - * @author lastwhisper - * @date 2019/10/26 - */ -@Service -public class OrderServiceImpl implements OrderService { - - @Autowired - private OrderMasterRepository orderMasterRepository; - - @Autowired - private OrderDetailRepository orderDetailRepository; - - @Autowired - private ProductClient productClient; - - @Override - @Transactional - public OrderDTO create(OrderDTO orderDTO) { - String orderId = KeyUtil.genUniqueKey(); - - // 参数校验?controller层做 - // 1.查询商品信息(调用商品服务) - List productIdList = orderDTO.getOrderDetailList().stream() - .map(OrderDetail::getProductId).collect(Collectors.toList()); - List productInfoList = productClient.listForOrder(productIdList); - // 2.计算总价 - BigDecimal orderAmount = new BigDecimal(BigInteger.ZERO); - for (OrderDetail orderDetail : orderDTO.getOrderDetailList()) { - for (ProductInfoOutput productInfo : productInfoList) { - if (orderDetail.getProductId().equals(productInfo.getProductId())) { - orderAmount = productInfo.getProductPrice() - .multiply(BigDecimal.valueOf(orderDetail.getProductQuantity())) - .add(orderAmount); - BeanUtils.copyProperties(productInfo, orderDetail); - orderDetail.setOrderId(orderId); - orderDetail.setDetailId(KeyUtil.genUniqueKey()); - // 保存订单详情 - orderDetailRepository.save(orderDetail); - } - } - } - // 3.扣库存(调用商品服务) - List decreaseStockInputList = orderDTO.getOrderDetailList().stream() - .map(o -> new DecreaseStockInput(o.getProductId(), o.getProductQuantity())) - .collect(Collectors.toList()); - productClient.decreaseStock(decreaseStockInputList); - // 4.订单入库 - OrderMaster orderMaster = new OrderMaster(); - orderDTO.setOrderId(orderId); - //相同字段 - BeanUtils.copyProperties(orderDTO, orderMaster); - //不同字段 - orderMaster.setOrderAmount(BigDecimal.valueOf(5499)); - orderMaster.setOrderStatus(OrderStatusEnum.NEW.getCode()); - orderMaster.setPayStatus(PayStatusEnum.WAIT.getCode()); - orderMasterRepository.save(orderMaster); - - return orderDTO; - } - - @Override - @Transactional - public OrderDTO finish(String orderId) { - //1.查询订单 - Optional optionalOrderMaster = orderMasterRepository.findById(orderId); - if (!optionalOrderMaster.isPresent()) { - throw new OrderException(ResultEnum.ORDER_NOT_EXIST); - } - //2.修改订单状态 - OrderMaster orderMaster = optionalOrderMaster.get(); - if(!OrderStatusEnum.NEW.getCode().equals(orderMaster.getOrderStatus())){ - throw new OrderException(ResultEnum.ORDER_STATUS_ERROR); - } - orderMaster.setOrderStatus(OrderStatusEnum.FINISHED.getCode()); - orderMasterRepository.save(orderMaster); - //3.封装OrderDTO - List orderDetailList = orderDetailRepository.findByOrOrderId(orderId); - if (CollectionUtils.isEmpty(orderDetailList)) { - throw new OrderException(ResultEnum.ORDER_DETAIL_NOT_EXIST); - } - - OrderDTO orderDTO = new OrderDTO(); - BeanUtils.copyProperties(orderMaster,orderDTO); - orderDTO.setOrderDetailList(orderDetailList); - - return orderDTO; - } - -} diff --git a/springcloud/order/order-server/src/main/resources/bootstrap.yml b/springcloud/order/order-server/src/main/resources/bootstrap.yml deleted file mode 100644 index 31bed6fb..00000000 --- a/springcloud/order/order-server/src/main/resources/bootstrap.yml +++ /dev/null @@ -1,32 +0,0 @@ -spring: - application: - name: order - cloud: - config: - discovery: - enabled: true - service-id: CONFIG - profile: test -# stream: -# bindings: -# myMessage: -# group: order -# content-type: application/json -eureka: - client: - service-url: - defaultZone: http://localhost:8761/eureka/ -hystrix: - command: - default: - execution: - isolation: - thread: - timeoutInMilliseconds: 1000 - getProductInfoList: - execution: - isolation: - thread: - timeoutInMilliseconds: 1000 -management: - context-path: / \ No newline at end of file diff --git a/springcloud/order/pom.xml b/springcloud/order/pom.xml deleted file mode 100644 index 3b728114..00000000 --- a/springcloud/order/pom.xml +++ /dev/null @@ -1,65 +0,0 @@ - - - - 4.0.0 - pom - - order-common - order-client - order-server - - - cn.lastwhisper - order - 0.0.1-SNAPSHOT - order - 订单服务 - - - org.springframework.boot - spring-boot-starter-parent - 2.0.2.RELEASE - - - - - UTF-8 - UTF-8 - 1.8 - Finchley.RELEASE - 0.0.1-SNAPSHOT - 0.0.1-SNAPSHOT - 0.0.1-SNAPSHOT - - - - - - org.springframework.cloud - spring-cloud-dependencies - ${spring-cloud.version} - pom - import - - - cn.lastwhisper - order-common - ${order-common.version} - - - cn.lastwhisper - product-client - ${product-client.version} - - - - cn.lastwhisper - product-common - ${product-common.version} - - - - - \ No newline at end of file diff --git a/springcloud/pom.xml b/springcloud/pom.xml deleted file mode 100644 index 8d077da7..00000000 --- a/springcloud/pom.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - 4.0.0 - - cn.lastwhisper - springcloud - pom - 1.0-SNAPSHOT - - - - \ No newline at end of file diff --git a/springcloud/product/product-server/pom.xml b/springcloud/product/product-server/pom.xml deleted file mode 100644 index 8e273e73..00000000 --- a/springcloud/product/product-server/pom.xml +++ /dev/null @@ -1,75 +0,0 @@ - - - - product - cn.lastwhisper - 0.0.1-SNAPSHOT - - 4.0.0 - - product-server - - - - org.springframework.boot - spring-boot-starter-data-jpa - - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.cloud - spring-cloud-starter-netflix-eureka-client - - - - org.springframework.cloud - spring-cloud-config-client - - - - org.springframework.boot - spring-boot-starter-amqp - - - - mysql - mysql-connector-java - runtime - - - org.projectlombok - lombok - true - - - org.springframework.boot - spring-boot-starter-test - test - - - org.junit.vintage - junit-vintage-engine - - - - - - product-common - cn.lastwhisper - - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - \ No newline at end of file diff --git a/springcloud/product/product-server/src/main/java/cn/lastwhisper/product/ProductApplication.java b/springcloud/product/product-server/src/main/java/cn/lastwhisper/product/ProductApplication.java deleted file mode 100644 index 9d449844..00000000 --- a/springcloud/product/product-server/src/main/java/cn/lastwhisper/product/ProductApplication.java +++ /dev/null @@ -1,15 +0,0 @@ -package cn.lastwhisper.product; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.cloud.client.discovery.EnableDiscoveryClient; - -@SpringBootApplication -@EnableDiscoveryClient -public class ProductApplication { - - public static void main(String[] args) { - SpringApplication.run(ProductApplication.class, args); - } - -} diff --git a/springcloud/product/product-server/src/main/java/cn/lastwhisper/product/controller/ProductController.java b/springcloud/product/product-server/src/main/java/cn/lastwhisper/product/controller/ProductController.java deleted file mode 100644 index f3a6dfa1..00000000 --- a/springcloud/product/product-server/src/main/java/cn/lastwhisper/product/controller/ProductController.java +++ /dev/null @@ -1,97 +0,0 @@ -package cn.lastwhisper.product.controller; - -import cn.lastwhisper.product.domain.ProductCategory; -import cn.lastwhisper.product.domain.ProductInfo; -import cn.lastwhisper.product.dto.CartDTO; -import cn.lastwhisper.product.service.CategoryService; -import cn.lastwhisper.product.service.ProductService; -import cn.lastwhisper.product.utils.ResultVOUtil; -import cn.lastwhisper.product.vo.ProductInfoVO; -import cn.lastwhisper.product.vo.ProductVO; -import cn.lastwhisper.product.vo.ResultVO; -import org.springframework.beans.BeanUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Collectors; - -/** - * - * @author lastwhisper - * @date 2019/10/24 - */ -@RestController -@RequestMapping("product") -public class ProductController { - - @Autowired - private ProductService productService; - - @Autowired - private CategoryService categoryService; - - /** - * 1. 查询所有在架的商品列表 - * 2. 获取类目type列表 - * 3. 根据type列表查询类目列表 - * 4. 根据接口json数据格式构造数据 - */ - @RequestMapping("/list") - public ResultVO list() { - //1. 查询所有在架的商品列表 - List productInfoList = productService.findUpAll(); - //2. 获取类目type列表 - List categoryTypeList = productInfoList.stream() - .map(ProductInfo::getCategoryType) - .collect(Collectors.toList()); - //3. 根据type列表查询类目列表 - List productCategoryList = categoryService.findByCategoryTypeIn(categoryTypeList); - //4. 根据接口json数据格式构造数据 - // 4.1 第一层:category list - List productVOList = new ArrayList<>(); - for (ProductCategory productCategory : productCategoryList) { - ProductVO productVO = new ProductVO(); - productVO.setCategoryName(productCategory.getCategoryName()); - productVO.setCategoryType(productCategory.getCategoryType()); - // 4.2 第二层:product list - List productInfoVOList = new ArrayList(); - for (ProductInfo productInfo : productInfoList) { - // 只有当类目相同时才将类目下的商品挂载到该类目下 - if (productCategory.getCategoryType().equals(productInfo.getCategoryType())) { - ProductInfoVO productInfoVO = new ProductInfoVO(); - BeanUtils.copyProperties(productInfo, productInfoVO); - productInfoVOList.add(productInfoVO); - } - } - productVO.setProductInfoVOList(productInfoVOList); - productVOList.add(productVO); - } - // 4.3 最外层 - //ResultVO> resultVO = new ResultVO<>(); - //resultVO.setCode(0); - //resultVO.setMsg("成功"); - //resultVO.setData(productVOList); - - return ResultVOUtil.success(productVOList); - } - - @PostMapping("/listForOrder") - public List listForOrder(@RequestBody List productIdList) { - try { - Thread.sleep(2000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - return productService.findList(productIdList); - } - - @PostMapping("/decreaseStock") - public void decreaseStock(@RequestBody List cartDTOList) { - productService.decreaseStock(cartDTOList); - } -} diff --git a/springcloud/product/product-server/src/main/resources/bootstrap.yml b/springcloud/product/product-server/src/main/resources/bootstrap.yml deleted file mode 100644 index 0770ea72..00000000 --- a/springcloud/product/product-server/src/main/resources/bootstrap.yml +++ /dev/null @@ -1,13 +0,0 @@ -spring: - application: - name: product - cloud: - config: - discovery: - enabled: true - service-id: CONFIG - profile: dev -eureka: - client: - service-url: - defaultZone: http://localhost:8761/eureka/ \ No newline at end of file diff --git a/springcloud/readme.txt b/springcloud/readme.txt deleted file mode 100644 index 90f4034a..00000000 --- a/springcloud/readme.txt +++ /dev/null @@ -1,22 +0,0 @@ -1、为什么需要DTO(Data Transfer Object),以OrderDTO为例。 -由于接口的入参涉及到OrderDetail、OrderMaster,而OrderMaster与OrderDetail可能有一对多的关系, -所以需要一个DTO封装OrderDetail与OrderMaster的数据,作为Controller与Service的中转。 -2、为什么需要VO? -(1)实体类与页面需要的数据很大程度不一致,需要封装VO数据进行返回 -(2)安全性 -3、为什么需要form? -接收接口入参,from转dto做不同级别的参数校验。 -参数校验级别分为: - (1)from入参json串不为空 - (2)from转dto时OrderDTO -4、为什么需要enum? -将一些表中的状态,比如订单(支付、未支付、等待支付)状态进行枚举表示,统一管理 - -https://www.cnblogs.com/qixuejia/p/4390086.html - - -一、项目:领域模型、vo、dto、po、domain、form、enums、utils -二、spring测试:继承 -三、日志:log4j、sfl4j、logback等日志区别,以及作用 -四、valid、json转换的使用 -五、常量,枚举的使用场景 diff --git a/tool/pom.xml b/tool/pom.xml new file mode 100644 index 00000000..adc9b361 --- /dev/null +++ b/tool/pom.xml @@ -0,0 +1,28 @@ + + + 4.0.0 + + cn.cunchang + tool + 1.0-SNAPSHOT + + + + + net.java.dev.jna + jna-platform + 5.5.0 + + + + junit + junit + 4.12 + + + + + + \ No newline at end of file diff --git a/tool/src/main/java/cn/cunchang/DeleteFile.java b/tool/src/main/java/cn/cunchang/DeleteFile.java new file mode 100644 index 00000000..94a55139 --- /dev/null +++ b/tool/src/main/java/cn/cunchang/DeleteFile.java @@ -0,0 +1,165 @@ +package cn.cunchang; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Properties; + +/** + * 删除指定文件夹下的 + * + * @author cunchang + * @date 2019/11/22 + */ +public class DeleteFile { + + /** + * 可能的值: + * /Users/cunchang/code/GitRepository + */ + private static HashSet targetDirs; + + /** + * 可能的值: + * .idea + * bin + */ + private static HashSet deleteDirs; + + /** + * 可能的值: + * .war + * .iml + * .jar + */ + private static HashSet deleteFiles; + + private static long count; + + public static void main(String[] args) throws IOException { + init(args); + check(); + delete(); + after(); +// File file = new File("/Users/cunchang/workspace/java/pdf-mark/target/classes/cn/cunchang/itext/test2/ReplaceRegion.class"); +// System.out.println(file.delete()); + } + + private static void init(String[] args) throws IOException { + targetDirs = new HashSet<>(); + deleteDirs = new HashSet<>(); + deleteFiles = new HashSet<>(); + + String configPath = "/config.properties"; + + if (args != null && args.length > 0) { + configPath = args[0]; + } + InputStream inputStream = DeleteFile.class.getResourceAsStream(configPath); + + Properties prop = new Properties(); + prop.load(inputStream); + + String targetDirsStr = prop.getProperty("targetDirs"); + String deleteDirsStr = prop.getProperty("deleteDirs"); + String deleteFilesStr = prop.getProperty("deleteFiles"); + String[] targetDirArr = targetDirsStr.split(";"); + String[] deleteDirsArr = deleteDirsStr.split(";"); + String[] deleteFilesArr = deleteFilesStr.split(";"); + System.out.println("targetDirs:" + Arrays.toString(targetDirArr)); + System.out.println("deleteDirs:" + Arrays.toString(deleteDirsArr)); + System.out.println("deleteFiles:" + Arrays.toString(deleteFilesArr)); + targetDirs.addAll(Arrays.asList(targetDirArr)); + deleteDirs.addAll(Arrays.asList(deleteDirsArr)); + deleteFiles.addAll(Arrays.asList(deleteFilesArr)); + } + + private static void check() { + if (targetDirs.isEmpty()) { + throw new IllegalArgumentException("targetDirs not empty"); + } + if (deleteDirs.isEmpty()) { + throw new IllegalArgumentException("deleteDirs not empty"); + } + if (deleteFiles.isEmpty()) { + throw new IllegalArgumentException("deleteFiles not empty"); + } + } + + private static void after() { + System.out.println("delete count:" + count); + } + + private static void delete() { + for (String targetDir : targetDirs) { + System.out.println("DeleteFile run,target==>" + targetDir); + recursionDelDir(new File(targetDir)); + } + } + + + /** + * 递归找到deleteDirs目录和deleteFiles文件 + * deleteDirs目录递归删除其下所有文件 + * deleteFiles文件直接删除 + */ + public static void recursionDelDir(File file) { + File[] subFiles = file.listFiles(); + if (subFiles == null||subFiles.length == 0) { + return; + } + for (File subFile : subFiles) { + if (subFile.isDirectory()) { + // 删除指定文件夹 + if (deleteDirs.contains(subFile.getName())) { + recursionDelFile(subFile); + } + } else { + // 删除指定后缀文件 + String fileName = subFile.getName(); + int lastIndex = fileName.lastIndexOf("."); + if (lastIndex == -1) { + System.out.println("跳过文件==>" +subFile.getAbsolutePath()); + continue; + } + fileName = fileName.substring(0, lastIndex); + if (deleteFiles.contains(fileName)) { + boolean deleteFlag = subFile.delete(); + System.out.println("delete file==>" + subFile.getAbsolutePath() + " :" + (deleteFlag ? "成功" : "失败")); + count++; + } + } + recursionDelDir(subFile); + } + } + + + /** + * 递归删除file目录下的文件 + */ + public static void recursionDelFile(File file) { + if (file == null) { + return; + } + File[] subFiles = file.listFiles(); + if (subFiles == null) { + return; + } + for (File subFile : subFiles) { + if (subFile.isDirectory()) { + recursionDelFile(subFile); + } else { + boolean deleteFlag = subFile.delete(); + System.out.println("delete file==>" + subFile.getAbsolutePath() + " :" + (deleteFlag ? "成功" : "失败")); + count++; + } + } + // 子目录都删除了,删除当前目录 + boolean deleteFlag = file.delete(); + System.out.println("delete dir==>" + file.getAbsolutePath() + " :" + (deleteFlag ? "成功" : "失败")); + count++; + } + +} diff --git a/tool/src/main/java/cn/cunchang/DeleteFileToTrash.java b/tool/src/main/java/cn/cunchang/DeleteFileToTrash.java new file mode 100644 index 00000000..9cf82a25 --- /dev/null +++ b/tool/src/main/java/cn/cunchang/DeleteFileToTrash.java @@ -0,0 +1,32 @@ +package cn.cunchang; + +import com.sun.jna.platform.FileUtils; +import com.sun.jna.platform.win32.W32FileUtils; + +import java.io.File; +import java.io.IOException; + +/** + * 删除指定文件夹 + * + * @author cunchang + * @date 2020/03/15 + */ +public class DeleteFileToTrash { + + // https://blog.csdn.net/Felix_Dreammaker/article/details/79180471 + public static void main(String[] args) { + + FileUtils fileUtils = W32FileUtils.getInstance(); + boolean flag = fileUtils.hasTrash(); + if (flag) { + try { + fileUtils.moveToTrash(new File[]{new File("C:\\Users\\Administrator\\Desktop\\xxxxx.bmp")}); + } catch (IOException e) { + e.printStackTrace(); + } + } + + } + +} diff --git a/tool/src/main/java/cn/cunchang/KillServer.java b/tool/src/main/java/cn/cunchang/KillServer.java new file mode 100644 index 00000000..251ea2b5 --- /dev/null +++ b/tool/src/main/java/cn/cunchang/KillServer.java @@ -0,0 +1,170 @@ +package cn.cunchang; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class KillServer { + private Set ports; + + // java KillServer 8080 8081 8082 8083 + public static void main(String[] args) throws InterruptedException { + // String os = System.getProperty("os.name"); + System.out.println("请输入要杀掉的" + System.getProperty("os.name") + "进程的端口号,如果有多个,则以空格相隔"); + System.out.println("Please input kill port"); + + Set ports = new HashSet<>(); + for (String port : args) { + try { + ports.add(Integer.parseInt(port)); + } catch (Exception e) { + System.out.println("错误的端口号,请输入一个或者多个端口,以英文逗号隔开"); + try { + Thread.sleep(5000); + } catch (InterruptedException e1) { + e1.printStackTrace(); + } + System.exit(0); + } + } + + KillServer kill = new KillServer(); + kill.ports = ports; + System.out.println("need kill " + ports.size() + " num"); + for (Integer pid : ports) { + kill.start(pid); + } + System.out.println("清理完毕,程序即将退出"); + System.out.println("SUCCESS"); + Thread.sleep(5000); + System.exit(0); + + } + + public void start(int port) { + Runtime runtime = Runtime.getRuntime(); + try { + //查找进程号 + Process p = runtime.exec("cmd /c netstat -ano | findstr \"" + port + "\""); + InputStream inputStream = p.getInputStream(); + List read = read(inputStream, StandardCharsets.UTF_8); + if (read.size() == 0) { + System.out.println("找不到该端口的进程"); + try { + Thread.sleep(6000); + System.exit(0); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } else { + for (String string : read) { + System.out.println(string); + } + System.out.println("找到" + read.size() + "个进程,正在准备清理"); + kill(read); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * 验证此行是否为指定的端口,因为 findstr命令会是把包含的找出来,例如查找80端口,但是会把8099查找出来 + * @param str + * @return + */ + private boolean validPort(String str) { + Pattern pattern = Pattern.compile("^ *[a-zA-Z]+ +\\S+"); + Matcher matcher = pattern.matcher(str); + + matcher.find(); + String find = matcher.group(); + int spstart = find.lastIndexOf(":"); + find = find.substring(spstart + 1); + + int port = 0; + try { + port = Integer.parseInt(find); + } catch (NumberFormatException e) { + System.out.println("查找到错误的端口:" + find); + return false; + } + if (this.ports.contains(port)) { + return true; + } else { + return false; + } + } + + /** + * 更换为一个Set,去掉重复的pid值 + * @param data + */ + public void kill(List data) { + Set pids = new HashSet<>(); + for (String line : data) { + int offset = line.lastIndexOf(" "); + String spid = line.substring(offset); + spid = spid.replaceAll(" ", ""); + int pid = 0; + try { + pid = Integer.parseInt(spid); + } catch (NumberFormatException e) { + System.out.println("获取的进程号错误:" + spid); + } + pids.add(pid); + } + killWithPid(pids); + } + + /** + * 一次性杀除所有的端口 + * @param pids + */ + public void killWithPid(Set pids) { + for (Integer pid : pids) { + try { + Process process = Runtime.getRuntime().exec("taskkill /F /pid " + pid + ""); + InputStream inputStream = process.getInputStream(); + String txt = readTxt(inputStream, "GBK"); + System.out.println(txt); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + private List read(InputStream in, Charset charset) throws IOException { + List data = new ArrayList<>(); + BufferedReader reader = new BufferedReader(new InputStreamReader(in, charset)); + String line; + while ((line = reader.readLine()) != null) { + boolean validPort = validPort(line); + if (validPort) { + data.add(line); + } + } + reader.close(); + return data; + } + + public String readTxt(InputStream in, String charset) throws IOException { + BufferedReader reader = new BufferedReader(new InputStreamReader(in, charset)); + StringBuilder sb = new StringBuilder(); + String line; + while ((line = reader.readLine()) != null) { + sb.append(line); + } + reader.close(); + return sb.toString(); + } +} \ No newline at end of file diff --git a/tool/src/main/resources/config.properties b/tool/src/main/resources/config.properties new file mode 100644 index 00000000..437a46ac --- /dev/null +++ b/tool/src/main/resources/config.properties @@ -0,0 +1,3 @@ +targetDirs=/Users/cunchang/workspace +deleteDirs=.idea;target;out +deleteFiles=.iml